From c7673096c9b3d01daf8f57638449bc534232214d Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 31 Mar 2016 12:18:44 +0400 Subject: [PATCH 01/14] deployment targets set to 10.8, QtCreator build instructions fixed openssl libraries --- Telegram/MetaStyle.xcodeproj/project.pbxproj | 4 ++-- Telegram/Updater.xcodeproj/project.pbxproj | 4 ++-- doc/building-qtcreator.md | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Telegram/MetaStyle.xcodeproj/project.pbxproj b/Telegram/MetaStyle.xcodeproj/project.pbxproj index 62abc68a2..6d7546ca2 100644 --- a/Telegram/MetaStyle.xcodeproj/project.pbxproj +++ b/Telegram/MetaStyle.xcodeproj/project.pbxproj @@ -636,7 +636,7 @@ "/usr/local/Qt-5.5.1/plugins/platforms", "/usr/local/Qt-5.5.1/plugins/imageformats", ); - MACOSX_DEPLOYMENT_TARGET = 10.7; + MACOSX_DEPLOYMENT_TARGET = 10.8; OBJROOT = ./../Mac/ReleaseIntermediateStyle; OTHER_CFLAGS = ( "-pipe", @@ -727,7 +727,7 @@ "/usr/local/Qt-5.5.1/plugins/platforms", "/usr/local/Qt-5.5.1/plugins/imageformats", ); - MACOSX_DEPLOYMENT_TARGET = 10.7; + MACOSX_DEPLOYMENT_TARGET = 10.8; OBJROOT = ./../Mac/DebugIntermediateStyle; ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = ( diff --git a/Telegram/Updater.xcodeproj/project.pbxproj b/Telegram/Updater.xcodeproj/project.pbxproj index 16e968a96..554e659ec 100644 --- a/Telegram/Updater.xcodeproj/project.pbxproj +++ b/Telegram/Updater.xcodeproj/project.pbxproj @@ -153,7 +153,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.7; + MACOSX_DEPLOYMENT_TARGET = 10.8; OBJROOT = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)IntermediateUpdater"; ONLY_ACTIVE_ARCH = YES; OTHER_CFLAGS = "-D_DEBUG"; @@ -191,7 +191,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.7; + MACOSX_DEPLOYMENT_TARGET = 10.8; OBJROOT = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)IntermediateUpdater"; SDKROOT = macosx; SYMROOT = ../Mac; diff --git a/doc/building-qtcreator.md b/doc/building-qtcreator.md index 30b93ab9c..fd8c7dee3 100644 --- a/doc/building-qtcreator.md +++ b/doc/building-qtcreator.md @@ -147,7 +147,7 @@ Install some packages for Qt (see **/home/user/TBuild/Libraries/QtStatic/qtbase/ In Terminal go to **/home/user/TBuild/Libraries/QtStatic** and there run - OPENSSL_LIBS='/usr/local/ssl/lib/libssl.a /usr/local/ssl/lib/libcrypto.a' ./configure -release -force-debug-info -opensource -confirm-license -qt-zlib -qt-libpng -qt-libjpeg -qt-freetype -qt-harfbuzz -qt-pcre -qt-xcb -qt-xkbcommon-x11 -no-opengl -static -openssl-linked -nomake examples -nomake tests + OPENSSL_LIBS='-L/usr/local/ssl/lib -lssl -lcrypto' ./configure -release -force-debug-info -opensource -confirm-license -qt-zlib -qt-libpng -qt-libjpeg -qt-freetype -qt-harfbuzz -qt-pcre -qt-xcb -qt-xkbcommon-x11 -no-opengl -static -openssl-linked -nomake examples -nomake tests make -j4 sudo make -j4 install From 5a3fea05acbc65196da4a122f62101cdc945532a Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 13 Apr 2016 00:31:28 +0300 Subject: [PATCH 02/14] ClickHandler, TopBarWidget and Overview layouts moved to separate files. Xcode and QtCreator builds are currently broken. --- Telegram/SourceFiles/apiwrap.cpp | 2 +- Telegram/SourceFiles/app.cpp | 26 +- Telegram/SourceFiles/app.h | 6 +- Telegram/SourceFiles/application.cpp | 6 +- Telegram/SourceFiles/application.h | 6 +- Telegram/SourceFiles/audio.h | 2 +- Telegram/SourceFiles/boxes/aboutbox.cpp | 2 +- Telegram/SourceFiles/boxes/abstractbox.cpp | 2 +- Telegram/SourceFiles/boxes/addcontactbox.cpp | 3 +- Telegram/SourceFiles/boxes/autolockbox.cpp | 2 +- Telegram/SourceFiles/boxes/backgroundbox.cpp | 2 +- Telegram/SourceFiles/boxes/confirmbox.cpp | 5 +- Telegram/SourceFiles/boxes/connectionbox.cpp | 2 +- Telegram/SourceFiles/boxes/contactsbox.cpp | 3 +- Telegram/SourceFiles/boxes/emojibox.cpp | 2 +- Telegram/SourceFiles/boxes/languagebox.cpp | 2 +- Telegram/SourceFiles/boxes/passcodebox.cpp | 2 +- Telegram/SourceFiles/boxes/sessionsbox.cpp | 2 +- Telegram/SourceFiles/boxes/stickersetbox.cpp | 4 +- Telegram/SourceFiles/boxes/usernamebox.cpp | 2 +- .../SourceFiles/{ => core}/basic_types.cpp | 0 Telegram/SourceFiles/{ => core}/basic_types.h | 0 Telegram/SourceFiles/core/click_handler.cpp | 63 + Telegram/SourceFiles/core/click_handler.h | 157 ++ .../SourceFiles/core/click_handler_types.cpp | 133 ++ .../SourceFiles/core/click_handler_types.h | 181 +++ Telegram/SourceFiles/dialogswidget.cpp | 3 +- Telegram/SourceFiles/dropdown.cpp | 2 +- Telegram/SourceFiles/facades.cpp | 29 +- Telegram/SourceFiles/history.cpp | 6 +- Telegram/SourceFiles/history.h | 13 +- Telegram/SourceFiles/history/history_common.h | 28 + Telegram/SourceFiles/historywidget.cpp | 14 +- Telegram/SourceFiles/historywidget.h | 9 +- .../inline_bot_layout_internal.cpp | 1 + .../inline_bots/inline_bot_layout_item.cpp | 1 + .../inline_bots/inline_bot_result.h | 2 +- .../inline_bots/inline_bot_send_data.h | 2 +- Telegram/SourceFiles/intro/introwidget.cpp | 2 +- Telegram/SourceFiles/layerwidget.cpp | 2 +- Telegram/SourceFiles/layout.cpp | 1107 +------------- Telegram/SourceFiles/layout.h | 313 +--- Telegram/SourceFiles/localimageloader.cpp | 2 +- Telegram/SourceFiles/localstorage.cpp | 5 +- Telegram/SourceFiles/localstorage.h | 2 +- Telegram/SourceFiles/mainwidget.cpp | 1293 ++++++----------- Telegram/SourceFiles/mainwidget.h | 133 +- .../{window.cpp => mainwindow.cpp} | 222 +-- .../SourceFiles/{window.h => mainwindow.h} | 6 +- Telegram/SourceFiles/mediaview.cpp | 2 +- Telegram/SourceFiles/mtproto/core_types.h | 2 +- .../SourceFiles/mtproto/file_download.cpp | 2 +- .../SourceFiles/overview/overview_layout.cpp | 1143 +++++++++++++++ .../SourceFiles/overview/overview_layout.h | 337 +++++ Telegram/SourceFiles/overviewwidget.cpp | 75 +- Telegram/SourceFiles/overviewwidget.h | 22 +- Telegram/SourceFiles/passcodewidget.cpp | 2 +- Telegram/SourceFiles/playerwidget.cpp | 2 +- Telegram/SourceFiles/profilewidget.cpp | 4 +- Telegram/SourceFiles/pspecific_linux.cpp | 2 +- Telegram/SourceFiles/pspecific_mac.cpp | 2 +- Telegram/SourceFiles/pspecific_mac_p.mm | 2 +- Telegram/SourceFiles/pspecific_win.cpp | 2 +- Telegram/SourceFiles/pspecific_winrt.cpp | 2 +- Telegram/SourceFiles/settingswidget.cpp | 17 +- Telegram/SourceFiles/settingswidget.h | 4 +- Telegram/SourceFiles/shortcuts.cpp | 12 +- Telegram/SourceFiles/stdafx.h | 2 +- Telegram/SourceFiles/structs.cpp | 5 +- Telegram/SourceFiles/structs.h | 60 + Telegram/SourceFiles/sysbuttons.cpp | 12 +- Telegram/SourceFiles/sysbuttons.h | 26 +- Telegram/SourceFiles/title.cpp | 4 +- Telegram/SourceFiles/title.h | 6 +- Telegram/SourceFiles/ui/animation.cpp | 2 +- Telegram/SourceFiles/ui/animation.h | 2 +- .../ui/buttons/peer_avatar_button.cpp | 6 + .../ui/buttons/peer_avatar_button.h | 7 +- Telegram/SourceFiles/ui/flatinput.cpp | 2 +- Telegram/SourceFiles/ui/flattextarea.cpp | 2 +- Telegram/SourceFiles/ui/text.cpp | 156 +- Telegram/SourceFiles/ui/text.h | 344 +---- Telegram/SourceFiles/ui/toast/toast.cpp | 11 +- Telegram/SourceFiles/ui/toast/toast.h | 4 +- .../SourceFiles/ui/toast/toast_manager.cpp | 25 +- Telegram/SourceFiles/ui/toast/toast_manager.h | 6 +- Telegram/SourceFiles/ui/twidget.cpp | 2 +- Telegram/SourceFiles/ui/twidget.h | 50 +- .../SourceFiles/window/top_bar_widget.cpp | 393 +++++ Telegram/SourceFiles/window/top_bar_widget.h | 114 ++ Telegram/Telegram.vcxproj | 90 +- Telegram/Telegram.vcxproj.filters | 108 +- Telegram/Telegram.xcodeproj/project.pbxproj | 24 +- Telegram/Telegram.xcodeproj/qt_preprocess.mak | 74 +- 94 files changed, 3706 insertions(+), 3279 deletions(-) rename Telegram/SourceFiles/{ => core}/basic_types.cpp (100%) rename Telegram/SourceFiles/{ => core}/basic_types.h (100%) create mode 100644 Telegram/SourceFiles/core/click_handler.cpp create mode 100644 Telegram/SourceFiles/core/click_handler.h create mode 100644 Telegram/SourceFiles/core/click_handler_types.cpp create mode 100644 Telegram/SourceFiles/core/click_handler_types.h create mode 100644 Telegram/SourceFiles/history/history_common.h rename Telegram/SourceFiles/{window.cpp => mainwindow.cpp} (94%) rename Telegram/SourceFiles/{window.h => mainwindow.h} (99%) create mode 100644 Telegram/SourceFiles/overview/overview_layout.cpp create mode 100644 Telegram/SourceFiles/overview/overview_layout.h create mode 100644 Telegram/SourceFiles/window/top_bar_widget.cpp create mode 100644 Telegram/SourceFiles/window/top_bar_widget.h diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 83596d4e7..62adaec33 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "lang.h" #include "application.h" -#include "window.h" +#include "mainwindow.h" #include "mainwidget.h" #include "apiwrap.h" diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index 6d11b479b..c227c243b 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -31,7 +31,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include #endif #include "localstorage.h" - +#include "apiwrap.h" #include "numbers.h" namespace { @@ -146,23 +146,29 @@ namespace App { return AppClass::app(); } - Window *wnd() { + MainWindow *wnd() { return AppClass::wnd(); } MainWidget *main() { - Window *w(wnd()); - return w ? w->mainWidget() : 0; + if (auto w = wnd()) { + return w->mainWidget(); + } + return nullptr; } SettingsWidget *settings() { - Window *w(wnd()); - return w ? w->settingsWidget() : 0; + if (auto w = wnd()) { + return w->settingsWidget(); + } + return nullptr; } bool passcoded() { - Window *w(wnd()); - return w ? w->passcodeWidget() : 0; + if (auto w = wnd()) { + return w->passcodeWidget(); + } + return false; } FileUploader *uploader() { @@ -181,7 +187,7 @@ namespace { if (audioPlayer()) { audioPlayer()->stopAndClear(); } - if (Window *w = wnd()) { + if (auto w = wnd()) { w->tempDirDelete(Local::ClearManagerAll); w->notifyClearFast(); w->setupIntro(true); @@ -196,7 +202,7 @@ namespace { globalNotifyChatsPtr = UnknownNotifySettings; if (App::uploader()) App::uploader()->clear(); clearStorageImages(); - if (Window *w = wnd()) { + if (auto w = wnd()) { w->getTitle()->updateBackButton(); w->updateTitleStatus(); w->getTitle()->resizeEvent(0); diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h index 3b53eb061..4e437b71b 100644 --- a/Telegram/SourceFiles/app.h +++ b/Telegram/SourceFiles/app.h @@ -20,10 +20,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #pragma once -#include "basic_types.h" +#include "core/basic_types.h" class AppClass; -class Window; +class MainWindow; class MainWidget; class SettingsWidget; class ApiWrap; @@ -48,7 +48,7 @@ class LayeredWidget; namespace App { AppClass *app(); - Window *wnd(); + MainWindow *wnd(); MainWidget *main(); SettingsWidget *settings(); bool passcoded(); diff --git a/Telegram/SourceFiles/application.cpp b/Telegram/SourceFiles/application.cpp index a011db893..a5d4a7334 100644 --- a/Telegram/SourceFiles/application.cpp +++ b/Telegram/SourceFiles/application.cpp @@ -718,7 +718,7 @@ AppClass::AppClass() : QObject() QMimeDatabase().mimeTypeForName(qsl("text/plain")); // create mime database - _window = new Window(); + _window = new MainWindow(); _window->createWinId(); _window->init(); @@ -1053,7 +1053,7 @@ void AppClass::checkMapVersion() { AppClass::~AppClass() { Shortcuts::finish(); - if (Window *w = _window) { + if (auto w = _window) { _window = 0; delete w; } @@ -1086,7 +1086,7 @@ AppClass *AppClass::app() { return AppObject; } -Window *AppClass::wnd() { +MainWindow *AppClass::wnd() { return AppObject ? AppObject->_window : 0; } diff --git a/Telegram/SourceFiles/application.h b/Telegram/SourceFiles/application.h index ae51569e8..774ebc85b 100644 --- a/Telegram/SourceFiles/application.h +++ b/Telegram/SourceFiles/application.h @@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #pragma once -#include "window.h" +#include "mainwindow.h" #include "pspecific.h" class UpdateChecker; @@ -153,7 +153,7 @@ public: ~AppClass(); static AppClass *app(); - static Window *wnd(); + static MainWindow *wnd(); static MainWidget *main(); FileUploader *uploader(); @@ -212,7 +212,7 @@ private: uint64 _lastActionTime; - Window *_window; + MainWindow *_window; FileUploader *_uploader; Translator *_translator; diff --git a/Telegram/SourceFiles/audio.h b/Telegram/SourceFiles/audio.h index 4eb75c88d..17bbf8cf0 100644 --- a/Telegram/SourceFiles/audio.h +++ b/Telegram/SourceFiles/audio.h @@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #pragma once -#include "basic_types.h" +#include "core/basic_types.h" void audioInit(); bool audioWorks(); diff --git a/Telegram/SourceFiles/boxes/aboutbox.cpp b/Telegram/SourceFiles/boxes/aboutbox.cpp index da41b067e..083d6b650 100644 --- a/Telegram/SourceFiles/boxes/aboutbox.cpp +++ b/Telegram/SourceFiles/boxes/aboutbox.cpp @@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "aboutbox.h" #include "mainwidget.h" -#include "window.h" +#include "mainwindow.h" #include "autoupdater.h" #include "boxes/confirmbox.h" diff --git a/Telegram/SourceFiles/boxes/abstractbox.cpp b/Telegram/SourceFiles/boxes/abstractbox.cpp index e9d1783ad..f721c6b57 100644 --- a/Telegram/SourceFiles/boxes/abstractbox.cpp +++ b/Telegram/SourceFiles/boxes/abstractbox.cpp @@ -25,7 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "abstractbox.h" #include "mainwidget.h" -#include "window.h" +#include "mainwindow.h" void BlueTitleShadow::paintEvent(QPaintEvent *e) { Painter p(this); diff --git a/Telegram/SourceFiles/boxes/addcontactbox.cpp b/Telegram/SourceFiles/boxes/addcontactbox.cpp index 7e58787bc..444742a81 100644 --- a/Telegram/SourceFiles/boxes/addcontactbox.cpp +++ b/Telegram/SourceFiles/boxes/addcontactbox.cpp @@ -28,7 +28,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "photocropbox.h" #include "ui/filedialog.h" #include "mainwidget.h" -#include "window.h" +#include "mainwindow.h" +#include "apiwrap.h" AddContactBox::AddContactBox(QString fname, QString lname, QString phone) : AbstractBox(st::boxWidth) , _user(0) diff --git a/Telegram/SourceFiles/boxes/autolockbox.cpp b/Telegram/SourceFiles/boxes/autolockbox.cpp index 3af3b2615..a755697ca 100644 --- a/Telegram/SourceFiles/boxes/autolockbox.cpp +++ b/Telegram/SourceFiles/boxes/autolockbox.cpp @@ -26,7 +26,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "autolockbox.h" #include "confirmbox.h" #include "mainwidget.h" -#include "window.h" +#include "mainwindow.h" AutoLockBox::AutoLockBox() : _close(this, lang(lng_box_ok), st::defaultBoxButton) { diff --git a/Telegram/SourceFiles/boxes/backgroundbox.cpp b/Telegram/SourceFiles/boxes/backgroundbox.cpp index edb6a2bd9..ddbdf4a39 100644 --- a/Telegram/SourceFiles/boxes/backgroundbox.cpp +++ b/Telegram/SourceFiles/boxes/backgroundbox.cpp @@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "backgroundbox.h" #include "mainwidget.h" -#include "window.h" +#include "mainwindow.h" #include "settingswidget.h" BackgroundInner::BackgroundInner() : diff --git a/Telegram/SourceFiles/boxes/confirmbox.cpp b/Telegram/SourceFiles/boxes/confirmbox.cpp index b836cbbb7..3f3f73edc 100644 --- a/Telegram/SourceFiles/boxes/confirmbox.cpp +++ b/Telegram/SourceFiles/boxes/confirmbox.cpp @@ -23,9 +23,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "confirmbox.h" #include "mainwidget.h" -#include "window.h" - +#include "mainwindow.h" +#include "apiwrap.h" #include "application.h" +#include "core/click_handler_types.h" TextParseOptions _confirmBoxTextOptions = { TextParseLinks | TextParseMultiline | TextParseRichText, // flags diff --git a/Telegram/SourceFiles/boxes/connectionbox.cpp b/Telegram/SourceFiles/boxes/connectionbox.cpp index c9d65c3bb..8f2fc96b0 100644 --- a/Telegram/SourceFiles/boxes/connectionbox.cpp +++ b/Telegram/SourceFiles/boxes/connectionbox.cpp @@ -25,7 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "connectionbox.h" #include "mainwidget.h" -#include "window.h" +#include "mainwindow.h" ConnectionBox::ConnectionBox() : AbstractBox(st::boxWidth) , _hostInput(this, st::connectionHostInputField, lang(lng_connection_host_ph), cConnectionProxy().host) diff --git a/Telegram/SourceFiles/boxes/contactsbox.cpp b/Telegram/SourceFiles/boxes/contactsbox.cpp index da166de86..326c94bef 100644 --- a/Telegram/SourceFiles/boxes/contactsbox.cpp +++ b/Telegram/SourceFiles/boxes/contactsbox.cpp @@ -26,11 +26,12 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "boxes/addcontactbox.h" #include "boxes/contactsbox.h" #include "mainwidget.h" -#include "window.h" +#include "mainwindow.h" #include "application.h" #include "ui/filedialog.h" #include "boxes/photocropbox.h" #include "boxes/confirmbox.h" +#include "apiwrap.h" QString cantInviteError() { return lng_cant_invite_not_contact(lt_more_info, textcmdLink(qsl("https://telegram.me/spambot"), lang(lng_cant_more_info))); diff --git a/Telegram/SourceFiles/boxes/emojibox.cpp b/Telegram/SourceFiles/boxes/emojibox.cpp index 9bd637bed..9aca04bc0 100644 --- a/Telegram/SourceFiles/boxes/emojibox.cpp +++ b/Telegram/SourceFiles/boxes/emojibox.cpp @@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "emojibox.h" #include "mainwidget.h" -#include "window.h" +#include "mainwindow.h" namespace { // copied from genemoji.cpp diff --git a/Telegram/SourceFiles/boxes/languagebox.cpp b/Telegram/SourceFiles/boxes/languagebox.cpp index 9400077e6..8c7fe47ed 100644 --- a/Telegram/SourceFiles/boxes/languagebox.cpp +++ b/Telegram/SourceFiles/boxes/languagebox.cpp @@ -26,7 +26,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "languagebox.h" #include "confirmbox.h" #include "mainwidget.h" -#include "window.h" +#include "mainwindow.h" #include "langloaderplain.h" diff --git a/Telegram/SourceFiles/boxes/passcodebox.cpp b/Telegram/SourceFiles/boxes/passcodebox.cpp index f444a960a..8468e86ff 100644 --- a/Telegram/SourceFiles/boxes/passcodebox.cpp +++ b/Telegram/SourceFiles/boxes/passcodebox.cpp @@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "passcodebox.h" #include "confirmbox.h" -#include "window.h" +#include "mainwindow.h" #include "localstorage.h" diff --git a/Telegram/SourceFiles/boxes/sessionsbox.cpp b/Telegram/SourceFiles/boxes/sessionsbox.cpp index 7bb3c4847..06d84ced1 100644 --- a/Telegram/SourceFiles/boxes/sessionsbox.cpp +++ b/Telegram/SourceFiles/boxes/sessionsbox.cpp @@ -25,7 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "sessionsbox.h" #include "mainwidget.h" -#include "window.h" +#include "mainwindow.h" #include "countries.h" #include "confirmbox.h" diff --git a/Telegram/SourceFiles/boxes/stickersetbox.cpp b/Telegram/SourceFiles/boxes/stickersetbox.cpp index 2756b15bc..814958521 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.cpp +++ b/Telegram/SourceFiles/boxes/stickersetbox.cpp @@ -23,10 +23,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "stickersetbox.h" #include "mainwidget.h" -#include "window.h" +#include "mainwindow.h" #include "settingswidget.h" #include "boxes/confirmbox.h" - +#include "apiwrap.h" #include "localstorage.h" StickerSetInner::StickerSetInner(const MTPInputStickerSet &set) : TWidget() diff --git a/Telegram/SourceFiles/boxes/usernamebox.cpp b/Telegram/SourceFiles/boxes/usernamebox.cpp index 57c940570..7d7bb157f 100644 --- a/Telegram/SourceFiles/boxes/usernamebox.cpp +++ b/Telegram/SourceFiles/boxes/usernamebox.cpp @@ -24,7 +24,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "application.h" #include "usernamebox.h" #include "mainwidget.h" -#include "window.h" +#include "mainwindow.h" UsernameBox::UsernameBox() : AbstractBox(st::boxWidth), _save(this, lang(lng_settings_save), st::defaultBoxButton), diff --git a/Telegram/SourceFiles/basic_types.cpp b/Telegram/SourceFiles/core/basic_types.cpp similarity index 100% rename from Telegram/SourceFiles/basic_types.cpp rename to Telegram/SourceFiles/core/basic_types.cpp diff --git a/Telegram/SourceFiles/basic_types.h b/Telegram/SourceFiles/core/basic_types.h similarity index 100% rename from Telegram/SourceFiles/basic_types.h rename to Telegram/SourceFiles/core/basic_types.h diff --git a/Telegram/SourceFiles/core/click_handler.cpp b/Telegram/SourceFiles/core/click_handler.cpp new file mode 100644 index 000000000..09809de14 --- /dev/null +++ b/Telegram/SourceFiles/core/click_handler.cpp @@ -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 ClickHandler::_active; +NeverFreedPointer 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; +} diff --git a/Telegram/SourceFiles/core/click_handler.h b/Telegram/SourceFiles/core/click_handler.h new file mode 100644 index 000000000..d03cb5d4c --- /dev/null +++ b/Telegram/SourceFiles/core/click_handler.h @@ -0,0 +1,157 @@ +/* +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; + +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; + } else if (_pressedHost == host) { + _pressedHost = nullptr; + } + } + +private: + + static NeverFreedPointer _active; + static NeverFreedPointer _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; + +}; diff --git a/Telegram/SourceFiles/core/click_handler_types.cpp b/Telegram/SourceFiles/core/click_handler_types.cpp new file mode 100644 index 000000000..3c317c3dd --- /dev/null +++ b/Telegram/SourceFiles/core/click_handler_types.cpp @@ -0,0 +1,133 @@ +/* +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()) { + Ui::showPeerHistory(peer, ShowAtTheEndMsgId); + App::sendBotCommand(peer, _cmd); + } else { + App::insertBotCommand(_cmd); + } + } +} diff --git a/Telegram/SourceFiles/core/click_handler_types.h b/Telegram/SourceFiles/core/click_handler_types.h new file mode 100644 index 000000000..9ca66ad85 --- /dev/null +++ b/Telegram/SourceFiles/core/click_handler_types.h @@ -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 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; + +}; diff --git a/Telegram/SourceFiles/dialogswidget.cpp b/Telegram/SourceFiles/dialogswidget.cpp index ee1dd621a..1f0aa382f 100644 --- a/Telegram/SourceFiles/dialogswidget.cpp +++ b/Telegram/SourceFiles/dialogswidget.cpp @@ -26,13 +26,14 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "ui/style.h" #include "lang.h" #include "application.h" -#include "window.h" +#include "mainwindow.h" #include "dialogswidget.h" #include "mainwidget.h" #include "boxes/addcontactbox.h" #include "boxes/contactsbox.h" #include "boxes/confirmbox.h" #include "localstorage.h" +#include "apiwrap.h" DialogsInner::DialogsInner(QWidget *parent, MainWidget *main) : SplittedWidget(parent) , dialogs(std_::make_unique(Dialogs::SortMode::Date)) diff --git a/Telegram/SourceFiles/dropdown.cpp b/Telegram/SourceFiles/dropdown.cpp index 8fce3e32e..93ce0f929 100644 --- a/Telegram/SourceFiles/dropdown.cpp +++ b/Telegram/SourceFiles/dropdown.cpp @@ -28,7 +28,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "historywidget.h" #include "localstorage.h" #include "lang.h" -#include "window.h" +#include "mainwindow.h" #include "apiwrap.h" #include "mainwidget.h" diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index fd74f4b6a..60aa53e2e 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -20,12 +20,11 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #include "stdafx.h" -#include "window.h" +#include "mainwindow.h" #include "mainwidget.h" #include "application.h" - +#include "core/click_handler_types.h" #include "boxes/confirmbox.h" - #include "layerwidget.h" #include "lang.h" @@ -136,13 +135,13 @@ void removeDialog(History *history) { } void showSettings() { - if (Window *w = wnd()) { + if (auto w = wnd()) { w->showSettings(); } } void activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button) { - if (Window *w = wnd()) { + if (auto w = wnd()) { qRegisterMetaType(); qRegisterMetaType(); QMetaObject::invokeMethod(w, "app_activateClickHandler", Qt::QueuedConnection, Q_ARG(ClickHandlerPtr, handler), Q_ARG(Qt::MouseButton, button)); @@ -150,7 +149,7 @@ void activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button) { } void logOutDelayed() { - if (Window *w = App::wnd()) { + if (auto w = App::wnd()) { QMetaObject::invokeMethod(w, "onLogoutSure", Qt::QueuedConnection); } } @@ -160,25 +159,25 @@ void logOutDelayed() { namespace Ui { void showMediaPreview(DocumentData *document) { - if (Window *w = App::wnd()) { + if (auto w = App::wnd()) { w->ui_showMediaPreview(document); } } void showMediaPreview(PhotoData *photo) { - if (Window *w = App::wnd()) { + if (auto w = App::wnd()) { w->ui_showMediaPreview(photo); } } void hideMediaPreview() { - if (Window *w = App::wnd()) { + if (auto w = App::wnd()) { w->ui_hideMediaPreview(); } } void showLayer(LayeredWidget *box, ShowLayerOptions options) { - if (Window *w = App::wnd()) { + if (auto w = App::wnd()) { w->ui_showLayer(box, options); } else { delete box; @@ -186,16 +185,16 @@ void showLayer(LayeredWidget *box, ShowLayerOptions options) { } 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() { - if (Window *w = App::wnd()) return w->ui_isLayerShown(); + if (auto w = App::wnd()) return w->ui_isLayerShown(); return false; } bool isMediaViewShown() { - if (Window *w = App::wnd()) return w->ui_isMediaViewShown(); + if (auto w = App::wnd()) return w->ui_isMediaViewShown(); return false; } @@ -236,7 +235,7 @@ void showPeerHistoryAsync(const PeerId &peer, MsgId msgId) { } PeerData *getPeerForMouseAction() { - if (Window *w = App::wnd()) { + if (auto w = App::wnd()) { return w->ui_getPeerForMouseAction(); } return nullptr; @@ -244,7 +243,7 @@ PeerData *getPeerForMouseAction() { bool hideWindowNoQuit() { if (!App::quitting()) { - if (Window *w = App::wnd()) { + if (auto w = App::wnd()) { if (cWorkMode() == dbiwmTrayOnly || cWorkMode() == dbiwmWindowAndTray) { return w->minimizeToTray(); } else if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) { diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index 4a0890ccc..4c90a95b5 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -21,18 +21,22 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "stdafx.h" #include "history.h" +#include "core/click_handler_types.h" #include "dialogs/dialogs_indexed_list.h" #include "ui/style.h" #include "lang.h" #include "mainwidget.h" #include "application.h" #include "fileuploader.h" -#include "window.h" +#include "mainwindow.h" #include "ui/filedialog.h" #include "boxes/addcontactbox.h" #include "boxes/confirmbox.h" #include "audio.h" #include "localstorage.h" +#include "apiwrap.h" +#include "window/top_bar_widget.h" +#include "playerwidget.h" namespace { diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index ce0d8aca7..ab525f3cb 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -2396,17 +2396,8 @@ void initImageLinkManager(); void reinitImageLinkManager(); void deinitImageLinkManager(); -struct LocationData { - LocationData(const LocationCoords &coords) : coords(coords), loading(false) { - } - - LocationCoords coords; - ImagePtr thumb; - bool loading; - - void load(); -}; - +struct LocationCoords; +struct LocationData; class LocationManager : public QObject { Q_OBJECT public: diff --git a/Telegram/SourceFiles/history/history_common.h b/Telegram/SourceFiles/history/history_common.h new file mode 100644 index 000000000..f5e807d5b --- /dev/null +++ b/Telegram/SourceFiles/history/history_common.h @@ -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, +}; diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index bebe9f51b..8d01e358d 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -30,12 +30,15 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "lang.h" #include "application.h" #include "mainwidget.h" -#include "window.h" +#include "mainwindow.h" #include "passcodewidget.h" -#include "window.h" +#include "mainwindow.h" #include "fileuploader.h" #include "audio.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 @@ -1489,7 +1492,7 @@ void HistoryInner::updateSize() { void HistoryInner::enterEvent(QEvent *e) { dragActionUpdate(QCursor::pos()); - return QWidget::enterEvent(e); +// return QWidget::enterEvent(e); } void HistoryInner::leaveEvent(QEvent *e) { @@ -1522,6 +1525,7 @@ void HistoryInner::adjustCurrent(int32 y) const { } void HistoryInner::adjustCurrent(int32 y, History *history) const { + t_assert(!history->isEmpty()); _curHistory = history; if (_curBlock >= history->blocks.size()) { _curBlock = history->blocks.size() - 1; @@ -5333,10 +5337,10 @@ void HistoryWidget::botCallbackDone(BotCallbackInfo info, const MTPmessages_BotC if (answerData.has_message()) { if (answerData.is_alert()) { Ui::showLayer(new InformBox(qs(answerData.vmessage))); - } else { + } else if (App::wnd()) { Ui::Toast::Config toast; toast.text = qs(answerData.vmessage); - Ui::Toast::Show(toast); + Ui::Toast::Show(App::wnd(), toast); } } } diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h index 8e74a0357..99d07a0d9 100644 --- a/Telegram/SourceFiles/historywidget.h +++ b/Telegram/SourceFiles/historywidget.h @@ -22,15 +22,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "localimageloader.h" #include "ui/boxshadow.h" - #include "dropdown.h" - -enum DragState { - DragStateNone = 0x00, - DragStateFiles = 0x01, - DragStatePhotoFiles = 0x02, - DragStateImage = 0x03, -}; +#include "history/history_common.h" class HistoryWidget; class HistoryInner : public TWidget, public AbstractTooltipShower { diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp index 5eaf00f75..1443e383b 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp @@ -25,6 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "localstorage.h" #include "mainwidget.h" #include "lang.h" +#include "playerwidget.h" namespace InlineBots { namespace Layout { diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.cpp index 398bf3e53..af11f174f 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.cpp @@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "stdafx.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_layout_internal.h" #include "localstorage.h" diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_result.h b/Telegram/SourceFiles/inline_bots/inline_bot_result.h index 567339c1c..cf98a37ff 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_result.h +++ b/Telegram/SourceFiles/inline_bots/inline_bot_result.h @@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #pragma once -#include "basic_types.h" +#include "core/basic_types.h" #include "structs.h" #include "mtproto/core_types.h" diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_send_data.h b/Telegram/SourceFiles/inline_bots/inline_bot_send_data.h index 2030a01be..031ee992e 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_send_data.h +++ b/Telegram/SourceFiles/inline_bots/inline_bot_send_data.h @@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #pragma once -#include "basic_types.h" +#include "core/basic_types.h" #include "structs.h" #include "mtproto/core_types.h" diff --git a/Telegram/SourceFiles/intro/introwidget.cpp b/Telegram/SourceFiles/intro/introwidget.cpp index 5941b4899..d79f80e0c 100644 --- a/Telegram/SourceFiles/intro/introwidget.cpp +++ b/Telegram/SourceFiles/intro/introwidget.cpp @@ -31,7 +31,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "intro/introsignup.h" #include "intro/intropwdcheck.h" #include "mainwidget.h" -#include "window.h" +#include "mainwindow.h" #include "application.h" #include "ui/text.h" diff --git a/Telegram/SourceFiles/layerwidget.cpp b/Telegram/SourceFiles/layerwidget.cpp index 6f843db98..a64912155 100644 --- a/Telegram/SourceFiles/layerwidget.cpp +++ b/Telegram/SourceFiles/layerwidget.cpp @@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "layerwidget.h" #include "application.h" -#include "window.h" +#include "mainwindow.h" #include "mainwidget.h" #include "ui/filedialog.h" diff --git a/Telegram/SourceFiles/layout.cpp b/Telegram/SourceFiles/layout.cpp index 746dbe5f8..a808b5d91 100644 --- a/Telegram/SourceFiles/layout.cpp +++ b/Telegram/SourceFiles/layout.cpp @@ -25,8 +25,9 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "mainwidget.h" #include "application.h" #include "fileuploader.h" -#include "window.h" +#include "mainwindow.h" #include "ui/filedialog.h" +#include "playerwidget.h" #include "boxes/addcontactbox.h" #include "boxes/confirmbox.h" @@ -216,1107 +217,3 @@ style::sprite documentCorner(int32 colorIndex) { RoundCorners documentCorners(int32 colorIndex) { return RoundCorners(DocBlueCorners + (colorIndex & 3)); } - -void LayoutMediaItemBase::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { - App::hoveredLinkItem(active ? _parent : nullptr); - Ui::repaintHistoryItem(_parent); -} - -void LayoutMediaItemBase::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) { - App::pressedLinkItem(pressed ? _parent : nullptr); - Ui::repaintHistoryItem(_parent); -} - -void LayoutRadialProgressItem::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { - if (p == _openl || p == _savel || p == _cancell) { - a_iconOver.start(active ? 1 : 0); - _a_iconOver.start(); - } - LayoutMediaItemBase::clickHandlerActiveChanged(p, active); -} - -void LayoutRadialProgressItem::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) { - LayoutMediaItemBase::clickHandlerPressedChanged(p, pressed); -} - -void LayoutRadialProgressItem::setLinks(ClickHandlerPtr &&openl, ClickHandlerPtr &&savel, ClickHandlerPtr &&cancell) { - _openl = std_::move(openl); - _savel = std_::move(savel); - _cancell = std_::move(cancell); -} - -void LayoutRadialProgressItem::step_iconOver(float64 ms, bool timer) { - float64 dt = ms / st::msgFileOverDuration; - if (dt >= 1) { - a_iconOver.finish(); - _a_iconOver.stop(); - } else if (!timer) { - a_iconOver.update(dt, anim::linear); - } - if (timer && iconAnimated()) { - Ui::repaintHistoryItem(_parent); - } -} - -void LayoutRadialProgressItem::step_radial(uint64 ms, bool timer) { - if (timer) { - Ui::repaintHistoryItem(_parent); - } else { - _radial->update(dataProgress(), dataFinished(), ms); - if (!_radial->animating()) { - checkRadialFinished(); - } - } -} - -void LayoutRadialProgressItem::ensureRadial() const { - if (!_radial) { - _radial = new RadialAnimation(animation(const_cast(this), &LayoutRadialProgressItem::step_radial)); - } -} - -void LayoutRadialProgressItem::checkRadialFinished() { - if (_radial && !_radial->animating() && dataLoaded()) { - delete _radial; - _radial = 0; - } -} - -LayoutRadialProgressItem::~LayoutRadialProgressItem() { - deleteAndMark(_radial); -} - -void LayoutAbstractFileItem::setStatusSize(int32 newSize, int32 fullSize, int32 duration, qint64 realDuration) const { - _statusSize = newSize; - if (_statusSize == FileStatusSizeReady) { - _statusText = (duration >= 0) ? formatDurationAndSizeText(duration, fullSize) : (duration < -1 ? formatGifAndSizeText(fullSize) : formatSizeText(fullSize)); - } else if (_statusSize == FileStatusSizeLoaded) { - _statusText = (duration >= 0) ? formatDurationText(duration) : (duration < -1 ? qsl("GIF") : formatSizeText(fullSize)); - } else if (_statusSize == FileStatusSizeFailed) { - _statusText = lang(lng_attach_failed); - } else if (_statusSize >= 0) { - _statusText = formatDownloadText(_statusSize, fullSize); - } else { - _statusText = formatPlayedText(-_statusSize - 1, realDuration); - } -} - -LayoutOverviewDate::LayoutOverviewDate(const QDate &date, bool month) -: _date(date) -, _text(month ? langMonthFull(date) : langDayOfMonthFull(date)) { - AddComponents(OverviewItemInfo::Bit()); -} - -void LayoutOverviewDate::initDimensions() { - _maxw = st::normalFont->width(_text); - _minh = st::linksDateMargin.top() + st::normalFont->height + st::linksDateMargin.bottom() + st::linksBorder; -} - -void LayoutOverviewDate::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContextOverview *context) const { - if (clip.intersects(QRect(0, st::linksDateMargin.top(), _width, st::normalFont->height))) { - p.setPen(st::linksDateColor); - p.setFont(st::semiboldFont); - p.drawTextLeft(0, st::linksDateMargin.top(), _width, _text); - } -} - -LayoutOverviewPhoto::LayoutOverviewPhoto(PhotoData *photo, HistoryItem *parent) : LayoutMediaItemBase(parent) -, _data(photo) -, _link(new PhotoOpenClickHandler(photo)) -, _goodLoaded(false) { - -} - -void LayoutOverviewPhoto::initDimensions() { - _maxw = 2 * st::overviewPhotoMinSize; - _minh = _maxw; -} - -int32 LayoutOverviewPhoto::resizeGetHeight(int32 width) { - width = qMin(width, _maxw); - if (width != _width || width != _height) { - _width = qMin(width, _maxw); - _height = _width; - } - return _height; -} - -void LayoutOverviewPhoto::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContextOverview *context) const { - bool good = _data->loaded(); - if (!good) { - _data->medium->automaticLoad(_parent); - good = _data->medium->loaded(); - } - if ((good && !_goodLoaded) || _pix.width() != _width * cIntRetinaFactor()) { - _goodLoaded = good; - - int32 size = _width * cIntRetinaFactor(); - if (_goodLoaded || _data->thumb->loaded()) { - QImage img = (_data->loaded() ? _data->full : (_data->medium->loaded() ? _data->medium : _data->thumb))->pix().toImage(); - if (!_goodLoaded) { - img = imageBlur(img); - } - if (img.width() == img.height()) { - if (img.width() != size) { - img = img.scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); - } - } else if (img.width() > img.height()) { - img = img.copy((img.width() - img.height()) / 2, 0, img.height(), img.height()).scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); - } else { - img = img.copy(0, (img.height() - img.width()) / 2, img.width(), img.width()).scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); - } - img.setDevicePixelRatio(cRetinaFactor()); - _data->forget(); - - _pix = QPixmap::fromImage(img, Qt::ColorOnly); - } else if (!_pix.isNull()) { - _pix = QPixmap(); - } - } - - if (_pix.isNull()) { - p.fillRect(0, 0, _width, _height, st::overviewPhotoBg); - } else { - p.drawPixmap(0, 0, _pix); - } - - if (selection == FullSelection) { - p.fillRect(QRect(0, 0, _width, _height), st::overviewPhotoSelectOverlay); - p.drawSprite(QPoint(rtl() ? 0 : (_width - st::overviewPhotoChecked.pxWidth()), _height - st::overviewPhotoChecked.pxHeight()), st::overviewPhotoChecked); - } else if (context->selecting) { - p.drawSprite(QPoint(rtl() ? 0 : (_width - st::overviewPhotoCheck.pxWidth()), _height - st::overviewPhotoCheck.pxHeight()), st::overviewPhotoCheck); - } -} - -void LayoutOverviewPhoto::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const { - if (hasPoint(x, y)) { - link = _link; - } -} - -LayoutOverviewVideo::LayoutOverviewVideo(DocumentData *video, HistoryItem *parent) : LayoutAbstractFileItem(parent) -, _data(video) -, _duration(formatDurationText(_data->duration())) -, _thumbLoaded(false) { - setDocumentLinks(_data); -} - -void LayoutOverviewVideo::initDimensions() { - _maxw = 2 * st::minPhotoSize; - _minh = _maxw; -} - -int32 LayoutOverviewVideo::resizeGetHeight(int32 width) { - _width = qMin(width, _maxw); - _height = _width; - return _height; -} - -void LayoutOverviewVideo::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContextOverview *context) const { - bool selected = (selection == FullSelection), thumbLoaded = _data->thumb->loaded(); - - _data->automaticLoad(_parent); - bool loaded = _data->loaded(), displayLoading = _data->displayLoading(); - if (displayLoading) { - ensureRadial(); - if (!_radial->animating()) { - _radial->start(_data->progress()); - } - } - updateStatusText(); - bool radial = isRadialAnimation(context->ms); - - if ((thumbLoaded && !_thumbLoaded) || (_pix.width() != _width * cIntRetinaFactor())) { - _thumbLoaded = thumbLoaded; - - if (_thumbLoaded && !_data->thumb->isNull()) { - int32 size = _width * cIntRetinaFactor(); - QImage img = imageBlur(_data->thumb->pix().toImage()); - if (img.width() == img.height()) { - if (img.width() != size) { - img = img.scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); - } - } else if (img.width() > img.height()) { - img = img.copy((img.width() - img.height()) / 2, 0, img.height(), img.height()).scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); - } else { - img = img.copy(0, (img.height() - img.width()) / 2, img.width(), img.width()).scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); - } - img.setDevicePixelRatio(cRetinaFactor()); - _data->forget(); - - _pix = QPixmap::fromImage(img, Qt::ColorOnly); - } else if (!_pix.isNull()) { - _pix = QPixmap(); - } - } - - if (_pix.isNull()) { - p.fillRect(0, 0, _width, _height, st::overviewPhotoBg); - } else { - p.drawPixmap(0, 0, _pix); - } - - if (selected) { - p.fillRect(QRect(0, 0, _width, _height), st::overviewPhotoSelectOverlay); - } - - if (!selected && !context->selecting && !loaded) { - if (clip.intersects(QRect(0, _height - st::normalFont->height, _width, st::normalFont->height))) { - int32 statusX = st::msgDateImgPadding.x(), statusY = _height - st::normalFont->height - st::msgDateImgPadding.y(); - int32 statusW = st::normalFont->width(_statusText) + 2 * st::msgDateImgPadding.x(); - int32 statusH = st::normalFont->height + 2 * st::msgDateImgPadding.y(); - statusX = _width - statusW + statusX; - p.fillRect(rtlrect(statusX - st::msgDateImgPadding.x(), statusY - st::msgDateImgPadding.y(), statusW, statusH, _width), selected ? st::msgDateImgBgSelected : st::msgDateImgBg); - p.setFont(st::normalFont); - p.setPen(st::white); - p.drawTextLeft(statusX, statusY, _width, _statusText, statusW - 2 * st::msgDateImgPadding.x()); - } - } - if (clip.intersects(QRect(0, 0, _width, st::normalFont->height))) { - int32 statusX = st::msgDateImgPadding.x(), statusY = st::msgDateImgPadding.y(); - int32 statusW = st::normalFont->width(_duration) + 2 * st::msgDateImgPadding.x(); - int32 statusH = st::normalFont->height + 2 * st::msgDateImgPadding.y(); - p.fillRect(rtlrect(statusX - st::msgDateImgPadding.x(), statusY - st::msgDateImgPadding.y(), statusW, statusH, _width), selected ? st::msgDateImgBgSelected : st::msgDateImgBg); - p.setFont(st::normalFont); - p.setPen(st::white); - p.drawTextLeft(statusX, statusY, _width, _duration, statusW - 2 * st::msgDateImgPadding.x()); - } - - QRect inner((_width - st::msgFileSize) / 2, (_height - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize); - if (clip.intersects(inner)) { - p.setPen(Qt::NoPen); - if (selected) { - p.setBrush(st::msgDateImgBgSelected); - } else if (_a_iconOver.animating()) { - _a_iconOver.step(context->ms); - float64 over = a_iconOver.current(); - p.setOpacity((st::msgDateImgBg->c.alphaF() * (1 - over)) + (st::msgDateImgBgOver->c.alphaF() * over)); - p.setBrush(st::black); - } else { - bool over = ClickHandler::showAsActive(loaded ? _openl : (_data->loading() ? _cancell : _savel)); - p.setBrush(over ? st::msgDateImgBgOver : st::msgDateImgBg); - } - - p.setRenderHint(QPainter::HighQualityAntialiasing); - p.drawEllipse(inner); - p.setRenderHint(QPainter::HighQualityAntialiasing, false); - - p.setOpacity((radial && loaded) ? _radial->opacity() : 1); - style::sprite icon; - if (radial) { - icon = (selected ? st::msgFileInCancelSelected : st::msgFileInCancel); - } else if (loaded) { - icon = (selected ? st::msgFileInPlaySelected : st::msgFileInPlay); - } else { - icon = (selected ? st::msgFileInDownloadSelected : st::msgFileInDownload); - } - p.drawSpriteCenter(inner, icon); - if (radial) { - p.setOpacity(1); - QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine))); - _radial->draw(p, rinner, st::msgFileRadialLine, selected ? st::msgInBgSelected : st::msgInBg); - } - } - - if (selected) { - p.drawSprite(QPoint(rtl() ? 0 : (_width - st::overviewPhotoChecked.pxWidth()), _height - st::overviewPhotoChecked.pxHeight()), st::overviewPhotoChecked); - } else if (context->selecting) { - p.drawSprite(QPoint(rtl() ? 0 : (_width - st::overviewPhotoCheck.pxWidth()), _height - st::overviewPhotoCheck.pxHeight()), st::overviewPhotoCheck); - } -} - -void LayoutOverviewVideo::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const { - bool loaded = _data->loaded(); - - if (hasPoint(x, y)) { - link = loaded ? _openl : (_data->loading() ? _cancell : _savel); - } -} - -void LayoutOverviewVideo::updateStatusText() const { - bool showPause = false; - int32 statusSize = 0; - if (_data->status == FileDownloadFailed || _data->status == FileUploadFailed) { - statusSize = FileStatusSizeFailed; - } else if (_data->status == FileUploading) { - statusSize = _data->uploadOffset; - } else if (_data->loading()) { - statusSize = _data->loadOffset(); - } else if (_data->loaded()) { - statusSize = FileStatusSizeLoaded; - } else { - statusSize = FileStatusSizeReady; - } - if (statusSize != _statusSize) { - int32 status = statusSize, size = _data->size; - if (statusSize >= 0 && statusSize < 0x7F000000) { - size = status; - status = FileStatusSizeReady; - } - setStatusSize(status, size, -1, 0); - _statusSize = statusSize; - } -} - -LayoutOverviewVoice::LayoutOverviewVoice(DocumentData *voice, HistoryItem *parent) : LayoutAbstractFileItem(parent) -, _data(voice) -, _namel(new DocumentOpenClickHandler(_data)) { - AddComponents(OverviewItemInfo::Bit()); - - t_assert(_data->voice() != 0); - - setDocumentLinks(_data); - - updateName(); - QString d = textcmdLink(1, textRichPrepare(langDateTime(date(_data->date)))); - TextParseOptions opts = { TextParseRichText, 0, 0, Qt::LayoutDirectionAuto }; - _details.setText(st::normalFont, lng_date_and_duration(lt_date, d, lt_duration, formatDurationText(_data->voice()->duration)), opts); - _details.setLink(1, MakeShared(parent)); -} - -void LayoutOverviewVoice::initDimensions() { - _maxw = st::profileMaxWidth; - _minh = st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom() + st::lineWidth; -} - -void LayoutOverviewVoice::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContextOverview *context) const { - bool selected = (selection == FullSelection); - - _data->automaticLoad(_parent); - bool loaded = _data->loaded(), displayLoading = _data->displayLoading(); - - if (displayLoading) { - ensureRadial(); - if (!_radial->animating()) { - _radial->start(_data->progress()); - } - } - bool showPause = updateStatusText(); - int32 nameVersion = _parent->fromOriginal()->nameVersion; - if (nameVersion > _nameVersion) { - updateName(); - } - bool radial = isRadialAnimation(context->ms); - - int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, datetop = -1; - - nameleft = st::msgFilePadding.left() + st::msgFileSize + st::msgFilePadding.right(); - nameright = st::msgFilePadding.left(); - nametop = st::msgFileNameTop; - statustop = st::msgFileStatusTop; - - if (selected) { - p.fillRect(clip.intersected(QRect(0, 0, _width, _height)), st::msgInBgSelected); - } - - QRect inner(rtlrect(st::msgFilePadding.left(), st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, _width)); - if (clip.intersects(inner)) { - p.setPen(Qt::NoPen); - if (selected) { - p.setBrush(st::msgFileInBgSelected); - } else if (_a_iconOver.animating()) { - _a_iconOver.step(context->ms); - float64 over = a_iconOver.current(); - p.setBrush(style::interpolate(st::msgFileInBg, st::msgFileInBgOver, over)); - } else { - bool over = ClickHandler::showAsActive(loaded ? _openl : (_data->loading() ? _cancell : _openl)); - p.setBrush(over ? st::msgFileInBgOver : st::msgFileInBg); - } - - p.setRenderHint(QPainter::HighQualityAntialiasing); - p.drawEllipse(inner); - p.setRenderHint(QPainter::HighQualityAntialiasing, false); - - if (radial) { - QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine))); - style::color bg(selected ? st::msgInBgSelected : st::msgInBg); - _radial->draw(p, rinner, st::msgFileRadialLine, bg); - } - - style::sprite icon; - if (showPause) { - icon = selected ? st::msgFileInPauseSelected : st::msgFileInPause; - } else if (_statusSize < 0 || _statusSize == FileStatusSizeLoaded) { - icon = selected ? st::msgFileInPlaySelected : st::msgFileInPlay; - } else if (_data->loading()) { - icon = selected ? st::msgFileInCancelSelected : st::msgFileInCancel; - } else { - icon = selected ? st::msgFileInDownloadSelected : st::msgFileInDownload; - } - p.drawSpriteCenter(inner, icon); - } - - int32 namewidth = _width - nameleft - nameright; - - if (clip.intersects(rtlrect(nameleft, nametop, namewidth, st::semiboldFont->height, _width))) { - p.setPen(st::black); - _name.drawLeftElided(p, nameleft, nametop, namewidth, _width); - } - - if (clip.intersects(rtlrect(nameleft, statustop, namewidth, st::normalFont->height, _width))) { - p.setFont(st::normalFont); - p.setPen(selected ? st::mediaInFgSelected : st::mediaInFg); - int32 unreadx = nameleft; - if (_statusSize == FileStatusSizeLoaded || _statusSize == FileStatusSizeReady) { - textstyleSet(&(selected ? st::mediaInStyleSelected : st::mediaInStyle)); - _details.drawLeftElided(p, nameleft, statustop, namewidth, _width); - textstyleRestore(); - unreadx += _details.maxWidth(); - } else { - int32 statusw = st::normalFont->width(_statusText); - p.drawTextLeft(nameleft, statustop, _width, _statusText, statusw); - unreadx += statusw; - } - if (_parent->isMediaUnread() && unreadx + st::mediaUnreadSkip + st::mediaUnreadSize <= _width) { - p.setPen(Qt::NoPen); - p.setBrush(selected ? st::msgFileInBgSelected : st::msgFileInBg); - - p.setRenderHint(QPainter::HighQualityAntialiasing, true); - p.drawEllipse(rtlrect(unreadx + st::mediaUnreadSkip, statustop + st::mediaUnreadTop, st::mediaUnreadSize, st::mediaUnreadSize, _width)); - p.setRenderHint(QPainter::HighQualityAntialiasing, false); - } - } -} - -void LayoutOverviewVoice::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const { - bool loaded = _data->loaded(); - - bool showPause = updateStatusText(); - - int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, datetop = 0; - - nameleft = st::msgFilePadding.left() + st::msgFileSize + st::msgFilePadding.right(); - nameright = st::msgFilePadding.left(); - nametop = st::msgFileNameTop; - statustop = st::msgFileStatusTop; - - QRect inner(rtlrect(st::msgFilePadding.left(), st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, _width)); - if (inner.contains(x, y)) { - link = loaded ? _openl : ((_data->loading() || _data->status == FileUploading) ? _cancell : _openl); - return; - } - if (rtlrect(nameleft, statustop, _width - nameleft - nameright, st::normalFont->height, _width).contains(x, y)) { - if (_statusSize == FileStatusSizeLoaded || _statusSize == FileStatusSizeReady) { - bool inText = false; - _details.getStateLeft(link, inText, x - nameleft, y - statustop, _width, _width); - cursor = inText ? HistoryInTextCursorState : HistoryDefaultCursorState; - } - } - if (hasPoint(x, y) && !link && !_data->loading()) { - link = _namel; - return; - } -} - -void LayoutOverviewVoice::updateName() const { - int32 version = 0; - if (const HistoryMessageForwarded *fwd = _parent->Get()) { - if (_parent->fromOriginal()->isChannel()) { - _name.setText(st::semiboldFont, lng_forwarded_channel(lt_channel, App::peerName(_parent->fromOriginal())), _textNameOptions); - } else { - _name.setText(st::semiboldFont, lng_forwarded(lt_user, App::peerName(_parent->fromOriginal())), _textNameOptions); - } - } else { - _name.setText(st::semiboldFont, App::peerName(_parent->from()), _textNameOptions); - } - version = _parent->fromOriginal()->nameVersion; - _nameVersion = version; -} - -bool LayoutOverviewVoice::updateStatusText() const { - bool showPause = false; - int32 statusSize = 0, realDuration = 0; - if (_data->status == FileDownloadFailed || _data->status == FileUploadFailed) { - statusSize = FileStatusSizeFailed; - } else if (_data->loaded()) { - AudioMsgId playing; - AudioPlayerState playingState = AudioPlayerStopped; - int64 playingPosition = 0, playingDuration = 0; - int32 playingFrequency = 0; - if (audioPlayer()) { - audioPlayer()->currentState(&playing, &playingState, &playingPosition, &playingDuration, &playingFrequency); - } - - if (playing == AudioMsgId(_data, _parent->fullId()) && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) { - statusSize = -1 - (playingPosition / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency)); - realDuration = playingDuration / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency); - showPause = (playingState == AudioPlayerPlaying || playingState == AudioPlayerResuming || playingState == AudioPlayerStarting); - } else { - statusSize = FileStatusSizeLoaded; - } - } else { - statusSize = FileStatusSizeReady; - } - if (statusSize != _statusSize) { - setStatusSize(statusSize, _data->size, _data->voice()->duration, realDuration); - } - return showPause; -} - -LayoutOverviewDocument::LayoutOverviewDocument(DocumentData *document, HistoryItem *parent) : LayoutAbstractFileItem(parent) -, _data(document) -, _msgl(new GoToMessageClickHandler(parent)) -, _namel(new DocumentOpenClickHandler(_data)) -, _thumbForLoaded(false) -, _name(documentName(_data)) -, _date(langDateTime(date(_data->date))) -, _namew(st::semiboldFont->width(_name)) -, _datew(st::normalFont->width(_date)) -, _colorIndex(documentColorIndex(_data, _ext)) { - AddComponents(OverviewItemInfo::Bit()); - - setDocumentLinks(_data); - - setStatusSize(FileStatusSizeReady, _data->size, _data->song() ? _data->song()->duration : -1, 0); - - if (withThumb()) { - _data->thumb->load(); - int32 tw = convertScale(_data->thumb->width()), th = convertScale(_data->thumb->height()); - if (tw > th) { - _thumbw = (tw * st::overviewFileSize) / th; - } else { - _thumbw = st::overviewFileSize; - } - } else { - _thumbw = 0; - } - - _extw = st::overviewFileExtFont->width(_ext); - if (_extw > st::overviewFileSize - st::overviewFileExtPadding * 2) { - _ext = st::overviewFileExtFont->elided(_ext, st::overviewFileSize - st::overviewFileExtPadding * 2, Qt::ElideMiddle); - _extw = st::overviewFileExtFont->width(_ext); - } -} - -void LayoutOverviewDocument::initDimensions() { - _maxw = st::profileMaxWidth; - if (_data->song()) { - _minh = st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom(); - } else { - _minh = st::overviewFilePadding.top() + st::overviewFileSize + st::overviewFilePadding.bottom() + st::lineWidth; - } -} - -void LayoutOverviewDocument::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContextOverview *context) const { - bool selected = (selection == FullSelection); - - _data->automaticLoad(_parent); - bool loaded = _data->loaded() || Local::willStickerImageLoad(_data->mediaKey()), displayLoading = _data->displayLoading(); - - if (displayLoading) { - ensureRadial(); - if (!_radial->animating()) { - _radial->start(_data->progress()); - } - } - bool showPause = updateStatusText(); - bool radial = isRadialAnimation(context->ms); - - int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, datetop = -1; - bool wthumb = withThumb(); - - if (_data->song()) { - nameleft = st::msgFilePadding.left() + st::msgFileSize + st::msgFilePadding.right(); - nameright = st::msgFilePadding.left(); - nametop = st::msgFileNameTop; - statustop = st::msgFileStatusTop; - - if (selected) { - p.fillRect(QRect(0, 0, _width, _height), st::msgInBgSelected); - } - - QRect inner(rtlrect(st::msgFilePadding.left(), st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, _width)); - if (clip.intersects(inner)) { - p.setPen(Qt::NoPen); - if (selected) { - p.setBrush(st::msgFileInBgSelected); - } else if (_a_iconOver.animating()) { - _a_iconOver.step(context->ms); - float64 over = a_iconOver.current(); - p.setBrush(style::interpolate(st::msgFileInBg, st::msgFileInBgOver, over)); - } else { - bool over = ClickHandler::showAsActive(loaded ? _openl : (_data->loading() ? _cancell : _openl)); - p.setBrush(over ? st::msgFileInBgOver : st::msgFileInBg); - } - - p.setRenderHint(QPainter::HighQualityAntialiasing); - p.drawEllipse(inner); - p.setRenderHint(QPainter::HighQualityAntialiasing, false); - - if (radial) { - QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine))); - style::color bg(selected ? st::msgInBgSelected : st::msgInBg); - _radial->draw(p, rinner, st::msgFileRadialLine, bg); - } - - style::sprite icon; - if (showPause) { - icon = selected ? st::msgFileInPauseSelected : st::msgFileInPause; - } else if (loaded) { - icon = selected ? st::msgFileInPlaySelected : st::msgFileInPlay; - } else if (_data->loading()) { - icon = selected ? st::msgFileInCancelSelected : st::msgFileInCancel; - } else { - icon = selected ? st::msgFileInDownloadSelected : st::msgFileInDownload; - } - p.drawSpriteCenter(inner, icon); - } - } else { - nameleft = st::overviewFileSize + st::overviewFilePadding.right(); - nametop = st::linksBorder + st::overviewFileNameTop; - statustop = st::linksBorder + st::overviewFileStatusTop; - datetop = st::linksBorder + st::overviewFileDateTop; - - QRect border(rtlrect(nameleft, 0, _width - nameleft, st::linksBorder, _width)); - if (!context->isAfterDate && clip.intersects(border)) { - p.fillRect(clip.intersected(border), st::linksBorderFg); - } - - QRect rthumb(rtlrect(0, st::linksBorder + st::overviewFilePadding.top(), st::overviewFileSize, st::overviewFileSize, _width)); - if (clip.intersects(rthumb)) { - if (wthumb) { - if (_data->thumb->loaded()) { - if (_thumb.isNull() || loaded != _thumbForLoaded) { - _thumbForLoaded = loaded; - ImagePixOptions options = ImagePixSmooth; - if (!_thumbForLoaded) options |= ImagePixBlurred; - _thumb = _data->thumb->pixNoCache(_thumbw, 0, options, st::overviewFileSize, st::overviewFileSize); - } - p.drawPixmap(rthumb.topLeft(), _thumb); - } else { - p.fillRect(rthumb, st::black); - } - } else { - p.fillRect(rthumb, documentColor(_colorIndex)); - if (!radial && loaded && !_ext.isEmpty()) { - p.setFont(st::overviewFileExtFont); - p.setPen(st::white); - p.drawText(rthumb.left() + (rthumb.width() - _extw) / 2, rthumb.top() + st::overviewFileExtTop + st::overviewFileExtFont->ascent, _ext); - } - } - if (selected) { - p.fillRect(rthumb, textstyleCurrent()->selectOverlay); - } - - if (radial || (!loaded && !_data->loading())) { - QRect inner(rthumb.x() + (rthumb.width() - st::msgFileSize) / 2, rthumb.y() + (rthumb.height() - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize); - if (clip.intersects(inner)) { - float64 radialOpacity = (radial && loaded && !_data->uploading()) ? _radial->opacity() : 1; - p.setPen(Qt::NoPen); - if (selected) { - p.setBrush(wthumb ? st::msgDateImgBgSelected : documentSelectedColor(_colorIndex)); - } else if (_a_iconOver.animating()) { - _a_iconOver.step(context->ms); - float64 over = a_iconOver.current(); - if (wthumb) { - p.setOpacity((st::msgDateImgBg->c.alphaF() * (1 - over)) + (st::msgDateImgBgOver->c.alphaF() * over)); - p.setBrush(st::black); - } else { - p.setBrush(style::interpolate(documentDarkColor(_colorIndex), documentOverColor(_colorIndex), over)); - } - } else { - bool over = ClickHandler::showAsActive(_data->loading() ? _cancell : _savel); - p.setBrush(over ? (wthumb ? st::msgDateImgBgOver : documentOverColor(_colorIndex)) : (wthumb ? st::msgDateImgBg : documentDarkColor(_colorIndex))); - } - p.setOpacity(radialOpacity * p.opacity()); - - p.setRenderHint(QPainter::HighQualityAntialiasing); - p.drawEllipse(inner); - p.setRenderHint(QPainter::HighQualityAntialiasing, false); - - p.setOpacity(radialOpacity); - style::sprite icon; - if (loaded || _data->loading()) { - icon = (selected ? st::msgFileInCancelSelected : st::msgFileInCancel); - } else { - icon = (selected ? st::msgFileInDownloadSelected : st::msgFileInDownload); - } - p.drawSpriteCenter(inner, icon); - if (radial) { - p.setOpacity(1); - - QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine))); - _radial->draw(p, rinner, st::msgFileRadialLine, selected ? st::msgInBgSelected : st::msgInBg); - } - } - } - if (selected || context->selecting) { - QRect check(rthumb.topLeft() + QPoint(rtl() ? 0 : (rthumb.width() - st::defaultCheckbox.diameter), rthumb.height() - st::defaultCheckbox.diameter), QSize(st::defaultCheckbox.diameter, st::defaultCheckbox.diameter)); - p.fillRect(check, selected ? st::overviewFileChecked : st::overviewFileCheck); - p.drawSpriteCenter(check, st::defaultCheckbox.checkIcon); - } - } - } - - int32 namewidth = _width - nameleft - nameright; - - if (clip.intersects(rtlrect(nameleft, nametop, qMin(namewidth, _namew), st::semiboldFont->height, _width))) { - p.setFont(st::semiboldFont); - p.setPen(st::black); - if (namewidth < _namew) { - p.drawTextLeft(nameleft, nametop, _width, st::semiboldFont->elided(_name, namewidth)); - } else { - p.drawTextLeft(nameleft, nametop, _width, _name, _namew); - } - } - - if (clip.intersects(rtlrect(nameleft, statustop, namewidth, st::normalFont->height, _width))) { - p.setFont(st::normalFont); - p.setPen(st::mediaInFg); - p.drawTextLeft(nameleft, statustop, _width, _statusText); - } - if (datetop >= 0 && clip.intersects(rtlrect(nameleft, datetop, _datew, st::normalFont->height, _width))) { - p.setFont(ClickHandler::showAsActive(_msgl) ? st::normalFont->underline() : st::normalFont); - p.setPen(st::mediaInFg); - p.drawTextLeft(nameleft, datetop, _width, _date, _datew); - } -} - -void LayoutOverviewDocument::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const { - bool loaded = _data->loaded() || Local::willStickerImageLoad(_data->mediaKey()); - - bool showPause = updateStatusText(); - - int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, datetop = 0; - bool wthumb = withThumb(); - - if (_data->song()) { - nameleft = st::msgFilePadding.left() + st::msgFileSize + st::msgFilePadding.right(); - nameright = st::msgFilePadding.left(); - nametop = st::msgFileNameTop; - statustop = st::msgFileStatusTop; - - QRect inner(rtlrect(st::msgFilePadding.left(), st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, _width)); - if (inner.contains(x, y)) { - link = loaded ? _openl : ((_data->loading() || _data->status == FileUploading) ? _cancell : _openl); - return; - } - if (hasPoint(x, y) && !_data->loading()) { - link = _namel; - return; - } - } else { - nameleft = st::overviewFileSize + st::overviewFilePadding.right(); - nametop = st::linksBorder + st::overviewFileNameTop; - statustop = st::linksBorder + st::overviewFileStatusTop; - datetop = st::linksBorder + st::overviewFileDateTop; - - QRect rthumb(rtlrect(0, st::linksBorder + st::overviewFilePadding.top(), st::overviewFileSize, st::overviewFileSize, _width)); - - if (rthumb.contains(x, y)) { - link = loaded ? _openl : ((_data->loading() || _data->status == FileUploading) ? _cancell : _savel); - return; - } - - if (_data->status != FileUploadFailed) { - if (rtlrect(nameleft, datetop, _datew, st::normalFont->height, _width).contains(x, y)) { - link = _msgl; - return; - } - } - if (!_data->loading() && _data->isValid()) { - if (loaded && rtlrect(0, st::linksBorder, nameleft, _height - st::linksBorder, _width).contains(x, y)) { - link = _namel; - return; - } - if (rtlrect(nameleft, nametop, qMin(_width - nameleft - nameright, _namew), st::semiboldFont->height, _width).contains(x, y)) { - link = _namel; - return; - } - } - } -} - -bool LayoutOverviewDocument::updateStatusText() const { - bool showPause = false; - int32 statusSize = 0, realDuration = 0; - if (_data->status == FileDownloadFailed || _data->status == FileUploadFailed) { - statusSize = FileStatusSizeFailed; - } else if (_data->status == FileUploading) { - statusSize = _data->uploadOffset; - } else if (_data->loading()) { - statusSize = _data->loadOffset(); - } else if (_data->loaded()) { - if (_data->song()) { - SongMsgId playing; - AudioPlayerState playingState = AudioPlayerStopped; - int64 playingPosition = 0, playingDuration = 0; - int32 playingFrequency = 0; - if (audioPlayer()) { - audioPlayer()->currentState(&playing, &playingState, &playingPosition, &playingDuration, &playingFrequency); - } - - if (playing == SongMsgId(_data, _parent->fullId()) && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) { - statusSize = -1 - (playingPosition / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency)); - realDuration = playingDuration / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency); - showPause = (playingState == AudioPlayerPlaying || playingState == AudioPlayerResuming || playingState == AudioPlayerStarting); - } else { - statusSize = FileStatusSizeLoaded; - } - if (!showPause && (playing == SongMsgId(_data, _parent->fullId())) && App::main() && App::main()->player()->seekingSong(playing)) { - showPause = true; - } - } else { - statusSize = FileStatusSizeLoaded; - } - } else { - statusSize = FileStatusSizeReady; - } - if (statusSize != _statusSize) { - setStatusSize(statusSize, _data->size, _data->song() ? _data->song()->duration : -1, realDuration); - } - return showPause; -} - -LayoutOverviewLink::LayoutOverviewLink(HistoryMedia *media, HistoryItem *parent) : LayoutMediaItemBase(parent) { - AddComponents(OverviewItemInfo::Bit()); - - QString text = _parent->originalText(); - EntitiesInText entities = _parent->originalEntities(); - - int32 from = 0, till = text.size(), lnk = entities.size(); - for (int32 i = 0; i < lnk; ++i) { - if (entities[i].type != EntityInTextUrl && entities[i].type != EntityInTextCustomUrl && entities[i].type != EntityInTextEmail) { - continue; - } - QString u = entities[i].text, t = text.mid(entities[i].offset, entities[i].length); - _links.push_back(Link(u.isEmpty() ? t : u, t)); - } - while (lnk > 0 && till > from) { - --lnk; - if (entities[lnk].type != EntityInTextUrl && entities[lnk].type != EntityInTextCustomUrl && entities[lnk].type != EntityInTextEmail) { - ++lnk; - break; - } - int32 afterLinkStart = entities[lnk].offset + entities[lnk].length; - if (till > afterLinkStart) { - if (!QRegularExpression(qsl("^[,.\\s_=+\\-;:`'\"\\(\\)\\[\\]\\{\\}<>*&^%\\$#@!\\\\/]+$")).match(text.mid(afterLinkStart, till - afterLinkStart)).hasMatch()) { - ++lnk; - break; - } - } - till = entities[lnk].offset; - } - if (!lnk) { - if (QRegularExpression(qsl("^[,.\\s\\-;:`'\"\\(\\)\\[\\]\\{\\}<>*&^%\\$#@!\\\\/]+$")).match(text.mid(from, till - from)).hasMatch()) { - till = from; - } - } - - _page = (media && media->type() == MediaTypeWebPage) ? static_cast(media)->webpage() : 0; - if (_page) { - if (_page->document) { - _photol.reset(new DocumentOpenClickHandler(_page->document)); - } else if (_page->photo) { - if (_page->type == WebPageProfile || _page->type == WebPageVideo) { - _photol = MakeShared(_page->url); - } else if (_page->type == WebPagePhoto || _page->siteName == qstr("Twitter") || _page->siteName == qstr("Facebook")) { - _photol.reset(new PhotoOpenClickHandler(_page->photo)); - } else { - _photol = MakeShared(_page->url); - } - } else { - _photol = MakeShared(_page->url); - } - } else if (!_links.isEmpty()) { - _photol = MakeShared(_links.front().lnk->text()); - } - if (from >= till && _page) { - text = _page->description; - from = 0; - till = text.size(); - } - if (till > from) { - TextParseOptions opts = { TextParseMultiline, int32(st::linksMaxWidth), 3 * st::normalFont->height, Qt::LayoutDirectionAuto }; - _text.setText(st::normalFont, text.mid(from, till - from), opts); - } - int32 tw = 0, th = 0; - if (_page && _page->photo) { - if (!_page->photo->loaded()) _page->photo->thumb->load(false, false); - - tw = convertScale(_page->photo->thumb->width()); - th = convertScale(_page->photo->thumb->height()); - } else if (_page && _page->document) { - if (!_page->document->thumb->loaded()) _page->document->thumb->load(false, false); - - tw = convertScale(_page->document->thumb->width()); - th = convertScale(_page->document->thumb->height()); - } - if (tw > st::dlgPhotoSize) { - if (th > tw) { - th = th * st::dlgPhotoSize / tw; - tw = st::dlgPhotoSize; - } else if (th > st::dlgPhotoSize) { - tw = tw * st::dlgPhotoSize / th; - th = st::dlgPhotoSize; - } - } - _pixw = qMax(tw, 1); - _pixh = qMax(th, 1); - - if (_page) { - _title = _page->title; - } - QString url(_page ? _page->url : (_links.isEmpty() ? QString() : _links.at(0).lnk->text())); - QVector parts = url.splitRef('/'); - if (!parts.isEmpty()) { - QStringRef domain = parts.at(0); - if (parts.size() > 2 && domain.endsWith(':') && parts.at(1).isEmpty()) { // http:// and others - domain = parts.at(2); - } - - parts = domain.split('@').back().split('.'); - if (parts.size() > 1) { - _letter = parts.at(parts.size() - 2).at(0).toUpper(); - if (_title.isEmpty()) { - _title.reserve(parts.at(parts.size() - 2).size()); - _title.append(_letter).append(parts.at(parts.size() - 2).mid(1)); - } - } - } - _titlew = st::semiboldFont->width(_title); -} - -void LayoutOverviewLink::initDimensions() { - _maxw = st::linksMaxWidth; - _minh = 0; - if (!_title.isEmpty()) { - _minh += st::semiboldFont->height; - } - if (!_text.isEmpty()) { - _minh += qMin(3 * st::normalFont->height, _text.countHeight(_maxw - st::dlgPhotoSize - st::dlgPhotoPadding)); - } - _minh += _links.size() * st::normalFont->height; - _minh = qMax(_minh, int32(st::dlgPhotoSize)) + st::linksMargin.top() + st::linksMargin.bottom() + st::linksBorder; -} - -int32 LayoutOverviewLink::resizeGetHeight(int32 width) { - _width = qMin(width, _maxw); - int32 w = _width - st::dlgPhotoSize - st::dlgPhotoPadding; - for (int32 i = 0, l = _links.size(); i < l; ++i) { - _links.at(i).lnk->setFullDisplayed(w >= _links.at(i).width); - } - - _height = 0; - if (!_title.isEmpty()) { - _height += st::semiboldFont->height; - } - if (!_text.isEmpty()) { - _height += qMin(3 * st::normalFont->height, _text.countHeight(_width - st::dlgPhotoSize - st::dlgPhotoPadding)); - } - _height += _links.size() * st::normalFont->height; - _height = qMax(_height, int32(st::dlgPhotoSize)) + st::linksMargin.top() + st::linksMargin.bottom() + st::linksBorder; - return _height; -} - -void LayoutOverviewLink::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContextOverview *context) const { - int32 left = st::dlgPhotoSize + st::dlgPhotoPadding, top = st::linksMargin.top() + st::linksBorder, w = _width - left; - if (clip.intersects(rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width))) { - if (_page && _page->photo) { - QPixmap pix; - if (_page->photo->medium->loaded()) { - pix = _page->photo->medium->pixSingle(_pixw, _pixh, st::dlgPhotoSize, st::dlgPhotoSize); - } else if (_page->photo->loaded()) { - pix = _page->photo->full->pixSingle(_pixw, _pixh, st::dlgPhotoSize, st::dlgPhotoSize); - } else { - pix = _page->photo->thumb->pixSingle(_pixw, _pixh, st::dlgPhotoSize, st::dlgPhotoSize); - } - p.drawPixmapLeft(0, top, _width, pix); - } else if (_page && _page->document && !_page->document->thumb->isNull()) { - p.drawPixmapLeft(0, top, _width, _page->document->thumb->pixSingle(_pixw, _pixh, st::dlgPhotoSize, st::dlgPhotoSize)); - } else { - int32 index = _letter.isEmpty() ? 0 : (_letter.at(0).unicode() % 4); - switch (index) { - case 0: App::roundRect(p, rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width), st::msgFileRedColor, DocRedCorners); break; - case 1: App::roundRect(p, rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width), st::msgFileYellowColor, DocYellowCorners); break; - case 2: App::roundRect(p, rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width), st::msgFileGreenColor, DocGreenCorners); break; - case 3: App::roundRect(p, rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width), st::msgFileBlueColor, DocBlueCorners); break; - } - - if (!_letter.isEmpty()) { - p.setFont(st::linksLetterFont->f); - p.setPen(st::white->p); - p.drawText(rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width), _letter, style::al_center); - } - } - - if (selection == FullSelection) { - App::roundRect(p, rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width), st::overviewPhotoSelectOverlay, PhotoSelectOverlayCorners); - p.drawSpriteLeft(QPoint(st::dlgPhotoSize - st::linksPhotoCheck.pxWidth(), top + st::dlgPhotoSize - st::linksPhotoCheck.pxHeight()), _width, st::linksPhotoChecked); - } else if (context->selecting) { - p.drawSpriteLeft(QPoint(st::dlgPhotoSize - st::linksPhotoCheck.pxWidth(), top + st::dlgPhotoSize - st::linksPhotoCheck.pxHeight()), _width, st::linksPhotoCheck); - } - } - - if (!_title.isEmpty() && _text.isEmpty() && _links.size() == 1) { - top += (st::dlgPhotoSize - st::semiboldFont->height - st::normalFont->height) / 2; - } else { - top = st::linksTextTop; - } - - p.setPen(st::black); - p.setFont(st::semiboldFont); - if (!_title.isEmpty()) { - if (clip.intersects(rtlrect(left, top, qMin(w, _titlew), st::semiboldFont->height, _width))) { - p.drawTextLeft(left, top, _width, (w < _titlew) ? st::semiboldFont->elided(_title, w) : _title); - } - top += st::semiboldFont->height; - } - p.setFont(st::msgFont->f); - if (!_text.isEmpty()) { - int32 h = qMin(st::normalFont->height * 3, _text.countHeight(w)); - if (clip.intersects(rtlrect(left, top, w, h, _width))) { - _text.drawLeftElided(p, left, top, w, _width, 3); - } - top += h; - } - - p.setPen(st::btnYesColor); - for (int32 i = 0, l = _links.size(); i < l; ++i) { - if (clip.intersects(rtlrect(left, top, qMin(w, _links.at(i).width), st::normalFont->height, _width))) { - p.setFont(ClickHandler::showAsActive(_links.at(i).lnk) ? st::normalFont->underline() : st::normalFont); - p.drawTextLeft(left, top, _width, (w < _links.at(i).width) ? st::normalFont->elided(_links.at(i).text, w) : _links.at(i).text); - } - top += st::normalFont->height; - } - - QRect border(rtlrect(left, 0, w, st::linksBorder, _width)); - if (!context->isAfterDate && clip.intersects(border)) { - p.fillRect(clip.intersected(border), st::linksBorderFg); - } -} - -void LayoutOverviewLink::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const { - int32 left = st::dlgPhotoSize + st::dlgPhotoPadding, top = st::linksMargin.top() + st::linksBorder, w = _width - left; - if (rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width).contains(x, y)) { - link = _photol; - return; - } - - if (!_title.isEmpty() && _text.isEmpty() && _links.size() == 1) { - top += (st::dlgPhotoSize - st::semiboldFont->height - st::normalFont->height) / 2; - } - if (!_title.isEmpty()) { - if (rtlrect(left, top, qMin(w, _titlew), st::semiboldFont->height, _width).contains(x, y)) { - link = _photol; - return; - } - top += st::webPageTitleFont->height; - } - if (!_text.isEmpty()) { - top += qMin(st::normalFont->height * 3, _text.countHeight(w)); - } - for (int32 i = 0, l = _links.size(); i < l; ++i) { - if (rtlrect(left, top, qMin(w, _links.at(i).width), st::normalFont->height, _width).contains(x, y)) { - link = _links.at(i).lnk; - return; - } - top += st::normalFont->height; - } -} - -LayoutOverviewLink::Link::Link(const QString &url, const QString &text) -: text(text) -, width(st::normalFont->width(text)) -, lnk(MakeShared(url)) { -} diff --git a/Telegram/SourceFiles/layout.h b/Telegram/SourceFiles/layout.h index 9fbcf90c8..7dee8bc15 100644 --- a/Telegram/SourceFiles/layout.h +++ b/Telegram/SourceFiles/layout.h @@ -91,12 +91,13 @@ public: }; -class LayoutMediaItemBase; class LayoutItemBase : public Composer, public ClickHandlerHost { public: LayoutItemBase() { } - LayoutItemBase &operator=(const LayoutItemBase &) = delete; + + LayoutItemBase(const LayoutItemBase &other) = delete; + LayoutItemBase &operator=(const LayoutItemBase &other) = delete; int32 maxWidth() const { return _maxw; @@ -142,311 +143,3 @@ protected: 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(document), std_::move(save), MakeShared(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 { - 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 _links; - -}; diff --git a/Telegram/SourceFiles/localimageloader.cpp b/Telegram/SourceFiles/localimageloader.cpp index 33904510b..f484ccb9b 100644 --- a/Telegram/SourceFiles/localimageloader.cpp +++ b/Telegram/SourceFiles/localimageloader.cpp @@ -25,7 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "boxes/photosendbox.h" #include "mainwidget.h" -#include "window.h" +#include "mainwindow.h" #include "lang.h" #include "boxes/confirmbox.h" diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp index 386f307c4..dc5a34e39 100644 --- a/Telegram/SourceFiles/localstorage.cpp +++ b/Telegram/SourceFiles/localstorage.cpp @@ -25,10 +25,11 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "serialize/serialize_document.h" #include "serialize/serialize_common.h" - #include "mainwidget.h" -#include "window.h" +#include "mainwindow.h" #include "lang.h" +#include "playerwidget.h" +#include "apiwrap.h" namespace { typedef quint64 FileKey; diff --git a/Telegram/SourceFiles/localstorage.h b/Telegram/SourceFiles/localstorage.h index 4d621c6d8..10264515a 100644 --- a/Telegram/SourceFiles/localstorage.h +++ b/Telegram/SourceFiles/localstorage.h @@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #pragma once -#include "basic_types.h" +#include "core/basic_types.h" namespace _local_inner { diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 78cd7023c..d3d478f0b 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -21,389 +21,35 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "stdafx.h" #include "mainwidget.h" +#include "ui/buttons/peer_avatar_button.h" #include "ui/style.h" +#include "window/top_bar_widget.h" +#include "apiwrap.h" +#include "dialogswidget.h" +#include "historywidget.h" +#include "profilewidget.h" +#include "overviewwidget.h" +#include "playerwidget.h" #include "lang.h" #include "boxes/addcontactbox.h" #include "fileuploader.h" #include "application.h" -#include "window.h" +#include "mainwindow.h" #include "settingswidget.h" #include "inline_bots/inline_bot_layout_item.h" #include "boxes/confirmbox.h" #include "boxes/stickersetbox.h" #include "boxes/contactsbox.h" #include "boxes/downloadpathbox.h" - #include "localstorage.h" - #include "shortcuts.h" - #include "audio.h" - #include "langloaderplain.h" -TopBarWidget::TopBarWidget(MainWidget *w) : TWidget(w) -, a_over(0) -, _a_appearance(animation(this, &TopBarWidget::step_appearance)) -, _selPeer(0) -, _selCount(0) -, _canDelete(false) -, _selStrLeft(-st::topBarButton.width / 2) -, _selStrWidth(0) -, _animating(false) -, _clearSelection(this, lang(lng_selected_clear), st::topBarButton) -, _forward(this, lang(lng_selected_forward), st::topBarActionButton) -, _delete(this, lang(lng_selected_delete), st::topBarActionButton) -, _selectionButtonsWidth(_clearSelection.width() + _forward.width() + _delete.width()), _forwardDeleteWidth(qMax(_forward.textWidth(), _delete.textWidth())) -, _info(this, nullptr, st::infoButton) -, _edit(this, lang(lng_profile_edit_contact), st::topBarButton) -, _leaveGroup(this, lang(lng_profile_delete_and_exit), st::topBarButton) -, _addContact(this, lang(lng_profile_add_contact), st::topBarButton) -, _deleteContact(this, lang(lng_profile_delete_contact), st::topBarButton) -, _mediaType(this, lang(lng_media_type), st::topBarButton) -, _search(this, st::topBarSearch) -, _sideShadow(this, st::shadowColor) { - - connect(&_forward, SIGNAL(clicked()), this, SLOT(onForwardSelection())); - connect(&_delete, SIGNAL(clicked()), this, SLOT(onDeleteSelection())); - connect(&_clearSelection, SIGNAL(clicked()), this, SLOT(onClearSelection())); - connect(&_info, SIGNAL(clicked()), this, SLOT(onInfoClicked())); - connect(&_addContact, SIGNAL(clicked()), this, SLOT(onAddContact())); - connect(&_deleteContact, SIGNAL(clicked()), this, SLOT(onDeleteContact())); - connect(&_edit, SIGNAL(clicked()), this, SLOT(onEdit())); - connect(&_leaveGroup, SIGNAL(clicked()), this, SLOT(onDeleteAndExit())); - connect(&_search, SIGNAL(clicked()), this, SLOT(onSearch())); - - setCursor(style::cur_pointer); - showAll(); -} - -void TopBarWidget::onForwardSelection() { - if (App::main()) App::main()->forwardSelectedItems(); -} - -void TopBarWidget::onDeleteSelection() { - if (App::main()) App::main()->deleteSelectedItems(); -} - -void TopBarWidget::onClearSelection() { - if (App::main()) App::main()->clearSelectedItems(); -} - -void TopBarWidget::onInfoClicked() { - PeerData *p = App::main() ? App::main()->historyPeer() : 0; - if (p) App::main()->showPeerProfile(p); -} - -void TopBarWidget::onAddContact() { - PeerData *p = App::main() ? App::main()->profilePeer() : 0; - UserData *u = p ? p->asUser() : 0; - if (u) Ui::showLayer(new AddContactBox(u->firstName, u->lastName, u->phone.isEmpty() ? App::phoneFromSharedContact(peerToUser(u->id)) : u->phone)); -} - -void TopBarWidget::onEdit() { - PeerData *p = App::main() ? App::main()->profilePeer() : 0; - if (p) { - if (p->isChannel()) { - Ui::showLayer(new EditChannelBox(p->asChannel())); - } else if (p->isChat()) { - Ui::showLayer(new EditNameTitleBox(p)); - } else if (p->isUser()) { - Ui::showLayer(new AddContactBox(p->asUser())); - } - } -} - -void TopBarWidget::onDeleteContact() { - PeerData *p = App::main() ? App::main()->profilePeer() : 0; - UserData *u = p ? p->asUser() : 0; - if (u) { - ConfirmBox *box = new ConfirmBox(lng_sure_delete_contact(lt_contact, p->name), lang(lng_box_delete)); - connect(box, SIGNAL(confirmed()), this, SLOT(onDeleteContactSure())); - Ui::showLayer(box); - } -} - -void TopBarWidget::onDeleteContactSure() { - PeerData *p = App::main() ? App::main()->profilePeer() : 0; - UserData *u = p ? p->asUser() : 0; - if (u) { - Ui::showChatsList(); - Ui::hideLayer(); - MTP::send(MTPcontacts_DeleteContact(u->inputUser), App::main()->rpcDone(&MainWidget::deletedContact, u)); - } -} - -void TopBarWidget::onDeleteAndExit() { - PeerData *p = App::main() ? App::main()->profilePeer() : 0; - ChatData *c = p ? p->asChat() : 0; - if (c) { - ConfirmBox *box = new ConfirmBox(lng_sure_delete_and_exit(lt_group, p->name), lang(lng_box_leave), st::attentionBoxButton); - connect(box, SIGNAL(confirmed()), this, SLOT(onDeleteAndExitSure())); - Ui::showLayer(box); - } -} - -void TopBarWidget::onDeleteAndExitSure() { - PeerData *p = App::main() ? App::main()->profilePeer() : 0; - ChatData *c = p ? p->asChat() : 0; - if (c) { - Ui::showChatsList(); - Ui::hideLayer(); - MTP::send(MTPmessages_DeleteChatUser(c->inputChat, App::self()->inputUser), App::main()->rpcDone(&MainWidget::deleteHistoryAfterLeave, p), App::main()->rpcFail(&MainWidget::leaveChatFailed, p)); - } -} - -void TopBarWidget::onSearch() { - Shortcuts::launch(qsl("search")); -} - -void TopBarWidget::enterEvent(QEvent *e) { - a_over.start(1); - _a_appearance.start(); -} - -void TopBarWidget::enterFromChildEvent(QEvent *e) { - a_over.start(1); - _a_appearance.start(); -} - -void TopBarWidget::leaveEvent(QEvent *e) { - a_over.start(0); - _a_appearance.start(); -} - -void TopBarWidget::leaveToChildEvent(QEvent *e) { - a_over.start(0); - _a_appearance.start(); -} - -void TopBarWidget::step_appearance(float64 ms, bool timer) { - float64 dt = ms / st::topBarDuration; - if (dt >= 1) { - _a_appearance.stop(); - a_over.finish(); - } else { - a_over.update(dt, anim::linear); - } - if (timer) update(); -} - -void TopBarWidget::paintEvent(QPaintEvent *e) { - QPainter p(this); - - if (e->rect().top() < st::topBarHeight) { // optimize shadow-only drawing - p.fillRect(QRect(0, 0, width(), st::topBarHeight), st::topBarBG->b); - if (_clearSelection.isHidden()) { - p.save(); - main()->paintTopBar(p, a_over.current(), _info.isHidden() ? 0 : _info.width()); - p.restore(); - } else { - p.setFont(st::linkFont->f); - p.setPen(st::btnDefLink.color->p); - p.drawText(_selStrLeft, st::topBarButton.textTop + st::linkFont->ascent, _selStr); - } - } -} - -void TopBarWidget::mousePressEvent(QMouseEvent *e) { - PeerData *p = App::main() ? App::main()->profilePeer() : 0; - if (e->button() == Qt::LeftButton && e->pos().y() < st::topBarHeight && (p || !_selCount)) { - emit clicked(); - } -} - -void TopBarWidget::resizeEvent(QResizeEvent *e) { - int32 r = width(); - if (!_forward.isHidden() || !_delete.isHidden()) { - int32 fullW = r - (_selectionButtonsWidth + (_selStrWidth - st::topBarButton.width) + st::topBarActionSkip); - int32 selectedClearWidth = st::topBarButton.width, forwardDeleteWidth = st::topBarActionButton.width - _forwardDeleteWidth, skip = st::topBarActionSkip; - while (fullW < 0) { - int fit = 0; - if (selectedClearWidth < -2 * (st::topBarMinPadding + 1)) { - fullW += 4; - selectedClearWidth += 2; - } else if (selectedClearWidth < -2 * st::topBarMinPadding) { - fullW += (-2 * st::topBarMinPadding - selectedClearWidth) * 2; - selectedClearWidth = -2 * st::topBarMinPadding; - } else { - ++fit; - } - if (fullW >= 0) break; - - if (forwardDeleteWidth > 2 * (st::topBarMinPadding + 1)) { - fullW += 4; - forwardDeleteWidth -= 2; - } else if (forwardDeleteWidth > 2 * st::topBarMinPadding) { - fullW += (forwardDeleteWidth - 2 * st::topBarMinPadding) * 2; - forwardDeleteWidth = 2 * st::topBarMinPadding; - } else { - ++fit; - } - if (fullW >= 0) break; - - if (skip > st::topBarMinPadding) { - --skip; - ++fullW; - } else { - ++fit; - } - if (fullW >= 0 || fit >= 3) break; - } - _clearSelection.setWidth(selectedClearWidth); - _forward.setWidth(_forwardDeleteWidth + forwardDeleteWidth); - _delete.setWidth(_forwardDeleteWidth + forwardDeleteWidth); - _selStrLeft = -selectedClearWidth / 2; - - int32 availX = _selStrLeft + _selStrWidth, availW = r - (_clearSelection.width() + selectedClearWidth / 2) - availX; - if (_forward.isHidden()) { - _delete.move(availX + (availW - _delete.width()) / 2, (st::topBarHeight - _forward.height()) / 2); - } else if (_delete.isHidden()) { - _forward.move(availX + (availW - _forward.width()) / 2, (st::topBarHeight - _forward.height()) / 2); - } else { - _forward.move(availX + (availW - _forward.width() - _delete.width() - skip) / 2, (st::topBarHeight - _forward.height()) / 2); - _delete.move(availX + (availW + _forward.width() - _delete.width() + skip) / 2, (st::topBarHeight - _forward.height()) / 2); - } - _clearSelection.move(r -= _clearSelection.width(), 0); - } - if (!_info.isHidden()) _info.move(r -= _info.width(), 0); - if (!_deleteContact.isHidden()) _deleteContact.move(r -= _deleteContact.width(), 0); - if (!_leaveGroup.isHidden()) _leaveGroup.move(r -= _leaveGroup.width(), 0); - if (!_edit.isHidden()) _edit.move(r -= _edit.width(), 0); - if (!_addContact.isHidden()) _addContact.move(r -= _addContact.width(), 0); - if (!_mediaType.isHidden()) _mediaType.move(r -= _mediaType.width(), 0); - _search.move(width() - (_info.isHidden() ? st::topBarForwardPadding.right() : _info.width()) - _search.width(), 0); - - _sideShadow.resize(st::lineWidth, height()); - _sideShadow.moveToLeft(0, 0); -} - -void TopBarWidget::startAnim() { - _info.hide(); - _edit.hide(); - _leaveGroup.hide(); - _addContact.hide(); - _deleteContact.hide(); - _clearSelection.hide(); - _delete.hide(); - _forward.hide(); - _mediaType.hide(); - _search.hide(); - - _animating = true; -} - -void TopBarWidget::stopAnim() { - _animating = false; - _sideShadow.setVisible(!Adaptive::OneColumn()); - showAll(); -} - -void TopBarWidget::showAll() { - if (_animating) { - resizeEvent(0); - return; - } - PeerData *p = App::main() ? App::main()->profilePeer() : 0, *h = App::main() ? App::main()->historyPeer() : 0, *o = App::main() ? App::main()->overviewPeer() : 0; - if (p && (p->isChat() || (p->isUser() && (p->asUser()->contact >= 0 || !App::phoneFromSharedContact(peerToUser(p->id)).isEmpty())))) { - if (p->isChat()) { - if (p->asChat()->canEdit()) { - _edit.show(); - } else { - _edit.hide(); - } - _leaveGroup.show(); - _addContact.hide(); - _deleteContact.hide(); - } else if (p->asUser()->contact > 0) { - _edit.show(); - _leaveGroup.hide(); - _addContact.hide(); - _deleteContact.show(); - } else { - _edit.hide(); - _leaveGroup.hide(); - _addContact.show(); - _deleteContact.hide(); - } - _clearSelection.hide(); - _info.hide(); - _delete.hide(); - _forward.hide(); - _mediaType.hide(); - _search.hide(); - } else { - if (p && p->isChannel() && (p->asChannel()->amCreator() || (p->isMegagroup() && p->asChannel()->amEditor()))) { - _edit.show(); - } else { - _edit.hide(); - } - _leaveGroup.hide(); - _addContact.hide(); - _deleteContact.hide(); - if (!p && _selCount) { - _clearSelection.show(); - if (_canDelete) { - _delete.show(); - } else { - _delete.hide(); - } - _forward.show(); - _mediaType.hide(); - } else { - _clearSelection.hide(); - _delete.hide(); - _forward.hide(); - if (App::main() && App::main()->mediaTypeSwitch()) { - _mediaType.show(); - } else { - _mediaType.hide(); - } - } - if (h && !o && !p && _clearSelection.isHidden()) { - if (Adaptive::OneColumn()) { - _info.setPeer(h); - _info.show(); - } else { - _info.hide(); - } - _search.show(); - } else { - _search.hide(); - _info.hide(); - } - } - _sideShadow.setVisible(!Adaptive::OneColumn()); - resizeEvent(0); -} - -void TopBarWidget::showSelected(uint32 selCount, bool canDelete) { - PeerData *p = App::main() ? App::main()->profilePeer() : 0; - _selPeer = App::main()->overviewPeer() ? App::main()->overviewPeer() : App::main()->peer(); - _selCount = selCount; - _canDelete = canDelete; - _selStr = (_selCount > 0) ? lng_selected_count(lt_count, _selCount) : QString(); - _selStrWidth = st::btnDefLink.font->width(_selStr); - setCursor((!p && _selCount) ? style::cur_default : style::cur_pointer); - showAll(); -} - -void TopBarWidget::updateAdaptiveLayout() { - showAll(); -} - -FlatButton *TopBarWidget::mediaTypeButton() { - return &_mediaType; -} - -MainWidget *TopBarWidget::main() { - return static_cast(parentWidget()); -} - -MainWidget::MainWidget(Window *window) : TWidget(window) +MainWidget::MainWidget(MainWindow *window) : TWidget(window) , _a_show(animation(this, &MainWidget::step_show)) -, dialogs(this) -, history(this) +, _dialogs(this) +, _history(this) , _player(this) , _topBar(this) , _mediaType(this) @@ -415,8 +61,8 @@ MainWidget::MainWidget(Window *window) : TWidget(window) updateScrollColors(); connect(App::wnd(), SIGNAL(resized(const QSize&)), this, SLOT(onParentResize(const QSize&))); - connect(&dialogs, SIGNAL(cancelled()), this, SLOT(dialogsCancelled())); - connect(&history, SIGNAL(cancelled()), &dialogs, SLOT(activate())); + connect(_dialogs, SIGNAL(cancelled()), this, SLOT(dialogsCancelled())); + connect(_history, SIGNAL(cancelled()), _dialogs, SLOT(activate())); connect(this, SIGNAL(peerPhotoChanged(PeerData*)), this, SIGNAL(dialogsUpdated())); connect(&noUpdatesTimer, SIGNAL(timeout()), this, SLOT(mtpPing())); connect(&_onlineTimer, SIGNAL(timeout()), this, SLOT(updateOnline())); @@ -426,10 +72,10 @@ MainWidget::MainWidget(Window *window) : TWidget(window) connect(&_byPtsTimer, SIGNAL(timeout()), this, SLOT(onGetDifferenceTimeByPts())); connect(&_byMinChannelTimer, SIGNAL(timeout()), this, SLOT(getDifference())); connect(&_failDifferenceTimer, SIGNAL(timeout()), this, SLOT(onGetDifferenceTimeAfterFail())); - connect(_api, SIGNAL(fullPeerUpdated(PeerData*)), this, SLOT(onFullPeerUpdated(PeerData*))); - connect(this, SIGNAL(peerUpdated(PeerData*)), &history, SLOT(peerUpdated(PeerData*))); - connect(&_topBar, SIGNAL(clicked()), this, SLOT(onTopBarClick())); - connect(&history, SIGNAL(historyShown(History*,MsgId)), this, SLOT(onHistoryShown(History*,MsgId))); + connect(_api.get(), SIGNAL(fullPeerUpdated(PeerData*)), this, SLOT(onFullPeerUpdated(PeerData*))); + connect(this, SIGNAL(peerUpdated(PeerData*)), _history, SLOT(peerUpdated(PeerData*))); + connect(_topBar, SIGNAL(clicked()), this, SLOT(onTopBarClick())); + connect(_history, SIGNAL(historyShown(History*,MsgId)), this, SLOT(onHistoryShown(History*,MsgId))); connect(&updateNotifySettingTimer, SIGNAL(timeout()), this, SLOT(onUpdateNotifySettings())); if (audioPlayer()) { connect(audioPlayer(), SIGNAL(updated(const AudioMsgId&)), this, SLOT(audioPlayProgress(const AudioMsgId&))); @@ -445,23 +91,23 @@ MainWidget::MainWidget(Window *window) : TWidget(window) connect(&_cacheBackgroundTimer, SIGNAL(timeout()), this, SLOT(onCacheBackground())); - dialogs.show(); + _dialogs->show(); if (Adaptive::OneColumn()) { - history.hide(); + _history->hide(); } else { - history.show(); + _history->show(); } App::wnd()->getTitle()->updateBackButton(); - _topBar.hide(); + _topBar->hide(); - _player.hide(); + _player->hide(); orderWidgets(); MTP::setGlobalFailHandler(rpcFail(&MainWidget::updateFail)); - _mediaType.hide(); - _topBar.mediaTypeButton()->installEventFilter(&_mediaType); + _mediaType->hide(); + _topBar->mediaTypeButton()->installEventFilter(_mediaType); show(); setFocus(); @@ -475,13 +121,13 @@ bool MainWidget::onForward(const PeerId &peer, ForwardWhatMessages what) { Ui::showLayer(new InformBox(lang(lng_forward_cant))); return false; } - history.cancelReply(); + _history->cancelReply(); _toForward.clear(); if (what == ForwardSelectedMessages) { - if (overview) { - overview->fillSelectedItems(_toForward, false); + if (_overview) { + _overview->fillSelectedItems(_toForward, false); } else { - history.fillSelectedItems(_toForward, false); + _history->fillSelectedItems(_toForward, false); } } else { HistoryItem *item = 0; @@ -498,8 +144,8 @@ bool MainWidget::onForward(const PeerId &peer, ForwardWhatMessages what) { } updateForwardingTexts(); Ui::showPeerHistory(peer, ShowAtUnreadMsgId); - history.onClearSelected(); - history.updateForwarding(); + _history->onClearSelected(); + _history->updateForwarding(); return true; } @@ -512,9 +158,9 @@ bool MainWidget::onShareUrl(const PeerId &peer, const QString &url, const QStrin History *h = App::history(peer); h->setMsgDraft(std_::make_unique(url + '\n' + text, 0, MessageCursor(url.size() + 1, url.size() + 1 + text.size(), QFIXED_MAX), false)); h->clearEditDraft(); - bool opened = history.peer() && (history.peer()->id == peer); + bool opened = _history->peer() && (_history->peer()->id == peer); if (opened) { - history.applyDraft(); + _history->applyDraft(); } else { Ui::showPeerHistory(peer, ShowAtUnreadMsgId); } @@ -530,9 +176,9 @@ bool MainWidget::onInlineSwitchChosen(const PeerId &peer, const QString &botAndQ History *h = App::history(peer); h->setMsgDraft(std_::make_unique(botAndQuery, 0, MessageCursor(botAndQuery.size(), botAndQuery.size(), QFIXED_MAX), false)); h->clearEditDraft(); - bool opened = history.peer() && (history.peer()->id == peer); + bool opened = _history->peer() && (_history->peer()->id == peer); if (opened) { - history.applyDraft(); + _history->applyDraft(); } else { Ui::showPeerHistory(peer, ShowAtUnreadMsgId); } @@ -598,7 +244,7 @@ void MainWidget::cancelForwarding() { if (_toForward.isEmpty()) return; _toForward.clear(); - history.cancelForwarding(); + _history->cancelForwarding(); } void MainWidget::finishForwarding(History *hist, bool broadcast, bool silent) { @@ -656,8 +302,8 @@ void MainWidget::finishForwarding(History *hist, bool broadcast, bool silent) { } hist->sendRequestId = MTP::send(MTPmessages_ForwardMessages(MTP_flags(sendFlags), forwardFrom->input, MTP_vector(ids), MTP_vector(randomIds), hist->peer->input), rpcDone(&MainWidget::sentUpdatesReceived), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId); - if (history.peer() == hist->peer) { - history.peerMessagesUpdated(); + if (_history->peer() == hist->peer) { + _history->peerMessagesUpdated(); } cancelForwarding(); @@ -665,7 +311,7 @@ void MainWidget::finishForwarding(History *hist, bool broadcast, bool silent) { historyToDown(hist); dialogsToUp(); - history.peerMessagesUpdated(hist->peer->id); + _history->peerMessagesUpdated(hist->peer->id); } void MainWidget::webPageUpdated(WebPageData *data) { @@ -697,7 +343,7 @@ void MainWidget::updateMutedIn(int32 seconds) { } void MainWidget::updateStickers() { - history.updateStickers(); + _history->updateStickers(); } void MainWidget::onUpdateMuted() { @@ -705,11 +351,11 @@ void MainWidget::onUpdateMuted() { } void MainWidget::onShareContact(const PeerId &peer, UserData *contact) { - history.onShareContact(peer, contact); + _history->onShareContact(peer, contact); } void MainWidget::onSendPaths(const PeerId &peer) { - history.onSendPaths(peer); + _history->onSendPaths(peer); } void MainWidget::onFilesOrForwardDrop(const PeerId &peer, const QMimeData *data) { @@ -721,30 +367,30 @@ void MainWidget::onFilesOrForwardDrop(const PeerId &peer, const QMimeData *data) onForward(peer, ForwardPressedMessage); } else { Ui::showPeerHistory(peer, ShowAtTheEndMsgId); - history.onFilesDrop(data); + _history->onFilesDrop(data); } } void MainWidget::rpcClear() { - history.rpcClear(); - dialogs.rpcClear(); - if (profile) profile->rpcClear(); - if (overview) overview->rpcClear(); + _history->rpcClear(); + _dialogs->rpcClear(); + if (_profile) _profile->rpcClear(); + if (_overview) _overview->rpcClear(); if (_api) _api->rpcClear(); RPCSender::rpcClear(); } QPixmap MainWidget::grabInner() { - if (overview && !overview->isHidden()) { - return myGrab(overview); - } else if (profile && !profile->isHidden()) { - return myGrab(profile); - } else if (Adaptive::OneColumn() && history.isHidden()) { - return myGrab(&dialogs, QRect(0, st::topBarHeight, dialogs.width(), dialogs.height() - st::topBarHeight)); - } else if (history.peer()) { - return myGrab(&history); + if (_overview && !_overview->isHidden()) { + return myGrab(_overview); + } else if (_profile && !_profile->isHidden()) { + return myGrab(_profile); + } else if (Adaptive::OneColumn() && _history->isHidden()) { + return myGrab(_dialogs, QRect(0, st::topBarHeight, _dialogs->width(), _dialogs->height() - st::topBarHeight)); + } else if (_history->peer()) { + return myGrab(_history); } else { - return myGrab(&history, QRect(0, st::topBarHeight, history.width(), history.height() - st::topBarHeight)); + return myGrab(_history, QRect(0, st::topBarHeight, _history->width(), _history->height() - st::topBarHeight)); } } @@ -752,47 +398,47 @@ bool MainWidget::isItemVisible(HistoryItem *item) { if (isHidden() || _a_show.animating()) { return false; } - return history.isItemVisible(item); + return _history->isItemVisible(item); } QPixmap MainWidget::grabTopBar() { - if (!_topBar.isHidden()) { - return myGrab(&_topBar); - } else if (Adaptive::OneColumn() && history.isHidden()) { - return myGrab(&dialogs, QRect(0, 0, dialogs.width(), st::topBarHeight)); + if (!_topBar->isHidden()) { + return myGrab(_topBar); + } else if (Adaptive::OneColumn() && _history->isHidden()) { + return myGrab(_dialogs, QRect(0, 0, _dialogs->width(), st::topBarHeight)); } else { - return myGrab(&history, QRect(0, 0, history.width(), st::topBarHeight)); + return myGrab(_history, QRect(0, 0, _history->width(), st::topBarHeight)); } } void MainWidget::notify_botCommandsChanged(UserData *bot) { - history.notify_botCommandsChanged(bot); + _history->notify_botCommandsChanged(bot); } void MainWidget::notify_inlineBotRequesting(bool requesting) { - history.notify_inlineBotRequesting(requesting); + _history->notify_inlineBotRequesting(requesting); } void MainWidget::notify_replyMarkupUpdated(const HistoryItem *item) { - history.notify_replyMarkupUpdated(item); + _history->notify_replyMarkupUpdated(item); } void MainWidget::notify_inlineKeyboardMoved(const HistoryItem *item, int oldKeyboardTop, int newKeyboardTop) { - history.notify_inlineKeyboardMoved(item, oldKeyboardTop, newKeyboardTop); + _history->notify_inlineKeyboardMoved(item, oldKeyboardTop, newKeyboardTop); } bool MainWidget::notify_switchInlineBotButtonReceived(const QString &query) { - return history.notify_switchInlineBotButtonReceived(query); + return _history->notify_switchInlineBotButtonReceived(query); } void MainWidget::notify_userIsBotChanged(UserData *bot) { - history.notify_userIsBotChanged(bot); + _history->notify_userIsBotChanged(bot); } void MainWidget::notify_userIsContactChanged(UserData *user, bool fromThisApp) { if (!user) return; - dialogs.notify_userIsContactChanged(user, fromThisApp); + _dialogs->notify_userIsContactChanged(user, fromThisApp); const SharedContactItems &items(App::sharedContactItems()); SharedContactItems::const_iterator i = items.constFind(peerToUser(user->id)); @@ -808,83 +454,83 @@ void MainWidget::notify_userIsContactChanged(UserData *user, bool fromThisApp) { } void MainWidget::notify_migrateUpdated(PeerData *peer) { - history.notify_migrateUpdated(peer); + _history->notify_migrateUpdated(peer); } void MainWidget::notify_clipStopperHidden(ClipStopperType type) { - history.notify_clipStopperHidden(type); + _history->notify_clipStopperHidden(type); } void MainWidget::ui_repaintHistoryItem(const HistoryItem *item) { - history.ui_repaintHistoryItem(item); + _history->ui_repaintHistoryItem(item); if (item->history()->lastMsg == item) { item->history()->updateChatListEntry(); } - if (overview) overview->ui_repaintHistoryItem(item); + if (_overview) _overview->ui_repaintHistoryItem(item); } void MainWidget::ui_repaintInlineItem(const InlineBots::Layout::ItemBase *layout) { - history.ui_repaintInlineItem(layout); + _history->ui_repaintInlineItem(layout); } bool MainWidget::ui_isInlineItemVisible(const InlineBots::Layout::ItemBase *layout) { - return history.ui_isInlineItemVisible(layout); + return _history->ui_isInlineItemVisible(layout); } bool MainWidget::ui_isInlineItemBeingChosen() { - return history.ui_isInlineItemBeingChosen(); + return _history->ui_isInlineItemBeingChosen(); } void MainWidget::notify_historyItemLayoutChanged(const HistoryItem *item) { - history.notify_historyItemLayoutChanged(item); - if (overview) overview->notify_historyItemLayoutChanged(item); + _history->notify_historyItemLayoutChanged(item); + if (_overview) _overview->notify_historyItemLayoutChanged(item); } void MainWidget::notify_inlineItemLayoutChanged(const InlineBots::Layout::ItemBase *layout) { - history.notify_inlineItemLayoutChanged(layout); + _history->notify_inlineItemLayoutChanged(layout); } void MainWidget::notify_historyMuteUpdated(History *history) { - dialogs.notify_historyMuteUpdated(history); + _dialogs->notify_historyMuteUpdated(history); } void MainWidget::notify_handlePendingHistoryUpdate() { - history.notify_handlePendingHistoryUpdate(); + _history->notify_handlePendingHistoryUpdate(); } void MainWidget::cmd_search() { - history.cmd_search(); + _history->cmd_search(); } void MainWidget::cmd_next_chat() { - history.cmd_next_chat(); + _history->cmd_next_chat(); } void MainWidget::cmd_previous_chat() { - history.cmd_previous_chat(); + _history->cmd_previous_chat(); } void MainWidget::noHider(HistoryHider *destroyed) { if (_hider == destroyed) { - _hider = 0; + _hider = nullptr; if (Adaptive::OneColumn()) { if (_forwardConfirm) { _forwardConfirm->startHide(); _forwardConfirm = 0; } - onHistoryShown(history.history(), history.msgId()); - if (profile || overview || (history.peer() && history.peer()->id)) { + onHistoryShown(_history->history(), _history->msgId()); + if (_profile || _overview || (_history->peer() && _history->peer()->id)) { QPixmap animCache = grabInner(), animTopBarCache = grabTopBar(); - dialogs.hide(); - if (overview) { - overview->show(); - overview->animShow(animCache, animTopBarCache); - } else if (profile) { - profile->show(); - profile->animShow(animCache, animTopBarCache); + _dialogs->hide(); + if (_overview) { + _overview->show(); + _overview->animShow(animCache, animTopBarCache); + } else if (_profile) { + _profile->show(); + _profile->animShow(animCache, animTopBarCache); } else { - history.show(); - history.animShow(animCache, animTopBarCache); + _history->show(); + _history->animShow(animCache, animTopBarCache); } } App::wnd()->getTitle()->updateBackButton(); @@ -904,7 +550,7 @@ void MainWidget::hiderLayer(HistoryHider *h) { } _hider = h; - connect(_hider, SIGNAL(forwarded()), &dialogs, SLOT(onCancelSearch())); + connect(_hider, SIGNAL(forwarded()), _dialogs, SLOT(onCancelSearch())); if (Adaptive::OneColumn()) { dialogsToUp(); @@ -912,21 +558,21 @@ void MainWidget::hiderLayer(HistoryHider *h) { QPixmap animCache = myGrab(this, QRect(0, _playerHeight, _dialogsWidth, height() - _playerHeight)); onHistoryShown(0, 0); - if (overview) { - overview->hide(); - } else if (profile) { - profile->hide(); + if (_overview) { + _overview->hide(); + } else if (_profile) { + _profile->hide(); } else { - history.hide(); + _history->hide(); } - dialogs.show(); + _dialogs->show(); resizeEvent(0); - dialogs.animShow(animCache); + _dialogs->animShow(animCache); App::wnd()->getTitle()->updateBackButton(); } else { _hider->show(); resizeEvent(0); - dialogs.activate(); + _dialogs->activate(); } } @@ -935,7 +581,7 @@ void MainWidget::forwardLayer(int32 forwardSelected) { } void MainWidget::deleteLayer(int32 selectedCount) { - if (selectedCount == -1 && !overview) { + if (selectedCount == -1 && !_overview) { if (HistoryItem *item = App::contextItem()) { if (item->suggestBanReportDeleteAll()) { Ui::showLayer(new RichDeleteMessageBox(item->history()->peer->asChannel(), item->from()->asUser(), item->id)); @@ -953,9 +599,9 @@ void MainWidget::deleteLayer(int32 selectedCount) { connect(box, SIGNAL(destroyed(QObject*)), App::uploader(), SLOT(unpause())); } } - connect(box, SIGNAL(confirmed()), overview ? overview : static_cast(&history), SLOT(onDeleteContextSure())); + connect(box, SIGNAL(confirmed()), _overview ? static_cast(_overview) : static_cast(_history), SLOT(onDeleteContextSure())); } else { - connect(box, SIGNAL(confirmed()), overview ? overview : static_cast(&history), SLOT(onDeleteSelectedSure())); + connect(box, SIGNAL(confirmed()), _overview ? static_cast(_overview) : static_cast(_history), SLOT(onDeleteSelectedSure())); } Ui::showLayer(box); } @@ -1002,11 +648,11 @@ void MainWidget::onForwardCancel(QObject *obj) { } void MainWidget::dialogsActivate() { - dialogs.activate(); + _dialogs->activate(); } DragState MainWidget::getDragState(const QMimeData *mime) { - return history.getDragState(mime); + return _history->getDragState(mime); } bool MainWidget::leaveChatFailed(PeerData *peer, const RPCError &error) { @@ -1065,7 +711,7 @@ void MainWidget::deletedContact(UserData *user, const MTPcontacts_Link &result) } void MainWidget::removeDialog(History *history) { - dialogs.removeDialog(history); + _dialogs->removeDialog(history); } void MainWidget::deleteConversation(PeerData *peer, bool deleteHistory) { @@ -1273,7 +919,7 @@ void MainWidget::checkedHistory(PeerData *peer, const MTPmessages_Messages &resu h->clear(true); h->addNewerSlice(QVector(), 0); h->asChannelHistory()->insertJoinedMessage(true); - history.peerMessagesUpdated(h->peer->id); + _history->peerMessagesUpdated(h->peer->id); } } } else { @@ -1298,7 +944,7 @@ void MainWidget::checkedHistory(PeerData *peer, const MTPmessages_Messages &resu if (peer->isChannel() && peer->asChannel()->inviter > 0 && h->lastMsgDate <= peer->asChannel()->inviteDate && peer->asChannel()->amIn()) { if (UserData *from = App::userLoaded(peer->asChannel()->inviter)) { h->asChannelHistory()->insertJoinedMessage(true); - history.peerMessagesUpdated(h->peer->id); + _history->peerMessagesUpdated(h->peer->id); } } } @@ -1346,35 +992,35 @@ void MainWidget::onCacheBackground() { } void MainWidget::forwardSelectedItems() { - if (overview) { - overview->onForwardSelected(); + if (_overview) { + _overview->onForwardSelected(); } else { - history.onForwardSelected(); + _history->onForwardSelected(); } } void MainWidget::deleteSelectedItems() { - if (overview) { - overview->onDeleteSelected(); + if (_overview) { + _overview->onDeleteSelected(); } else { - history.onDeleteSelected(); + _history->onDeleteSelected(); } } void MainWidget::clearSelectedItems() { - if (overview) { - overview->onClearSelected(); + if (_overview) { + _overview->onClearSelected(); } else { - history.onClearSelected(); + _history->onClearSelected(); } } Dialogs::IndexedList *MainWidget::contactsList() { - return dialogs.contactsList(); + return _dialogs->contactsList(); } Dialogs::IndexedList *MainWidget::dialogsList() { - return dialogs.dialogsList(); + return _dialogs->dialogsList(); } namespace { @@ -1437,9 +1083,9 @@ void executeParsedCommand(const QString &command) { void MainWidget::sendMessage(History *hist, const QString &text, MsgId replyTo, bool broadcast, bool silent, WebPageId webPageId) { readServerHistory(hist, false); - history.fastShowAtEnd(hist); + _history->fastShowAtEnd(hist); - if (!hist || !history.canSendMessages(hist->peer)) { + if (!hist || !_history->canSendMessages(hist->peer)) { return; } @@ -1450,7 +1096,7 @@ void MainWidget::sendMessage(History *hist, const QString &text, MsgId replyTo, QString command = parseCommandFromMessage(hist, text); - if (replyTo < 0) replyTo = history.replyToId(); + if (replyTo < 0) replyTo = _history->replyToId(); while (command.isEmpty() && textSplit(sendingText, sendingEntities, leftText, leftEntities, MaxMessageSize)) { FullMsgId newId(peerToChannel(hist->peer->id), clientMsgId()); uint64 randomId = rand_value(); @@ -1552,32 +1198,32 @@ void MainWidget::readServerHistory(History *hist, bool force) { } uint64 MainWidget::animActiveTimeStart(const HistoryItem *msg) const { - return history.animActiveTimeStart(msg); + return _history->animActiveTimeStart(msg); } void MainWidget::stopAnimActive() { - history.stopAnimActive(); + _history->stopAnimActive(); } void MainWidget::sendBotCommand(PeerData *peer, const QString &cmd, MsgId replyTo) { - history.sendBotCommand(peer, cmd, replyTo); + _history->sendBotCommand(peer, cmd, replyTo); } void MainWidget::app_sendBotCallback(const HistoryMessageReplyMarkup::Button *button, const HistoryItem *msg, int row, int col) { - history.app_sendBotCallback(button, msg, row, col); + _history->app_sendBotCallback(button, msg, row, col); } bool MainWidget::insertBotCommand(const QString &cmd, bool specialGif) { - return history.insertBotCommand(cmd, specialGif); + return _history->insertBotCommand(cmd, specialGif); } void MainWidget::searchMessages(const QString &query, PeerData *inPeer) { App::wnd()->hideMediaview(); - dialogs.searchMessages(query, inPeer); + _dialogs->searchMessages(query, inPeer); if (Adaptive::OneColumn()) { Ui::showChatsList(); } else { - dialogs.activate(); + _dialogs->activate(); } } @@ -1630,17 +1276,17 @@ void MainWidget::overviewPreloaded(PeerData *peer, const MTPmessages_Messages &r } void MainWidget::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) { - if (profile) profile->mediaOverviewUpdated(peer, type); - if (!_player.isHidden()) _player.mediaOverviewUpdated(peer, type); - if (overview && (overview->peer() == peer || overview->peer()->migrateFrom() == peer)) { - overview->mediaOverviewUpdated(peer, type); + if (_profile) _profile->mediaOverviewUpdated(peer, type); + if (!_player->isHidden()) _player->mediaOverviewUpdated(peer, type); + if (_overview && (_overview->peer() == peer || _overview->peer()->migrateFrom() == peer)) { + _overview->mediaOverviewUpdated(peer, type); int32 mask = 0; History *h = peer ? App::historyLoaded((peer->migrateTo() ? peer->migrateTo() : peer)->id) : 0; History *m = (peer && peer->migrateFrom()) ? App::historyLoaded(peer->migrateFrom()->id) : 0; if (h) { for (int32 i = 0; i < OverviewCount; ++i) { - if (!h->overview[i].isEmpty() || h->overviewCount(i) > 0 || i == overview->type()) { + if (!h->overview[i].isEmpty() || h->overviewCount(i) > 0 || i == _overview->type()) { mask |= (1 << i); } else if (m && (!m->overview[i].isEmpty() || m->overviewCount(i) > 0)) { mask |= (1 << i); @@ -1648,37 +1294,37 @@ void MainWidget::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) { } } if (mask != _mediaTypeMask) { - _mediaType.resetButtons(); + _mediaType->resetButtons(); for (int32 i = 0; i < OverviewCount; ++i) { if (mask & (1 << i)) { switch (i) { - case OverviewPhotos: connect(_mediaType.addButton(new IconedButton(this, st::dropdownMediaPhotos, lang(lng_media_type_photos))), SIGNAL(clicked()), this, SLOT(onPhotosSelect())); break; - case OverviewVideos: connect(_mediaType.addButton(new IconedButton(this, st::dropdownMediaVideos, lang(lng_media_type_videos))), SIGNAL(clicked()), this, SLOT(onVideosSelect())); break; - case OverviewMusicFiles: connect(_mediaType.addButton(new IconedButton(this, st::dropdownMediaSongs, lang(lng_media_type_songs))), SIGNAL(clicked()), this, SLOT(onSongsSelect())); break; - case OverviewFiles: connect(_mediaType.addButton(new IconedButton(this, st::dropdownMediaDocuments, lang(lng_media_type_files))), SIGNAL(clicked()), this, SLOT(onDocumentsSelect())); break; - case OverviewVoiceFiles: connect(_mediaType.addButton(new IconedButton(this, st::dropdownMediaAudios, lang(lng_media_type_audios))), SIGNAL(clicked()), this, SLOT(onAudiosSelect())); break; - case OverviewLinks: connect(_mediaType.addButton(new IconedButton(this, st::dropdownMediaLinks, lang(lng_media_type_links))), SIGNAL(clicked()), this, SLOT(onLinksSelect())); break; + case OverviewPhotos: connect(_mediaType->addButton(new IconedButton(this, st::dropdownMediaPhotos, lang(lng_media_type_photos))), SIGNAL(clicked()), this, SLOT(onPhotosSelect())); break; + case OverviewVideos: connect(_mediaType->addButton(new IconedButton(this, st::dropdownMediaVideos, lang(lng_media_type_videos))), SIGNAL(clicked()), this, SLOT(onVideosSelect())); break; + case OverviewMusicFiles: connect(_mediaType->addButton(new IconedButton(this, st::dropdownMediaSongs, lang(lng_media_type_songs))), SIGNAL(clicked()), this, SLOT(onSongsSelect())); break; + case OverviewFiles: connect(_mediaType->addButton(new IconedButton(this, st::dropdownMediaDocuments, lang(lng_media_type_files))), SIGNAL(clicked()), this, SLOT(onDocumentsSelect())); break; + case OverviewVoiceFiles: connect(_mediaType->addButton(new IconedButton(this, st::dropdownMediaAudios, lang(lng_media_type_audios))), SIGNAL(clicked()), this, SLOT(onAudiosSelect())); break; + case OverviewLinks: connect(_mediaType->addButton(new IconedButton(this, st::dropdownMediaLinks, lang(lng_media_type_links))), SIGNAL(clicked()), this, SLOT(onLinksSelect())); break; } } } _mediaTypeMask = mask; - _mediaType.move(width() - _mediaType.width(), st::topBarHeight); - overview->updateTopBarSelection(); + _mediaType->move(width() - _mediaType->width(), st::topBarHeight); + _overview->updateTopBarSelection(); } } } void MainWidget::changingMsgId(HistoryItem *row, MsgId newId) { - if (overview) overview->changingMsgId(row, newId); + if (_overview) _overview->changingMsgId(row, newId); } void MainWidget::itemRemoved(HistoryItem *item) { - dialogs.itemRemoved(item); - if (history.peer() == item->history()->peer || (history.peer() && history.peer() == item->history()->peer->migrateTo())) { - history.itemRemoved(item); + _dialogs->itemRemoved(item); + if (_history->peer() == item->history()->peer || (_history->peer() && _history->peer() == item->history()->peer->migrateTo())) { + _history->itemRemoved(item); } - if (overview && (overview->peer() == item->history()->peer || (overview->peer() && overview->peer() == item->history()->peer->migrateTo()))) { - overview->itemRemoved(item); + if (_overview && (_overview->peer() == item->history()->peer || (_overview->peer() && _overview->peer() == item->history()->peer->migrateTo()))) { + _overview->itemRemoved(item); } if (!_toForward.isEmpty()) { SelectedItemSet::iterator i = _toForward.find(item->id); @@ -1696,8 +1342,8 @@ void MainWidget::itemRemoved(HistoryItem *item) { } void MainWidget::itemEdited(HistoryItem *item) { - if (history.peer() == item->history()->peer || (history.peer() && history.peer() == item->history()->peer->migrateTo())) { - history.itemEdited(item); + if (_history->peer() == item->history()->peer || (_history->peer() && _history->peer() == item->history()->peer->migrateTo())) { + _history->itemEdited(item); } } @@ -1734,8 +1380,8 @@ void MainWidget::loadMediaBack(PeerData *peer, MediaOverviewType type, bool many } void MainWidget::peerUsernameChanged(PeerData *peer) { - if (profile && profile->peer() == peer) { - profile->peerUsernameChanged(); + if (_profile && _profile->peer() == peer) { + _profile->peerUsernameChanged(); } if (App::settings() && peer == App::self()) { App::settings()->usernameChanged(); @@ -1751,11 +1397,11 @@ void MainWidget::checkLastUpdate(bool afterSleep) { } void MainWidget::showAddContact() { - dialogs.onAddContact(); + _dialogs->onAddContact(); } void MainWidget::showNewGroup() { - dialogs.onNewGroup(); + _dialogs->onNewGroup(); } void MainWidget::overviewLoaded(History *history, const MTPmessages_Messages &result, mtpRequestId req) { @@ -1910,13 +1556,13 @@ void MainWidget::documentPlayProgress(const SongMsgId &songId) { } if (playing == songId) { - _player.updateState(playing, playingState, playingPosition, playingDuration, playingFrequency); + _player->updateState(playing, playingState, playingPosition, playingDuration, playingFrequency); if (!(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing && !_a_show.animating()) { - if (_player.isHidden()) { - _player.clearSelection(); - _player.show(); - _playerHeight = _contentScrollAddToY = _player.height(); + if (_player->isHidden()) { + _player->clearSelection(); + _player->show(); + _playerHeight = _contentScrollAddToY = _player->height(); resizeEvent(0); } } @@ -1933,9 +1579,9 @@ void MainWidget::documentPlayProgress(const SongMsgId &songId) { } void MainWidget::hidePlayer() { - if (!_player.isHidden()) { - _player.hide(); - _contentScrollAddToY = -_player.height(); + if (!_player->isHidden()) { + _player->hide(); + _contentScrollAddToY = -_player->height(); _playerHeight = 0; resizeEvent(0); } @@ -1965,8 +1611,8 @@ void MainWidget::documentLoadProgress(FileLoader *loader) { int64 playingPosition = 0, playingDuration = 0; int32 playingFrequency = 0; audioPlayer()->currentState(&playing, &playingState, &playingPosition, &playingDuration, &playingFrequency); - if (playing.song == document && !_player.isHidden()) { - _player.updateState(playing, playingState, playingPosition, playingDuration, playingFrequency); + if (playing.song == document && !_player->isHidden()) { + _player->updateState(playing, playingState, playingPosition, playingDuration, playingFrequency); } } } @@ -2037,27 +1683,27 @@ void MainWidget::onParentResize(const QSize &newSize) { void MainWidget::updateOnlineDisplay() { if (this != App::main()) return; - history.updateOnlineDisplay(history.x(), width() - history.x() - st::sysBtnDelta * 2 - st::sysCls.img.pxWidth() - st::sysRes.img.pxWidth() - st::sysMin.img.pxWidth()); - if (profile) profile->updateOnlineDisplay(); + _history->updateOnlineDisplay(_history->x(), width() - _history->x() - st::sysBtnDelta * 2 - st::sysCls.img.pxWidth() - st::sysRes.img.pxWidth() - st::sysMin.img.pxWidth()); + if (_profile) _profile->updateOnlineDisplay(); if (App::wnd()->settingsWidget()) App::wnd()->settingsWidget()->updateOnlineDisplay(); } void MainWidget::onSendFileConfirm(const FileLoadResultPtr &file, bool ctrlShiftEnter) { - bool lastKeyboardUsed = history.lastForceReplyReplied(FullMsgId(peerToChannel(file->to.peer), file->to.replyTo)); - history.confirmSendFile(file, ctrlShiftEnter); - history.cancelReply(lastKeyboardUsed); + bool lastKeyboardUsed = _history->lastForceReplyReplied(FullMsgId(peerToChannel(file->to.peer), file->to.replyTo)); + _history->confirmSendFile(file, ctrlShiftEnter); + _history->cancelReply(lastKeyboardUsed); } void MainWidget::onSendFileCancel(const FileLoadResultPtr &file) { - history.cancelSendFile(file); + _history->cancelSendFile(file); } void MainWidget::onShareContactConfirm(const QString &phone, const QString &fname, const QString &lname, MsgId replyTo, bool ctrlShiftEnter) { - history.confirmShareContact(phone, fname, lname, replyTo, ctrlShiftEnter); + _history->confirmShareContact(phone, fname, lname, replyTo, ctrlShiftEnter); } void MainWidget::onShareContactCancel() { - history.cancelShareContact(); + _history->cancelShareContact(); } void MainWidget::dialogsCancelled() { @@ -2065,7 +1711,7 @@ void MainWidget::dialogsCancelled() { _hider->startHide(); noHider(_hider); } - history.activate(); + _history->activate(); } void MainWidget::serviceNotification(const QString &msg, const MTPMessageMedia &media) { @@ -2078,7 +1724,7 @@ void MainWidget::serviceNotification(const QString &msg, const MTPMessageMedia & item = App::histories().addNewMessage(MTP_message(MTP_flags(flags), MTP_int(clientMsgId()), MTP_int(ServiceUserId), MTP_peerUser(MTP_int(MTP::authedId())), MTPnullFwdHeader, MTPint(), MTPint(), MTP_int(unixtime()), MTP_string(sendingText), media, MTPnullMarkup, localEntities, MTPint(), MTPint()), NewMessageUnread); } if (item) { - history.peerMessagesUpdated(item->history()->peer->id); + _history->peerMessagesUpdated(item->history()->peer->id); } } @@ -2169,12 +1815,12 @@ void MainWidget::backgroundParams(const QRect &forRect, QRect &to, QRect &from) } void MainWidget::updateScrollColors() { - history.updateScrollColors(); - if (overview) overview->updateScrollColors(); + _history->updateScrollColors(); + if (_overview) _overview->updateScrollColors(); } void MainWidget::setChatBackground(const App::WallPaper &wp) { - _background = new App::WallPaper(wp); + _background = std_::make_unique(wp); _background->full->loadEvenCancelled(); checkChatBackground(); } @@ -2193,8 +1839,7 @@ void MainWidget::checkChatBackground() { } else { App::initBackground(_background->id, _background->full->pix().toImage()); } - delete _background; - _background = 0; + _background = nullptr; QTimer::singleShot(0, this, SLOT(update())); } } @@ -2205,38 +1850,38 @@ ImagePtr MainWidget::newBackgroundThumb() { } ApiWrap *MainWidget::api() { - return _api; + return _api.get(); } void MainWidget::messageDataReceived(ChannelData *channel, MsgId msgId) { - history.messageDataReceived(channel, msgId); + _history->messageDataReceived(channel, msgId); } void MainWidget::updateBotKeyboard(History *h) { - history.updateBotKeyboard(h); + _history->updateBotKeyboard(h); } void MainWidget::pushReplyReturn(HistoryItem *item) { - history.pushReplyReturn(item); + _history->pushReplyReturn(item); } void MainWidget::setInnerFocus() { - if (_hider || !history.peer()) { + if (_hider || !_history->peer()) { if (_hider && _hider->wasOffered()) { _hider->setFocus(); - } else if (overview) { - overview->activate(); - } else if (profile) { - profile->activate(); + } else if (_overview) { + _overview->activate(); + } else if (_profile) { + _profile->activate(); } else { dialogsActivate(); } - } else if (overview) { - overview->activate(); - } else if (profile) { - profile->activate(); + } else if (_overview) { + _overview->activate(); + } else if (_profile) { + _profile->activate(); } else { - history.setInnerFocus(); + _history->setInnerFocus(); } } @@ -2315,11 +1960,11 @@ bool MainWidget::viewsIncrementFail(const RPCError &error, mtpRequestId req) { } HistoryItem *MainWidget::atTopImportantMsg(int32 &bottomUnderScrollTop) const { - return history.atTopImportantMsg(bottomUnderScrollTop); + return _history->atTopImportantMsg(bottomUnderScrollTop); } void MainWidget::createDialog(History *history) { - dialogs.createDialog(history); + _dialogs->createDialog(history); } void MainWidget::choosePeer(PeerId peerId, MsgId showAtMsgId) { @@ -2337,19 +1982,19 @@ void MainWidget::clearBotStartToken(PeerData *peer) { } void MainWidget::contactsReceived() { - history.contactsReceived(); + _history->contactsReceived(); } void MainWidget::updateAfterDrag() { - if (overview) { - overview->updateAfterDrag(); + if (_overview) { + _overview->updateAfterDrag(); } else { - history.updateAfterDrag(); + _history->updateAfterDrag(); } } void MainWidget::ctrlEnterSubmitUpdated() { - history.updateFieldSubmitSettings(); + _history->updateFieldSubmitSettings(); } void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, bool back) { @@ -2375,11 +2020,11 @@ void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, bool bac Ui::hideLayer(); if (_hider) { _hider->startHide(); - _hider = 0; + _hider = nullptr; } QPixmap animCache, animTopBarCache; - if (!_a_show.animating() && ((history.isHidden() && (profile || overview)) || (Adaptive::OneColumn() && (history.isHidden() || !peerId)))) { + if (!_a_show.animating() && ((_history->isHidden() && (_profile || _overview)) || (Adaptive::OneColumn() && (_history->isHidden() || !peerId)))) { if (peerId) { animCache = grabInner(); } else if (Adaptive::OneColumn()) { @@ -2390,26 +2035,26 @@ void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, bool bac if (peerId || !Adaptive::OneColumn()) { animTopBarCache = grabTopBar(); } - history.show(); + _history->show(); } - if (history.peer() && history.peer()->id != peerId) clearBotStartToken(history.peer()); - history.showHistory(peerId, showAtMsgId); + if (_history->peer() && _history->peer()->id != peerId) clearBotStartToken(_history->peer()); + _history->showHistory(peerId, showAtMsgId); - bool noPeer = (!history.peer() || !history.peer()->id), onlyDialogs = noPeer && Adaptive::OneColumn(); - if (profile || overview) { - if (profile) { - profile->hide(); - profile->clear(); - profile->deleteLater(); - profile->rpcClear(); - profile = 0; + bool noPeer = (!_history->peer() || !_history->peer()->id), onlyDialogs = noPeer && Adaptive::OneColumn(); + if (_profile || _overview) { + if (_profile) { + _profile->hide(); + _profile->clear(); + _profile->deleteLater(); + _profile->rpcClear(); + _profile = nullptr; } - if (overview) { - overview->hide(); - overview->clear(); - overview->deleteLater(); - overview->rpcClear(); - overview = 0; + if (_overview) { + _overview->hide(); + _overview->clear(); + _overview->deleteLater(); + _overview->rpcClear(); + _overview = nullptr; } clearBotStartToken(_peerInStack); dlgUpdated(); @@ -2418,17 +2063,17 @@ void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, bool bac _stack.clear(); } if (onlyDialogs) { - _topBar.hide(); - history.hide(); + _topBar->hide(); + _history->hide(); if (!_a_show.animating()) { - dialogs.show(); + _dialogs->show(); if (!animCache.isNull()) { - dialogs.animShow(animCache); + _dialogs->animShow(animCache); } } } else { if (noPeer) { - _topBar.hide(); + _topBar->hide(); resizeEvent(0); } else if (wasActivePeer != activePeer()) { if (activePeer()->isChannel()) { @@ -2436,11 +2081,11 @@ void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, bool bac } _viewsIncremented.remove(activePeer()); } - if (Adaptive::OneColumn() && !dialogs.isHidden()) dialogs.hide(); + if (Adaptive::OneColumn() && !_dialogs->isHidden()) _dialogs->hide(); if (!_a_show.animating()) { - if (history.isHidden()) history.show(); + if (_history->isHidden()) _history->show(); if (!animCache.isNull()) { - history.animShow(animCache, animTopBarCache, back); + _history->animShow(animCache, animTopBarCache, back); } else if (App::wnd()) { QTimer::singleShot(0, App::wnd(), SLOT(setInnerFocus())); } @@ -2450,20 +2095,20 @@ void MainWidget::ui_showPeerHistory(quint64 peerId, qint32 showAtMsgId, bool bac // wasActivePeer->asChannel()->ptsWaitingForShortPoll(false); //} - if (!dialogs.isHidden()) { + if (!_dialogs->isHidden()) { if (!back) { - dialogs.scrollToPeer(peerId, showAtMsgId); + _dialogs->scrollToPeer(peerId, showAtMsgId); } - dialogs.update(); + _dialogs->update(); } App::wnd()->getTitle()->updateBackButton(); } PeerData *MainWidget::ui_getPeerForMouseAction() { - if (profile) { - return profile->ui_getPeerForMouseAction(); + if (_profile) { + return _profile->ui_getPeerForMouseAction(); } - return history.ui_getPeerForMouseAction(); + return _history->ui_getPeerForMouseAction(); } void MainWidget::peerBefore(const PeerData *inPeer, MsgId inMsg, PeerData *&outPeer, MsgId &outMsg) { @@ -2472,7 +2117,7 @@ void MainWidget::peerBefore(const PeerData *inPeer, MsgId inMsg, PeerData *&outP outMsg = 0; return; } - dialogs.peerBefore(inPeer, inMsg, outPeer, outMsg); + _dialogs->peerBefore(inPeer, inMsg, outPeer, outMsg); } void MainWidget::peerAfter(const PeerData *inPeer, MsgId inMsg, PeerData *&outPeer, MsgId &outMsg) { @@ -2481,35 +2126,35 @@ void MainWidget::peerAfter(const PeerData *inPeer, MsgId inMsg, PeerData *&outPe outMsg = 0; return; } - dialogs.peerAfter(inPeer, inMsg, outPeer, outMsg); + _dialogs->peerAfter(inPeer, inMsg, outPeer, outMsg); } PeerData *MainWidget::historyPeer() { - return history.peer(); + return _history->peer(); } PeerData *MainWidget::peer() { - return overview ? overview->peer() : history.peer(); + return _overview ? _overview->peer() : _history->peer(); } PeerData *MainWidget::activePeer() { - return history.peer() ? history.peer() : _peerInStack; + return _history->peer() ? _history->peer() : _peerInStack; } MsgId MainWidget::activeMsgId() { - return history.peer() ? history.msgId() : _msgIdInStack; + return _history->peer() ? _history->msgId() : _msgIdInStack; } PeerData *MainWidget::profilePeer() { - return profile ? profile->peer() : 0; + return _profile ? _profile->peer() : 0; } PeerData *MainWidget::overviewPeer() { - return overview ? overview->peer() : 0; + return _overview ? _overview->peer() : 0; } bool MainWidget::mediaTypeSwitch() { - if (!overview) return false; + if (!_overview) return false; for (int32 i = 0; i < OverviewCount; ++i) { if (!(_mediaTypeMask & ~(1 << i))) { @@ -2525,63 +2170,63 @@ void MainWidget::showMediaOverview(PeerData *peer, MediaOverviewType type, bool } App::wnd()->hideSettings(); - if (overview && overview->peer() == peer) { - if (overview->type() != type) { - overview->switchType(type); + if (_overview && _overview->peer() == peer) { + if (_overview->type() != type) { + _overview->switchType(type); } else if (type == OverviewMusicFiles) { // hack for player showBackFromStack(); } return; } - QRect topBarRect = QRect(_topBar.x(), _topBar.y(), _topBar.width(), st::topBarHeight); - QRect historyRect = QRect(history.x(), topBarRect.y() + topBarRect.height(), history.width(), history.y() + history.height() - topBarRect.y() - topBarRect.height()); + QRect topBarRect = QRect(_topBar->x(), _topBar->y(), _topBar->width(), st::topBarHeight); + QRect historyRect = QRect(_history->x(), topBarRect.y() + topBarRect.height(), _history->width(), _history->y() + _history->height() - topBarRect.y() - topBarRect.height()); QPixmap animCache, animTopBarCache; - if (!_a_show.animating() && (Adaptive::OneColumn() || profile || overview || history.peer())) { + if (!_a_show.animating() && (Adaptive::OneColumn() || _profile || _overview || _history->peer())) { animCache = grabInner(); animTopBarCache = grabTopBar(); } if (!back) { - if (overview) { - _stack.push_back(new StackItemOverview(overview->peer(), overview->type(), overview->lastWidth(), overview->lastScrollTop())); - } else if (profile) { - _stack.push_back(new StackItemProfile(profile->peer(), profile->lastScrollTop())); - } else if (history.peer()) { + if (_overview) { + _stack.push_back(new StackItemOverview(_overview->peer(), _overview->type(), _overview->lastWidth(), _overview->lastScrollTop())); + } else if (_profile) { + _stack.push_back(new StackItemProfile(_profile->peer(), _profile->lastScrollTop())); + } else if (_history->peer()) { dlgUpdated(); - _peerInStack = history.peer(); - _msgIdInStack = history.msgId(); + _peerInStack = _history->peer(); + _msgIdInStack = _history->msgId(); dlgUpdated(); - _stack.push_back(new StackItemHistory(_peerInStack, _msgIdInStack, history.replyReturns())); + _stack.push_back(new StackItemHistory(_peerInStack, _msgIdInStack, _history->replyReturns())); } } - if (overview) { - overview->hide(); - overview->clear(); - overview->deleteLater(); - overview->rpcClear(); + if (_overview) { + _overview->hide(); + _overview->clear(); + _overview->deleteLater(); + _overview->rpcClear(); } - if (profile) { - profile->hide(); - profile->clear(); - profile->deleteLater(); - profile->rpcClear(); - profile = 0; + if (_profile) { + _profile->hide(); + _profile->clear(); + _profile->deleteLater(); + _profile->rpcClear(); + _profile = nullptr; } - overview = new OverviewWidget(this, peer, type); + _overview = new OverviewWidget(this, peer, type); _mediaTypeMask = 0; - _topBar.show(); - resizeEvent(0); + _topBar->show(); + resizeEvent(nullptr); mediaOverviewUpdated(peer, type); if (!animCache.isNull()) { - overview->animShow(animCache, animTopBarCache, back, lastScrollTop); + _overview->animShow(animCache, animTopBarCache, back, lastScrollTop); } else { - overview->fastShow(); + _overview->fastShow(); } - history.animStop(); - if (back) clearBotStartToken(history.peer()); - history.showHistory(0, 0); - history.hide(); - if (Adaptive::OneColumn()) dialogs.hide(); + _history->animStop(); + if (back) clearBotStartToken(_history->peer()); + _history->showHistory(0, 0); + _history->hide(); + if (Adaptive::OneColumn()) _dialogs->hide(); orderWidgets(); @@ -2594,44 +2239,44 @@ void MainWidget::showPeerProfile(PeerData *peer, bool back, int32 lastScrollTop) } App::wnd()->hideSettings(); - if (profile && profile->peer() == peer) return; + if (_profile && _profile->peer() == peer) return; QPixmap animCache = grabInner(), animTopBarCache = grabTopBar(); if (!back) { - if (overview) { - _stack.push_back(new StackItemOverview(overview->peer(), overview->type(), overview->lastWidth(), overview->lastScrollTop())); - } else if (profile) { - _stack.push_back(new StackItemProfile(profile->peer(), profile->lastScrollTop())); - } else if (history.peer()) { + if (_overview) { + _stack.push_back(new StackItemOverview(_overview->peer(), _overview->type(), _overview->lastWidth(), _overview->lastScrollTop())); + } else if (_profile) { + _stack.push_back(new StackItemProfile(_profile->peer(), _profile->lastScrollTop())); + } else if (_history->peer()) { dlgUpdated(); - _peerInStack = history.peer(); - _msgIdInStack = history.msgId(); + _peerInStack = _history->peer(); + _msgIdInStack = _history->msgId(); dlgUpdated(); - _stack.push_back(new StackItemHistory(_peerInStack, _msgIdInStack, history.replyReturns())); + _stack.push_back(new StackItemHistory(_peerInStack, _msgIdInStack, _history->replyReturns())); } } - if (overview) { - overview->hide(); - overview->clear(); - overview->deleteLater(); - overview->rpcClear(); - overview = 0; + if (_overview) { + _overview->hide(); + _overview->clear(); + _overview->deleteLater(); + _overview->rpcClear(); + _overview = nullptr; } - if (profile) { - profile->hide(); - profile->clear(); - profile->deleteLater(); - profile->rpcClear(); + if (_profile) { + _profile->hide(); + _profile->clear(); + _profile->deleteLater(); + _profile->rpcClear(); } - profile = new ProfileWidget(this, peer); - _topBar.show(); + _profile = new ProfileWidget(this, peer); + _topBar->show(); resizeEvent(0); - profile->animShow(animCache, animTopBarCache, back, lastScrollTop); - history.animStop(); - if (back) clearBotStartToken(history.peer()); - history.showHistory(0, 0); - history.hide(); - if (Adaptive::OneColumn()) dialogs.hide(); + _profile->animShow(animCache, animTopBarCache, back, lastScrollTop); + _history->animStop(); + if (back) clearBotStartToken(_history->peer()); + _history->showHistory(0, 0); + _history->hide(); + if (Adaptive::OneColumn()) _dialogs->hide(); orderWidgets(); @@ -2661,7 +2306,7 @@ void MainWidget::showBackFromStack() { } StackItemHistory *histItem = static_cast(item); Ui::showPeerHistory(histItem->peer->id, App::main()->activeMsgId(), true); - history.setReplyReturns(histItem->peer->id, histItem->replyReturns); + _history->setReplyReturns(histItem->peer->id, histItem->replyReturns); } else if (item->type() == ProfileStackItem) { StackItemProfile *profItem = static_cast(item); showPeerProfile(profItem->peer, true, profItem->lastScrollTop); @@ -2673,43 +2318,43 @@ void MainWidget::showBackFromStack() { } void MainWidget::orderWidgets() { - _topBar.raise(); - _player.raise(); - dialogs.raise(); - _mediaType.raise(); + _topBar->raise(); + _player->raise(); + _dialogs->raise(); + _mediaType->raise(); if (_hider) _hider->raise(); } QRect MainWidget::historyRect() const { - QRect r(history.historyRect()); - r.moveLeft(r.left() + history.x()); - r.moveTop(r.top() + history.y()); + QRect r(_history->historyRect()); + r.moveLeft(r.left() + _history->x()); + r.moveTop(r.top() + _history->y()); return r; } void MainWidget::dlgUpdated() { if (_peerInStack) { - dialogs.dlgUpdated(App::history(_peerInStack->id), _msgIdInStack); + _dialogs->dlgUpdated(App::history(_peerInStack->id), _msgIdInStack); } } void MainWidget::dlgUpdated(Dialogs::Mode list, Dialogs::Row *row) { if (row) { - dialogs.dlgUpdated(list, row); + _dialogs->dlgUpdated(list, row); } } void MainWidget::dlgUpdated(History *row, MsgId msgId) { if (!row) return; if (msgId < 0 && -msgId < ServerMaxMsgId && row->peer->migrateFrom()) { - dialogs.dlgUpdated(App::history(row->peer->migrateFrom()->id), -msgId); + _dialogs->dlgUpdated(App::history(row->peer->migrateFrom()->id), -msgId); } else { - dialogs.dlgUpdated(row, msgId); + _dialogs->dlgUpdated(row, msgId); } } void MainWidget::windowShown() { - history.windowShown(); + _history->windowShown(); } void MainWidget::sentUpdatesReceived(uint64 randomId, const MTPUpdates &result) { @@ -2739,23 +2384,23 @@ void MainWidget::onActiveChannelUpdateFull() { } void MainWidget::historyToDown(History *hist) { - history.historyToDown(hist); + _history->historyToDown(hist); } void MainWidget::dialogsToUp() { - dialogs.dialogsToUp(); + _dialogs->dialogsToUp(); } void MainWidget::newUnreadMsg(History *hist, HistoryItem *item) { - history.newUnreadMsg(hist, item); + _history->newUnreadMsg(hist, item); } void MainWidget::historyWasRead() { - history.historyWasRead(false); + _history->historyWasRead(false); } void MainWidget::historyCleared(History *hist) { - history.historyCleared(hist); + _history->historyCleared(hist); } void MainWidget::animShow(const QPixmap &bgAnimCache, bool back) { @@ -2822,17 +2467,17 @@ void MainWidget::paintEvent(QPaintEvent *e) { } void MainWidget::hideAll() { - dialogs.hide(); - history.hide(); - if (profile) { - profile->hide(); + _dialogs->hide(); + _history->hide(); + if (_profile) { + _profile->hide(); } - if (overview) { - overview->hide(); + if (_overview) { + _overview->hide(); } - _topBar.hide(); - _mediaType.hide(); - _player.hide(); + _topBar->hide(); + _mediaType->hide(); + _player->hide(); _playerHeight = 0; } @@ -2852,25 +2497,25 @@ void MainWidget::showAll() { } } if (selectingPeer()) { - dialogs.show(); - history.hide(); - if (overview) overview->hide(); - if (profile) profile->hide(); - _topBar.hide(); - } else if (overview) { - overview->show(); - } else if (profile) { - profile->show(); - } else if (history.peer()) { - history.show(); - history.resizeEvent(0); + _dialogs->show(); + _history->hide(); + if (_overview) _overview->hide(); + if (_profile) _profile->hide(); + _topBar->hide(); + } else if (_overview) { + _overview->show(); + } else if (_profile) { + _profile->show(); + } else if (_history->peer()) { + _history->show(); + _history->resizeEvent(0); } else { - dialogs.show(); - history.hide(); + _dialogs->show(); + _history->hide(); } - if (!selectingPeer() && (profile || overview || history.peer())) { - _topBar.show(); - dialogs.hide(); + if (!selectingPeer() && (_profile || _overview || _history->peer())) { + _topBar->show(); + _dialogs->hide(); } } else { if (_hider) { @@ -2880,17 +2525,17 @@ void MainWidget::showAll() { _forwardConfirm = 0; } } - dialogs.show(); - if (overview) { - overview->show(); - } else if (profile) { - profile->show(); + _dialogs->show(); + if (_overview) { + _overview->show(); + } else if (_profile) { + _profile->show(); } else { - history.show(); - history.resizeEvent(0); + _history->show(); + _history->resizeEvent(0); } - if (profile || overview || history.peer()) { - _topBar.show(); + if (_profile || _overview || _history->peer()) { + _topBar->show(); } } if (audioPlayer()) { @@ -2900,11 +2545,11 @@ void MainWidget::showAll() { int32 playingFrequency = 0; audioPlayer()->currentState(&playing, &playingState, &playingPosition, &playingDuration, &playingFrequency); if (playing) { - _player.updateState(playing, playingState, playingPosition, playingDuration, playingFrequency); + _player->updateState(playing, playingState, playingPosition, playingDuration, playingFrequency); if (!(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) { - _player.clearSelection(); - _player.show(); - _playerHeight = _player.height(); + _player->clearSelection(); + _player->show(); + _playerHeight = _player->height(); } } } @@ -2914,32 +2559,32 @@ void MainWidget::showAll() { } void MainWidget::resizeEvent(QResizeEvent *e) { - int32 tbh = _topBar.isHidden() ? 0 : st::topBarHeight; + int32 tbh = _topBar->isHidden() ? 0 : st::topBarHeight; if (Adaptive::OneColumn()) { _dialogsWidth = width(); - _player.setGeometry(0, 0, _dialogsWidth, _player.height()); - dialogs.setGeometry(0, _playerHeight, _dialogsWidth, height() - _playerHeight); - _topBar.setGeometry(0, _playerHeight, _dialogsWidth, st::topBarHeight); - history.setGeometry(0, _playerHeight + tbh, _dialogsWidth, height() - _playerHeight - tbh); + _player->setGeometry(0, 0, _dialogsWidth, _player->height()); + _dialogs->setGeometry(0, _playerHeight, _dialogsWidth, height() - _playerHeight); + _topBar->setGeometry(0, _playerHeight, _dialogsWidth, st::topBarHeight); + _history->setGeometry(0, _playerHeight + tbh, _dialogsWidth, height() - _playerHeight - tbh); if (_hider) _hider->setGeometry(0, 0, _dialogsWidth, height()); } else { _dialogsWidth = chatsListWidth(width()); - dialogs.resize(_dialogsWidth, height()); - dialogs.moveToLeft(0, 0); - _player.resize(width() - _dialogsWidth, _player.height()); - _player.moveToLeft(_dialogsWidth, 0); - _topBar.resize(width() - _dialogsWidth, st::topBarHeight); - _topBar.moveToLeft(_dialogsWidth, _playerHeight); - history.resize(width() - _dialogsWidth, height() - _playerHeight - tbh); - history.moveToLeft(_dialogsWidth, _playerHeight + tbh); + _dialogs->resize(_dialogsWidth, height()); + _dialogs->moveToLeft(0, 0); + _player->resize(width() - _dialogsWidth, _player->height()); + _player->moveToLeft(_dialogsWidth, 0); + _topBar->resize(width() - _dialogsWidth, st::topBarHeight); + _topBar->moveToLeft(_dialogsWidth, _playerHeight); + _history->resize(width() - _dialogsWidth, height() - _playerHeight - tbh); + _history->moveToLeft(_dialogsWidth, _playerHeight + tbh); if (_hider) { _hider->resize(width() - _dialogsWidth, height()); _hider->moveToLeft(_dialogsWidth, 0); } } - _mediaType.moveToLeft(width() - _mediaType.width(), _playerHeight + st::topBarHeight); - if (profile) profile->setGeometry(history.geometry()); - if (overview) overview->setGeometry(history.geometry()); + _mediaType->moveToLeft(width() - _mediaType->width(), _playerHeight + st::topBarHeight); + if (_profile) _profile->setGeometry(_history->geometry()); + if (_overview) _overview->setGeometry(_history->geometry()); _contentScrollAddToY = 0; } @@ -2952,96 +2597,96 @@ void MainWidget::keyPressEvent(QKeyEvent *e) { void MainWidget::updateAdaptiveLayout() { showAll(); - _topBar.updateAdaptiveLayout(); - history.updateAdaptiveLayout(); - if (overview) overview->updateAdaptiveLayout(); - if (profile) profile->updateAdaptiveLayout(); - _player.updateAdaptiveLayout(); + _topBar->updateAdaptiveLayout(); + _history->updateAdaptiveLayout(); + if (_overview) _overview->updateAdaptiveLayout(); + if (_profile) _profile->updateAdaptiveLayout(); + _player->updateAdaptiveLayout(); } bool MainWidget::needBackButton() { - return overview || profile || (history.peer() && history.peer()->id); + return _overview || _profile || (_history->peer() && _history->peer()->id); } void MainWidget::paintTopBar(QPainter &p, float64 over, int32 decreaseWidth) { - if (profile) { - profile->paintTopBar(p, over, decreaseWidth); - } else if (overview) { - overview->paintTopBar(p, over, decreaseWidth); + if (_profile) { + _profile->paintTopBar(p, over, decreaseWidth); + } else if (_overview) { + _overview->paintTopBar(p, over, decreaseWidth); } else { - history.paintTopBar(p, over, decreaseWidth); + _history->paintTopBar(p, over, decreaseWidth); } } void MainWidget::onPhotosSelect() { - if (overview) overview->switchType(OverviewPhotos); - _mediaType.hideStart(); + if (_overview) _overview->switchType(OverviewPhotos); + _mediaType->hideStart(); } void MainWidget::onVideosSelect() { - if (overview) overview->switchType(OverviewVideos); - _mediaType.hideStart(); + if (_overview) _overview->switchType(OverviewVideos); + _mediaType->hideStart(); } void MainWidget::onSongsSelect() { - if (overview) overview->switchType(OverviewMusicFiles); - _mediaType.hideStart(); + if (_overview) _overview->switchType(OverviewMusicFiles); + _mediaType->hideStart(); } void MainWidget::onDocumentsSelect() { - if (overview) overview->switchType(OverviewFiles); - _mediaType.hideStart(); + if (_overview) _overview->switchType(OverviewFiles); + _mediaType->hideStart(); } void MainWidget::onAudiosSelect() { - if (overview) overview->switchType(OverviewVoiceFiles); - _mediaType.hideStart(); + if (_overview) _overview->switchType(OverviewVoiceFiles); + _mediaType->hideStart(); } void MainWidget::onLinksSelect() { - if (overview) overview->switchType(OverviewLinks); - _mediaType.hideStart(); + if (_overview) _overview->switchType(OverviewLinks); + _mediaType->hideStart(); } -TopBarWidget *MainWidget::topBar() { - return &_topBar; +Window::TopBarWidget *MainWidget::topBar() { + return _topBar; } PlayerWidget *MainWidget::player() { - return &_player; + return _player; } void MainWidget::onTopBarClick() { - if (profile) { - profile->topBarClick(); - } else if (overview) { - overview->topBarClick(); + if (_profile) { + _profile->topBarClick(); + } else if (_overview) { + _overview->topBarClick(); } else { - history.topBarClick(); + _history->topBarClick(); } } void MainWidget::onHistoryShown(History *history, MsgId atMsgId) { - if ((!Adaptive::OneColumn() || !selectingPeer()) && (profile || overview || history)) { - _topBar.show(); + if ((!Adaptive::OneColumn() || !selectingPeer()) && (_profile || _overview || history)) { + _topBar->show(); } else { - _topBar.hide(); + _topBar->hide(); } resizeEvent(0); if (_a_show.animating()) { - _topBar.hide(); + _topBar->hide(); } dlgUpdated(history, atMsgId); } void MainWidget::searchInPeer(PeerData *peer) { - dialogs.searchInPeer(peer); + _dialogs->searchInPeer(peer); if (Adaptive::OneColumn()) { dialogsToUp(); Ui::showChatsList(); } else { - dialogs.activate(); + _dialogs->activate(); } } @@ -3147,9 +2792,9 @@ void MainWidget::gotChannelDifference(ChannelData *channel, const MTPupdates_Cha h->asChannelHistory()->unreadCountAll = d.vunread_count.v; h->inboxReadBefore = d.vread_inbox_max_id.v + 1; } - if (history.peer() == channel) { - history.updateToEndVisibility(); - history.preloadHistoryIfNeeded(); + if (_history->peer() == channel) { + _history->updateToEndVisibility(); + _history->preloadHistoryIfNeeded(); } h->asChannelHistory()->getRangeDifference(); } @@ -3177,7 +2822,7 @@ void MainWidget::gotChannelDifference(ChannelData *channel, const MTPupdates_Cha switch (msg.type()) { case mtpc_message: { const auto &d(msg.c_message()); - if (App::checkEntitiesAndViewsUpdate(d)) { // new message, index my forwarded messages to links overview, already in blocks + if (App::checkEntitiesAndViewsUpdate(d)) { // new message, index my forwarded messages to links _overview, already in blocks LOG(("Skipping message, because it is already in blocks!")); } else { msgsIds.insert((uint64(uint32(d.vid.v)) << 32) | uint64(i), i + 1); @@ -3299,7 +2944,7 @@ void MainWidget::gotState(const MTPupdates_State &state) { noUpdatesTimer.start(NoUpdatesTimeout); _ptsWaiter.setRequesting(false); - dialogs.loadDialogs(); + _dialogs->loadDialogs(); updateOnline(); App::emitPeerUpdated(); @@ -3435,7 +3080,7 @@ void MainWidget::feedDifference(const MTPVector &users, const MTPVector feedMessageIds(other); App::feedMsgs(msgs, NewMessageUnread); feedUpdateVector(other, true); - history.peerMessagesUpdated(); + _history->peerMessagesUpdated(); } bool MainWidget::failDifference(const RPCError &error) { @@ -3584,7 +3229,7 @@ void MainWidget::start(const MTPUser &user) { App::wnd()->sendServiceHistoryRequest(); Local::readStickers(); Local::readSavedGifs(); - history.start(); + _history->start(); } bool MainWidget::started() { @@ -3663,9 +3308,9 @@ void MainWidget::openPeerByName(const QString &username, MsgId msgId, const QStr } if (peer->isUser() && peer->asUser()->botInfo) { peer->asUser()->botInfo->startToken = startToken; - if (peer == history.peer()) { - history.updateControlsVisibility(); - history.resizeEvent(0); + if (peer == _history->peer()) { + _history->updateControlsVisibility(); + _history->resizeEvent(0); } } Ui::showPeerHistoryAsync(peer->id, msgId); @@ -3689,7 +3334,7 @@ void MainWidget::stickersBox(const MTPInputStickerSet &set) { void MainWidget::onStickersInstalled(uint64 setId) { emit stickersUpdated(); - history.stickersInstalled(setId); + _history->stickersInstalled(setId); } void MainWidget::onFullPeerUpdated(PeerData *peer) { @@ -3704,17 +3349,17 @@ void MainWidget::onSelfParticipantUpdated(ChannelData *channel) { checkPeerHistory(channel); } else { h->asChannelHistory()->checkJoinedMessage(true); - history.peerMessagesUpdated(channel->id); + _history->peerMessagesUpdated(channel->id); } } else if (h) { h->asChannelHistory()->checkJoinedMessage(); - history.peerMessagesUpdated(channel->id); + _history->peerMessagesUpdated(channel->id); } } bool MainWidget::contentOverlapped(const QRect &globalRect) { - return (history.contentOverlapped(globalRect) || - _mediaType.overlaps(globalRect)); + return (_history->contentOverlapped(globalRect) || + _mediaType->overlaps(globalRect)); } void MainWidget::usernameResolveDone(QPair msgIdAndStartToken, const MTPcontacts_ResolvedPeer &result) { @@ -3746,9 +3391,9 @@ void MainWidget::usernameResolveDone(QPair msgIdAndStartToken, c } if (peer->isUser() && peer->asUser()->botInfo) { peer->asUser()->botInfo->startToken = startToken; - if (peer == history.peer()) { - history.updateControlsVisibility(); - history.resizeEvent(0); + if (peer == _history->peer()) { + _history->updateControlsVisibility(); + _history->resizeEvent(0); } } Ui::showPeerHistory(peer->id, msgId); @@ -3893,12 +3538,12 @@ void MainWidget::applyNotifySetting(const MTPNotifyPeer &peer, const MTPPeerNoti } if (updatePeer) { - if (history.peer() == updatePeer) { - history.updateNotifySettings(); + if (_history->peer() == updatePeer) { + _history->updateNotifySettings(); } - dialogs.updateNotifySettings(updatePeer); - if (profile && profile->peer() == updatePeer) { - profile->updateNotifySettings(); + _dialogs->updateNotifySettings(updatePeer); + if (_profile && _profile->peer() == updatePeer) { + _profile->updateNotifySettings(); } } } @@ -3959,7 +3604,7 @@ void MainWidget::updateNotifySetting(PeerData *peer, NotifySettingStatus notify, } App::history(peer->id)->setMute(notify == NotifySettingSetMuted); } - if (history.peer() == peer) history.updateNotifySettings(); + if (_history->peer() == peer) _history->updateNotifySettings(); updateNotifySettingTimer.start(NotifySettingSaveTimeout); } @@ -4032,25 +3677,25 @@ void MainWidget::incrementSticker(DocumentData *sticker) { ++it->count; Local::writeStickers(); } - history.updateRecentStickers(); + _history->updateRecentStickers(); } void MainWidget::activate() { if (_a_show.animating()) return; - if (!profile && !overview) { + if (!_profile && !_overview) { if (_hider) { if (_hider->wasOffered()) { _hider->setFocus(); } else { - dialogs.activate(); + _dialogs->activate(); } } else if (App::wnd() && !Ui::isLayerShown()) { if (!cSendPaths().isEmpty()) { forwardLayer(-1); - } else if (history.peer()) { - history.activate(); + } else if (_history->peer()) { + _history->activate(); } else { - dialogs.activate(); + _dialogs->activate(); } } } @@ -4058,8 +3703,8 @@ void MainWidget::activate() { } void MainWidget::destroyData() { - history.destroyData(); - dialogs.destroyData(); + _history->destroyData(); + _dialogs->destroyData(); } void MainWidget::updateOnlineDisplayIn(int32 msecs) { @@ -4071,7 +3716,7 @@ bool MainWidget::isActive() const { } bool MainWidget::historyIsActive() const { - return isActive() && !profile && !overview && history.isActive(); + return isActive() && !_profile && !_overview && _history->isActive(); } bool MainWidget::lastWasOnline() const { @@ -4083,17 +3728,15 @@ uint64 MainWidget::lastSetOnline() const { } int32 MainWidget::dlgsWidth() const { - return dialogs.width(); + return _dialogs->width(); } MainWidget::~MainWidget() { - if (App::main() == this) history.showHistory(0, 0); - - delete _background; + if (App::main() == this) _history->showHistory(0, 0); delete _hider; MTP::clearGlobalHandlers(); - delete _api; + if (App::wnd()) App::wnd()->noMain(this); } @@ -4244,7 +3887,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) { MTPDmessage::Flags flags = mtpCastFlags(d.vflags.v) | MTPDmessage::Flag::f_from_id; HistoryItem *item = App::histories().addNewMessage(MTP_message(MTP_flags(flags), d.vid, d.is_out() ? MTP_int(MTP::authedId()) : d.vuser_id, MTP_peerUser(d.is_out() ? d.vuser_id : MTP_int(MTP::authedId())), d.vfwd_from, d.vvia_bot_id, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup, d.has_entities() ? d.ventities : MTPnullEntities, MTPint(), MTPint()), NewMessageUnread); if (item) { - history.peerMessagesUpdated(item->history()->peer->id); + _history->peerMessagesUpdated(item->history()->peer->id); } ptsApplySkippedUpdates(); @@ -4279,7 +3922,7 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) { MTPDmessage::Flags flags = mtpCastFlags(d.vflags.v) | MTPDmessage::Flag::f_from_id; HistoryItem *item = App::histories().addNewMessage(MTP_message(MTP_flags(flags), d.vid, d.vfrom_id, MTP_peerChat(d.vchat_id), d.vfwd_from, d.vvia_bot_id, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup, d.has_entities() ? d.ventities : MTPnullEntities, MTPint(), MTPint()), NewMessageUnread); if (item) { - history.peerMessagesUpdated(item->history()->peer->id); + _history->peerMessagesUpdated(item->history()->peer->id); } ptsApplySkippedUpdates(); @@ -4400,7 +4043,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { // update before applying skipped bool needToAdd = true; - if (d.vmessage.type() == mtpc_message) { // index forwarded messages to links overview + if (d.vmessage.type() == mtpc_message) { // index forwarded messages to links _overview if (App::checkEntitiesAndViewsUpdate(d.vmessage.c_message())) { // already in blocks LOG(("Skipping message, because it is already in blocks!")); needToAdd = false; @@ -4409,7 +4052,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { if (needToAdd) { HistoryItem *item = App::histories().addNewMessage(d.vmessage, NewMessageUnread); if (item) { - history.peerMessagesUpdated(item->history()->peer->id); + _history->peerMessagesUpdated(item->history()->peer->id); } } ptsApplySkippedUpdates(); @@ -4428,7 +4071,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { if (wasLast && !h->lastMsg) { checkPeerHistory(h->peer); } - history.peerMessagesUpdated(); + _history->peerMessagesUpdated(); } else { App::historyUnregItem(msgRow); if (App::wnd()) App::wnd()->changingMsgId(msgRow, d.vid.v); @@ -4492,8 +4135,8 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { // update before applying skipped PeerId id = peerFromMTP(d.vpeer); App::feedOutboxRead(id, d.vmax_id.v); - if (history.peer() && history.peer()->id == id) { - history.update(); + if (_history->peer() && _history->peer()->id == id) { + _history->update(); } if (History *h = App::historyLoaded(id)) { if (h->lastMsg && h->lastMsg->out() && h->lastMsg->id <= d.vmax_id.v) { @@ -4514,7 +4157,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { // update before applying skipped App::feedWebPage(d.vwebpage); - history.updatePreview(); + _history->updatePreview(); webPagesUpdate(); ptsApplySkippedUpdates(); @@ -4529,7 +4172,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { // update before applying skipped App::feedWereDeleted(NoChannel, d.vmessages.c_vector().v); - history.peerMessagesUpdated(); + _history->peerMessagesUpdated(); ptsApplySkippedUpdates(); } break; @@ -4773,7 +4416,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { // update before applying skipped bool needToAdd = true; - if (d.vmessage.type() == mtpc_message) { // index forwarded messages to links overview + if (d.vmessage.type() == mtpc_message) { // index forwarded messages to links _overview if (App::checkEntitiesAndViewsUpdate(d.vmessage.c_message())) { // already in blocks LOG(("Skipping message, because it is already in blocks!")); needToAdd = false; @@ -4782,7 +4425,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { if (needToAdd) { HistoryItem *item = App::histories().addNewMessage(d.vmessage, NewMessageUnread); if (item) { - history.peerMessagesUpdated(item->history()->peer->id); + _history->peerMessagesUpdated(item->history()->peer->id); } } if (channel && !_handlingChannelDifference) { @@ -4858,7 +4501,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { // update before applying skipped App::feedWereDeleted(d.vchannel_id.v, d.vmessages.c_vector().v); - history.peerMessagesUpdated(); + _history->peerMessagesUpdated(); if (channel && !_handlingChannelDifference) { channel->ptsApplySkippedUpdates(); diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index 945225f6b..18c214d5a 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -20,15 +20,22 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #pragma once -#include "apiwrap.h" -#include "dialogswidget.h" -#include "historywidget.h" -#include "profilewidget.h" -#include "overviewwidget.h" -#include "playerwidget.h" -#include "ui/buttons/peer_avatar_button.h" +#include "localimageloader.h" +#include "history/history_common.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 MainWidget; class ConfirmBox; @@ -37,90 +44,8 @@ class HistoryWidget; class ProfileWidget; class OverviewWidget; class PlayerWidget; - -namespace Dialogs { -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; - -}; +class HistoryHider; +class Dropdown; enum StackItemType { HistoryStackItem, @@ -220,7 +145,7 @@ class MainWidget : public TWidget, public RPCSender { public: - MainWidget(Window *window); + MainWidget(MainWindow *window); void paintEvent(QPaintEvent *e) override; void resizeEvent(QResizeEvent *e) override; @@ -230,7 +155,7 @@ public: bool needBackButton(); void paintTopBar(QPainter &p, float64 over, int32 decreaseWidth); - TopBarWidget *topBar(); + Window::TopBarWidget *topBar(); PlayerWidget *player(); int contentScrollAddToY() const; @@ -623,14 +548,14 @@ private: int _dialogsWidth = st::dlgMinWidth; - DialogsWidget dialogs; - HistoryWidget history; - ProfileWidget* profile = nullptr; - OverviewWidget* overview = nullptr; - PlayerWidget _player; - TopBarWidget _topBar; + ChildWidget _dialogs; + ChildWidget _history; + ChildWidget _profile = nullptr; + ChildWidget _overview = nullptr; + ChildWidget _player; + ChildWidget _topBar; ConfirmBox *_forwardConfirm = nullptr; // for single column layout - HistoryHider *_hider = nullptr; + ChildWidget _hider = nullptr; StackItems _stack; PeerData *_peerInStack = nullptr; MsgId _msgIdInStack = 0; @@ -638,7 +563,7 @@ private: int _playerHeight = 0; int _contentScrollAddToY = 0; - Dropdown _mediaType; + ChildWidget _mediaType; int32 _mediaTypeMask = 0; int32 updDate = 0; @@ -711,8 +636,8 @@ private: void viewsIncrementDone(QVector ids, const MTPVector &result, mtpRequestId req); bool viewsIncrementFail(const RPCError &error, mtpRequestId req); - App::WallPaper *_background = nullptr; + std_::unique_ptr _background; - ApiWrap *_api; + std_::unique_ptr _api; }; diff --git a/Telegram/SourceFiles/window.cpp b/Telegram/SourceFiles/mainwindow.cpp similarity index 94% rename from Telegram/SourceFiles/window.cpp rename to Telegram/SourceFiles/mainwindow.cpp index 1c6b252ad..fe4e23e7a 100644 --- a/Telegram/SourceFiles/window.cpp +++ b/Telegram/SourceFiles/mainwindow.cpp @@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #include "stdafx.h" -#include "window.h" +#include "mainwindow.h" #include "zip.h" @@ -364,7 +364,7 @@ NotifyWindow::~NotifyWindow() { 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); icon32 = icon256.scaledToWidth(32, Qt::SmoothTransformation); icon64 = icon256.scaledToWidth(64, Qt::SmoothTransformation); @@ -400,7 +400,7 @@ Window::Window(QWidget *parent) : PsMainWindow(parent) { setAttribute(Qt::WA_OpaquePaintEvent); } -void Window::inactivePress(bool inactive) { +void MainWindow::inactivePress(bool inactive) { _inactivePress = inactive; if (_inactivePress) { _inactiveTimer.start(200); @@ -409,15 +409,15 @@ void Window::inactivePress(bool inactive) { } } -bool Window::inactivePress() const { +bool MainWindow::inactivePress() const { return _inactivePress; } -void Window::onInactiveTimer() { +void MainWindow::onInactiveTimer() { inactivePress(false); } -void Window::stateChanged(Qt::WindowState state) { +void MainWindow::stateChanged(Qt::WindowState state) { psUserActionDone(); updateIsActive((state == Qt::WindowMinimized) ? Global::OfflineBlurTimeout() : Global::OnlineFocusTimeout()); @@ -429,7 +429,7 @@ void Window::stateChanged(Qt::WindowState state) { psSavePosition(state); } -void Window::init() { +void MainWindow::init() { psInitFrameless(); setWindowIcon(wndIcon); @@ -446,7 +446,7 @@ void Window::init() { psInitSize(); } -void Window::firstShow() { +void MainWindow::firstShow() { #ifdef Q_OS_WIN trayIconMenu = new PopupMenu(); trayIconMenu->deleteOnHide(false); @@ -472,11 +472,11 @@ void Window::firstShow() { updateTrayMenu(); } -QWidget *Window::filedialogParent() { +QWidget *MainWindow::filedialogParent() { return (_mediaView && _mediaView->isVisible()) ? (QWidget*)_mediaView : (QWidget*)this; } -void Window::clearWidgets() { +void MainWindow::clearWidgets() { Ui::hideLayer(true); if (_passcode) { _passcode->hide(); @@ -511,7 +511,7 @@ void Window::clearWidgets() { updateGlobalMenu(); } -QPixmap Window::grabInner() { +QPixmap MainWindow::grabInner() { QPixmap result; if (settings) { result = myGrab(settings); @@ -525,7 +525,7 @@ QPixmap Window::grabInner() { return result; } -void Window::clearPasscode() { +void MainWindow::clearPasscode() { if (!_passcode) return; QPixmap bg = grabInner(); @@ -546,7 +546,7 @@ void Window::clearPasscode() { updateGlobalMenu(); } -void Window::setupPasscode(bool anim) { +void MainWindow::setupPasscode(bool anim) { QPixmap bg = grabInner(); if (_passcode) { @@ -570,7 +570,7 @@ void Window::setupPasscode(bool anim) { updateGlobalMenu(); } -void Window::checkAutoLockIn(int msec) { +void MainWindow::checkAutoLockIn(int msec) { if (_autoLockTimer.isActive()) { int remain = _autoLockTimer.remainingTime(); if (remain > 0 && remain <= msec) return; @@ -578,7 +578,7 @@ void Window::checkAutoLockIn(int msec) { _autoLockTimer.start(msec); } -void Window::checkAutoLock() { +void MainWindow::checkAutoLock() { if (!cHasPasscode() || App::passcoded()) return; App::app()->checkLocalTime(); @@ -591,7 +591,7 @@ void Window::checkAutoLock() { } } -void Window::setupIntro(bool anim) { +void MainWindow::setupIntro(bool anim) { cSetContactsReceived(false); cSetDialogsReceived(false); 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); } -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; if (!h || (!force && h->isEmpty())) { _delayedServiceMsgs.push_back(DelayedServiceMsg(msg, media)); @@ -630,7 +630,7 @@ void Window::serviceNotification(const QString &msg, const MTPMessageMedia &medi main->serviceNotification(msg, media); } -void Window::showDelayedServiceMsgs() { +void MainWindow::showDelayedServiceMsgs() { QVector toAdd = _delayedServiceMsgs; _delayedServiceMsgs.clear(); for (QVector::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; 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)); } -void Window::setupMain(bool anim, const MTPUser *self) { +void MainWindow::setupMain(bool anim, const MTPUser *self) { QPixmap bg = anim ? grabInner() : QPixmap(); clearWidgets(); main = new MainWidget(this); @@ -673,14 +673,14 @@ void Window::setupMain(bool anim, const MTPUser *self) { _mediaView = new MediaView(); } -void Window::updateCounter() { +void MainWindow::updateCounter() { if (!Global::started() || App::quitting()) return; psUpdateCounter(); title->updateCounter(); } -void Window::showSettings() { +void MainWindow::showSettings() { if (_passcode) return; if (isHidden()) showFromTray(); @@ -705,7 +705,7 @@ void Window::showSettings() { fixOrder(); } -void Window::hideSettings(bool fast) { +void MainWindow::hideSettings(bool fast) { if (!settings || _passcode) return; if (fast) { @@ -738,14 +738,14 @@ void Window::hideSettings(bool fast) { fixOrder(); } -void Window::mtpStateChanged(int32 dc, int32 state) { +void MainWindow::mtpStateChanged(int32 dc, int32 state) { if (dc == MTP::maindc()) { updateTitleStatus(); if (settings) settings->updateConnectionType(); } } -void Window::updateTitleStatus() { +void MainWindow::updateTitleStatus() { int32 state = MTP::dcstate(); if (state == MTP::ConnectingState || state == MTP::DisconnectedState || (state < 0 && state > -600)) { if (main || getms() > 5000 || _connecting) { @@ -759,48 +759,48 @@ void Window::updateTitleStatus() { } } -IntroWidget *Window::introWidget() { +IntroWidget *MainWindow::introWidget() { return intro; } -MainWidget *Window::mainWidget() { +MainWidget *MainWindow::mainWidget() { return main; } -SettingsWidget *Window::settingsWidget() { +SettingsWidget *MainWindow::settingsWidget() { return settings; } -PasscodeWidget *Window::passcodeWidget() { +PasscodeWidget *MainWindow::passcodeWidget() { 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); } -void Window::showPhoto(PhotoData *photo, HistoryItem *item) { +void MainWindow::showPhoto(PhotoData *photo, HistoryItem *item) { if (_mediaView->isHidden()) Ui::hideLayer(true); _mediaView->showPhoto(photo, item); _mediaView->activateWindow(); _mediaView->setFocus(); } -void Window::showPhoto(PhotoData *photo, PeerData *peer) { +void MainWindow::showPhoto(PhotoData *photo, PeerData *peer) { if (_mediaView->isHidden()) Ui::hideLayer(true); _mediaView->showPhoto(photo, peer); _mediaView->activateWindow(); _mediaView->setFocus(); } -void Window::showDocument(DocumentData *doc, HistoryItem *item) { +void MainWindow::showDocument(DocumentData *doc, HistoryItem *item) { if (_mediaView->isHidden()) Ui::hideLayer(true); _mediaView->showDocument(doc, item); _mediaView->activateWindow(); _mediaView->setFocus(); } -void Window::ui_showLayer(LayeredWidget *box, ShowLayerOptions options) { +void MainWindow::ui_showLayer(LayeredWidget *box, ShowLayerOptions options) { if (box) { bool fast = (options.testFlag(ForceFastShowLayer)) || Ui::isLayerShown(); if (layerBg) { @@ -837,15 +837,15 @@ void Window::ui_showLayer(LayeredWidget *box, ShowLayerOptions options) { } } -bool Window::ui_isLayerShown() { +bool MainWindow::ui_isLayerShown() { return !!layerBg; } -bool Window::ui_isMediaViewShown() { +bool MainWindow::ui_isMediaViewShown() { 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 (!_mediaPreview) { _mediaPreview = std_::make_unique(this); @@ -857,7 +857,7 @@ void Window::ui_showMediaPreview(DocumentData *document) { _mediaPreview->showPreview(document); } -void Window::ui_showMediaPreview(PhotoData *photo) { +void MainWindow::ui_showMediaPreview(PhotoData *photo) { if (!photo) return; if (!_mediaPreview) { _mediaPreview = std_::make_unique(this); @@ -869,12 +869,12 @@ void Window::ui_showMediaPreview(PhotoData *photo) { _mediaPreview->showPreview(photo); } -void Window::ui_hideMediaPreview() { +void MainWindow::ui_hideMediaPreview() { if (!_mediaPreview) return; _mediaPreview->hidePreview(); } -PeerData *Window::ui_getPeerForMouseAction() { +PeerData *MainWindow::ui_getPeerForMouseAction() { if (_mediaView && !_mediaView->isHidden()) { return _mediaView->ui_getPeerForMouseAction(); } else if (main) { @@ -883,7 +883,7 @@ PeerData *Window::ui_getPeerForMouseAction() { return nullptr; } -void Window::showConnecting(const QString &text, const QString &reconnect) { +void MainWindow::showConnecting(const QString &text, const QString &reconnect) { if (_connecting) { _connecting->set(text, reconnect); } else { @@ -895,11 +895,11 @@ void Window::showConnecting(const QString &text, const QString &reconnect) { if (settings) settings->update(); } -bool Window::connectingVisible() const { +bool MainWindow::connectingVisible() const { return _connecting && !_connecting->isHidden(); } -void Window::hideConnecting() { +void MainWindow::hideConnecting() { if (_connecting) { _connecting->deleteLater(); _connecting = 0; @@ -907,18 +907,18 @@ void Window::hideConnecting() { if (settings) settings->update(); } -bool Window::historyIsActive() const { +bool MainWindow::historyIsActive() const { return isActive(false) && main && main->historyIsActive() && (!settings || !settings->isVisible()); } -void Window::checkHistoryActivation() { +void MainWindow::checkHistoryActivation() { if (main && MTP::authedId() && historyIsActive()) { main->historyWasRead(); } QTimer::singleShot(1, this, SLOT(updateTrayMenu())); } -void Window::layerHidden() { +void MainWindow::layerHidden() { if (layerBg) { layerBg->hide(); layerBg->deleteLater(); @@ -928,7 +928,7 @@ void Window::layerHidden() { setInnerFocus(); } -void Window::hideMediaview() { +void MainWindow::hideMediaview() { if (_mediaView && !_mediaView->isHidden()) { _mediaView->hide(); #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 (layerBg && layerBg->contentOverlapped(globalRect)) return true; return false; } -void Window::setInnerFocus() { +void MainWindow::setInnerFocus() { if (layerBg && layerBg->canSetFocus()) { layerBg->setInnerFocus(); } 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); } -QRect Window::photoRect() const { +QRect MainWindow::photoRect() const { if (settings) { return settings->geometry(); } else if (main) { @@ -973,15 +973,15 @@ QRect Window::photoRect() const { return QRect(0, 0, 0, 0); } -void Window::wStartDrag(QMouseEvent *e) { +void MainWindow::wStartDrag(QMouseEvent *e) { dragStart = e->globalPos() - frameGeometry().topLeft(); 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()); const int32 raw = psResizeRowWidth(); @@ -1015,11 +1015,11 @@ HitTestType Window::hitTest(const QPoint &p) const { return HitTestNone; } -QRect Window::iconRect() const { +QRect MainWindow::iconRect() const { 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()) { case QEvent::MouseButtonPress: case QEvent::KeyPress: @@ -1088,7 +1088,7 @@ bool Window::eventFilter(QObject *obj, QEvent *e) { return PsMainWindow::eventFilter(obj, e); } -void Window::mouseMoveEvent(QMouseEvent *e) { +void MainWindow::mouseMoveEvent(QMouseEvent *e) { if (e->buttons() & Qt::LeftButton) { if (dragging) { 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; } -bool Window::minimizeToTray() { +bool MainWindow::minimizeToTray() { if (App::quitting() || !psHasTrayIcon()) return false; hide(); @@ -1123,7 +1123,7 @@ bool Window::minimizeToTray() { return true; } -void Window::updateTrayMenu(bool force) { +void MainWindow::updateTrayMenu(bool force) { if (!trayIconMenu || (cPlatform() == dbipWindows && !force)) return; bool active = isActive(false); @@ -1153,25 +1153,25 @@ void Window::updateTrayMenu(bool force) { psTrayMenuUpdated(); } -void Window::onShowAddContact() { +void MainWindow::onShowAddContact() { if (isHidden()) showFromTray(); if (main) main->showAddContact(); } -void Window::onShowNewGroup() { +void MainWindow::onShowNewGroup() { if (isHidden()) showFromTray(); if (main) Ui::showLayer(new GroupInfoBox(CreatingGroupGroup, false), KeepOtherLayers); } -void Window::onShowNewChannel() { +void MainWindow::onShowNewChannel() { if (isHidden()) showFromTray(); if (main) Ui::showLayer(new GroupInfoBox(CreatingGroupChannel, false), KeepOtherLayers); } -void Window::onLogout() { +void MainWindow::onLogout() { if (isHidden()) showFromTray(); ConfirmBox *box = new ConfirmBox(lang(lng_sure_logout), lang(lng_settings_logout), st::attentionBoxButton); @@ -1179,7 +1179,7 @@ void Window::onLogout() { Ui::showLayer(box); } -void Window::onLogoutSure() { +void MainWindow::onLogoutSure() { if (MTP::authedId()) { App::logOut(); } else { @@ -1187,17 +1187,17 @@ void Window::onLogoutSure() { } } -void Window::updateGlobalMenu() { +void MainWindow::updateGlobalMenu() { #ifdef Q_OS_MAC psMacUpdateMenu(); #endif } -void Window::quitFromTray() { +void MainWindow::quitFromTray() { App::quit(); } -void Window::activate() { +void MainWindow::activate() { bool wasHidden = !isVisible(); setWindowState(windowState() & ~Qt::WindowMinimized); setVisible(true); @@ -1211,45 +1211,45 @@ void Window::activate() { } } -void Window::noIntro(IntroWidget *was) { +void MainWindow::noIntro(IntroWidget *was) { if (was == intro) { intro = 0; } } -void Window::noSettings(SettingsWidget *was) { +void MainWindow::noSettings(SettingsWidget *was) { if (was == settings) { settings = 0; } checkHistoryActivation(); } -void Window::noMain(MainWidget *was) { +void MainWindow::noMain(MainWidget *was) { if (was == main) { main = 0; } } -void Window::noBox(BackgroundWidget *was) { +void MainWindow::noBox(BackgroundWidget *was) { if (was == layerBg) { layerBg = 0; } } -void Window::layerFinishedHide(BackgroundWidget *was) { +void MainWindow::layerFinishedHide(BackgroundWidget *was) { if (was == layerBg) { QTimer::singleShot(0, this, SLOT(layerHidden())); } } -void Window::fixOrder() { +void MainWindow::fixOrder() { title->raise(); if (layerBg) layerBg->raise(); if (_mediaPreview) _mediaPreview->raise(); if (_connecting) _connecting->raise(); } -void Window::showFromTray(QSystemTrayIcon::ActivationReason reason) { +void MainWindow::showFromTray(QSystemTrayIcon::ActivationReason reason) { if (reason != QSystemTrayIcon::Context) { QTimer::singleShot(1, this, SLOT(updateTrayMenu())); QTimer::singleShot(1, this, SLOT(updateGlobalMenu())); @@ -1258,7 +1258,7 @@ void Window::showFromTray(QSystemTrayIcon::ActivationReason reason) { } } -void Window::toggleTray(QSystemTrayIcon::ActivationReason reason) { +void MainWindow::toggleTray(QSystemTrayIcon::ActivationReason reason) { if ((cPlatform() == dbipMac || cPlatform() == dbipMacOld) && isActive(false)) return; if (reason == QSystemTrayIcon::Context) { updateTrayMenu(true); @@ -1272,7 +1272,7 @@ void Window::toggleTray(QSystemTrayIcon::ActivationReason reason) { } } -void Window::toggleDisplayNotifyFromTray() { +void MainWindow::toggleDisplayNotifyFromTray() { if (App::passcoded()) { if (!isActive()) showFromTray(); Ui::showLayer(new InformBox(lang(lng_passcode_need_unblock))); @@ -1290,7 +1290,7 @@ void Window::toggleDisplayNotifyFromTray() { } } -void Window::closeEvent(QCloseEvent *e) { +void MainWindow::closeEvent(QCloseEvent *e) { if (MTP::authedId() && !Sandbox::isSavingSession() && Ui::hideWindowNoQuit()) { e->ignore(); } else { @@ -1298,11 +1298,11 @@ void Window::closeEvent(QCloseEvent *e) { } } -TitleWidget *Window::getTitle() { +TitleWidget *MainWindow::getTitle() { return title; } -void Window::resizeEvent(QResizeEvent *e) { +void MainWindow::resizeEvent(QResizeEvent *e) { if (!title) return; Adaptive::Layout layout = Adaptive::OneColumnLayout; @@ -1322,7 +1322,7 @@ void Window::resizeEvent(QResizeEvent *e) { emit resized(QSize(width(), height() - st::titleHeight)); } -void Window::updateAdaptiveLayout() { +void MainWindow::updateAdaptiveLayout() { title->updateAdaptiveLayout(); if (main) main->updateAdaptiveLayout(); if (settings) settings->updateAdaptiveLayout(); @@ -1330,25 +1330,25 @@ void Window::updateAdaptiveLayout() { if (layerBg) layerBg->updateAdaptiveLayout(); } -bool Window::needBackButton() { +bool MainWindow::needBackButton() { return !!settings; } -Window::TempDirState Window::tempDirState() { +MainWindow::TempDirState MainWindow::tempDirState() { if (_clearManager && _clearManager->hasTask(Local::ClearManagerDownloads)) { return TempDirRemoving; } return QDir(cTempDir()).exists() ? TempDirExists : TempDirEmpty; } -Window::TempDirState Window::localStorageState() { +MainWindow::TempDirState MainWindow::localStorageState() { if (_clearManager && _clearManager->hasTask(Local::ClearManagerStorage)) { return TempDirRemoving; } 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->addTask(task)) { return; @@ -1364,7 +1364,7 @@ void Window::tempDirDelete(int task) { _clearManager->start(); } -void Window::onClearFinished(int task, void *manager) { +void MainWindow::onClearFinished(int task, void *manager) { if (manager && manager == _clearManager) { _clearManager->deleteLater(); _clearManager = 0; @@ -1372,7 +1372,7 @@ void Window::onClearFinished(int task, void *manager) { emit tempDirCleared(task); } -void Window::onClearFailed(int task, void *manager) { +void MainWindow::onClearFailed(int task, void *manager) { if (manager && manager == _clearManager) { _clearManager->deleteLater(); _clearManager = 0; @@ -1380,7 +1380,7 @@ void Window::onClearFailed(int task, void *manager) { emit tempDirClearFailed(task); } -void Window::notifySchedule(History *history, HistoryItem *item) { +void MainWindow::notifySchedule(History *history, HistoryItem *item) { if (App::quitting() || !history->currentNotification() || !main) return; PeerData *notifyByFrom = (!history->peer->isUser() && item->mentionsMe()) ? item->from() : 0; @@ -1451,11 +1451,11 @@ void Window::notifySchedule(History *history, HistoryItem *item) { } } -void Window::notifyFire() { +void MainWindow::notifyFire() { notifyShowNext(); } -void Window::notifyClear(History *history) { +void MainWindow::notifyClear(History *history) { if (!history) { for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { (*i)->unlinkHistory(); @@ -1480,7 +1480,7 @@ void Window::notifyClear(History *history) { notifyShowNext(); } -void Window::notifyClearFast() { +void MainWindow::notifyClearFast() { notifyWaiters.clear(); notifySettingWaiters.clear(); for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { @@ -1492,7 +1492,7 @@ void Window::notifyClearFast() { notifyWhenAlerts.clear(); } -void Window::notifySettingGot() { +void MainWindow::notifySettingGot() { int32 t = unixtime(); for (NotifyWaiters::iterator i = notifySettingWaiters.begin(); i != notifySettingWaiters.end();) { History *history = i.key(); @@ -1534,7 +1534,7 @@ void Window::notifySettingGot() { notifyShowNext(); } -void Window::notifyShowNext(NotifyWindow *remove) { +void MainWindow::notifyShowNext(NotifyWindow *remove) { if (App::quitting()) return; int32 count = NotifyWindowsCount; @@ -1711,7 +1711,7 @@ void Window::notifyShowNext(NotifyWindow *remove) { } } -void Window::notifyItemRemoved(HistoryItem *item) { +void MainWindow::notifyItemRemoved(HistoryItem *item) { if (cCustomNotifies()) { for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { (*i)->itemRemoved(item); @@ -1719,7 +1719,7 @@ void Window::notifyItemRemoved(HistoryItem *item) { } } -void Window::notifyStopHiding() { +void MainWindow::notifyStopHiding() { if (cCustomNotifies()) { for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { (*i)->stopHiding(); @@ -1727,7 +1727,7 @@ void Window::notifyStopHiding() { } } -void Window::notifyStartHiding() { +void MainWindow::notifyStartHiding() { if (cCustomNotifies()) { for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { (*i)->startHiding(); @@ -1735,7 +1735,7 @@ void Window::notifyStartHiding() { } } -void Window::notifyUpdateAllPhotos() { +void MainWindow::notifyUpdateAllPhotos() { if (cCustomNotifies()) { for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { (*i)->updatePeerPhoto(); @@ -1744,11 +1744,11 @@ void Window::notifyUpdateAllPhotos() { 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); } -void Window::notifyUpdateAll() { +void MainWindow::notifyUpdateAll() { if (cCustomNotifies()) { for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { (*i)->updateNotifyDisplay(); @@ -1757,7 +1757,7 @@ void Window::notifyUpdateAll() { psClearNotifies(); } -void Window::notifyActivateAll() { +void MainWindow::notifyActivateAll() { if (cCustomNotifies()) { for (NotifyWindows::const_iterator i = notifyWindows.cbegin(), e = notifyWindows.cend(); i != e; ++i) { psActivateNotify(*i); @@ -1765,11 +1765,11 @@ void Window::notifyActivateAll() { } } -QImage Window::iconLarge() const { +QImage MainWindow::iconLarge() const { 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); QString cnt = (count < 100) ? QString("%1").arg(count) : QString("..%1").arg(count % 10, 1, 10, QChar('0')); @@ -1807,7 +1807,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; if (size < 0) { size = -size; @@ -1874,7 +1874,7 @@ QImage Window::iconWithCounter(int size, int count, style::color bg, bool smallI return img; } -void Window::sendPaths() { +void MainWindow::sendPaths() { if (App::passcoded()) return; hideMediaview(); if (settings) { @@ -1887,35 +1887,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 (!_mediaView || _mediaView->isHidden()) return; _mediaView->mediaOverviewUpdated(peer, type); } -void Window::documentUpdated(DocumentData *doc) { +void MainWindow::documentUpdated(DocumentData *doc) { if (!_mediaView || _mediaView->isHidden()) return; _mediaView->documentUpdated(doc); } -void Window::changingMsgId(HistoryItem *row, MsgId newId) { +void MainWindow::changingMsgId(HistoryItem *row, MsgId newId) { if (main) main->changingMsgId(row, newId); if (!_mediaView || _mediaView->isHidden()) return; _mediaView->changingMsgId(row, newId); } -bool Window::isActive(bool cached) const { +bool MainWindow::isActive(bool cached) const { if (cached) return _isActive; return isActiveWindow() && isVisible() && !(windowState() & Qt::WindowMinimized); } -void Window::updateIsActive(int timeout) { +void MainWindow::updateIsActive(int timeout) { if (timeout) return _isActiveTimer.start(timeout); _isActive = isActive(false); if (main) main->updateOnline(); } -Window::~Window() { +MainWindow::~MainWindow() { notifyClearFast(); delete _clearManager; delete _connecting; diff --git a/Telegram/SourceFiles/window.h b/Telegram/SourceFiles/mainwindow.h similarity index 99% rename from Telegram/SourceFiles/window.h rename to Telegram/SourceFiles/mainwindow.h index 72056e65d..e1189eb35 100644 --- a/Telegram/SourceFiles/window.h +++ b/Telegram/SourceFiles/mainwindow.h @@ -123,12 +123,12 @@ typedef QList NotifyWindows; class MediaPreviewWidget; -class Window : public PsMainWindow { +class MainWindow : public PsMainWindow { Q_OBJECT public: - Window(QWidget *parent = 0); - ~Window(); + MainWindow(QWidget *parent = 0); + ~MainWindow(); void init(); void firstShow(); diff --git a/Telegram/SourceFiles/mediaview.cpp b/Telegram/SourceFiles/mediaview.cpp index 9a1e974d3..16f4b018a 100644 --- a/Telegram/SourceFiles/mediaview.cpp +++ b/Telegram/SourceFiles/mediaview.cpp @@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "mediaview.h" #include "mainwidget.h" -#include "window.h" +#include "mainwindow.h" #include "application.h" #include "ui/filedialog.h" diff --git a/Telegram/SourceFiles/mtproto/core_types.h b/Telegram/SourceFiles/mtproto/core_types.h index b55857636..924b93ba2 100644 --- a/Telegram/SourceFiles/mtproto/core_types.h +++ b/Telegram/SourceFiles/mtproto/core_types.h @@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #pragma once -#include "basic_types.h" +#include "core/basic_types.h" namespace MTP { diff --git a/Telegram/SourceFiles/mtproto/file_download.cpp b/Telegram/SourceFiles/mtproto/file_download.cpp index 86033cd11..73d61b131 100644 --- a/Telegram/SourceFiles/mtproto/file_download.cpp +++ b/Telegram/SourceFiles/mtproto/file_download.cpp @@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "mtproto/file_download.h" #include "mainwidget.h" -#include "window.h" +#include "mainwindow.h" #include "application.h" #include "localstorage.h" diff --git a/Telegram/SourceFiles/overview/overview_layout.cpp b/Telegram/SourceFiles/overview/overview_layout.cpp new file mode 100644 index 000000000..3a789f3c6 --- /dev/null +++ b/Telegram/SourceFiles/overview/overview_layout.cpp @@ -0,0 +1,1143 @@ +/* +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 "overview/overview_layout.h" + +#include "lang.h" +#include "mainwidget.h" +#include "application.h" +#include "fileuploader.h" +#include "mainwindow.h" +#include "ui/filedialog.h" +#include "playerwidget.h" +#include "boxes/addcontactbox.h" +#include "boxes/confirmbox.h" +#include "audio.h" +#include "localstorage.h" + +namespace Overview { +namespace Layout { + +void ItemBase::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { + App::hoveredLinkItem(active ? _parent : nullptr); + Ui::repaintHistoryItem(_parent); +} + +void ItemBase::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) { + App::pressedLinkItem(pressed ? _parent : nullptr); + Ui::repaintHistoryItem(_parent); +} + +void RadialProgressItem::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { + if (p == _openl || p == _savel || p == _cancell) { + a_iconOver.start(active ? 1 : 0); + _a_iconOver.start(); + } + ItemBase::clickHandlerActiveChanged(p, active); +} + +void RadialProgressItem::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) { + ItemBase::clickHandlerPressedChanged(p, pressed); +} + +void RadialProgressItem::setLinks(ClickHandlerPtr &&openl, ClickHandlerPtr &&savel, ClickHandlerPtr &&cancell) { + _openl = std_::move(openl); + _savel = std_::move(savel); + _cancell = std_::move(cancell); +} + +void RadialProgressItem::step_iconOver(float64 ms, bool timer) { + float64 dt = ms / st::msgFileOverDuration; + if (dt >= 1) { + a_iconOver.finish(); + _a_iconOver.stop(); + } else if (!timer) { + a_iconOver.update(dt, anim::linear); + } + if (timer && iconAnimated()) { + Ui::repaintHistoryItem(_parent); + } +} + +void RadialProgressItem::step_radial(uint64 ms, bool timer) { + if (timer) { + Ui::repaintHistoryItem(_parent); + } else { + _radial->update(dataProgress(), dataFinished(), ms); + if (!_radial->animating()) { + checkRadialFinished(); + } + } +} + +void RadialProgressItem::ensureRadial() const { + if (!_radial) { + _radial = new RadialAnimation(animation(const_cast(this), &RadialProgressItem::step_radial)); + } +} + +void RadialProgressItem::checkRadialFinished() { + if (_radial && !_radial->animating() && dataLoaded()) { + delete _radial; + _radial = nullptr; + } +} + +RadialProgressItem::~RadialProgressItem() { + deleteAndMark(_radial); +} + +void FileBase::setStatusSize(int32 newSize, int32 fullSize, int32 duration, qint64 realDuration) const { + _statusSize = newSize; + if (_statusSize == FileStatusSizeReady) { + _statusText = (duration >= 0) ? formatDurationAndSizeText(duration, fullSize) : (duration < -1 ? formatGifAndSizeText(fullSize) : formatSizeText(fullSize)); + } else if (_statusSize == FileStatusSizeLoaded) { + _statusText = (duration >= 0) ? formatDurationText(duration) : (duration < -1 ? qsl("GIF") : formatSizeText(fullSize)); + } else if (_statusSize == FileStatusSizeFailed) { + _statusText = lang(lng_attach_failed); + } else if (_statusSize >= 0) { + _statusText = formatDownloadText(_statusSize, fullSize); + } else { + _statusText = formatPlayedText(-_statusSize - 1, realDuration); + } +} + +Date::Date(const QDate &date, bool month) +: _date(date) +, _text(month ? langMonthFull(date) : langDayOfMonthFull(date)) { + AddComponents(Info::Bit()); +} + +void Date::initDimensions() { + _maxw = st::normalFont->width(_text); + _minh = st::linksDateMargin.top() + st::normalFont->height + st::linksDateMargin.bottom() + st::linksBorder; +} + +void Date::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const { + if (clip.intersects(QRect(0, st::linksDateMargin.top(), _width, st::normalFont->height))) { + p.setPen(st::linksDateColor); + p.setFont(st::semiboldFont); + p.drawTextLeft(0, st::linksDateMargin.top(), _width, _text); + } +} + +Photo::Photo(PhotoData *photo, HistoryItem *parent) : ItemBase(parent) +, _data(photo) +, _link(new PhotoOpenClickHandler(photo)) +, _goodLoaded(false) { +} + +void Photo::initDimensions() { + _maxw = 2 * st::overviewPhotoMinSize; + _minh = _maxw; +} + +int32 Photo::resizeGetHeight(int32 width) { + width = qMin(width, _maxw); + if (width != _width || width != _height) { + _width = qMin(width, _maxw); + _height = _width; + } + return _height; +} + +void Photo::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const { + bool good = _data->loaded(); + if (!good) { + _data->medium->automaticLoad(_parent); + good = _data->medium->loaded(); + } + if ((good && !_goodLoaded) || _pix.width() != _width * cIntRetinaFactor()) { + _goodLoaded = good; + + int32 size = _width * cIntRetinaFactor(); + if (_goodLoaded || _data->thumb->loaded()) { + QImage img = (_data->loaded() ? _data->full : (_data->medium->loaded() ? _data->medium : _data->thumb))->pix().toImage(); + if (!_goodLoaded) { + img = imageBlur(img); + } + if (img.width() == img.height()) { + if (img.width() != size) { + img = img.scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); + } + } else if (img.width() > img.height()) { + img = img.copy((img.width() - img.height()) / 2, 0, img.height(), img.height()).scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); + } else { + img = img.copy(0, (img.height() - img.width()) / 2, img.width(), img.width()).scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); + } + img.setDevicePixelRatio(cRetinaFactor()); + _data->forget(); + + _pix = QPixmap::fromImage(img, Qt::ColorOnly); + } else if (!_pix.isNull()) { + _pix = QPixmap(); + } + } + + if (_pix.isNull()) { + p.fillRect(0, 0, _width, _height, st::overviewPhotoBg); + } else { + p.drawPixmap(0, 0, _pix); + } + + if (selection == FullSelection) { + p.fillRect(QRect(0, 0, _width, _height), st::overviewPhotoSelectOverlay); + p.drawSprite(QPoint(rtl() ? 0 : (_width - st::overviewPhotoChecked.pxWidth()), _height - st::overviewPhotoChecked.pxHeight()), st::overviewPhotoChecked); + } else if (context->selecting) { + p.drawSprite(QPoint(rtl() ? 0 : (_width - st::overviewPhotoCheck.pxWidth()), _height - st::overviewPhotoCheck.pxHeight()), st::overviewPhotoCheck); + } +} + +void Photo::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const { + if (hasPoint(x, y)) { + link = _link; + } +} + +Video::Video(DocumentData *video, HistoryItem *parent) : FileBase(parent) +, _data(video) +, _duration(formatDurationText(_data->duration())) +, _thumbLoaded(false) { + setDocumentLinks(_data); +} + +void Video::initDimensions() { + _maxw = 2 * st::minPhotoSize; + _minh = _maxw; +} + +int32 Video::resizeGetHeight(int32 width) { + _width = qMin(width, _maxw); + _height = _width; + return _height; +} + +void Video::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const { + bool selected = (selection == FullSelection), thumbLoaded = _data->thumb->loaded(); + + _data->automaticLoad(_parent); + bool loaded = _data->loaded(), displayLoading = _data->displayLoading(); + if (displayLoading) { + ensureRadial(); + if (!_radial->animating()) { + _radial->start(_data->progress()); + } + } + updateStatusText(); + bool radial = isRadialAnimation(context->ms); + + if ((thumbLoaded && !_thumbLoaded) || (_pix.width() != _width * cIntRetinaFactor())) { + _thumbLoaded = thumbLoaded; + + if (_thumbLoaded && !_data->thumb->isNull()) { + int32 size = _width * cIntRetinaFactor(); + QImage img = imageBlur(_data->thumb->pix().toImage()); + if (img.width() == img.height()) { + if (img.width() != size) { + img = img.scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); + } + } else if (img.width() > img.height()) { + img = img.copy((img.width() - img.height()) / 2, 0, img.height(), img.height()).scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); + } else { + img = img.copy(0, (img.height() - img.width()) / 2, img.width(), img.width()).scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); + } + img.setDevicePixelRatio(cRetinaFactor()); + _data->forget(); + + _pix = QPixmap::fromImage(img, Qt::ColorOnly); + } else if (!_pix.isNull()) { + _pix = QPixmap(); + } + } + + if (_pix.isNull()) { + p.fillRect(0, 0, _width, _height, st::overviewPhotoBg); + } else { + p.drawPixmap(0, 0, _pix); + } + + if (selected) { + p.fillRect(QRect(0, 0, _width, _height), st::overviewPhotoSelectOverlay); + } + + if (!selected && !context->selecting && !loaded) { + if (clip.intersects(QRect(0, _height - st::normalFont->height, _width, st::normalFont->height))) { + int32 statusX = st::msgDateImgPadding.x(), statusY = _height - st::normalFont->height - st::msgDateImgPadding.y(); + int32 statusW = st::normalFont->width(_statusText) + 2 * st::msgDateImgPadding.x(); + int32 statusH = st::normalFont->height + 2 * st::msgDateImgPadding.y(); + statusX = _width - statusW + statusX; + p.fillRect(rtlrect(statusX - st::msgDateImgPadding.x(), statusY - st::msgDateImgPadding.y(), statusW, statusH, _width), selected ? st::msgDateImgBgSelected : st::msgDateImgBg); + p.setFont(st::normalFont); + p.setPen(st::white); + p.drawTextLeft(statusX, statusY, _width, _statusText, statusW - 2 * st::msgDateImgPadding.x()); + } + } + if (clip.intersects(QRect(0, 0, _width, st::normalFont->height))) { + int32 statusX = st::msgDateImgPadding.x(), statusY = st::msgDateImgPadding.y(); + int32 statusW = st::normalFont->width(_duration) + 2 * st::msgDateImgPadding.x(); + int32 statusH = st::normalFont->height + 2 * st::msgDateImgPadding.y(); + p.fillRect(rtlrect(statusX - st::msgDateImgPadding.x(), statusY - st::msgDateImgPadding.y(), statusW, statusH, _width), selected ? st::msgDateImgBgSelected : st::msgDateImgBg); + p.setFont(st::normalFont); + p.setPen(st::white); + p.drawTextLeft(statusX, statusY, _width, _duration, statusW - 2 * st::msgDateImgPadding.x()); + } + + QRect inner((_width - st::msgFileSize) / 2, (_height - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize); + if (clip.intersects(inner)) { + p.setPen(Qt::NoPen); + if (selected) { + p.setBrush(st::msgDateImgBgSelected); + } else if (_a_iconOver.animating()) { + _a_iconOver.step(context->ms); + float64 over = a_iconOver.current(); + p.setOpacity((st::msgDateImgBg->c.alphaF() * (1 - over)) + (st::msgDateImgBgOver->c.alphaF() * over)); + p.setBrush(st::black); + } else { + bool over = ClickHandler::showAsActive(loaded ? _openl : (_data->loading() ? _cancell : _savel)); + p.setBrush(over ? st::msgDateImgBgOver : st::msgDateImgBg); + } + + p.setRenderHint(QPainter::HighQualityAntialiasing); + p.drawEllipse(inner); + p.setRenderHint(QPainter::HighQualityAntialiasing, false); + + p.setOpacity((radial && loaded) ? _radial->opacity() : 1); + style::sprite icon; + if (radial) { + icon = (selected ? st::msgFileInCancelSelected : st::msgFileInCancel); + } else if (loaded) { + icon = (selected ? st::msgFileInPlaySelected : st::msgFileInPlay); + } else { + icon = (selected ? st::msgFileInDownloadSelected : st::msgFileInDownload); + } + p.drawSpriteCenter(inner, icon); + if (radial) { + p.setOpacity(1); + QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine))); + _radial->draw(p, rinner, st::msgFileRadialLine, selected ? st::msgInBgSelected : st::msgInBg); + } + } + + if (selected) { + p.drawSprite(QPoint(rtl() ? 0 : (_width - st::overviewPhotoChecked.pxWidth()), _height - st::overviewPhotoChecked.pxHeight()), st::overviewPhotoChecked); + } else if (context->selecting) { + p.drawSprite(QPoint(rtl() ? 0 : (_width - st::overviewPhotoCheck.pxWidth()), _height - st::overviewPhotoCheck.pxHeight()), st::overviewPhotoCheck); + } +} + +void Video::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const { + bool loaded = _data->loaded(); + + if (hasPoint(x, y)) { + link = loaded ? _openl : (_data->loading() ? _cancell : _savel); + } +} + +void Video::updateStatusText() const { + bool showPause = false; + int32 statusSize = 0; + if (_data->status == FileDownloadFailed || _data->status == FileUploadFailed) { + statusSize = FileStatusSizeFailed; + } else if (_data->status == FileUploading) { + statusSize = _data->uploadOffset; + } else if (_data->loading()) { + statusSize = _data->loadOffset(); + } else if (_data->loaded()) { + statusSize = FileStatusSizeLoaded; + } else { + statusSize = FileStatusSizeReady; + } + if (statusSize != _statusSize) { + int32 status = statusSize, size = _data->size; + if (statusSize >= 0 && statusSize < 0x7F000000) { + size = status; + status = FileStatusSizeReady; + } + setStatusSize(status, size, -1, 0); + _statusSize = statusSize; + } +} + +Voice::Voice(DocumentData *voice, HistoryItem *parent) : FileBase(parent) +, _data(voice) +, _namel(new DocumentOpenClickHandler(_data)) { + AddComponents(Info::Bit()); + + t_assert(_data->voice() != 0); + + setDocumentLinks(_data); + + updateName(); + QString d = textcmdLink(1, textRichPrepare(langDateTime(date(_data->date)))); + TextParseOptions opts = { TextParseRichText, 0, 0, Qt::LayoutDirectionAuto }; + _details.setText(st::normalFont, lng_date_and_duration(lt_date, d, lt_duration, formatDurationText(_data->voice()->duration)), opts); + _details.setLink(1, MakeShared(parent)); +} + +void Voice::initDimensions() { + _maxw = st::profileMaxWidth; + _minh = st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom() + st::lineWidth; +} + +void Voice::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const { + bool selected = (selection == FullSelection); + + _data->automaticLoad(_parent); + bool loaded = _data->loaded(), displayLoading = _data->displayLoading(); + + if (displayLoading) { + ensureRadial(); + if (!_radial->animating()) { + _radial->start(_data->progress()); + } + } + bool showPause = updateStatusText(); + int32 nameVersion = _parent->fromOriginal()->nameVersion; + if (nameVersion > _nameVersion) { + updateName(); + } + bool radial = isRadialAnimation(context->ms); + + int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, datetop = -1; + + nameleft = st::msgFilePadding.left() + st::msgFileSize + st::msgFilePadding.right(); + nameright = st::msgFilePadding.left(); + nametop = st::msgFileNameTop; + statustop = st::msgFileStatusTop; + + if (selected) { + p.fillRect(clip.intersected(QRect(0, 0, _width, _height)), st::msgInBgSelected); + } + + QRect inner(rtlrect(st::msgFilePadding.left(), st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, _width)); + if (clip.intersects(inner)) { + p.setPen(Qt::NoPen); + if (selected) { + p.setBrush(st::msgFileInBgSelected); + } else if (_a_iconOver.animating()) { + _a_iconOver.step(context->ms); + float64 over = a_iconOver.current(); + p.setBrush(style::interpolate(st::msgFileInBg, st::msgFileInBgOver, over)); + } else { + bool over = ClickHandler::showAsActive(loaded ? _openl : (_data->loading() ? _cancell : _openl)); + p.setBrush(over ? st::msgFileInBgOver : st::msgFileInBg); + } + + p.setRenderHint(QPainter::HighQualityAntialiasing); + p.drawEllipse(inner); + p.setRenderHint(QPainter::HighQualityAntialiasing, false); + + if (radial) { + QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine))); + style::color bg(selected ? st::msgInBgSelected : st::msgInBg); + _radial->draw(p, rinner, st::msgFileRadialLine, bg); + } + + style::sprite icon; + if (showPause) { + icon = selected ? st::msgFileInPauseSelected : st::msgFileInPause; + } else if (_statusSize < 0 || _statusSize == FileStatusSizeLoaded) { + icon = selected ? st::msgFileInPlaySelected : st::msgFileInPlay; + } else if (_data->loading()) { + icon = selected ? st::msgFileInCancelSelected : st::msgFileInCancel; + } else { + icon = selected ? st::msgFileInDownloadSelected : st::msgFileInDownload; + } + p.drawSpriteCenter(inner, icon); + } + + int32 namewidth = _width - nameleft - nameright; + + if (clip.intersects(rtlrect(nameleft, nametop, namewidth, st::semiboldFont->height, _width))) { + p.setPen(st::black); + _name.drawLeftElided(p, nameleft, nametop, namewidth, _width); + } + + if (clip.intersects(rtlrect(nameleft, statustop, namewidth, st::normalFont->height, _width))) { + p.setFont(st::normalFont); + p.setPen(selected ? st::mediaInFgSelected : st::mediaInFg); + int32 unreadx = nameleft; + if (_statusSize == FileStatusSizeLoaded || _statusSize == FileStatusSizeReady) { + textstyleSet(&(selected ? st::mediaInStyleSelected : st::mediaInStyle)); + _details.drawLeftElided(p, nameleft, statustop, namewidth, _width); + textstyleRestore(); + unreadx += _details.maxWidth(); + } else { + int32 statusw = st::normalFont->width(_statusText); + p.drawTextLeft(nameleft, statustop, _width, _statusText, statusw); + unreadx += statusw; + } + if (_parent->isMediaUnread() && unreadx + st::mediaUnreadSkip + st::mediaUnreadSize <= _width) { + p.setPen(Qt::NoPen); + p.setBrush(selected ? st::msgFileInBgSelected : st::msgFileInBg); + + p.setRenderHint(QPainter::HighQualityAntialiasing, true); + p.drawEllipse(rtlrect(unreadx + st::mediaUnreadSkip, statustop + st::mediaUnreadTop, st::mediaUnreadSize, st::mediaUnreadSize, _width)); + p.setRenderHint(QPainter::HighQualityAntialiasing, false); + } + } +} + +void Voice::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const { + bool loaded = _data->loaded(); + + bool showPause = updateStatusText(); + + int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, datetop = 0; + + nameleft = st::msgFilePadding.left() + st::msgFileSize + st::msgFilePadding.right(); + nameright = st::msgFilePadding.left(); + nametop = st::msgFileNameTop; + statustop = st::msgFileStatusTop; + + QRect inner(rtlrect(st::msgFilePadding.left(), st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, _width)); + if (inner.contains(x, y)) { + link = loaded ? _openl : ((_data->loading() || _data->status == FileUploading) ? _cancell : _openl); + return; + } + if (rtlrect(nameleft, statustop, _width - nameleft - nameright, st::normalFont->height, _width).contains(x, y)) { + if (_statusSize == FileStatusSizeLoaded || _statusSize == FileStatusSizeReady) { + bool inText = false; + _details.getStateLeft(link, inText, x - nameleft, y - statustop, _width, _width); + cursor = inText ? HistoryInTextCursorState : HistoryDefaultCursorState; + } + } + if (hasPoint(x, y) && !link && !_data->loading()) { + link = _namel; + return; + } +} + +void Voice::updateName() const { + int32 version = 0; + if (const HistoryMessageForwarded *fwd = _parent->Get()) { + if (_parent->fromOriginal()->isChannel()) { + _name.setText(st::semiboldFont, lng_forwarded_channel(lt_channel, App::peerName(_parent->fromOriginal())), _textNameOptions); + } else { + _name.setText(st::semiboldFont, lng_forwarded(lt_user, App::peerName(_parent->fromOriginal())), _textNameOptions); + } + } else { + _name.setText(st::semiboldFont, App::peerName(_parent->from()), _textNameOptions); + } + version = _parent->fromOriginal()->nameVersion; + _nameVersion = version; +} + +bool Voice::updateStatusText() const { + bool showPause = false; + int32 statusSize = 0, realDuration = 0; + if (_data->status == FileDownloadFailed || _data->status == FileUploadFailed) { + statusSize = FileStatusSizeFailed; + } else if (_data->loaded()) { + AudioMsgId playing; + AudioPlayerState playingState = AudioPlayerStopped; + int64 playingPosition = 0, playingDuration = 0; + int32 playingFrequency = 0; + if (audioPlayer()) { + audioPlayer()->currentState(&playing, &playingState, &playingPosition, &playingDuration, &playingFrequency); + } + + if (playing == AudioMsgId(_data, _parent->fullId()) && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) { + statusSize = -1 - (playingPosition / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency)); + realDuration = playingDuration / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency); + showPause = (playingState == AudioPlayerPlaying || playingState == AudioPlayerResuming || playingState == AudioPlayerStarting); + } else { + statusSize = FileStatusSizeLoaded; + } + } else { + statusSize = FileStatusSizeReady; + } + if (statusSize != _statusSize) { + setStatusSize(statusSize, _data->size, _data->voice()->duration, realDuration); + } + return showPause; +} + +Document::Document(DocumentData *document, HistoryItem *parent) : FileBase(parent) +, _data(document) +, _msgl(new GoToMessageClickHandler(parent)) +, _namel(new DocumentOpenClickHandler(_data)) +, _thumbForLoaded(false) +, _name(documentName(_data)) +, _date(langDateTime(date(_data->date))) +, _namew(st::semiboldFont->width(_name)) +, _datew(st::normalFont->width(_date)) +, _colorIndex(documentColorIndex(_data, _ext)) { + AddComponents(Info::Bit()); + + setDocumentLinks(_data); + + setStatusSize(FileStatusSizeReady, _data->size, _data->song() ? _data->song()->duration : -1, 0); + + if (withThumb()) { + _data->thumb->load(); + int32 tw = convertScale(_data->thumb->width()), th = convertScale(_data->thumb->height()); + if (tw > th) { + _thumbw = (tw * st::overviewFileSize) / th; + } else { + _thumbw = st::overviewFileSize; + } + } else { + _thumbw = 0; + } + + _extw = st::overviewFileExtFont->width(_ext); + if (_extw > st::overviewFileSize - st::overviewFileExtPadding * 2) { + _ext = st::overviewFileExtFont->elided(_ext, st::overviewFileSize - st::overviewFileExtPadding * 2, Qt::ElideMiddle); + _extw = st::overviewFileExtFont->width(_ext); + } +} + +void Document::initDimensions() { + _maxw = st::profileMaxWidth; + if (_data->song()) { + _minh = st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom(); + } else { + _minh = st::overviewFilePadding.top() + st::overviewFileSize + st::overviewFilePadding.bottom() + st::lineWidth; + } +} + +void Document::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const { + bool selected = (selection == FullSelection); + + _data->automaticLoad(_parent); + bool loaded = _data->loaded() || Local::willStickerImageLoad(_data->mediaKey()), displayLoading = _data->displayLoading(); + + if (displayLoading) { + ensureRadial(); + if (!_radial->animating()) { + _radial->start(_data->progress()); + } + } + bool showPause = updateStatusText(); + bool radial = isRadialAnimation(context->ms); + + int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, datetop = -1; + bool wthumb = withThumb(); + + if (_data->song()) { + nameleft = st::msgFilePadding.left() + st::msgFileSize + st::msgFilePadding.right(); + nameright = st::msgFilePadding.left(); + nametop = st::msgFileNameTop; + statustop = st::msgFileStatusTop; + + if (selected) { + p.fillRect(QRect(0, 0, _width, _height), st::msgInBgSelected); + } + + QRect inner(rtlrect(st::msgFilePadding.left(), st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, _width)); + if (clip.intersects(inner)) { + p.setPen(Qt::NoPen); + if (selected) { + p.setBrush(st::msgFileInBgSelected); + } else if (_a_iconOver.animating()) { + _a_iconOver.step(context->ms); + float64 over = a_iconOver.current(); + p.setBrush(style::interpolate(st::msgFileInBg, st::msgFileInBgOver, over)); + } else { + bool over = ClickHandler::showAsActive(loaded ? _openl : (_data->loading() ? _cancell : _openl)); + p.setBrush(over ? st::msgFileInBgOver : st::msgFileInBg); + } + + p.setRenderHint(QPainter::HighQualityAntialiasing); + p.drawEllipse(inner); + p.setRenderHint(QPainter::HighQualityAntialiasing, false); + + if (radial) { + QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine))); + style::color bg(selected ? st::msgInBgSelected : st::msgInBg); + _radial->draw(p, rinner, st::msgFileRadialLine, bg); + } + + style::sprite icon; + if (showPause) { + icon = selected ? st::msgFileInPauseSelected : st::msgFileInPause; + } else if (loaded) { + icon = selected ? st::msgFileInPlaySelected : st::msgFileInPlay; + } else if (_data->loading()) { + icon = selected ? st::msgFileInCancelSelected : st::msgFileInCancel; + } else { + icon = selected ? st::msgFileInDownloadSelected : st::msgFileInDownload; + } + p.drawSpriteCenter(inner, icon); + } + } else { + nameleft = st::overviewFileSize + st::overviewFilePadding.right(); + nametop = st::linksBorder + st::overviewFileNameTop; + statustop = st::linksBorder + st::overviewFileStatusTop; + datetop = st::linksBorder + st::overviewFileDateTop; + + QRect border(rtlrect(nameleft, 0, _width - nameleft, st::linksBorder, _width)); + if (!context->isAfterDate && clip.intersects(border)) { + p.fillRect(clip.intersected(border), st::linksBorderFg); + } + + QRect rthumb(rtlrect(0, st::linksBorder + st::overviewFilePadding.top(), st::overviewFileSize, st::overviewFileSize, _width)); + if (clip.intersects(rthumb)) { + if (wthumb) { + if (_data->thumb->loaded()) { + if (_thumb.isNull() || loaded != _thumbForLoaded) { + _thumbForLoaded = loaded; + ImagePixOptions options = ImagePixSmooth; + if (!_thumbForLoaded) options |= ImagePixBlurred; + _thumb = _data->thumb->pixNoCache(_thumbw, 0, options, st::overviewFileSize, st::overviewFileSize); + } + p.drawPixmap(rthumb.topLeft(), _thumb); + } else { + p.fillRect(rthumb, st::black); + } + } else { + p.fillRect(rthumb, documentColor(_colorIndex)); + if (!radial && loaded && !_ext.isEmpty()) { + p.setFont(st::overviewFileExtFont); + p.setPen(st::white); + p.drawText(rthumb.left() + (rthumb.width() - _extw) / 2, rthumb.top() + st::overviewFileExtTop + st::overviewFileExtFont->ascent, _ext); + } + } + if (selected) { + p.fillRect(rthumb, textstyleCurrent()->selectOverlay); + } + + if (radial || (!loaded && !_data->loading())) { + QRect inner(rthumb.x() + (rthumb.width() - st::msgFileSize) / 2, rthumb.y() + (rthumb.height() - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize); + if (clip.intersects(inner)) { + float64 radialOpacity = (radial && loaded && !_data->uploading()) ? _radial->opacity() : 1; + p.setPen(Qt::NoPen); + if (selected) { + p.setBrush(wthumb ? st::msgDateImgBgSelected : documentSelectedColor(_colorIndex)); + } else if (_a_iconOver.animating()) { + _a_iconOver.step(context->ms); + float64 over = a_iconOver.current(); + if (wthumb) { + p.setOpacity((st::msgDateImgBg->c.alphaF() * (1 - over)) + (st::msgDateImgBgOver->c.alphaF() * over)); + p.setBrush(st::black); + } else { + p.setBrush(style::interpolate(documentDarkColor(_colorIndex), documentOverColor(_colorIndex), over)); + } + } else { + bool over = ClickHandler::showAsActive(_data->loading() ? _cancell : _savel); + p.setBrush(over ? (wthumb ? st::msgDateImgBgOver : documentOverColor(_colorIndex)) : (wthumb ? st::msgDateImgBg : documentDarkColor(_colorIndex))); + } + p.setOpacity(radialOpacity * p.opacity()); + + p.setRenderHint(QPainter::HighQualityAntialiasing); + p.drawEllipse(inner); + p.setRenderHint(QPainter::HighQualityAntialiasing, false); + + p.setOpacity(radialOpacity); + style::sprite icon; + if (loaded || _data->loading()) { + icon = (selected ? st::msgFileInCancelSelected : st::msgFileInCancel); + } else { + icon = (selected ? st::msgFileInDownloadSelected : st::msgFileInDownload); + } + p.drawSpriteCenter(inner, icon); + if (radial) { + p.setOpacity(1); + + QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine))); + _radial->draw(p, rinner, st::msgFileRadialLine, selected ? st::msgInBgSelected : st::msgInBg); + } + } + } + if (selected || context->selecting) { + QRect check(rthumb.topLeft() + QPoint(rtl() ? 0 : (rthumb.width() - st::defaultCheckbox.diameter), rthumb.height() - st::defaultCheckbox.diameter), QSize(st::defaultCheckbox.diameter, st::defaultCheckbox.diameter)); + p.fillRect(check, selected ? st::overviewFileChecked : st::overviewFileCheck); + p.drawSpriteCenter(check, st::defaultCheckbox.checkIcon); + } + } + } + + int32 namewidth = _width - nameleft - nameright; + + if (clip.intersects(rtlrect(nameleft, nametop, qMin(namewidth, _namew), st::semiboldFont->height, _width))) { + p.setFont(st::semiboldFont); + p.setPen(st::black); + if (namewidth < _namew) { + p.drawTextLeft(nameleft, nametop, _width, st::semiboldFont->elided(_name, namewidth)); + } else { + p.drawTextLeft(nameleft, nametop, _width, _name, _namew); + } + } + + if (clip.intersects(rtlrect(nameleft, statustop, namewidth, st::normalFont->height, _width))) { + p.setFont(st::normalFont); + p.setPen(st::mediaInFg); + p.drawTextLeft(nameleft, statustop, _width, _statusText); + } + if (datetop >= 0 && clip.intersects(rtlrect(nameleft, datetop, _datew, st::normalFont->height, _width))) { + p.setFont(ClickHandler::showAsActive(_msgl) ? st::normalFont->underline() : st::normalFont); + p.setPen(st::mediaInFg); + p.drawTextLeft(nameleft, datetop, _width, _date, _datew); + } +} + +void Document::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const { + bool loaded = _data->loaded() || Local::willStickerImageLoad(_data->mediaKey()); + + bool showPause = updateStatusText(); + + int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, datetop = 0; + bool wthumb = withThumb(); + + if (_data->song()) { + nameleft = st::msgFilePadding.left() + st::msgFileSize + st::msgFilePadding.right(); + nameright = st::msgFilePadding.left(); + nametop = st::msgFileNameTop; + statustop = st::msgFileStatusTop; + + QRect inner(rtlrect(st::msgFilePadding.left(), st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, _width)); + if (inner.contains(x, y)) { + link = loaded ? _openl : ((_data->loading() || _data->status == FileUploading) ? _cancell : _openl); + return; + } + if (hasPoint(x, y) && !_data->loading()) { + link = _namel; + return; + } + } else { + nameleft = st::overviewFileSize + st::overviewFilePadding.right(); + nametop = st::linksBorder + st::overviewFileNameTop; + statustop = st::linksBorder + st::overviewFileStatusTop; + datetop = st::linksBorder + st::overviewFileDateTop; + + QRect rthumb(rtlrect(0, st::linksBorder + st::overviewFilePadding.top(), st::overviewFileSize, st::overviewFileSize, _width)); + + if (rthumb.contains(x, y)) { + link = loaded ? _openl : ((_data->loading() || _data->status == FileUploading) ? _cancell : _savel); + return; + } + + if (_data->status != FileUploadFailed) { + if (rtlrect(nameleft, datetop, _datew, st::normalFont->height, _width).contains(x, y)) { + link = _msgl; + return; + } + } + if (!_data->loading() && _data->isValid()) { + if (loaded && rtlrect(0, st::linksBorder, nameleft, _height - st::linksBorder, _width).contains(x, y)) { + link = _namel; + return; + } + if (rtlrect(nameleft, nametop, qMin(_width - nameleft - nameright, _namew), st::semiboldFont->height, _width).contains(x, y)) { + link = _namel; + return; + } + } + } +} + +bool Document::updateStatusText() const { + bool showPause = false; + int32 statusSize = 0, realDuration = 0; + if (_data->status == FileDownloadFailed || _data->status == FileUploadFailed) { + statusSize = FileStatusSizeFailed; + } else if (_data->status == FileUploading) { + statusSize = _data->uploadOffset; + } else if (_data->loading()) { + statusSize = _data->loadOffset(); + } else if (_data->loaded()) { + if (_data->song()) { + SongMsgId playing; + AudioPlayerState playingState = AudioPlayerStopped; + int64 playingPosition = 0, playingDuration = 0; + int32 playingFrequency = 0; + if (audioPlayer()) { + audioPlayer()->currentState(&playing, &playingState, &playingPosition, &playingDuration, &playingFrequency); + } + + if (playing == SongMsgId(_data, _parent->fullId()) && !(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) { + statusSize = -1 - (playingPosition / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency)); + realDuration = playingDuration / (playingFrequency ? playingFrequency : AudioVoiceMsgFrequency); + showPause = (playingState == AudioPlayerPlaying || playingState == AudioPlayerResuming || playingState == AudioPlayerStarting); + } else { + statusSize = FileStatusSizeLoaded; + } + if (!showPause && (playing == SongMsgId(_data, _parent->fullId())) && App::main() && App::main()->player()->seekingSong(playing)) { + showPause = true; + } + } else { + statusSize = FileStatusSizeLoaded; + } + } else { + statusSize = FileStatusSizeReady; + } + if (statusSize != _statusSize) { + setStatusSize(statusSize, _data->size, _data->song() ? _data->song()->duration : -1, realDuration); + } + return showPause; +} + +Link::Link(HistoryMedia *media, HistoryItem *parent) : ItemBase(parent) { + AddComponents(Info::Bit()); + + QString text = _parent->originalText(); + EntitiesInText entities = _parent->originalEntities(); + + int32 from = 0, till = text.size(), lnk = entities.size(); + for (int32 i = 0; i < lnk; ++i) { + if (entities[i].type != EntityInTextUrl && entities[i].type != EntityInTextCustomUrl && entities[i].type != EntityInTextEmail) { + continue; + } + QString u = entities[i].text, t = text.mid(entities[i].offset, entities[i].length); + _links.push_back(LinkEntry(u.isEmpty() ? t : u, t)); + } + while (lnk > 0 && till > from) { + --lnk; + if (entities[lnk].type != EntityInTextUrl && entities[lnk].type != EntityInTextCustomUrl && entities[lnk].type != EntityInTextEmail) { + ++lnk; + break; + } + int32 afterLinkStart = entities[lnk].offset + entities[lnk].length; + if (till > afterLinkStart) { + if (!QRegularExpression(qsl("^[,.\\s_=+\\-;:`'\"\\(\\)\\[\\]\\{\\}<>*&^%\\$#@!\\\\/]+$")).match(text.mid(afterLinkStart, till - afterLinkStart)).hasMatch()) { + ++lnk; + break; + } + } + till = entities[lnk].offset; + } + if (!lnk) { + if (QRegularExpression(qsl("^[,.\\s\\-;:`'\"\\(\\)\\[\\]\\{\\}<>*&^%\\$#@!\\\\/]+$")).match(text.mid(from, till - from)).hasMatch()) { + till = from; + } + } + + _page = (media && media->type() == MediaTypeWebPage) ? static_cast(media)->webpage() : 0; + if (_page) { + if (_page->document) { + _photol.reset(new DocumentOpenClickHandler(_page->document)); + } else if (_page->photo) { + if (_page->type == WebPageProfile || _page->type == WebPageVideo) { + _photol = MakeShared(_page->url); + } else if (_page->type == WebPagePhoto || _page->siteName == qstr("Twitter") || _page->siteName == qstr("Facebook")) { + _photol.reset(new PhotoOpenClickHandler(_page->photo)); + } else { + _photol = MakeShared(_page->url); + } + } else { + _photol = MakeShared(_page->url); + } + } else if (!_links.isEmpty()) { + _photol = MakeShared(_links.front().lnk->text()); + } + if (from >= till && _page) { + text = _page->description; + from = 0; + till = text.size(); + } + if (till > from) { + TextParseOptions opts = { TextParseMultiline, int32(st::linksMaxWidth), 3 * st::normalFont->height, Qt::LayoutDirectionAuto }; + _text.setText(st::normalFont, text.mid(from, till - from), opts); + } + int32 tw = 0, th = 0; + if (_page && _page->photo) { + if (!_page->photo->loaded()) _page->photo->thumb->load(false, false); + + tw = convertScale(_page->photo->thumb->width()); + th = convertScale(_page->photo->thumb->height()); + } else if (_page && _page->document) { + if (!_page->document->thumb->loaded()) _page->document->thumb->load(false, false); + + tw = convertScale(_page->document->thumb->width()); + th = convertScale(_page->document->thumb->height()); + } + if (tw > st::dlgPhotoSize) { + if (th > tw) { + th = th * st::dlgPhotoSize / tw; + tw = st::dlgPhotoSize; + } else if (th > st::dlgPhotoSize) { + tw = tw * st::dlgPhotoSize / th; + th = st::dlgPhotoSize; + } + } + _pixw = qMax(tw, 1); + _pixh = qMax(th, 1); + + if (_page) { + _title = _page->title; + } + QString url(_page ? _page->url : (_links.isEmpty() ? QString() : _links.at(0).lnk->text())); + QVector parts = url.splitRef('/'); + if (!parts.isEmpty()) { + QStringRef domain = parts.at(0); + if (parts.size() > 2 && domain.endsWith(':') && parts.at(1).isEmpty()) { // http:// and others + domain = parts.at(2); + } + + parts = domain.split('@').back().split('.'); + if (parts.size() > 1) { + _letter = parts.at(parts.size() - 2).at(0).toUpper(); + if (_title.isEmpty()) { + _title.reserve(parts.at(parts.size() - 2).size()); + _title.append(_letter).append(parts.at(parts.size() - 2).mid(1)); + } + } + } + _titlew = st::semiboldFont->width(_title); +} + +void Link::initDimensions() { + _maxw = st::linksMaxWidth; + _minh = 0; + if (!_title.isEmpty()) { + _minh += st::semiboldFont->height; + } + if (!_text.isEmpty()) { + _minh += qMin(3 * st::normalFont->height, _text.countHeight(_maxw - st::dlgPhotoSize - st::dlgPhotoPadding)); + } + _minh += _links.size() * st::normalFont->height; + _minh = qMax(_minh, int32(st::dlgPhotoSize)) + st::linksMargin.top() + st::linksMargin.bottom() + st::linksBorder; +} + +int32 Link::resizeGetHeight(int32 width) { + _width = qMin(width, _maxw); + int32 w = _width - st::dlgPhotoSize - st::dlgPhotoPadding; + for (int32 i = 0, l = _links.size(); i < l; ++i) { + _links.at(i).lnk->setFullDisplayed(w >= _links.at(i).width); + } + + _height = 0; + if (!_title.isEmpty()) { + _height += st::semiboldFont->height; + } + if (!_text.isEmpty()) { + _height += qMin(3 * st::normalFont->height, _text.countHeight(_width - st::dlgPhotoSize - st::dlgPhotoPadding)); + } + _height += _links.size() * st::normalFont->height; + _height = qMax(_height, int32(st::dlgPhotoSize)) + st::linksMargin.top() + st::linksMargin.bottom() + st::linksBorder; + return _height; +} + +void Link::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const { + int32 left = st::dlgPhotoSize + st::dlgPhotoPadding, top = st::linksMargin.top() + st::linksBorder, w = _width - left; + if (clip.intersects(rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width))) { + if (_page && _page->photo) { + QPixmap pix; + if (_page->photo->medium->loaded()) { + pix = _page->photo->medium->pixSingle(_pixw, _pixh, st::dlgPhotoSize, st::dlgPhotoSize); + } else if (_page->photo->loaded()) { + pix = _page->photo->full->pixSingle(_pixw, _pixh, st::dlgPhotoSize, st::dlgPhotoSize); + } else { + pix = _page->photo->thumb->pixSingle(_pixw, _pixh, st::dlgPhotoSize, st::dlgPhotoSize); + } + p.drawPixmapLeft(0, top, _width, pix); + } else if (_page && _page->document && !_page->document->thumb->isNull()) { + p.drawPixmapLeft(0, top, _width, _page->document->thumb->pixSingle(_pixw, _pixh, st::dlgPhotoSize, st::dlgPhotoSize)); + } else { + int32 index = _letter.isEmpty() ? 0 : (_letter.at(0).unicode() % 4); + switch (index) { + case 0: App::roundRect(p, rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width), st::msgFileRedColor, DocRedCorners); break; + case 1: App::roundRect(p, rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width), st::msgFileYellowColor, DocYellowCorners); break; + case 2: App::roundRect(p, rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width), st::msgFileGreenColor, DocGreenCorners); break; + case 3: App::roundRect(p, rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width), st::msgFileBlueColor, DocBlueCorners); break; + } + + if (!_letter.isEmpty()) { + p.setFont(st::linksLetterFont->f); + p.setPen(st::white->p); + p.drawText(rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width), _letter, style::al_center); + } + } + + if (selection == FullSelection) { + App::roundRect(p, rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width), st::overviewPhotoSelectOverlay, PhotoSelectOverlayCorners); + p.drawSpriteLeft(QPoint(st::dlgPhotoSize - st::linksPhotoCheck.pxWidth(), top + st::dlgPhotoSize - st::linksPhotoCheck.pxHeight()), _width, st::linksPhotoChecked); + } else if (context->selecting) { + p.drawSpriteLeft(QPoint(st::dlgPhotoSize - st::linksPhotoCheck.pxWidth(), top + st::dlgPhotoSize - st::linksPhotoCheck.pxHeight()), _width, st::linksPhotoCheck); + } + } + + if (!_title.isEmpty() && _text.isEmpty() && _links.size() == 1) { + top += (st::dlgPhotoSize - st::semiboldFont->height - st::normalFont->height) / 2; + } else { + top = st::linksTextTop; + } + + p.setPen(st::black); + p.setFont(st::semiboldFont); + if (!_title.isEmpty()) { + if (clip.intersects(rtlrect(left, top, qMin(w, _titlew), st::semiboldFont->height, _width))) { + p.drawTextLeft(left, top, _width, (w < _titlew) ? st::semiboldFont->elided(_title, w) : _title); + } + top += st::semiboldFont->height; + } + p.setFont(st::msgFont->f); + if (!_text.isEmpty()) { + int32 h = qMin(st::normalFont->height * 3, _text.countHeight(w)); + if (clip.intersects(rtlrect(left, top, w, h, _width))) { + _text.drawLeftElided(p, left, top, w, _width, 3); + } + top += h; + } + + p.setPen(st::btnYesColor); + for (int32 i = 0, l = _links.size(); i < l; ++i) { + if (clip.intersects(rtlrect(left, top, qMin(w, _links.at(i).width), st::normalFont->height, _width))) { + p.setFont(ClickHandler::showAsActive(_links.at(i).lnk) ? st::normalFont->underline() : st::normalFont); + p.drawTextLeft(left, top, _width, (w < _links.at(i).width) ? st::normalFont->elided(_links.at(i).text, w) : _links.at(i).text); + } + top += st::normalFont->height; + } + + QRect border(rtlrect(left, 0, w, st::linksBorder, _width)); + if (!context->isAfterDate && clip.intersects(border)) { + p.fillRect(clip.intersected(border), st::linksBorderFg); + } +} + +void Link::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const { + int32 left = st::dlgPhotoSize + st::dlgPhotoPadding, top = st::linksMargin.top() + st::linksBorder, w = _width - left; + if (rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width).contains(x, y)) { + link = _photol; + return; + } + + if (!_title.isEmpty() && _text.isEmpty() && _links.size() == 1) { + top += (st::dlgPhotoSize - st::semiboldFont->height - st::normalFont->height) / 2; + } + if (!_title.isEmpty()) { + if (rtlrect(left, top, qMin(w, _titlew), st::semiboldFont->height, _width).contains(x, y)) { + link = _photol; + return; + } + top += st::webPageTitleFont->height; + } + if (!_text.isEmpty()) { + top += qMin(st::normalFont->height * 3, _text.countHeight(w)); + } + for (int32 i = 0, l = _links.size(); i < l; ++i) { + if (rtlrect(left, top, qMin(w, _links.at(i).width), st::normalFont->height, _width).contains(x, y)) { + link = _links.at(i).lnk; + return; + } + top += st::normalFont->height; + } +} + +Link::LinkEntry::LinkEntry(const QString &url, const QString &text) +: text(text) +, width(st::normalFont->width(text)) +, lnk(MakeShared(url)) { +} + +} // namespace Layout +} // namespace Overview diff --git a/Telegram/SourceFiles/overview/overview_layout.h b/Telegram/SourceFiles/overview/overview_layout.h new file mode 100644 index 000000000..9a155d01c --- /dev/null +++ b/Telegram/SourceFiles/overview/overview_layout.h @@ -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, uint32 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(document), std_::move(save), MakeShared(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 { + int top = 0; +}; + +class Date : public AbstractItem { +public: + Date(const QDate &date, bool month); + + void initDimensions() override; + void paint(Painter &p, const QRect &clip, uint32 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, uint32 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, uint32 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, uint32 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, uint32 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, uint32 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 _links; + +}; + +} // namespace Layout +} // namespace Overview diff --git a/Telegram/SourceFiles/overviewwidget.cpp b/Telegram/SourceFiles/overviewwidget.cpp index f9237984e..6d4a595be 100644 --- a/Telegram/SourceFiles/overviewwidget.cpp +++ b/Telegram/SourceFiles/overviewwidget.cpp @@ -21,7 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "stdafx.h" #include "lang.h" -#include "window.h" +#include "mainwindow.h" #include "mainwidget.h" #include "overviewwidget.h" #include "boxes/addcontactbox.h" @@ -29,6 +29,9 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "boxes/photocropbox.h" #include "application.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 @@ -333,7 +336,7 @@ void OverviewInner::moveToNextItem(MsgId &msgId, int32 &index, MsgId upTo, int32 } 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; } 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; update(int32(col * w), _marginTop + int32(row * vsize), qCeil(w), vsize); } else { - int32 top = _items.at(itemIndex)->Get()->top; + int32 top = _items.at(itemIndex)->Get()->top; if (_reversed) top = _height - top; update(_rowsLeft, _marginTop + top, _rowWidth, _items.at(itemIndex)->height()); } @@ -698,7 +701,7 @@ QPoint OverviewInner::mapMouseToItem(QPoint p, MsgId itemId, int32 itemIndex) { p.setX(p.x() - int32(col * w) - st::overviewPhotoSkip); p.setY(p.y() - _marginTop - row * (_rowWidth + st::overviewPhotoSkip) - st::overviewPhotoSkip); } else { - int32 top = _items.at(itemIndex)->Get()->top; + int32 top = _items.at(itemIndex)->Get()->top; if (_reversed) top = _height - top; p.setY(p.y() - _marginTop - top); } @@ -734,7 +737,7 @@ int32 OverviewInner::itemTop(const FullMsgId &msgId) const { int32 itemIndex = -1; fixItemIndex(itemIndex, (msgId.channel == _channel) ? msgId.msg : ((_migrated && msgId.channel == _migrated->channelId()) ? -msgId.msg : 0)); if (itemIndex >= 0) { - int32 top = _items.at(itemIndex)->Get()->top; + int32 top = _items.at(itemIndex)->Get()->top; if (_reversed) top = _height - top; return _marginTop + top; } @@ -785,7 +788,7 @@ uint32 OverviewInner::itemSelectedValue(int32 index) const { selfrom = _dragSelToIndex; selto = _dragSelFromIndex; } - if (_items.at(index)->toLayoutMediaItem()) { // draw item + if (_items.at(index)->toMediaItem()) { // draw item if (index >= _dragSelToIndex && index <= _dragSelFromIndex && _dragSelToIndex >= 0) { return (_dragSelecting && _items.at(index)->msgId() > 0) ? FullSelection : 0; } else if (!_selected.isEmpty()) { @@ -809,7 +812,7 @@ void OverviewInner::paintEvent(QPaintEvent *e) { p.setClipRect(r); } 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())) { 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; for (int32 j = 0, l = _items.size(); j < l; ++j) { 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()->top; + int32 nextItemTop = (j + 1 == l) ? (_reversed ? 0 : _height) : _items.at(nexti)->Get()->top; if (_reversed) nextItemTop = _height - nextItemTop; if (_marginTop + nextItemTop > r.top()) { - OverviewItemInfo *info = _items.at(i)->Get(); + auto info = _items.at(i)->Get(); int32 curY = info->top; if (_reversed) curY = _height - curY; 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); _items.at(i)->paint(p, r.translated(-_rowsLeft, -_marginTop - curY), itemSelectedValue(i), &context); y = curY; @@ -908,7 +911,7 @@ void OverviewInner::onUpdateSelected() { upon = false; } if (i >= 0) { - if (LayoutMediaItemBase *media = _items.at(i)->toLayoutMediaItem()) { + if (auto media = _items.at(i)->toMediaItem()) { item = media->getItem(); index = i; if (upon) { @@ -921,23 +924,23 @@ void OverviewInner::onUpdateSelected() { for (int32 j = 0, l = _items.size(); j < l; ++j) { bool lastItem = (j + 1 == l); int32 i = _reversed ? (l - j - 1) : j, nexti = _reversed ? (i - 1) : (i + 1); - int32 nextItemTop = lastItem ? (_reversed ? 0 : _height) : _items.at(nexti)->Get()->top; + int32 nextItemTop = lastItem ? (_reversed ? 0 : _height) : _items.at(nexti)->Get()->top; if (_reversed) nextItemTop = _height - nextItemTop; if (_marginTop + nextItemTop > m.y() || lastItem) { - int32 top = _items.at(i)->Get()->top; + int32 top = _items.at(i)->Get()->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(); bool beforeItem = (_marginTop + top + h / 2) >= m.y(); if (_reversed) beforeItem = !beforeItem; if (i > 0 && (beforeItem || i == _items.size() - 1)) { --i; - if (!_items.at(i)->toLayoutMediaItem()) break; // wtf - top = _items.at(i)->Get()->top; + if (!_items.at(i)->toMediaItem()) break; // wtf + top = _items.at(i)->Get()->top; } else if (i < _items.size() - 1 && (!beforeItem || !i)) { ++i; - if (!_items.at(i)->toLayoutMediaItem()) break; // wtf - top = _items.at(i)->Get()->top; + if (!_items.at(i)->toMediaItem()) break; // wtf + top = _items.at(i)->Get()->top; } else { break; // wtf } @@ -945,7 +948,7 @@ void OverviewInner::onUpdateSelected() { j = _reversed ? (l - i - 1) : i; } - if (LayoutMediaItemBase *media = _items.at(i)->toLayoutMediaItem()) { + if (auto media = _items.at(i)->toMediaItem()) { item = media->getItem(); index = i; media->getState(lnk, cursorState, m.x() - _rowsLeft, m.y() - _marginTop - top); @@ -1325,7 +1328,7 @@ int32 OverviewInner::resizeToWidth(int32 nwidth, int32 scrollTop, int32 minHeigh for (int32 i = 0, l = _items.size(); i < l; ++i) { int32 h = _items.at(i)->resizeGetHeight(_rowWidth); if (resize) { - _items.at(i)->Get()->top = _height + (_reversed ? h : 0); + _items.at(i)->Get()->top = _height + (_reversed ? h : 0); _height += h; } } @@ -1632,7 +1635,7 @@ void OverviewInner::mediaOverviewUpdated() { allGood = false; } HistoryItem *item = App::histItemById(itemChannel(msgid), itemMsgId(msgid)); - LayoutMediaItemBase *layout = layoutPrepare(item); + auto layout = layoutPrepare(item); if (!layout) continue; setLayoutItem(index, layout, 0); @@ -1658,17 +1661,17 @@ void OverviewInner::mediaOverviewUpdated() { if (allGood) { if (_items.size() > index && complexMsgId(_items.at(index)->getItem()) == msgid) { if (withDates) prevDate = _items.at(index)->getItem()->date.date(); - top = _items.at(index)->Get()->top; + top = _items.at(index)->Get()->top; if (!_reversed) { top += _items.at(index)->height(); } ++index; 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; if (withDates) prevDate = _items.at(index)->getItem()->date.date(); - top = _items.at(index)->Get()->top; + top = _items.at(index)->Get()->top; if (!_reversed) { top += _items.at(index)->height(); } @@ -1678,7 +1681,7 @@ void OverviewInner::mediaOverviewUpdated() { allGood = false; } HistoryItem *item = App::histItemById(itemChannel(msgid), itemMsgId(msgid)); - LayoutMediaItemBase *layout = layoutPrepare(item); + auto layout = layoutPrepare(item); if (!layout) continue; if (withDates) { @@ -1795,7 +1798,7 @@ void OverviewInner::repaintItem(const HistoryItem *msg) { if (history == _migrated) msgid = -msgid; for (int32 i = 0, l = _items.size(); i != l; ++i) { if (complexMsgId(_items.at(i)->getItem()) == msgid) { - int32 top = _items.at(i)->Get()->top; + int32 top = _items.at(i)->Get()->top; if (_reversed) top = _height - top; update(_rowsLeft, _marginTop + top, _rowWidth, _items.at(i)->height()); break; @@ -1840,7 +1843,7 @@ void OverviewInner::recountMargins() { } } -LayoutMediaItemBase *OverviewInner::layoutPrepare(HistoryItem *item) { +Overview::Layout::ItemBase *OverviewInner::layoutPrepare(HistoryItem *item) { if (!item) return nullptr; LayoutItems::const_iterator i = _layoutItems.cend(); @@ -1848,59 +1851,59 @@ LayoutMediaItemBase *OverviewInner::layoutPrepare(HistoryItem *item) { if (_type == OverviewPhotos) { if (media && media->type() == MediaTypePhoto) { if ((i = _layoutItems.constFind(item)) == _layoutItems.cend()) { - i = _layoutItems.insert(item, new LayoutOverviewPhoto(static_cast(media)->photo(), item)); + i = _layoutItems.insert(item, new Overview::Layout::Photo(static_cast(media)->photo(), item)); i.value()->initDimensions(); } } } else if (_type == OverviewVideos) { if (media && media->type() == MediaTypeVideo) { 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(); } } } else if (_type == OverviewVoiceFiles) { if (media && (media->type() == MediaTypeVoiceFile)) { 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(); } } } else if (_type == OverviewFiles || _type == OverviewMusicFiles) { if (media && (media->type() == MediaTypeFile || media->type() == MediaTypeMusicFile || media->type() == MediaTypeGif)) { 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(); } } } else if (_type == OverviewLinks) { 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(); } } 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(); if (!month) key = key * 100 + date.day(); LayoutDates::const_iterator i = _layoutDates.constFind(key); 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(); } 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) { _items[index] = item; } else { _items.push_back(item); } int32 h = item->resizeGetHeight(_rowWidth); - if (OverviewItemInfo *info = item->Get()) { + if (auto info = item->Get()) { info->top = top + (_reversed ? h : 0); } return h; diff --git a/Telegram/SourceFiles/overviewwidget.h b/Telegram/SourceFiles/overviewwidget.h index 0d82fecac..e0c039726 100644 --- a/Telegram/SourceFiles/overviewwidget.h +++ b/Telegram/SourceFiles/overviewwidget.h @@ -20,6 +20,16 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #pragma once +namespace Overview { +namespace Layout { + +class AbstractItem; +class ItemBase; +class Date; + +} // namespace Layout +} // namespace Overview + class OverviewWidget; class OverviewInner : public QWidget, public AbstractTooltipShower, public RPCSender { Q_OBJECT @@ -152,15 +162,15 @@ private: int32 _rowsLeft, _rowWidth; - typedef QVector Items; + typedef QVector Items; Items _items; - typedef QMap LayoutItems; + typedef QMap LayoutItems; LayoutItems _layoutItems; - typedef QMap LayoutDates; + typedef QMap LayoutDates; LayoutDates _layoutDates; - LayoutMediaItemBase *layoutPrepare(HistoryItem *item); - LayoutOverviewItemBase *layoutPrepare(const QDate &date, bool month); - int32 setLayoutItem(int32 index, LayoutOverviewItemBase *item, int32 top); + Overview::Layout::ItemBase *layoutPrepare(HistoryItem *item); + Overview::Layout::AbstractItem *layoutPrepare(const QDate &date, bool month); + int32 setLayoutItem(int32 index, Overview::Layout::AbstractItem *item, int32 top); FlatInput _search; IconedButton _cancelSearch; diff --git a/Telegram/SourceFiles/passcodewidget.cpp b/Telegram/SourceFiles/passcodewidget.cpp index 0d75d5612..95aa4871d 100644 --- a/Telegram/SourceFiles/passcodewidget.cpp +++ b/Telegram/SourceFiles/passcodewidget.cpp @@ -25,7 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "localstorage.h" #include "passcodewidget.h" -#include "window.h" +#include "mainwindow.h" #include "application.h" #include "ui/text.h" diff --git a/Telegram/SourceFiles/playerwidget.cpp b/Telegram/SourceFiles/playerwidget.cpp index 7644265db..454763a2e 100644 --- a/Telegram/SourceFiles/playerwidget.cpp +++ b/Telegram/SourceFiles/playerwidget.cpp @@ -24,7 +24,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "boxes/addcontactbox.h" #include "application.h" -#include "window.h" +#include "mainwindow.h" #include "playerwidget.h" #include "mainwidget.h" diff --git a/Telegram/SourceFiles/profilewidget.cpp b/Telegram/SourceFiles/profilewidget.cpp index 25831b845..ff4d80940 100644 --- a/Telegram/SourceFiles/profilewidget.cpp +++ b/Telegram/SourceFiles/profilewidget.cpp @@ -21,7 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "stdafx.h" #include "lang.h" -#include "window.h" +#include "mainwindow.h" #include "mainwidget.h" #include "profilewidget.h" #include "boxes/addcontactbox.h" @@ -30,6 +30,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "application.h" #include "boxes/contactsbox.h" #include "ui/filedialog.h" +#include "apiwrap.h" +#include "window/top_bar_widget.h" ProfileInner::ProfileInner(ProfileWidget *profile, ScrollArea *scroll, PeerData *peer) : TWidget(0) , _profile(profile) diff --git a/Telegram/SourceFiles/pspecific_linux.cpp b/Telegram/SourceFiles/pspecific_linux.cpp index e3af2b9de..368563a9f 100644 --- a/Telegram/SourceFiles/pspecific_linux.cpp +++ b/Telegram/SourceFiles/pspecific_linux.cpp @@ -488,7 +488,7 @@ namespace { } bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) { - Window *wnd = App::wnd(); + auto wnd = App::wnd(); if (!wnd) return false; return false; diff --git a/Telegram/SourceFiles/pspecific_mac.cpp b/Telegram/SourceFiles/pspecific_mac.cpp index 531c59561..9eb8f9f8e 100644 --- a/Telegram/SourceFiles/pspecific_mac.cpp +++ b/Telegram/SourceFiles/pspecific_mac.cpp @@ -40,7 +40,7 @@ namespace { } bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) { - Window *wnd = AppClass::wnd(); + auto wnd = AppClass::wnd(); if (!wnd) return false; return wnd->psFilterNativeEvent(message); diff --git a/Telegram/SourceFiles/pspecific_mac_p.mm b/Telegram/SourceFiles/pspecific_mac_p.mm index 9bacdd112..4e3c1998f 100644 --- a/Telegram/SourceFiles/pspecific_mac_p.mm +++ b/Telegram/SourceFiles/pspecific_mac_p.mm @@ -18,7 +18,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "stdafx.h" #include "pspecific_mac_p.h" -#include "window.h" +#include "mainwindow.h" #include "mainwidget.h" #include "application.h" diff --git a/Telegram/SourceFiles/pspecific_win.cpp b/Telegram/SourceFiles/pspecific_win.cpp index 26665b0d5..6b97fab50 100644 --- a/Telegram/SourceFiles/pspecific_win.cpp +++ b/Telegram/SourceFiles/pspecific_win.cpp @@ -802,7 +802,7 @@ namespace { } bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) { - Window *wnd = App::wnd(); + auto wnd = App::wnd(); if (!wnd) return false; MSG *msg = (MSG*)message; diff --git a/Telegram/SourceFiles/pspecific_winrt.cpp b/Telegram/SourceFiles/pspecific_winrt.cpp index ee96c9ae5..816e62d22 100644 --- a/Telegram/SourceFiles/pspecific_winrt.cpp +++ b/Telegram/SourceFiles/pspecific_winrt.cpp @@ -802,7 +802,7 @@ namespace { } bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) { - Window *wnd = App::wnd(); + auto wnd = App::wnd(); if (!wnd) return false; MSG *msg = (MSG*)message; diff --git a/Telegram/SourceFiles/settingswidget.cpp b/Telegram/SourceFiles/settingswidget.cpp index cba8bc9ed..28c6a91f2 100644 --- a/Telegram/SourceFiles/settingswidget.cpp +++ b/Telegram/SourceFiles/settingswidget.cpp @@ -41,9 +41,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "boxes/stickersetbox.h" #include "langloaderplain.h" #include "ui/filedialog.h" - +#include "apiwrap.h" #include "autoupdater.h" - #include "localstorage.h" 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(&_downloadPathClear, SIGNAL(clicked()), this, SLOT(onDownloadPathClear())); switch (App::wnd()->tempDirState()) { - case Window::TempDirEmpty: _tempDirClearState = TempDirEmpty; break; - case Window::TempDirExists: _tempDirClearState = TempDirExists; break; - case Window::TempDirRemoving: _tempDirClearState = TempDirClearing; break; + case MainWindow::TempDirEmpty: _tempDirClearState = TempDirEmpty; break; + case MainWindow::TempDirExists: _tempDirClearState = TempDirExists; break; + case MainWindow::TempDirRemoving: _tempDirClearState = TempDirClearing; break; } connect(App::wnd(), SIGNAL(tempDirCleared(int)), this, SLOT(onTempDirCleared(int))); connect(App::wnd(), SIGNAL(tempDirClearFailed(int)), this, SLOT(onTempDirClearFailed(int))); @@ -302,9 +301,9 @@ SettingsInner::SettingsInner(SettingsWidget *parent) : TWidget(parent) // local storage connect(&_localStorageClear, SIGNAL(clicked()), this, SLOT(onLocalStorageClear())); switch (App::wnd()->localStorageState()) { - case Window::TempDirEmpty: _storageClearState = TempDirEmpty; break; - case Window::TempDirExists: _storageClearState = TempDirExists; break; - case Window::TempDirRemoving: _storageClearState = TempDirClearing; break; + case MainWindow::TempDirEmpty: _storageClearState = TempDirEmpty; break; + case MainWindow::TempDirExists: _storageClearState = TempDirExists; break; + case MainWindow::TempDirRemoving: _storageClearState = TempDirClearing; break; } // chat background @@ -1836,7 +1835,7 @@ void SettingsInner::onPhotoUpdateDone(PeerId peer) { update(); } -SettingsWidget::SettingsWidget(Window *parent) : TWidget(parent) +SettingsWidget::SettingsWidget(MainWindow *parent) : TWidget(parent) , _a_show(animation(this, &SettingsWidget::step_show)) , _scroll(this, st::setScroll) , _inner(this) diff --git a/Telegram/SourceFiles/settingswidget.h b/Telegram/SourceFiles/settingswidget.h index d9ee03988..4162c9844 100644 --- a/Telegram/SourceFiles/settingswidget.h +++ b/Telegram/SourceFiles/settingswidget.h @@ -26,7 +26,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include -class Window; +class MainWindow; class Settings; class Slider : public QWidget { @@ -313,7 +313,7 @@ class SettingsWidget : public TWidget { public: - SettingsWidget(Window *parent); + SettingsWidget(MainWindow *parent); void paintEvent(QPaintEvent *e); void resizeEvent(QResizeEvent *e); diff --git a/Telegram/SourceFiles/shortcuts.cpp b/Telegram/SourceFiles/shortcuts.cpp index bf5dde9cd..2e5599ac5 100644 --- a/Telegram/SourceFiles/shortcuts.cpp +++ b/Telegram/SourceFiles/shortcuts.cpp @@ -19,18 +19,18 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #include "stdafx.h" - #include "shortcuts.h" -#include "window.h" +#include "mainwindow.h" #include "passcodewidget.h" #include "mainwidget.h" +#include "playerwidget.h" namespace ShortcutCommands { typedef void(*Handler)(); void lock_telegram() { - if (Window *w = App::wnd()) { + if (auto w = App::wnd()) { if (App::passcoded()) { w->passcodeWidget()->onSubmit(); } else if (cHasPasscode()) { @@ -40,7 +40,7 @@ namespace ShortcutCommands { } void minimize_telegram() { - if (Window *w = App::wnd()) { + if (auto w = App::wnd()) { if (cWorkMode() == dbiwmTrayOnly) { w->minimizeToTray(); } else { @@ -51,8 +51,8 @@ namespace ShortcutCommands { void close_telegram() { if (!Ui::hideWindowNoQuit()) { - if (Window *w = App::wnd()) { - App::wnd()->close(); + if (auto w = App::wnd()) { + w->close(); } } } diff --git a/Telegram/SourceFiles/stdafx.h b/Telegram/SourceFiles/stdafx.h index 8a521c56a..db0521fb8 100644 --- a/Telegram/SourceFiles/stdafx.h +++ b/Telegram/SourceFiles/stdafx.h @@ -31,7 +31,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include #include -#include "basic_types.h" +#include "core/basic_types.h" #include "config.h" #include "mtproto/facade.h" diff --git a/Telegram/SourceFiles/structs.cpp b/Telegram/SourceFiles/structs.cpp index cc31492ef..dacd819d7 100644 --- a/Telegram/SourceFiles/structs.cpp +++ b/Telegram/SourceFiles/structs.cpp @@ -28,11 +28,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "mainwidget.h" #include "application.h" #include "fileuploader.h" -#include "window.h" +#include "mainwindow.h" #include "ui/filedialog.h" - +#include "apiwrap.h" #include "boxes/confirmbox.h" - #include "audio.h" #include "localstorage.h" diff --git a/Telegram/SourceFiles/structs.h b/Telegram/SourceFiles/structs.h index aff75db40..fe2255bb0 100644 --- a/Telegram/SourceFiles/structs.h +++ b/Telegram/SourceFiles/structs.h @@ -1312,3 +1312,63 @@ struct MessageCursor { inline bool operator==(const MessageCursor &a, const MessageCursor &b) { 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; + +}; diff --git a/Telegram/SourceFiles/sysbuttons.cpp b/Telegram/SourceFiles/sysbuttons.cpp index bdc31b9c6..fe2546b4e 100644 --- a/Telegram/SourceFiles/sysbuttons.cpp +++ b/Telegram/SourceFiles/sysbuttons.cpp @@ -111,7 +111,7 @@ void SysBtn::step_color(float64 ms, bool timer) { 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())); } @@ -119,7 +119,7 @@ void MinimizeBtn::onClick() { 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())); } @@ -127,7 +127,7 @@ void MaximizeBtn::onClick() { 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())); } @@ -135,7 +135,7 @@ void RestoreBtn::onClick() { 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())); } @@ -143,7 +143,7 @@ void CloseBtn::onClick() { 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())); } @@ -161,7 +161,7 @@ void UpdateBtn::onClick() { 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())); } diff --git a/Telegram/SourceFiles/sysbuttons.h b/Telegram/SourceFiles/sysbuttons.h index e9c12272d..88ff7b0a1 100644 --- a/Telegram/SourceFiles/sysbuttons.h +++ b/Telegram/SourceFiles/sysbuttons.h @@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "ui/animation.h" #include "ui/button.h" -class Window; +class MainWindow; class SysBtn : public Button { Q_OBJECT @@ -62,7 +62,7 @@ class MinimizeBtn : public SysBtn { public: - MinimizeBtn(QWidget *parent, Window *window); + MinimizeBtn(QWidget *parent, MainWindow *window); public slots: @@ -70,7 +70,7 @@ public slots: private: - Window *wnd; + MainWindow *wnd; }; class MaximizeBtn : public SysBtn { @@ -78,7 +78,7 @@ class MaximizeBtn : public SysBtn { public: - MaximizeBtn(QWidget *parent, Window *window); + MaximizeBtn(QWidget *parent, MainWindow *window); public slots: @@ -86,7 +86,7 @@ public slots: private: - Window *wnd; + MainWindow *wnd; }; class RestoreBtn : public SysBtn { @@ -94,7 +94,7 @@ class RestoreBtn : public SysBtn { public: - RestoreBtn(QWidget *parent, Window *window); + RestoreBtn(QWidget *parent, MainWindow *window); public slots: @@ -102,7 +102,7 @@ public slots: private: - Window *wnd; + MainWindow *wnd; }; class CloseBtn : public SysBtn { @@ -110,7 +110,7 @@ class CloseBtn : public SysBtn { public: - CloseBtn(QWidget *parent, Window *window); + CloseBtn(QWidget *parent, MainWindow *window); public slots: @@ -118,7 +118,7 @@ public slots: private: - Window *wnd; + MainWindow *wnd; }; class UpdateBtn : public SysBtn { @@ -126,7 +126,7 @@ class UpdateBtn : public SysBtn { public: - UpdateBtn(QWidget *parent, Window *window, const QString &text = QString()); + UpdateBtn(QWidget *parent, MainWindow *window, const QString &text = QString()); public slots: @@ -134,7 +134,7 @@ public slots: private: - Window *wnd; + MainWindow *wnd; }; class LockBtn : public SysBtn { @@ -142,7 +142,7 @@ class LockBtn : public SysBtn { public: - LockBtn(QWidget *parent, Window *window); + LockBtn(QWidget *parent, MainWindow *window); public slots: @@ -150,5 +150,5 @@ public slots: private: - Window *wnd; + MainWindow *wnd; }; diff --git a/Telegram/SourceFiles/title.cpp b/Telegram/SourceFiles/title.cpp index 117aa49a2..6c599915d 100644 --- a/Telegram/SourceFiles/title.cpp +++ b/Telegram/SourceFiles/title.cpp @@ -24,7 +24,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "title.h" #include "mainwidget.h" -#include "window.h" +#include "mainwindow.h" #include "application.h" #include "boxes/contactsbox.h" #include "boxes/aboutbox.h" @@ -49,7 +49,7 @@ void TitleHider::setLevel(float64 level) { update(); } -TitleWidget::TitleWidget(Window *window) : TWidget(window) +TitleWidget::TitleWidget(MainWindow *window) : TWidget(window) , wnd(window) , hideLevel(0) , hider(0) diff --git a/Telegram/SourceFiles/title.h b/Telegram/SourceFiles/title.h index 018695890..a0cf52226 100644 --- a/Telegram/SourceFiles/title.h +++ b/Telegram/SourceFiles/title.h @@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include #include "sysbuttons.h" -class Window; +class MainWindow; class TitleHider : public QWidget { public: @@ -44,7 +44,7 @@ class TitleWidget : public TWidget { public: - TitleWidget(Window *parent); + TitleWidget(MainWindow *parent); void paintEvent(QPaintEvent *e); void resizeEvent(QResizeEvent *e); @@ -78,7 +78,7 @@ signals: private: - Window *wnd; + MainWindow *wnd; style::color statusColor; diff --git a/Telegram/SourceFiles/ui/animation.cpp b/Telegram/SourceFiles/ui/animation.cpp index 047a3346b..a9ce8f910 100644 --- a/Telegram/SourceFiles/ui/animation.cpp +++ b/Telegram/SourceFiles/ui/animation.cpp @@ -30,7 +30,7 @@ extern "C" { } #include "mainwidget.h" -#include "window.h" +#include "mainwindow.h" namespace { AnimationManager *_manager = 0; diff --git a/Telegram/SourceFiles/ui/animation.h b/Telegram/SourceFiles/ui/animation.h index 9621f793c..68ccb9236 100644 --- a/Telegram/SourceFiles/ui/animation.h +++ b/Telegram/SourceFiles/ui/animation.h @@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #pragma once -#include "basic_types.h" +#include "core/basic_types.h" #include #include diff --git a/Telegram/SourceFiles/ui/buttons/peer_avatar_button.cpp b/Telegram/SourceFiles/ui/buttons/peer_avatar_button.cpp index 7dbadc50c..23acb4609 100644 --- a/Telegram/SourceFiles/ui/buttons/peer_avatar_button.cpp +++ b/Telegram/SourceFiles/ui/buttons/peer_avatar_button.cpp @@ -21,6 +21,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "stdafx.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) , _peer(peer) , _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); } } + +} // namespace Ui diff --git a/Telegram/SourceFiles/ui/buttons/peer_avatar_button.h b/Telegram/SourceFiles/ui/buttons/peer_avatar_button.h index d0861fef9..88e0b8464 100644 --- a/Telegram/SourceFiles/ui/buttons/peer_avatar_button.h +++ b/Telegram/SourceFiles/ui/buttons/peer_avatar_button.h @@ -22,7 +22,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "ui/button.h" #include "ui/style.h" -#include "structs.h" + +class PeerData; + +namespace Ui { class PeerAvatarButton : public Button { public: @@ -38,3 +41,5 @@ private: const style::PeerAvatarButton &_st; }; + +} // namespace Ui diff --git a/Telegram/SourceFiles/ui/flatinput.cpp b/Telegram/SourceFiles/ui/flatinput.cpp index 574239407..e175f043e 100644 --- a/Telegram/SourceFiles/ui/flatinput.cpp +++ b/Telegram/SourceFiles/ui/flatinput.cpp @@ -22,7 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "ui/style.h" #include "flatinput.h" -#include "window.h" +#include "mainwindow.h" #include "countryinput.h" #include "lang.h" diff --git a/Telegram/SourceFiles/ui/flattextarea.cpp b/Telegram/SourceFiles/ui/flattextarea.cpp index d54753132..9ef9551ff 100644 --- a/Telegram/SourceFiles/ui/flattextarea.cpp +++ b/Telegram/SourceFiles/ui/flattextarea.cpp @@ -22,7 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "flattextarea.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) , _oldtext(v) diff --git a/Telegram/SourceFiles/ui/text.cpp b/Telegram/SourceFiles/ui/text.cpp index cea666df0..190da42ce 100644 --- a/Telegram/SourceFiles/ui/text.cpp +++ b/Telegram/SourceFiles/ui/text.cpp @@ -21,13 +21,13 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "stdafx.h" #include "text.h" -#include "lang.h" +#include +#include "core/click_handler_types.h" +#include "lang.h" #include "pspecific.h" #include "boxes/confirmbox.h" -#include "window.h" - -#include +#include "mainwindow.h" namespace { @@ -57,47 +57,6 @@ namespace { } } -ClickHandlerHost::~ClickHandlerHost() { - ClickHandler::hostDestroyed(this); -} - -NeverFreedPointer ClickHandler::_active; -NeverFreedPointer 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; -} - const QRegularExpression &reDomain() { return _reDomain; } @@ -954,113 +913,6 @@ namespace { } } -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()) { - Ui::showPeerHistory(peer, ShowAtTheEndMsgId); - App::sendBotCommand(peer, _cmd); - } else { - App::insertBotCommand(_cmd); - } - } -} - class TextPainter { public: diff --git a/Telegram/SourceFiles/ui/text.h b/Telegram/SourceFiles/ui/text.h index 74c7aa3f1..c890745f5 100644 --- a/Telegram/SourceFiles/ui/text.h +++ b/Telegram/SourceFiles/ui/text.h @@ -20,6 +20,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #pragma once +#include "core/click_handler.h" + enum EntityInTextType { EntityInTextUrl, EntityInTextCustomUrl, @@ -34,10 +36,10 @@ enum EntityInTextType { EntityInTextPre, // block }; struct EntityInText { - EntityInText(EntityInTextType type, int32 offset, int32 length, const QString &text = QString()) : type(type), offset(offset), length(length), text(text) { + EntityInText(EntityInTextType type, int offset, int length, const QString &text = QString()) : type(type), offset(offset), length(length), text(text) { } EntityInTextType type; - int32 offset, length; + int offset, length; QString text; }; typedef QList EntitiesInText; @@ -309,344 +311,6 @@ private: friend class TextPainter; }; -class ClickHandler; -using ClickHandlerPtr = QSharedPointer; - -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; - } else if (_pressedHost == host) { - _pressedHost = nullptr; - } - } - -private: - - static NeverFreedPointer _active; - static NeverFreedPointer _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; - -}; - -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 TextClickHandlerPtr; - -class HiddenUrlClickHandler : public UrlClickHandler { -public: - HiddenUrlClickHandler(QString url) : UrlClickHandler(url, false) { - } - void onClick(Qt::MouseButton button) const override; - -}; - -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); -} - -class LocationClickHandler : public TextClickHandler { -public: - LocationClickHandler(const LocationCoords &coords) : _coords(coords) { - setup(); - } - QString copyToClipboardContextItem() const override; - - QString text() const override { - return _text; - } - void onClick(Qt::MouseButton button) const override; - -protected: - QString url() const override { - return _text; - } - -private: - - void setup(); - LocationCoords _coords; - QString _text; - -}; - -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; - -}; - static const QChar TextCommand(0x0010); enum TextCommands { TextCommandBold = 0x01, diff --git a/Telegram/SourceFiles/ui/toast/toast.cpp b/Telegram/SourceFiles/ui/toast/toast.cpp index 341d427cd..02d67e92a 100644 --- a/Telegram/SourceFiles/ui/toast/toast.cpp +++ b/Telegram/SourceFiles/ui/toast/toast.cpp @@ -23,7 +23,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "ui/toast/toast_manager.h" #include "ui/toast/toast_widget.h" -#include "window.h" namespace Ui { namespace Toast { @@ -35,12 +34,10 @@ Instance::Instance(const Config &config, QWidget *widgetParent, const Private &) _a_fade.start(); } -void Show(const Config &config) { - if (internal::Manager *manager = internal::Manager::instance()) { - if (Window *window = App::wnd()) { - auto toast = std_::make_unique(config, window, Instance::Private()); - manager->addToast(std_::move(toast)); - } +void Show(QWidget *parent, const Config &config) { + if (auto manager = internal::Manager::instance(parent)) { + auto toast = std_::make_unique(config, parent, Instance::Private()); + manager->addToast(std_::move(toast)); } } diff --git a/Telegram/SourceFiles/ui/toast/toast.h b/Telegram/SourceFiles/ui/toast/toast.h index be634dfdb..d4a15b3a0 100644 --- a/Telegram/SourceFiles/ui/toast/toast.h +++ b/Telegram/SourceFiles/ui/toast/toast.h @@ -33,7 +33,7 @@ struct Config { QString text; int durationMs = DefaultDuration; }; -void Show(const Config &config); +void Show(QWidget *parent, const Config &config); class Instance { struct Private { @@ -57,7 +57,7 @@ private: // ToastManager should reset _widget pointer if _widget is destroyed. friend class internal::Manager; - friend void Show(const Config &config); + friend void Show(QWidget *parent, const Config &config); std_::unique_ptr _widget; }; diff --git a/Telegram/SourceFiles/ui/toast/toast_manager.cpp b/Telegram/SourceFiles/ui/toast/toast_manager.cpp index 29479c9a9..39c63f1c3 100644 --- a/Telegram/SourceFiles/ui/toast/toast_manager.cpp +++ b/Telegram/SourceFiles/ui/toast/toast_manager.cpp @@ -21,30 +21,31 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "stdafx.h" #include "ui/toast/toast_manager.h" +#include "application.h" #include "ui/toast/toast_widget.h" -#include "window.h" namespace Ui { namespace Toast { namespace internal { -Manager *Manager::_instance = nullptr; +namespace { -Manager::Manager(QObject *parent) : QObject(parent) { - t_assert(_instance == nullptr); - _instance = this; +NeverFreedPointer> _managers; +} // namespace + +Manager::Manager(QWidget *parent) : QObject(parent) { connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(onHideTimeout())); connect(parent, SIGNAL(resized()), this, SLOT(onParentResized())); } -Manager *Manager::instance() { - if (!_instance) { - if (Window *w = App::wnd()) { - _instance = new Manager(w); - } +Manager *Manager::instance(QWidget *parent) { + _managers.makeIfNull(); + auto i = _managers->constFind(parent); + if (i == _managers->cend()) { + i = _managers->insert(parent, new Manager(parent)); } - return _instance; + return i.value(); } void Manager::addToast(std_::unique_ptr &&toast) { @@ -115,7 +116,7 @@ void Manager::startNextHideTimer() { } Manager::~Manager() { - _instance = nullptr; + _managers->remove(parent()); } } // namespace internal diff --git a/Telegram/SourceFiles/ui/toast/toast_manager.h b/Telegram/SourceFiles/ui/toast/toast_manager.h index f2b514a9e..28419cf72 100644 --- a/Telegram/SourceFiles/ui/toast/toast_manager.h +++ b/Telegram/SourceFiles/ui/toast/toast_manager.h @@ -34,7 +34,7 @@ public: Manager(const Manager &other) = delete; Manager &operator=(const Manager &other) = delete; - static Manager *instance(); + static Manager *instance(QWidget *parent); void addToast(std_::unique_ptr &&toast); @@ -46,7 +46,7 @@ private slots: void onToastWidgetParentResized(); private: - Manager(QObject *parent); + Manager(QWidget *parent); void startNextHideTimer(); SingleTimer _hideTimer; @@ -56,8 +56,6 @@ private: QMap _toastByWidget; QList _toasts; - static Manager *_instance; - }; } // namespace internal diff --git a/Telegram/SourceFiles/ui/twidget.cpp b/Telegram/SourceFiles/ui/twidget.cpp index eced0da47..cb3ea81b7 100644 --- a/Telegram/SourceFiles/ui/twidget.cpp +++ b/Telegram/SourceFiles/ui/twidget.cpp @@ -21,7 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "stdafx.h" #include "application.h" -#include "window.h" +#include "mainwindow.h" namespace Fonts { diff --git a/Telegram/SourceFiles/ui/twidget.h b/Telegram/SourceFiles/ui/twidget.h index 4667e43a9..9d4b5468f 100644 --- a/Telegram/SourceFiles/ui/twidget.h +++ b/Telegram/SourceFiles/ui/twidget.h @@ -156,12 +156,12 @@ void rtlupdate(int x, int y, int w, int h) { \ update(myrtlrect(x, y, w, h)); \ } \ protected: \ -void enterEvent(QEvent *e) { \ +void enterEvent(QEvent *e) override { \ TWidget *p(tparent()); \ if (p) p->leaveToChildEvent(e); \ return QWidget::enterEvent(e); \ } \ -void leaveEvent(QEvent *e) { \ +void leaveEvent(QEvent *e) override { \ TWidget *p(tparent()); \ if (p) p->enterFromChildEvent(e); \ return QWidget::leaveEvent(e); \ @@ -172,8 +172,7 @@ class TWidget : public QWidget { T_WIDGET public: - - TWidget(QWidget *parent = 0) : QWidget(parent) { + TWidget(QWidget *parent = nullptr) : QWidget(parent) { } bool event(QEvent *e) { return QWidget::event(e); @@ -185,8 +184,6 @@ public: bool inFocusChain() const; -private: - }; void myEnsureResized(QWidget *target); @@ -229,3 +226,44 @@ private: const char *_member; }; + +// A simple wrap around T* to explicitly state ownership +template +class ChildWidget { +public: + ChildWidget(std::nullptr_t) : _widget(nullptr) { + } + // No default constructor, but constructors with at least + // one argument are simply make functions. + template + ChildWidget(Parent &&parent, Args&&... args) : _widget(new T(std_::forward(parent), std_::forward(args)...)) { + } + + ChildWidget(const ChildWidget &other) = delete; + ChildWidget &operator=(const ChildWidget &other) = delete; + + ChildWidget &operator=(std::nullptr_t) { + _widget = nullptr; + return *this; + } + ChildWidget &operator=(T *widget) { + _widget = widget; + return *this; + } + + T *operator->() const { + return _widget; + } + T &operator*() const { + return *_widget; + } + + // So we can pass this pointer to methods like connect(). + operator T*() const { + return _widget; + } + +private: + T *_widget; + +}; diff --git a/Telegram/SourceFiles/window/top_bar_widget.cpp b/Telegram/SourceFiles/window/top_bar_widget.cpp new file mode 100644 index 000000000..b6b1ace0d --- /dev/null +++ b/Telegram/SourceFiles/window/top_bar_widget.cpp @@ -0,0 +1,393 @@ +/* +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 "window/top_bar_widget.h" + +#include "boxes/addcontactbox.h" +#include "boxes/confirmbox.h" +#include "mainwidget.h" +#include "shortcuts.h" +#include "lang.h" +#include "ui/buttons/peer_avatar_button.h" +#include "ui/flatbutton.h" + +namespace Window { + +TopBarWidget::TopBarWidget(MainWidget *w) : TWidget(w) +, a_over(0) +, _a_appearance(animation(this, &TopBarWidget::step_appearance)) +, _selPeer(0) +, _selCount(0) +, _canDelete(false) +, _selStrLeft(-st::topBarButton.width / 2) +, _selStrWidth(0) +, _animating(false) +, _clearSelection(this, lang(lng_selected_clear), st::topBarButton) +, _forward(this, lang(lng_selected_forward), st::topBarActionButton) +, _delete(this, lang(lng_selected_delete), st::topBarActionButton) +, _selectionButtonsWidth(_clearSelection->width() + _forward->width() + _delete->width()) +, _forwardDeleteWidth(qMax(_forward->textWidth(), _delete->textWidth())) +, _info(this, nullptr, st::infoButton) +, _edit(this, lang(lng_profile_edit_contact), st::topBarButton) +, _leaveGroup(this, lang(lng_profile_delete_and_exit), st::topBarButton) +, _addContact(this, lang(lng_profile_add_contact), st::topBarButton) +, _deleteContact(this, lang(lng_profile_delete_contact), st::topBarButton) +, _mediaType(this, lang(lng_media_type), st::topBarButton) +, _search(this, st::topBarSearch) +, _sideShadow(this, st::shadowColor) { + + connect(_forward, SIGNAL(clicked()), this, SLOT(onForwardSelection())); + connect(_delete, SIGNAL(clicked()), this, SLOT(onDeleteSelection())); + connect(_clearSelection, SIGNAL(clicked()), this, SLOT(onClearSelection())); + connect(_info, SIGNAL(clicked()), this, SLOT(onInfoClicked())); + connect(_addContact, SIGNAL(clicked()), this, SLOT(onAddContact())); + connect(_deleteContact, SIGNAL(clicked()), this, SLOT(onDeleteContact())); + connect(_edit, SIGNAL(clicked()), this, SLOT(onEdit())); + connect(_leaveGroup, SIGNAL(clicked()), this, SLOT(onDeleteAndExit())); + connect(_search, SIGNAL(clicked()), this, SLOT(onSearch())); + + setCursor(style::cur_pointer); + showAll(); +} + +void TopBarWidget::onForwardSelection() { + if (App::main()) App::main()->forwardSelectedItems(); +} + +void TopBarWidget::onDeleteSelection() { + if (App::main()) App::main()->deleteSelectedItems(); +} + +void TopBarWidget::onClearSelection() { + if (App::main()) App::main()->clearSelectedItems(); +} + +void TopBarWidget::onInfoClicked() { + PeerData *p = App::main() ? App::main()->historyPeer() : 0; + if (p) App::main()->showPeerProfile(p); +} + +void TopBarWidget::onAddContact() { + PeerData *p = App::main() ? App::main()->profilePeer() : 0; + UserData *u = p ? p->asUser() : 0; + if (u) Ui::showLayer(new AddContactBox(u->firstName, u->lastName, u->phone.isEmpty() ? App::phoneFromSharedContact(peerToUser(u->id)) : u->phone)); +} + +void TopBarWidget::onEdit() { + PeerData *p = App::main() ? App::main()->profilePeer() : 0; + if (p) { + if (p->isChannel()) { + Ui::showLayer(new EditChannelBox(p->asChannel())); + } else if (p->isChat()) { + Ui::showLayer(new EditNameTitleBox(p)); + } else if (p->isUser()) { + Ui::showLayer(new AddContactBox(p->asUser())); + } + } +} + +void TopBarWidget::onDeleteContact() { + PeerData *p = App::main() ? App::main()->profilePeer() : 0; + UserData *u = p ? p->asUser() : 0; + if (u) { + ConfirmBox *box = new ConfirmBox(lng_sure_delete_contact(lt_contact, p->name), lang(lng_box_delete)); + connect(box, SIGNAL(confirmed()), this, SLOT(onDeleteContactSure())); + Ui::showLayer(box); + } +} + +void TopBarWidget::onDeleteContactSure() { + PeerData *p = App::main() ? App::main()->profilePeer() : 0; + UserData *u = p ? p->asUser() : 0; + if (u) { + Ui::showChatsList(); + Ui::hideLayer(); + MTP::send(MTPcontacts_DeleteContact(u->inputUser), App::main()->rpcDone(&MainWidget::deletedContact, u)); + } +} + +void TopBarWidget::onDeleteAndExit() { + PeerData *p = App::main() ? App::main()->profilePeer() : 0; + ChatData *c = p ? p->asChat() : 0; + if (c) { + ConfirmBox *box = new ConfirmBox(lng_sure_delete_and_exit(lt_group, p->name), lang(lng_box_leave), st::attentionBoxButton); + connect(box, SIGNAL(confirmed()), this, SLOT(onDeleteAndExitSure())); + Ui::showLayer(box); + } +} + +void TopBarWidget::onDeleteAndExitSure() { + PeerData *p = App::main() ? App::main()->profilePeer() : 0; + ChatData *c = p ? p->asChat() : 0; + if (c) { + Ui::showChatsList(); + Ui::hideLayer(); + MTP::send(MTPmessages_DeleteChatUser(c->inputChat, App::self()->inputUser), App::main()->rpcDone(&MainWidget::deleteHistoryAfterLeave, p), App::main()->rpcFail(&MainWidget::leaveChatFailed, p)); + } +} + +void TopBarWidget::onSearch() { + Shortcuts::launch(qsl("search")); +} + +void TopBarWidget::enterEvent(QEvent *e) { + a_over.start(1); + _a_appearance.start(); +} + +void TopBarWidget::enterFromChildEvent(QEvent *e) { + a_over.start(1); + _a_appearance.start(); +} + +void TopBarWidget::leaveEvent(QEvent *e) { + a_over.start(0); + _a_appearance.start(); +} + +void TopBarWidget::leaveToChildEvent(QEvent *e) { + a_over.start(0); + _a_appearance.start(); +} + +void TopBarWidget::step_appearance(float64 ms, bool timer) { + float64 dt = ms / st::topBarDuration; + if (dt >= 1) { + _a_appearance.stop(); + a_over.finish(); + } else { + a_over.update(dt, anim::linear); + } + if (timer) update(); +} + +void TopBarWidget::paintEvent(QPaintEvent *e) { + QPainter p(this); + + if (e->rect().top() < st::topBarHeight) { // optimize shadow-only drawing + p.fillRect(QRect(0, 0, width(), st::topBarHeight), st::topBarBG->b); + if (_clearSelection->isHidden()) { + p.save(); + main()->paintTopBar(p, a_over.current(), _info->isHidden() ? 0 : _info->width()); + p.restore(); + } else { + p.setFont(st::linkFont->f); + p.setPen(st::btnDefLink.color->p); + p.drawText(_selStrLeft, st::topBarButton.textTop + st::linkFont->ascent, _selStr); + } + } +} + +void TopBarWidget::mousePressEvent(QMouseEvent *e) { + PeerData *p = App::main() ? App::main()->profilePeer() : 0; + if (e->button() == Qt::LeftButton && e->pos().y() < st::topBarHeight && (p || !_selCount)) { + emit clicked(); + } +} + +void TopBarWidget::resizeEvent(QResizeEvent *e) { + int32 r = width(); + if (!_forward->isHidden() || !_delete->isHidden()) { + int32 fullW = r - (_selectionButtonsWidth + (_selStrWidth - st::topBarButton.width) + st::topBarActionSkip); + int32 selectedClearWidth = st::topBarButton.width, forwardDeleteWidth = st::topBarActionButton.width - _forwardDeleteWidth, skip = st::topBarActionSkip; + while (fullW < 0) { + int fit = 0; + if (selectedClearWidth < -2 * (st::topBarMinPadding + 1)) { + fullW += 4; + selectedClearWidth += 2; + } else if (selectedClearWidth < -2 * st::topBarMinPadding) { + fullW += (-2 * st::topBarMinPadding - selectedClearWidth) * 2; + selectedClearWidth = -2 * st::topBarMinPadding; + } else { + ++fit; + } + if (fullW >= 0) break; + + if (forwardDeleteWidth > 2 * (st::topBarMinPadding + 1)) { + fullW += 4; + forwardDeleteWidth -= 2; + } else if (forwardDeleteWidth > 2 * st::topBarMinPadding) { + fullW += (forwardDeleteWidth - 2 * st::topBarMinPadding) * 2; + forwardDeleteWidth = 2 * st::topBarMinPadding; + } else { + ++fit; + } + if (fullW >= 0) break; + + if (skip > st::topBarMinPadding) { + --skip; + ++fullW; + } else { + ++fit; + } + if (fullW >= 0 || fit >= 3) break; + } + _clearSelection->setWidth(selectedClearWidth); + _forward->setWidth(_forwardDeleteWidth + forwardDeleteWidth); + _delete->setWidth(_forwardDeleteWidth + forwardDeleteWidth); + _selStrLeft = -selectedClearWidth / 2; + + int32 availX = _selStrLeft + _selStrWidth, availW = r - (_clearSelection->width() + selectedClearWidth / 2) - availX; + if (_forward->isHidden()) { + _delete->move(availX + (availW - _delete->width()) / 2, (st::topBarHeight - _forward->height()) / 2); + } else if (_delete->isHidden()) { + _forward->move(availX + (availW - _forward->width()) / 2, (st::topBarHeight - _forward->height()) / 2); + } else { + _forward->move(availX + (availW - _forward->width() - _delete->width() - skip) / 2, (st::topBarHeight - _forward->height()) / 2); + _delete->move(availX + (availW + _forward->width() - _delete->width() + skip) / 2, (st::topBarHeight - _forward->height()) / 2); + } + _clearSelection->move(r -= _clearSelection->width(), 0); + } + if (!_info->isHidden()) _info->move(r -= _info->width(), 0); + if (!_deleteContact->isHidden()) _deleteContact->move(r -= _deleteContact->width(), 0); + if (!_leaveGroup->isHidden()) _leaveGroup->move(r -= _leaveGroup->width(), 0); + if (!_edit->isHidden()) _edit->move(r -= _edit->width(), 0); + if (!_addContact->isHidden()) _addContact->move(r -= _addContact->width(), 0); + if (!_mediaType->isHidden()) _mediaType->move(r -= _mediaType->width(), 0); + _search->move(width() - (_info->isHidden() ? st::topBarForwardPadding.right() : _info->width()) - _search->width(), 0); + + _sideShadow->resize(st::lineWidth, height()); + _sideShadow->moveToLeft(0, 0); +} + +void TopBarWidget::startAnim() { + _info->hide(); + _edit->hide(); + _leaveGroup->hide(); + _addContact->hide(); + _deleteContact->hide(); + _clearSelection->hide(); + _delete->hide(); + _forward->hide(); + _mediaType->hide(); + _search->hide(); + + _animating = true; +} + +void TopBarWidget::stopAnim() { + _animating = false; + _sideShadow->setVisible(!Adaptive::OneColumn()); + showAll(); +} + +void TopBarWidget::showAll() { + if (_animating) { + resizeEvent(0); + return; + } + PeerData *p = App::main() ? App::main()->profilePeer() : 0, *h = App::main() ? App::main()->historyPeer() : 0, *o = App::main() ? App::main()->overviewPeer() : 0; + if (p && (p->isChat() || (p->isUser() && (p->asUser()->contact >= 0 || !App::phoneFromSharedContact(peerToUser(p->id)).isEmpty())))) { + if (p->isChat()) { + if (p->asChat()->canEdit()) { + _edit->show(); + } else { + _edit->hide(); + } + _leaveGroup->show(); + _addContact->hide(); + _deleteContact->hide(); + } else if (p->asUser()->contact > 0) { + _edit->show(); + _leaveGroup->hide(); + _addContact->hide(); + _deleteContact->show(); + } else { + _edit->hide(); + _leaveGroup->hide(); + _addContact->show(); + _deleteContact->hide(); + } + _clearSelection->hide(); + _info->hide(); + _delete->hide(); + _forward->hide(); + _mediaType->hide(); + _search->hide(); + } else { + if (p && p->isChannel() && (p->asChannel()->amCreator() || (p->isMegagroup() && p->asChannel()->amEditor()))) { + _edit->show(); + } else { + _edit->hide(); + } + _leaveGroup->hide(); + _addContact->hide(); + _deleteContact->hide(); + if (!p && _selCount) { + _clearSelection->show(); + if (_canDelete) { + _delete->show(); + } else { + _delete->hide(); + } + _forward->show(); + _mediaType->hide(); + } else { + _clearSelection->hide(); + _delete->hide(); + _forward->hide(); + if (App::main() && App::main()->mediaTypeSwitch()) { + _mediaType->show(); + } else { + _mediaType->hide(); + } + } + if (h && !o && !p && _clearSelection->isHidden()) { + if (Adaptive::OneColumn()) { + _info->setPeer(h); + _info->show(); + } else { + _info->hide(); + } + _search->show(); + } else { + _search->hide(); + _info->hide(); + } + } + _sideShadow->setVisible(!Adaptive::OneColumn()); + resizeEvent(nullptr); +} + +void TopBarWidget::showSelected(uint32 selCount, bool canDelete) { + PeerData *p = App::main() ? App::main()->profilePeer() : 0; + _selPeer = App::main()->overviewPeer() ? App::main()->overviewPeer() : App::main()->peer(); + _selCount = selCount; + _canDelete = canDelete; + _selStr = (_selCount > 0) ? lng_selected_count(lt_count, _selCount) : QString(); + _selStrWidth = st::btnDefLink.font->width(_selStr); + setCursor((!p && _selCount) ? style::cur_default : style::cur_pointer); + showAll(); +} + +void TopBarWidget::updateAdaptiveLayout() { + showAll(); +} + +FlatButton *TopBarWidget::mediaTypeButton() { + return _mediaType; +} + +MainWidget *TopBarWidget::main() { + return static_cast(parentWidget()); +} + +} // namespace Window diff --git a/Telegram/SourceFiles/window/top_bar_widget.h b/Telegram/SourceFiles/window/top_bar_widget.h new file mode 100644 index 000000000..3c94114e6 --- /dev/null +++ b/Telegram/SourceFiles/window/top_bar_widget.h @@ -0,0 +1,114 @@ +/* +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 "ui/twidget.h" + +namespace Ui { +class PeerAvatarButton; +} // namespace Ui +class FlatButton; +class IconedButton; +class PlainShadow; + +namespace Window { + +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 = nullptr; + uint32 _selCount; + bool _canDelete; + QString _selStr; + int32 _selStrLeft, _selStrWidth; + + bool _animating; + + ChildWidget _clearSelection; + ChildWidget _forward, _delete; + int _selectionButtonsWidth, _forwardDeleteWidth; + + ChildWidget _info; + ChildWidget _edit, _leaveGroup, _addContact, _deleteContact; + ChildWidget _mediaType; + + ChildWidget _search; + + ChildWidget _sideShadow; + +}; + +} // namespace Window diff --git a/Telegram/Telegram.vcxproj b/Telegram/Telegram.vcxproj index c651652de..1fb2d8faf 100644 --- a/Telegram/Telegram.vcxproj +++ b/Telegram/Telegram.vcxproj @@ -348,6 +348,10 @@ true true + + true + true + true true @@ -435,6 +439,10 @@ true true + + true + true + true true @@ -443,10 +451,6 @@ true true - - true - true - true true @@ -631,6 +635,10 @@ true true + + true + true + true true @@ -718,6 +726,10 @@ true true + + true + true + true true @@ -726,10 +738,6 @@ true true - - true - true - @@ -940,6 +948,10 @@ true true + + true + true + true true @@ -1027,6 +1039,10 @@ true true + + true + true + true true @@ -1035,17 +1051,12 @@ true true - - true - true - - @@ -1063,6 +1074,9 @@ + + + @@ -1107,6 +1121,7 @@ + @@ -1160,7 +1175,8 @@ - + + NotUsing NotUsing @@ -1213,25 +1229,28 @@ .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/mtproto/connection_tcp.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\openssl\Release\include" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\..\..\Libraries\breakpad\src" "-I.\ThirdParty\minizip" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.1\QtGui" - + $(QTDIR)\bin\moc.exe;%(FullPath) Moc%27ing basic_types.h... .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp - "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/basic_types.h" -DAL_LIBTYPE_STATIC -DCUSTOM_API_ID -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\openssl\Release\include" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\..\..\Libraries\breakpad\src" "-I.\ThirdParty\minizip" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.1\QtGui" + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/core/basic_types.h" -DAL_LIBTYPE_STATIC -DCUSTOM_API_ID -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\openssl\Release\include" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\..\..\Libraries\breakpad\src" "-I.\ThirdParty\minizip" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.1\QtGui" $(QTDIR)\bin\moc.exe;%(FullPath) Moc%27ing basic_types.h... .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp - "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/basic_types.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\openssl_debug\Debug\include" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\..\..\Libraries\breakpad\src" "-I.\ThirdParty\minizip" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.1\QtGui" + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/core/basic_types.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\openssl_debug\Debug\include" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\..\..\Libraries\breakpad\src" "-I.\ThirdParty\minizip" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.1\QtGui" $(QTDIR)\bin\moc.exe;%(FullPath) Moc%27ing basic_types.h... .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp - "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/basic_types.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\openssl\Release\include" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\..\..\Libraries\breakpad\src" "-I.\ThirdParty\minizip" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.1\QtGui" + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/core/basic_types.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\openssl\Release\include" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\..\..\Libraries\breakpad\src" "-I.\ThirdParty\minizip" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.1\QtGui" + + + @@ -1339,6 +1358,7 @@ .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/mtproto/session.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\openssl\Release\include" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\..\..\Libraries\breakpad\src" "-I.\ThirdParty\minizip" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.1\QtGui" + @@ -1520,22 +1540,36 @@ "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/ui/toast/toast_manager.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\openssl\Release\include" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\..\..\Libraries\breakpad\src" "-I.\ThirdParty\minizip" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.1\QtGui" + + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing top_bar_widget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/window/top_bar_widget.h" -DAL_LIBTYPE_STATIC -DCUSTOM_API_ID -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\openssl\Release\include" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\..\..\Libraries\breakpad\src" "-I.\ThirdParty\minizip" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.1\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing top_bar_widget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/window/top_bar_widget.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\openssl_debug\Debug\include" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\..\..\Libraries\breakpad\src" "-I.\ThirdParty\minizip" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.1\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing top_bar_widget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/window/top_bar_widget.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\openssl\Release\include" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\..\..\Libraries\breakpad\src" "-I.\ThirdParty\minizip" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.1\QtGui" + - - Moc%27ing window.h... + + Moc%27ing mainwindow.h... .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp - "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\openssl_debug\Debug\include" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\..\..\Libraries\breakpad\src" "-I.\ThirdParty\minizip" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.1\QtGui" "-fstdafx.h" "-f../../SourceFiles/window.h" - Moc%27ing window.h... - Moc%27ing window.h... + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/mainwindow.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\openssl_debug\Debug\include" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\..\..\Libraries\breakpad\src" "-I.\ThirdParty\minizip" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.1\QtGui" + Moc%27ing mainwindow.h... + Moc%27ing mainwindow.h... .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp - "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\openssl\Release\include" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\..\..\Libraries\breakpad\src" "-I.\ThirdParty\minizip" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.1\QtGui" "-fstdafx.h" "-f../../SourceFiles/window.h" - "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DAL_LIBTYPE_STATIC -DCUSTOM_API_ID -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\openssl\Release\include" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\..\..\Libraries\breakpad\src" "-I.\ThirdParty\minizip" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.1\QtGui" "-fstdafx.h" "-f../../SourceFiles/window.h" - $(QTDIR)\bin\moc.exe;%(FullPath) - $(QTDIR)\bin\moc.exe;%(FullPath) - $(QTDIR)\bin\moc.exe;%(FullPath) + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/mainwindow.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\openssl\Release\include" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\..\..\Libraries\breakpad\src" "-I.\ThirdParty\minizip" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.1\QtGui" + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/mainwindow.h" -DAL_LIBTYPE_STATIC -DCUSTOM_API_ID -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\openssl\Release\include" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\..\..\Libraries\breakpad\src" "-I.\ThirdParty\minizip" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.1\QtGui" + $(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath) + $(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath) .\GeneratedFiles\style_classes.h diff --git a/Telegram/Telegram.vcxproj.filters b/Telegram/Telegram.vcxproj.filters index 2c6bfa628..86772f8db 100644 --- a/Telegram/Telegram.vcxproj.filters +++ b/Telegram/Telegram.vcxproj.filters @@ -67,6 +67,18 @@ {24292a88-6707-4070-b2d2-8b53acd5cdd0} + + {162feb92-08a4-4abf-9936-79c389d4fcb9} + + + {39b5a449-928d-4add-9610-95c03878d52f} + + + {0192d4a5-ecf0-4076-937a-d3a08443e543} + + + {ddcc5634-90e7-4815-ba86-a3db539f4774} + @@ -99,9 +111,6 @@ Source Files - - Source Files - Source Files @@ -177,15 +186,6 @@ Source Files - - Generated Files\Deploy - - - Generated Files\Debug - - - Generated Files\Release - Generated Files\Deploy @@ -825,18 +825,6 @@ Generated Files\Release - - Source Files - - - Generated Files\Deploy - - - Generated Files\Debug - - - Generated Files\Release - inline_bots @@ -1035,6 +1023,51 @@ ui\buttons + + window + + + Generated Files\Deploy + + + Generated Files\Deploy + + + Generated Files\Debug + + + Generated Files\Release + + + Source Files + + + Generated Files\Debug + + + Generated Files\Release + + + core + + + core + + + Generated Files\Deploy + + + Generated Files\Debug + + + Generated Files\Release + + + core + + + overview + @@ -1175,6 +1208,18 @@ ui\buttons + + history + + + core + + + core + + + overview + @@ -1183,9 +1228,6 @@ Source Files - - Source Files - Source Files @@ -1378,9 +1420,6 @@ Source Files - - Source Files - ui @@ -1417,6 +1456,15 @@ ui\toast + + window + + + Source Files + + + core + diff --git a/Telegram/Telegram.xcodeproj/project.pbxproj b/Telegram/Telegram.xcodeproj/project.pbxproj index 68dd8e923..fe744af85 100644 --- a/Telegram/Telegram.xcodeproj/project.pbxproj +++ b/Telegram/Telegram.xcodeproj/project.pbxproj @@ -162,7 +162,7 @@ 5FC914F652D1B16FDA8F0634 /* moc_contactsbox.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 26083D8E535AFF927591E1A5 /* moc_contactsbox.cpp */; settings = {ATTRIBUTES = (); }; }; 60CB4898955209B665E7B07D /* moc_twidget.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 55A654A2EE8554FF062742B8 /* moc_twidget.cpp */; settings = {ATTRIBUTES = (); }; }; 668DDDA0C55405E7FCFD6CA5 /* CoreServices.framework in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 9742F24EE18EA44D52824F1E /* CoreServices.framework */; }; - 68FFEB7CA30BF0149161B809 /* window.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = CA56ACFB53D87637192CC9B2 /* window.cpp */; settings = {ATTRIBUTES = (); }; }; + 68FFEB7CA30BF0149161B809 /* mainwindow.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = CA56ACFB53D87637192CC9B2 /* mainwindow.cpp */; settings = {ATTRIBUTES = (); }; }; 6A8BC88AB464B92706EFE6FF /* moc_countryinput.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 9D9F4744B2F9FF22569D4535 /* moc_countryinput.cpp */; settings = {ATTRIBUTES = (); }; }; 6C79FBC5CFA36AC3EA6ABBD4 /* moc_dropdown.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = AC9B5F6FB4B984C8D76F7AE2 /* moc_dropdown.cpp */; settings = {ATTRIBUTES = (); }; }; 6E4DB0CBEF415196AFD4149F /* fileuploader.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 9B36BB8C5B8CA7B07F3F35F0 /* fileuploader.cpp */; settings = {ATTRIBUTES = (); }; }; @@ -194,7 +194,7 @@ 9809A3AF1946D51ACB41D716 /* moc_photocropbox.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = AF61D864B8C444ADD4E1B391 /* moc_photocropbox.cpp */; settings = {ATTRIBUTES = (); }; }; 98E4F55DB5D8E64AB9F08C83 /* moc_localimageloader.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 1D7899ACAA9F973CADFA34C1 /* moc_localimageloader.cpp */; settings = {ATTRIBUTES = (); }; }; 99F0A9B2AFE5ABDCBFC04510 /* rpc_sender.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 89F92B278CA31C393E245056 /* rpc_sender.cpp */; settings = {ATTRIBUTES = (); }; }; - 9A0D5DDC7816FC2538EB6A96 /* moc_window.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 6B46A0EE3C3B9D3B5A24946E /* moc_window.cpp */; settings = {ATTRIBUTES = (); }; }; + 9A0D5DDC7816FC2538EB6A96 /* moc_mainwindow.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 6B46A0EE3C3B9D3B5A24946E /* moc_mainwindow.cpp */; settings = {ATTRIBUTES = (); }; }; 9A523F51135FD4E2464673A6 /* moc_session.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 63AF8520023B4EA40306CB03 /* moc_session.cpp */; settings = {ATTRIBUTES = (); }; }; 9D294F23E02CFDF22C288382 /* moc_emojibox.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 0C0DC15EB416789673526AA5 /* moc_emojibox.cpp */; settings = {ATTRIBUTES = (); }; }; 9F33AC0693BC81B27D8F518D /* Qt5Gui in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 04391BE7A8B9D811E255100A /* Qt5Gui */; }; @@ -467,7 +467,7 @@ 1A4C47331E186344291B8178 /* dropdown.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = dropdown.h; path = SourceFiles/dropdown.h; sourceTree = ""; }; 1B4A65B84270FF2FED008EB6 /* moc_introphone.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_introphone.cpp; path = GeneratedFiles/Debug/moc_introphone.cpp; sourceTree = ""; }; 1D7899ACAA9F973CADFA34C1 /* moc_localimageloader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_localimageloader.cpp; path = GeneratedFiles/Debug/moc_localimageloader.cpp; sourceTree = ""; }; - 1DC02F674A7192FF8BE391A7 /* basic_types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = basic_types.h; path = SourceFiles/basic_types.h; sourceTree = ""; }; + 1DC02F674A7192FF8BE391A7 /* basic_types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = basic_types.h; path = SourceFiles/core/basic_types.h; sourceTree = ""; }; 1DEFC0760BB9340529F582F7 /* confirmbox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = confirmbox.h; path = SourceFiles/boxes/confirmbox.h; sourceTree = ""; }; 1E5EEB5782B6357057356F9E /* moc_flatinput.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_flatinput.cpp; path = GeneratedFiles/Debug/moc_flatinput.cpp; sourceTree = ""; }; 1FAE75C970AA73F2DEDDB508 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qavfcamera.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qavfcamera.pri"; sourceTree = ""; }; @@ -494,7 +494,7 @@ 2E48BB382B895A5ACD79AF9F /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_bluetooth_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_bluetooth_private.pri"; sourceTree = ""; }; 2E6D9B1D2743D24E31B0B284 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_xmlpatterns.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_xmlpatterns.pri"; sourceTree = ""; }; 2EA58EF6CDF368B0132BAEB9 /* settings.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = settings.h; path = SourceFiles/settings.h; sourceTree = ""; }; - 301BB513F2F5D447B3BF22DF /* window.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = window.h; path = SourceFiles/window.h; sourceTree = ""; }; + 301BB513F2F5D447B3BF22DF /* mainwindow.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mainwindow.h; path = SourceFiles/mainwindow.h; sourceTree = ""; }; 311004331A04F3D69C98643C /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_serialport_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_serialport_private.pri"; sourceTree = ""; }; 31120EDB269DFF13E1D49847 /* qicns */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = qicns; path = "/usr/local/Qt-5.5.1/plugins/imageformats/libqicns$(QT_LIBRARY_SUFFIX).a"; sourceTree = ""; }; 315C7FACB4A9E18AA95486CA /* dcenter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = dcenter.cpp; path = SourceFiles/mtproto/dcenter.cpp; sourceTree = ""; }; @@ -563,7 +563,7 @@ 6868ADA9E9A9801B2BA92B97 /* countryinput.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = countryinput.h; path = SourceFiles/ui/countryinput.h; sourceTree = ""; }; 69347C39E4D922E94D0860BF /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_designercomponents_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_designercomponents_private.pri"; sourceTree = ""; }; 6A510365F9F6367ECB0DB065 /* images.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = images.cpp; path = SourceFiles/ui/images.cpp; sourceTree = ""; }; - 6B46A0EE3C3B9D3B5A24946E /* moc_window.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_window.cpp; path = GeneratedFiles/Debug/moc_window.cpp; sourceTree = ""; }; + 6B46A0EE3C3B9D3B5A24946E /* moc_mainwindow.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_mainwindow.cpp; path = GeneratedFiles/Debug/moc_mainwindow.cpp; sourceTree = ""; }; 6B90F69947805586A6FAE80E /* sysbuttons.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = sysbuttons.cpp; path = SourceFiles/sysbuttons.cpp; sourceTree = ""; }; 6C08BFC27C4C303A3A5181DB /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_printsupport.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_printsupport.pri"; sourceTree = ""; }; 6C86B6E6AB1857B735B720D6 /* layerwidget.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = layerwidget.h; path = SourceFiles/layerwidget.h; sourceTree = ""; }; @@ -583,7 +583,7 @@ 7C2F42B222EE88E26A6FED62 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_designer_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_designer_private.pri"; sourceTree = ""; }; 7CA6945B22800A0F30B75DA5 /* addcontactbox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = addcontactbox.cpp; path = SourceFiles/boxes/addcontactbox.cpp; sourceTree = ""; }; 7CDE9D7CB2C729BC3612372B /* addcontactbox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = addcontactbox.h; path = SourceFiles/boxes/addcontactbox.h; sourceTree = ""; }; - 7D075A915E8739C1B6BC5F43 /* basic_types.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = basic_types.cpp; path = SourceFiles/basic_types.cpp; sourceTree = ""; }; + 7D075A915E8739C1B6BC5F43 /* basic_types.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = basic_types.cpp; path = SourceFiles/core/basic_types.cpp; sourceTree = ""; }; 7D28E9003CE64D8A7F2E292E /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_concurrent_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_concurrent_private.pri"; sourceTree = ""; }; 7DBFC0B5EAF874BA10E3D603 /* scheme_auto.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = scheme_auto.h; path = SourceFiles/mtproto/scheme_auto.h; sourceTree = ""; }; 7DE30A90667C03C4F91A2A91 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_sql.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_sql.pri"; sourceTree = ""; }; @@ -703,7 +703,7 @@ C84546C18DCBB04166195DCF /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtposition_positionpoll.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtposition_positionpoll.pri"; sourceTree = ""; }; C913E6A1001E07EE7C13CE93 /* style.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = style.h; path = SourceFiles/ui/style.h; sourceTree = ""; }; C9FFCCE4FCB845744636795F /* moc_flatbutton.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_flatbutton.cpp; path = GeneratedFiles/Debug/moc_flatbutton.cpp; sourceTree = ""; }; - CA56ACFB53D87637192CC9B2 /* window.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = window.cpp; path = SourceFiles/window.cpp; sourceTree = ""; }; + CA56ACFB53D87637192CC9B2 /* mainwindow.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = mainwindow.cpp; path = SourceFiles/mainwindow.cpp; sourceTree = ""; }; CCF75CFFB857487FB18F99F9 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qoffscreen.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qoffscreen.pri"; sourceTree = ""; }; CE0D5EFE401BF9815FACE579 /* pspecific_mac.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = pspecific_mac.h; path = SourceFiles/pspecific_mac.h; sourceTree = ""; }; CE7FFE194127BD789A2C877A /* moc_confirmbox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_confirmbox.cpp; path = GeneratedFiles/Debug/moc_confirmbox.cpp; sourceTree = ""; }; @@ -1148,8 +1148,8 @@ 3BE70E2A82DC2BF402165ED5 /* sysbuttons.h */, 2BB2A1BB8DB0993F78F4E3C7 /* title.cpp */, 4D504A849F15EB58E53A4E5F /* title.h */, - CA56ACFB53D87637192CC9B2 /* window.cpp */, - 301BB513F2F5D447B3BF22DF /* window.h */, + CA56ACFB53D87637192CC9B2 /* mainwindow.cpp */, + 301BB513F2F5D447B3BF22DF /* mainwindow.h */, 24F7D3E789E91B10E422C116 /* config.h */, C913E6A1001E07EE7C13CE93 /* style.h */, ); @@ -1327,7 +1327,7 @@ 93AFE74928551FC3D7E8390B /* moc_settingswidget.cpp */, B88236FC554B694F618D848C /* moc_sysbuttons.cpp */, 1080B6D395843B8F76A2E45E /* moc_title.cpp */, - 6B46A0EE3C3B9D3B5A24946E /* moc_window.cpp */, + 6B46A0EE3C3B9D3B5A24946E /* moc_mainwindow.cpp */, 924D4939FD169BB4B8AEB1C9 /* moc_facade.cpp */, B714EA71A09A832FAA846A0A /* moc_connection.cpp */, 2C540BAEABD7F9B5FA11008E /* moc_dcenter.cpp */, @@ -1707,7 +1707,7 @@ 5CE57D44510AB2A11886AB52 /* title.cpp in Compile Sources */, 077A4AF81CA41C38002188D2 /* connection_auto.cpp in Compile Sources */, 4078D5D614EB3ECF7F1848C7 /* basic_types.cpp in Compile Sources */, - 68FFEB7CA30BF0149161B809 /* window.cpp in Compile Sources */, + 68FFEB7CA30BF0149161B809 /* mainwindow.cpp in Compile Sources */, 0CB7DE9A54CC9BF86FB7B5CA /* facade.cpp in Compile Sources */, DF259E9677CC63AF8754032B /* connection.cpp in Compile Sources */, 074FCB9119D36E60004C6EB2 /* moc_popupmenu.cpp in Compile Sources */, @@ -1793,7 +1793,7 @@ FD2FE0C564A7389A2E609EC7 /* moc_sysbuttons.cpp in Compile Sources */, E97B3CFAB59B49BACFFC5F7C /* moc_title.cpp in Compile Sources */, 07D8510819F8340A00623D75 /* moc_usernamebox.cpp in Compile Sources */, - 9A0D5DDC7816FC2538EB6A96 /* moc_window.cpp in Compile Sources */, + 9A0D5DDC7816FC2538EB6A96 /* moc_mainwindow.cpp in Compile Sources */, 06EABCC49D2EEE4076322BE7 /* moc_facade.cpp in Compile Sources */, 0755AEDE1AD12A80004D738A /* moc_intropwdcheck.cpp in Compile Sources */, 07DE92AA1AA4928200A18F6F /* moc_autolockbox.cpp in Compile Sources */, diff --git a/Telegram/Telegram.xcodeproj/qt_preprocess.mak b/Telegram/Telegram.xcodeproj/qt_preprocess.mak index 727c563f4..4e0c0fabc 100644 --- a/Telegram/Telegram.xcodeproj/qt_preprocess.mak +++ b/Telegram/Telegram.xcodeproj/qt_preprocess.mak @@ -56,7 +56,7 @@ compilers: GeneratedFiles/qrc_telegram.cpp\ GeneratedFiles/Debug/moc_sysbuttons.cpp\ GeneratedFiles/Debug/moc_title.cpp\ GeneratedFiles/Debug/moc_basic_types.cpp\ - GeneratedFiles/Debug/moc_window.cpp\ + GeneratedFiles/Debug/moc_mainwindow.cpp\ GeneratedFiles/Debug/moc_facade.cpp\ GeneratedFiles/Debug/moc_connection.cpp\ GeneratedFiles/Debug/moc_connection_abstract.cpp\ @@ -181,7 +181,7 @@ compiler_moc_header_make_all: GeneratedFiles/Debug/moc_apiwrap.cpp\ GeneratedFiles/Debug/moc_sysbuttons.cpp\ GeneratedFiles/Debug/moc_title.cpp\ GeneratedFiles/Debug/moc_basic_types.cpp\ - GeneratedFiles/Debug/moc_window.cpp\ + GeneratedFiles/Debug/moc_mainwindow.cpp\ GeneratedFiles/Debug/moc_facade.cpp\ GeneratedFiles/Debug/moc_connection.cpp\ GeneratedFiles/Debug/moc_connection_abstract.cpp\ @@ -249,7 +249,7 @@ compiler_moc_header_clean: GeneratedFiles/Debug/moc_sysbuttons.cpp\ GeneratedFiles/Debug/moc_title.cpp\ GeneratedFiles/Debug/moc_basic_types.cpp\ - GeneratedFiles/Debug/moc_window.cpp\ + GeneratedFiles/Debug/moc_mainwindow.cpp\ GeneratedFiles/Debug/moc_facade.cpp\ GeneratedFiles/Debug/moc_connection.cpp\ GeneratedFiles/Debug/moc_connection_abstract.cpp\ @@ -294,7 +294,7 @@ compiler_moc_header_clean: GeneratedFiles/Debug/moc_intropwdcheck.cpp\ GeneratedFiles/Debug/moc_introsignup.cpp\ GeneratedFiles/Debug/moc_pspecific_mac.cpp -GeneratedFiles/Debug/moc_apiwrap.cpp: SourceFiles/basic_types.h \ +GeneratedFiles/Debug/moc_apiwrap.cpp: SourceFiles/core/basic_types.h \ SourceFiles/logs.h \ SourceFiles/apiwrap.h /usr/local/Qt-5.5.1/bin/moc $(DEFINES) -D__APPLE__ -D__GNUC__=4 -I/usr/local/Qt-5.5.1/mkspecs/macx-clang -I. -I/usr/local/Qt-5.5.1/include/QtGui/5.5.1/QtGui -I/usr/local/Qt-5.5.1/include/QtCore/5.5.1/QtCore -I/usr/local/Qt-5.5.1/include -I./SourceFiles -I./GeneratedFiles -I../../Libraries/lzma/C -I../../Libraries/libexif-0.6.20 -I/usr/local/Qt-5.5.1/include -I/usr/local/Qt-5.5.1/include/QtMultimedia -I/usr/local/Qt-5.5.1/include/QtWidgets -I/usr/local/Qt-5.5.1/include/QtNetwork -I/usr/local/Qt-5.5.1/include/QtGui -I/usr/local/Qt-5.5.1/include/QtCore -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1 -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1/backward -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/5.1/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include SourceFiles/apiwrap.h -o GeneratedFiles/Debug/moc_apiwrap.cpp @@ -302,12 +302,12 @@ GeneratedFiles/Debug/moc_apiwrap.cpp: SourceFiles/basic_types.h \ GeneratedFiles/Debug/moc_application.cpp: ../../Libraries/QtStatic/qtbase/include/QtNetwork/QLocalSocket \ ../../Libraries/QtStatic/qtbase/include/QtNetwork/QLocalServer \ ../../Libraries/QtStatic/qtbase/include/QtNetwork/QNetworkReply \ - SourceFiles/window.h \ + SourceFiles/mainwindow.h \ SourceFiles/title.h \ ../../Libraries/QtStatic/qtbase/include/QtWidgets/QWidget \ SourceFiles/sysbuttons.h \ SourceFiles/ui/animation.h \ - SourceFiles/basic_types.h \ + SourceFiles/core/basic_types.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \ SourceFiles/logs.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QTimer \ @@ -323,7 +323,7 @@ GeneratedFiles/Debug/moc_application.cpp: ../../Libraries/QtStatic/qtbase/includ SourceFiles/application.h /usr/local/Qt-5.5.1/bin/moc $(DEFINES) -D__APPLE__ -D__GNUC__=4 -I/usr/local/Qt-5.5.1/mkspecs/macx-clang -I. -I/usr/local/Qt-5.5.1/include/QtGui/5.5.1/QtGui -I/usr/local/Qt-5.5.1/include/QtCore/5.5.1/QtCore -I/usr/local/Qt-5.5.1/include -I./SourceFiles -I./GeneratedFiles -I../../Libraries/lzma/C -I../../Libraries/libexif-0.6.20 -I/usr/local/Qt-5.5.1/include -I/usr/local/Qt-5.5.1/include/QtMultimedia -I/usr/local/Qt-5.5.1/include/QtWidgets -I/usr/local/Qt-5.5.1/include/QtNetwork -I/usr/local/Qt-5.5.1/include/QtGui -I/usr/local/Qt-5.5.1/include/QtCore -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1 -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1/backward -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/5.1/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include SourceFiles/application.h -o GeneratedFiles/Debug/moc_application.cpp -GeneratedFiles/Debug/moc_audio.cpp: SourceFiles/basic_types.h \ +GeneratedFiles/Debug/moc_audio.cpp: SourceFiles/core/basic_types.h \ SourceFiles/audio.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \ SourceFiles/logs.h \ @@ -331,7 +331,7 @@ GeneratedFiles/Debug/moc_audio.cpp: SourceFiles/basic_types.h \ ../../Libraries/QtStatic/qtbase/include/QtGui/QColor /usr/local/Qt-5.5.1/bin/moc $(DEFINES) -D__APPLE__ -D__GNUC__=4 -I/usr/local/Qt-5.5.1/mkspecs/macx-clang -I. -I/usr/local/Qt-5.5.1/include/QtGui/5.5.1/QtGui -I/usr/local/Qt-5.5.1/include/QtCore/5.5.1/QtCore -I/usr/local/Qt-5.5.1/include -I./SourceFiles -I./GeneratedFiles -I../../Libraries/lzma/C -I../../Libraries/libexif-0.6.20 -I/usr/local/Qt-5.5.1/include -I/usr/local/Qt-5.5.1/include/QtMultimedia -I/usr/local/Qt-5.5.1/include/QtWidgets -I/usr/local/Qt-5.5.1/include/QtNetwork -I/usr/local/Qt-5.5.1/include/QtGui -I/usr/local/Qt-5.5.1/include/QtCore -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1 -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1/backward -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/5.1/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include SourceFiles/audio.h -o GeneratedFiles/Debug/moc_audio.cpp -GeneratedFiles/Debug/moc_autoupdater.cpp: SourceFiles/basic_types.h \ +GeneratedFiles/Debug/moc_autoupdater.cpp: SourceFiles/core/basic_types.h \ SourceFiles/autoupdater.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \ SourceFiles/logs.h \ @@ -393,7 +393,7 @@ GeneratedFiles/Debug/moc_mainwidget.cpp: ../../Libraries/QtStatic/qtbase/include SourceFiles/ui/twidget.h \ SourceFiles/ui/flatcheckbox.h \ SourceFiles/ui/animation.h \ - SourceFiles/basic_types.h \ + SourceFiles/core/basic_types.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \ SourceFiles/logs.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QTimer \ @@ -417,7 +417,7 @@ GeneratedFiles/Debug/moc_settingswidget.cpp: SourceFiles/ui/flatbutton.h \ SourceFiles/ui/twidget.h \ SourceFiles/ui/flatcheckbox.h \ SourceFiles/ui/animation.h \ - SourceFiles/basic_types.h \ + SourceFiles/core/basic_types.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \ SourceFiles/logs.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QTimer \ @@ -431,7 +431,7 @@ GeneratedFiles/Debug/moc_settingswidget.cpp: SourceFiles/ui/flatbutton.h \ GeneratedFiles/Debug/moc_sysbuttons.cpp: ../../Libraries/QtStatic/qtbase/include/QtWidgets/QWidget \ SourceFiles/ui/animation.h \ - SourceFiles/basic_types.h \ + SourceFiles/core/basic_types.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \ SourceFiles/logs.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QTimer \ @@ -445,7 +445,7 @@ GeneratedFiles/Debug/moc_sysbuttons.cpp: ../../Libraries/QtStatic/qtbase/include GeneratedFiles/Debug/moc_title.cpp: ../../Libraries/QtStatic/qtbase/include/QtWidgets/QWidget \ SourceFiles/sysbuttons.h \ SourceFiles/ui/animation.h \ - SourceFiles/basic_types.h \ + SourceFiles/core/basic_types.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \ SourceFiles/logs.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QTimer \ @@ -455,18 +455,18 @@ GeneratedFiles/Debug/moc_title.cpp: ../../Libraries/QtStatic/qtbase/include/QtWi SourceFiles/title.h /usr/local/Qt-5.5.1/bin/moc $(DEFINES) -D__APPLE__ -D__GNUC__=4 -I/usr/local/Qt-5.5.1/mkspecs/macx-clang -I. -I/usr/local/Qt-5.5.1/include/QtGui/5.5.1/QtGui -I/usr/local/Qt-5.5.1/include/QtCore/5.5.1/QtCore -I/usr/local/Qt-5.5.1/include -I./SourceFiles -I./GeneratedFiles -I../../Libraries/lzma/C -I../../Libraries/libexif-0.6.20 -I/usr/local/Qt-5.5.1/include -I/usr/local/Qt-5.5.1/include/QtMultimedia -I/usr/local/Qt-5.5.1/include/QtWidgets -I/usr/local/Qt-5.5.1/include/QtNetwork -I/usr/local/Qt-5.5.1/include/QtGui -I/usr/local/Qt-5.5.1/include/QtCore -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1 -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1/backward -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/5.1/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include SourceFiles/title.h -o GeneratedFiles/Debug/moc_title.cpp -GeneratedFiles/Debug/moc_basic_types.cpp: SourceFiles/basic_types.h \ +GeneratedFiles/Debug/moc_basic_types.cpp: SourceFiles/core/basic_types.h \ ../../Libraries/QtStatic/qtbase/include/QtWidgets/QWidget \ ../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \ SourceFiles/logs.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QTimer - /usr/local/Qt-5.5.1/bin/moc $(DEFINES) -D__APPLE__ -D__GNUC__=4 -I/usr/local/Qt-5.5.1/mkspecs/macx-clang -I. -I/usr/local/Qt-5.5.1/include/QtGui/5.5.1/QtGui -I/usr/local/Qt-5.5.1/include/QtCore/5.5.1/QtCore -I/usr/local/Qt-5.5.1/include -I./SourceFiles -I./GeneratedFiles -I../../Libraries/lzma/C -I../../Libraries/libexif-0.6.20 -I/usr/local/Qt-5.5.1/include -I/usr/local/Qt-5.5.1/include/QtMultimedia -I/usr/local/Qt-5.5.1/include/QtWidgets -I/usr/local/Qt-5.5.1/include/QtNetwork -I/usr/local/Qt-5.5.1/include/QtGui -I/usr/local/Qt-5.5.1/include/QtCore -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1 -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1/backward -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/5.1/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include SourceFiles/basic_types.h -o GeneratedFiles/Debug/moc_basic_types.cpp + /usr/local/Qt-5.5.1/bin/moc $(DEFINES) -D__APPLE__ -D__GNUC__=4 -I/usr/local/Qt-5.5.1/mkspecs/macx-clang -I. -I/usr/local/Qt-5.5.1/include/QtGui/5.5.1/QtGui -I/usr/local/Qt-5.5.1/include/QtCore/5.5.1/QtCore -I/usr/local/Qt-5.5.1/include -I./SourceFiles -I./GeneratedFiles -I../../Libraries/lzma/C -I../../Libraries/libexif-0.6.20 -I/usr/local/Qt-5.5.1/include -I/usr/local/Qt-5.5.1/include/QtMultimedia -I/usr/local/Qt-5.5.1/include/QtWidgets -I/usr/local/Qt-5.5.1/include/QtNetwork -I/usr/local/Qt-5.5.1/include/QtGui -I/usr/local/Qt-5.5.1/include/QtCore -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1 -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1/backward -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/5.1/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include SourceFiles/core/basic_types.h -o GeneratedFiles/Debug/moc_basic_types.cpp -GeneratedFiles/Debug/moc_window.cpp: SourceFiles/title.h \ +GeneratedFiles/Debug/moc_mainwindow.cpp: SourceFiles/title.h \ ../../Libraries/QtStatic/qtbase/include/QtWidgets/QWidget \ SourceFiles/sysbuttons.h \ SourceFiles/ui/animation.h \ - SourceFiles/basic_types.h \ + SourceFiles/core/basic_types.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \ SourceFiles/logs.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QTimer \ @@ -481,8 +481,8 @@ GeneratedFiles/Debug/moc_window.cpp: SourceFiles/title.h \ SourceFiles/pspecific_winrt.h \ SourceFiles/passcodewidget.h \ SourceFiles/ui/boxshadow.h \ - SourceFiles/window.h - /usr/local/Qt-5.5.1/bin/moc $(DEFINES) -D__APPLE__ -D__GNUC__=4 -I/usr/local/Qt-5.5.1/mkspecs/macx-clang -I. -I/usr/local/Qt-5.5.1/include/QtGui/5.5.1/QtGui -I/usr/local/Qt-5.5.1/include/QtCore/5.5.1/QtCore -I/usr/local/Qt-5.5.1/include -I./SourceFiles -I./GeneratedFiles -I../../Libraries/lzma/C -I../../Libraries/libexif-0.6.20 -I/usr/local/Qt-5.5.1/include -I/usr/local/Qt-5.5.1/include/QtMultimedia -I/usr/local/Qt-5.5.1/include/QtWidgets -I/usr/local/Qt-5.5.1/include/QtNetwork -I/usr/local/Qt-5.5.1/include/QtGui -I/usr/local/Qt-5.5.1/include/QtCore -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1 -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1/backward -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/5.1/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include SourceFiles/window.h -o GeneratedFiles/Debug/moc_window.cpp + SourceFiles/mainwindow.h + /usr/local/Qt-5.5.1/bin/moc $(DEFINES) -D__APPLE__ -D__GNUC__=4 -I/usr/local/Qt-5.5.1/mkspecs/macx-clang -I. -I/usr/local/Qt-5.5.1/include/QtGui/5.5.1/QtGui -I/usr/local/Qt-5.5.1/include/QtCore/5.5.1/QtCore -I/usr/local/Qt-5.5.1/include -I./SourceFiles -I./GeneratedFiles -I../../Libraries/lzma/C -I../../Libraries/libexif-0.6.20 -I/usr/local/Qt-5.5.1/include -I/usr/local/Qt-5.5.1/include/QtMultimedia -I/usr/local/Qt-5.5.1/include/QtWidgets -I/usr/local/Qt-5.5.1/include/QtNetwork -I/usr/local/Qt-5.5.1/include/QtGui -I/usr/local/Qt-5.5.1/include/QtCore -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1 -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1/backward -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/5.1/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include SourceFiles/mainwindow.h -o GeneratedFiles/Debug/moc_mainwindow.cpp GeneratedFiles/Debug/moc_facade.cpp: SourceFiles/mtproto/session.h \ SourceFiles/mtproto/connection.h \ @@ -491,7 +491,7 @@ GeneratedFiles/Debug/moc_facade.cpp: SourceFiles/mtproto/session.h \ SourceFiles/mtproto/connection_http.h \ SourceFiles/mtproto/connection_tcp.h \ SourceFiles/mtproto/core_types.h \ - SourceFiles/basic_types.h \ + SourceFiles/core/basic_types.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \ SourceFiles/logs.h \ SourceFiles/mtproto/scheme_auto.h \ @@ -504,7 +504,7 @@ GeneratedFiles/Debug/moc_facade.cpp: SourceFiles/mtproto/session.h \ /usr/local/Qt-5.5.1/bin/moc $(DEFINES) -D__APPLE__ -D__GNUC__=4 -I/usr/local/Qt-5.5.1/mkspecs/macx-clang -I. -I/usr/local/Qt-5.5.1/include/QtGui/5.5.1/QtGui -I/usr/local/Qt-5.5.1/include/QtCore/5.5.1/QtCore -I/usr/local/Qt-5.5.1/include -I./SourceFiles -I./GeneratedFiles -I../../Libraries/lzma/C -I../../Libraries/libexif-0.6.20 -I/usr/local/Qt-5.5.1/include -I/usr/local/Qt-5.5.1/include/QtMultimedia -I/usr/local/Qt-5.5.1/include/QtWidgets -I/usr/local/Qt-5.5.1/include/QtNetwork -I/usr/local/Qt-5.5.1/include/QtGui -I/usr/local/Qt-5.5.1/include/QtCore -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1 -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1/backward -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/5.1/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include SourceFiles/mtproto/facade.h -o GeneratedFiles/Debug/moc_facade.cpp GeneratedFiles/Debug/moc_connection.cpp: SourceFiles/mtproto/core_types.h \ - SourceFiles/basic_types.h \ + SourceFiles/core/basic_types.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \ SourceFiles/logs.h \ SourceFiles/mtproto/scheme_auto.h \ @@ -514,7 +514,7 @@ GeneratedFiles/Debug/moc_connection.cpp: SourceFiles/mtproto/core_types.h \ /usr/local/Qt-5.5.1/bin/moc $(DEFINES) -D__APPLE__ -D__GNUC__=4 -I/usr/local/Qt-5.5.1/mkspecs/macx-clang -I. -I/usr/local/Qt-5.5.1/include/QtGui/5.5.1/QtGui -I/usr/local/Qt-5.5.1/include/QtCore/5.5.1/QtCore -I/usr/local/Qt-5.5.1/include -I./SourceFiles -I./GeneratedFiles -I../../Libraries/lzma/C -I../../Libraries/libexif-0.6.20 -I/usr/local/Qt-5.5.1/include -I/usr/local/Qt-5.5.1/include/QtMultimedia -I/usr/local/Qt-5.5.1/include/QtWidgets -I/usr/local/Qt-5.5.1/include/QtNetwork -I/usr/local/Qt-5.5.1/include/QtGui -I/usr/local/Qt-5.5.1/include/QtCore -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1 -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1/backward -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/5.1/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include SourceFiles/mtproto/connection.h -o GeneratedFiles/Debug/moc_connection.cpp GeneratedFiles/Debug/moc_connection_abstract.cpp: SourceFiles/mtproto/core_types.h \ - SourceFiles/basic_types.h \ + SourceFiles/core/basic_types.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \ SourceFiles/logs.h \ SourceFiles/mtproto/scheme_auto.h \ @@ -524,7 +524,7 @@ GeneratedFiles/Debug/moc_connection_abstract.cpp: SourceFiles/mtproto/core_types /usr/local/Qt-5.5.1/bin/moc $(DEFINES) -D__APPLE__ -D__GNUC__=4 -I/usr/local/Qt-5.5.1/mkspecs/macx-clang -I. -I/usr/local/Qt-5.5.1/include/QtGui/5.5.1/QtGui -I/usr/local/Qt-5.5.1/include/QtCore/5.5.1/QtCore -I/usr/local/Qt-5.5.1/include -I./SourceFiles -I./GeneratedFiles -I../../Libraries/lzma/C -I../../Libraries/libexif-0.6.20 -I/usr/local/Qt-5.5.1/include -I/usr/local/Qt-5.5.1/include/QtMultimedia -I/usr/local/Qt-5.5.1/include/QtWidgets -I/usr/local/Qt-5.5.1/include/QtNetwork -I/usr/local/Qt-5.5.1/include/QtGui -I/usr/local/Qt-5.5.1/include/QtCore -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1 -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1/backward -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/5.1/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include SourceFiles/mtproto/connection_abstract.h -o GeneratedFiles/Debug/moc_connection_abstract.cpp GeneratedFiles/Debug/moc_connection_auto.cpp: SourceFiles/mtproto/core_types.h \ - SourceFiles/basic_types.h \ + SourceFiles/core/basic_types.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \ SourceFiles/logs.h \ SourceFiles/mtproto/scheme_auto.h \ @@ -534,7 +534,7 @@ GeneratedFiles/Debug/moc_connection_auto.cpp: SourceFiles/mtproto/core_types.h \ /usr/local/Qt-5.5.1/bin/moc $(DEFINES) -D__APPLE__ -D__GNUC__=4 -I/usr/local/Qt-5.5.1/mkspecs/macx-clang -I. -I/usr/local/Qt-5.5.1/include/QtGui/5.5.1/QtGui -I/usr/local/Qt-5.5.1/include/QtCore/5.5.1/QtCore -I/usr/local/Qt-5.5.1/include -I./SourceFiles -I./GeneratedFiles -I../../Libraries/lzma/C -I../../Libraries/libexif-0.6.20 -I/usr/local/Qt-5.5.1/include -I/usr/local/Qt-5.5.1/include/QtMultimedia -I/usr/local/Qt-5.5.1/include/QtWidgets -I/usr/local/Qt-5.5.1/include/QtNetwork -I/usr/local/Qt-5.5.1/include/QtGui -I/usr/local/Qt-5.5.1/include/QtCore -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1 -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1/backward -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/5.1/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include SourceFiles/mtproto/connection_auto.h -o GeneratedFiles/Debug/moc_connection_auto.cpp GeneratedFiles/Debug/moc_connection_http.cpp: SourceFiles/mtproto/core_types.h \ - SourceFiles/basic_types.h \ + SourceFiles/core/basic_types.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \ SourceFiles/logs.h \ SourceFiles/mtproto/scheme_auto.h \ @@ -544,7 +544,7 @@ GeneratedFiles/Debug/moc_connection_http.cpp: SourceFiles/mtproto/core_types.h \ /usr/local/Qt-5.5.1/bin/moc $(DEFINES) -D__APPLE__ -D__GNUC__=4 -I/usr/local/Qt-5.5.1/mkspecs/macx-clang -I. -I/usr/local/Qt-5.5.1/include/QtGui/5.5.1/QtGui -I/usr/local/Qt-5.5.1/include/QtCore/5.5.1/QtCore -I/usr/local/Qt-5.5.1/include -I./SourceFiles -I./GeneratedFiles -I../../Libraries/lzma/C -I../../Libraries/libexif-0.6.20 -I/usr/local/Qt-5.5.1/include -I/usr/local/Qt-5.5.1/include/QtMultimedia -I/usr/local/Qt-5.5.1/include/QtWidgets -I/usr/local/Qt-5.5.1/include/QtNetwork -I/usr/local/Qt-5.5.1/include/QtGui -I/usr/local/Qt-5.5.1/include/QtCore -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1 -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1/backward -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/5.1/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include SourceFiles/mtproto/connection_http.h -o GeneratedFiles/Debug/moc_connection_http.cpp GeneratedFiles/Debug/moc_connection_tcp.cpp: SourceFiles/mtproto/core_types.h \ - SourceFiles/basic_types.h \ + SourceFiles/core/basic_types.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \ SourceFiles/logs.h \ SourceFiles/mtproto/scheme_auto.h \ @@ -565,7 +565,7 @@ GeneratedFiles/Debug/moc_session.cpp: SourceFiles/mtproto/connection.h \ SourceFiles/mtproto/connection_http.h \ SourceFiles/mtproto/connection_tcp.h \ SourceFiles/mtproto/core_types.h \ - SourceFiles/basic_types.h \ + SourceFiles/core/basic_types.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \ SourceFiles/logs.h \ SourceFiles/mtproto/scheme_auto.h \ @@ -576,7 +576,7 @@ GeneratedFiles/Debug/moc_session.cpp: SourceFiles/mtproto/connection.h \ SourceFiles/mtproto/session.h /usr/local/Qt-5.5.1/bin/moc $(DEFINES) -D__APPLE__ -D__GNUC__=4 -I/usr/local/Qt-5.5.1/mkspecs/macx-clang -I. -I/usr/local/Qt-5.5.1/include/QtGui/5.5.1/QtGui -I/usr/local/Qt-5.5.1/include/QtCore/5.5.1/QtCore -I/usr/local/Qt-5.5.1/include -I./SourceFiles -I./GeneratedFiles -I../../Libraries/lzma/C -I../../Libraries/libexif-0.6.20 -I/usr/local/Qt-5.5.1/include -I/usr/local/Qt-5.5.1/include/QtMultimedia -I/usr/local/Qt-5.5.1/include/QtWidgets -I/usr/local/Qt-5.5.1/include/QtNetwork -I/usr/local/Qt-5.5.1/include/QtGui -I/usr/local/Qt-5.5.1/include/QtCore -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1 -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1/backward -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/5.1/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include SourceFiles/mtproto/session.h -o GeneratedFiles/Debug/moc_session.cpp -GeneratedFiles/Debug/moc_animation.cpp: SourceFiles/basic_types.h \ +GeneratedFiles/Debug/moc_animation.cpp: SourceFiles/core/basic_types.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \ SourceFiles/logs.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QTimer \ @@ -604,7 +604,7 @@ GeneratedFiles/Debug/moc_countryinput.cpp: ../../Libraries/QtStatic/qtbase/inclu SourceFiles/ui/flatinput.h \ ../../Libraries/QtStatic/qtbase/include/QtWidgets/QLineEdit \ SourceFiles/ui/animation.h \ - SourceFiles/basic_types.h \ + SourceFiles/core/basic_types.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \ SourceFiles/logs.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QTimer \ @@ -624,7 +624,7 @@ GeneratedFiles/Debug/moc_flatbutton.cpp: SourceFiles/ui/button.h \ SourceFiles/ui/twidget.h \ SourceFiles/ui/flatcheckbox.h \ SourceFiles/ui/animation.h \ - SourceFiles/basic_types.h \ + SourceFiles/core/basic_types.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \ SourceFiles/logs.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QTimer \ @@ -646,7 +646,7 @@ GeneratedFiles/Debug/moc_flatinput.cpp: ../../Libraries/QtStatic/qtbase/include/ GeneratedFiles/style_classes.h \ GeneratedFiles/style_auto.h \ SourceFiles/ui/animation.h \ - SourceFiles/basic_types.h \ + SourceFiles/core/basic_types.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \ SourceFiles/logs.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QTimer \ @@ -665,7 +665,7 @@ GeneratedFiles/Debug/moc_flattextarea.cpp: ../../Libraries/QtStatic/qtbase/inclu GeneratedFiles/style_classes.h \ GeneratedFiles/style_auto.h \ SourceFiles/ui/animation.h \ - SourceFiles/basic_types.h \ + SourceFiles/core/basic_types.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \ SourceFiles/logs.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QTimer \ @@ -721,7 +721,7 @@ GeneratedFiles/Debug/moc_connectionbox.cpp: SourceFiles/boxes/abstractbox.h \ GeneratedFiles/style_classes.h \ GeneratedFiles/style_auto.h \ SourceFiles/ui/animation.h \ - SourceFiles/basic_types.h \ + SourceFiles/core/basic_types.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \ SourceFiles/logs.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QTimer \ @@ -742,7 +742,7 @@ GeneratedFiles/Debug/moc_downloadpathbox.cpp: SourceFiles/boxes/abstractbox.h \ GeneratedFiles/style_classes.h \ GeneratedFiles/style_auto.h \ SourceFiles/ui/animation.h \ - SourceFiles/basic_types.h \ + SourceFiles/core/basic_types.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \ SourceFiles/logs.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QTimer \ @@ -799,7 +799,7 @@ GeneratedFiles/Debug/moc_introwidget.cpp: ../../Libraries/QtStatic/qtbase/includ SourceFiles/ui/twidget.h \ SourceFiles/ui/flatcheckbox.h \ SourceFiles/ui/animation.h \ - SourceFiles/basic_types.h \ + SourceFiles/core/basic_types.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \ SourceFiles/logs.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QTimer \ @@ -816,7 +816,7 @@ GeneratedFiles/Debug/moc_introcode.cpp: ../../Libraries/QtStatic/qtbase/include/ SourceFiles/ui/twidget.h \ SourceFiles/ui/flatcheckbox.h \ SourceFiles/ui/animation.h \ - SourceFiles/basic_types.h \ + SourceFiles/core/basic_types.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \ SourceFiles/logs.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QTimer \ @@ -836,7 +836,7 @@ GeneratedFiles/Debug/moc_introphone.cpp: ../../Libraries/QtStatic/qtbase/include SourceFiles/ui/twidget.h \ SourceFiles/ui/flatcheckbox.h \ SourceFiles/ui/animation.h \ - SourceFiles/basic_types.h \ + SourceFiles/core/basic_types.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \ SourceFiles/logs.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QTimer \ @@ -860,7 +860,7 @@ GeneratedFiles/Debug/moc_intropwdcheck.cpp: ../../Libraries/QtStatic/qtbase/incl SourceFiles/ui/twidget.h \ SourceFiles/ui/flatcheckbox.h \ SourceFiles/ui/animation.h \ - SourceFiles/basic_types.h \ + SourceFiles/core/basic_types.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \ SourceFiles/logs.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QTimer \ @@ -884,7 +884,7 @@ GeneratedFiles/Debug/moc_introsignup.cpp: ../../Libraries/QtStatic/qtbase/includ SourceFiles/ui/twidget.h \ SourceFiles/ui/flatcheckbox.h \ SourceFiles/ui/animation.h \ - SourceFiles/basic_types.h \ + SourceFiles/core/basic_types.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \ SourceFiles/logs.h \ ../../Libraries/QtStatic/qtbase/include/QtCore/QTimer \ From a033e3174314a67a6bef6287860f473dcb8ec4e2 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 13 Apr 2016 08:55:01 +0300 Subject: [PATCH 03/14] Possible crash fixed in ClickHandler. --- Telegram/SourceFiles/core/click_handler.h | 3 ++- Telegram/SourceFiles/dialogs/dialogs_layout.cpp | 6 +++--- Telegram/SourceFiles/historywidget.cpp | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Telegram/SourceFiles/core/click_handler.h b/Telegram/SourceFiles/core/click_handler.h index d03cb5d4c..8c997e6b9 100644 --- a/Telegram/SourceFiles/core/click_handler.h +++ b/Telegram/SourceFiles/core/click_handler.h @@ -130,7 +130,8 @@ public: static void hostDestroyed(ClickHandlerHost *host) { if (_activeHost == host) { _activeHost = nullptr; - } else if (_pressedHost == host) { + } + if (_pressedHost == host) { _pressedHost = nullptr; } } diff --git a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp index d9c5fbc22..64671379c 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp @@ -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); } - paintItemCallback(nameleft, namewidth); + paintItemCallback(nameleft, namewidth, item); } if (history->peer->isUser() && history->peer->isVerified()) { @@ -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) { auto history = row->history(); 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(); if (history->peer->migrateFrom()) { 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) { auto item = row->item(); 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; item->drawInDialog(p, QRect(nameleft, texttop, lastWidth, st::dlgFont->height), active, row->_cacheFor, row->_cache); }); diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 8d01e358d..73efbe930 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -8047,7 +8047,7 @@ void HistoryWidget::drawPinnedBar(Painter &p) { 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); - _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 { p.setFont(st::msgDateFont); p.setPen(st::msgInDateFg); From c4a7d48d96e248f192f6eb3f6f4d8bf9b4302e7b Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 13 Apr 2016 21:29:32 +0300 Subject: [PATCH 04/14] Selection of text in attachments: captions, web page previews. Text/HistoryItem/HistoryMedia::getState() unified. Text::getStateElided added. Tested with web page previews only. --- Telegram/SourceFiles/boxes/confirmbox.cpp | 4 +- Telegram/SourceFiles/dropdown.cpp | 2 +- Telegram/SourceFiles/history.cpp | 532 +++++++++--------- Telegram/SourceFiles/history.h | 179 ++++-- Telegram/SourceFiles/historywidget.cpp | 204 +++---- Telegram/SourceFiles/historywidget.h | 2 +- .../inline_bot_layout_internal.cpp | 14 +- .../inline_bots/inline_bot_layout_internal.h | 14 +- .../inline_bots/inline_bot_layout_item.h | 2 +- Telegram/SourceFiles/layout.h | 2 +- Telegram/SourceFiles/mediaview.cpp | 7 +- .../SourceFiles/overview/overview_layout.cpp | 18 +- .../SourceFiles/overview/overview_layout.h | 14 +- Telegram/SourceFiles/overviewwidget.cpp | 14 +- Telegram/SourceFiles/overviewwidget.h | 4 +- Telegram/SourceFiles/profilewidget.cpp | 4 +- Telegram/SourceFiles/ui/flatlabel.cpp | 6 +- Telegram/SourceFiles/ui/text.cpp | 371 ++++++------ Telegram/SourceFiles/ui/text.h | 96 +++- 19 files changed, 815 insertions(+), 674 deletions(-) diff --git a/Telegram/SourceFiles/boxes/confirmbox.cpp b/Telegram/SourceFiles/boxes/confirmbox.cpp index 3f3f73edc..910243ea0 100644 --- a/Telegram/SourceFiles/boxes/confirmbox.cpp +++ b/Telegram/SourceFiles/boxes/confirmbox.cpp @@ -119,10 +119,10 @@ void ConfirmBox::updateHover() { QPoint m(mapFromGlobal(_lastMousePos)); 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(); - ClickHandler::setActive(handler, this); + ClickHandler::setActive(state.link, this); } void ConfirmBox::closePressed() { diff --git a/Telegram/SourceFiles/dropdown.cpp b/Telegram/SourceFiles/dropdown.cpp index 93ce0f929..676ff0025 100644 --- a/Telegram/SourceFiles/dropdown.cpp +++ b/Telegram/SourceFiles/dropdown.cpp @@ -1349,7 +1349,7 @@ void StickerPanInner::paintInlineItems(Painter &p, const QRect &r) { int w = item->width(); if (left + w > fromx) { 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); } left += w; diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index 4c90a95b5..930d7c65e 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -2687,10 +2687,9 @@ void ReplyKeyboard::paint(Painter &p, const QRect &clip) const { } } -void ReplyKeyboard::getState(ClickHandlerPtr &lnk, int x, int y) const { +ClickHandlerPtr ReplyKeyboard::getState(int x, int y) const { t_assert(_width > 0); - lnk.clear(); for_const (const ButtonRow &row, _rows) { for_const (const Button &button, row) { QRect rect(button.rect); @@ -2699,11 +2698,11 @@ void ReplyKeyboard::getState(ClickHandlerPtr &lnk, int x, int y) const { if (rect.x() + rect.width() > _width) break; if (rect.contains(x, y)) { - lnk = button.link; - return; + return button.link; } } } + return ClickHandlerPtr(); } void ReplyKeyboard::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { @@ -3464,10 +3463,11 @@ int HistoryPhoto::resizeGetHeight(int width) { return _height; } -void HistoryPhoto::draw(Painter &p, const QRect &r, bool selected, uint64 ms) const { +void HistoryPhoto::draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const { if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return; _data->automaticLoad(_parent); + bool selected = (selection == FullSelection); bool loaded = _data->loaded(), displayLoading = _data->displayLoading(); bool notChild = (_parent->getMedia() == this); @@ -3561,12 +3561,14 @@ void HistoryPhoto::draw(Painter &p, const QRect &r, bool selected, uint64 ms) co } } else { p.setPen(st::black); - _caption.draw(p, st::msgPadding.left(), skipy + height + st::mediaPadding.bottom() + st::mediaCaptionSkip, captionw); + _caption.draw(p, st::msgPadding.left(), skipy + height + st::mediaPadding.bottom() + st::mediaCaptionSkip, captionw, style::al_left, 0, -1, selection); } } -void HistoryPhoto::getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const { - if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return; +HistoryTextState HistoryPhoto::getState(int x, int y, HistoryStateRequest request) const { + HistoryTextState result; + + if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return result; int skipx = 0, skipy = 0, width = _width, height = _height; bool bubble = _parent->hasBubble(); @@ -3577,10 +3579,8 @@ void HistoryPhoto::getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int int captionw = width - st::msgPadding.left() - st::msgPadding.right(); height -= _caption.countHeight(captionw) + st::msgPadding.bottom(); if (x >= st::msgPadding.left() && y >= height && x < st::msgPadding.left() + captionw && y < _height) { - bool inText = false; - _caption.getState(lnk, inText, x - st::msgPadding.left(), y - height, captionw); - state = inText ? HistoryInTextCursorState : HistoryDefaultCursorState; - return; + result = _caption.getState(x - st::msgPadding.left(), y - height, captionw, request.forText()); + return result; } height -= st::mediaCaptionSkip; } @@ -3589,26 +3589,27 @@ void HistoryPhoto::getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int } if (x >= skipx && y >= skipy && x < skipx + width && y < skipy + height) { if (_data->uploading()) { - lnk = _cancell; + result.link = _cancell; } else if (_data->loaded()) { - lnk = _openl; + result.link = _openl; } else if (_data->loading()) { DelayedStorageImage *delayed = _data->full->toDelayedStorageImage(); if (!delayed || !delayed->location().isNull()) { - lnk = _cancell; + result.link = _cancell; } } else { - lnk = _savel; + result.link = _savel; } if (_caption.isEmpty() && _parent->getMedia() == this) { int32 fullRight = skipx + width, fullBottom = skipy + height; bool inDate = _parent->pointInTime(fullRight, fullBottom, x, y, InfoDisplayOverImage); if (inDate) { - state = HistoryInDateCursorState; + result.cursor = HistoryInDateCursorState; } } - return; + return result; } + return result; } void HistoryPhoto::updateSentMedia(const MTPMessageMedia &media) { @@ -3681,11 +3682,11 @@ void HistoryPhoto::detachFromParent() { } const QString HistoryPhoto::inDialogsText() const { - return _caption.isEmpty() ? lang(lng_in_dlg_photo) : _caption.original(0, 0xFFFF, Text::ExpandLinksNone); + return _caption.isEmpty() ? lang(lng_in_dlg_photo) : _caption.original(AllTextSelection, Text::ExpandLinksNone); } const QString HistoryPhoto::inHistoryText() const { - return qsl("[ ") + lang(lng_in_dlg_photo) + (_caption.isEmpty() ? QString() : (qsl(", ") + _caption.original(0, 0xFFFF, Text::ExpandLinksAll))) + qsl(" ]"); + return qsl("[ ") + lang(lng_in_dlg_photo) + (_caption.isEmpty() ? QString() : (qsl(", ") + _caption.original(AllTextSelection, Text::ExpandLinksAll))) + qsl(" ]"); } ImagePtr HistoryPhoto::replyPreview() { @@ -3788,11 +3789,12 @@ int HistoryVideo::resizeGetHeight(int width) { return _height; } -void HistoryVideo::draw(Painter &p, const QRect &r, bool selected, uint64 ms) const { +void HistoryVideo::draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const { if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return; _data->automaticLoad(_parent); bool loaded = _data->loaded(), displayLoading = _data->displayLoading(); + bool selected = (selection == FullSelection); int skipx = 0, skipy = 0, width = _width, height = _height; bool bubble = _parent->hasBubble(); @@ -3879,12 +3881,14 @@ void HistoryVideo::draw(Painter &p, const QRect &r, bool selected, uint64 ms) co } } else { p.setPen(st::black); - _caption.draw(p, st::msgPadding.left(), skipy + height + st::mediaPadding.bottom() + st::mediaCaptionSkip, captionw); + _caption.draw(p, st::msgPadding.left(), skipy + height + st::mediaPadding.bottom() + st::mediaCaptionSkip, captionw, style::al_left, 0, -1, selection); } } -void HistoryVideo::getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const { - if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return; +HistoryTextState HistoryVideo::getState(int x, int y, HistoryStateRequest request) const { + HistoryTextState result; + + if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return result; bool loaded = _data->loaded(); @@ -3898,9 +3902,7 @@ void HistoryVideo::getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int int32 captionw = width - st::msgPadding.left() - st::msgPadding.right(); height -= _caption.countHeight(captionw) + st::msgPadding.bottom(); if (x >= st::msgPadding.left() && y >= height && x < st::msgPadding.left() + captionw && y < _height) { - bool inText = false; - _caption.getState(lnk, inText, x - st::msgPadding.left(), y - height, captionw); - state = inText ? HistoryInTextCursorState : HistoryDefaultCursorState; + result = _caption.getState(x - st::msgPadding.left(), y - height, captionw); } height -= st::mediaCaptionSkip; } @@ -3908,16 +3910,17 @@ void HistoryVideo::getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int height -= skipy + st::mediaPadding.bottom(); } if (x >= skipx && y >= skipy && x < skipx + width && y < skipy + height) { - lnk = loaded ? _openl : (_data->loading() ? _cancell : _savel); + result.link = loaded ? _openl : (_data->loading() ? _cancell : _savel); if (_caption.isEmpty() && _parent->getMedia() == this) { int32 fullRight = skipx + width, fullBottom = skipy + height; bool inDate = _parent->pointInTime(fullRight, fullBottom, x, y, InfoDisplayOverImage); if (inDate) { - state = HistoryInDateCursorState; + result.cursor = HistoryInDateCursorState; } } - return; + return result; } + return result; } void HistoryVideo::setStatusSize(int32 newSize) const { @@ -3925,11 +3928,11 @@ void HistoryVideo::setStatusSize(int32 newSize) const { } const QString HistoryVideo::inDialogsText() const { - return _caption.isEmpty() ? lang(lng_in_dlg_video) : _caption.original(0, 0xFFFF, Text::ExpandLinksNone); + return _caption.isEmpty() ? lang(lng_in_dlg_video) : _caption.original(AllTextSelection, Text::ExpandLinksNone); } const QString HistoryVideo::inHistoryText() const { - return qsl("[ ") + lang(lng_in_dlg_video) + (_caption.isEmpty() ? QString() : (qsl(", ") + _caption.original(0, 0xFFFF, Text::ExpandLinksAll))) + qsl(" ]"); + return qsl("[ ") + lang(lng_in_dlg_video) + (_caption.isEmpty() ? QString() : (qsl(", ") + _caption.original(AllTextSelection, Text::ExpandLinksAll))) + qsl(" ]"); } void HistoryVideo::updateStatusText() const { @@ -4126,11 +4129,12 @@ int HistoryDocument::resizeGetHeight(int width) { return _height; } -void HistoryDocument::draw(Painter &p, const QRect &r, bool selected, uint64 ms) const { +void HistoryDocument::draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const { if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return; _data->automaticLoad(_parent); bool loaded = _data->loaded(), displayLoading = _data->displayLoading(); + bool selected = (selection == FullSelection); int captionw = _width - st::msgPadding.left() - st::msgPadding.right(); @@ -4342,12 +4346,14 @@ void HistoryDocument::draw(Painter &p, const QRect &r, bool selected, uint64 ms) if (auto captioned = Get()) { p.setPen(st::black); - captioned->_caption.draw(p, st::msgPadding.left(), bottom, captionw); + captioned->_caption.draw(p, st::msgPadding.left(), bottom, captionw, style::al_left, 0, -1, selection); } } -void HistoryDocument::getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const { - if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return; +HistoryTextState HistoryDocument::getState(int x, int y, HistoryStateRequest request) const { + HistoryTextState result; + + if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return result; bool out = _parent->out(), isPost = _parent->isPost(), outbg = out && !isPost; bool loaded = _data->loaded(); @@ -4363,14 +4369,14 @@ void HistoryDocument::getState(ClickHandlerPtr &lnk, HistoryCursorState &state, QRect rthumb(rtlrect(st::msgFileThumbPadding.left(), st::msgFileThumbPadding.top(), st::msgFileThumbSize, st::msgFileThumbSize, _width)); if ((_data->loading() || _data->uploading() || !loaded) && rthumb.contains(x, y)) { - lnk = (_data->loading() || _data->uploading()) ? _cancell : _savel; - return; + result.link = (_data->loading() || _data->uploading()) ? _cancell : _savel; + return result; } if (_data->status != FileUploadFailed) { if (rtlrect(nameleft, linktop, thumbed->_linkw, st::semiboldFont->height, _width).contains(x, y)) { - lnk = (_data->loading() || _data->uploading()) ? thumbed->_linkcancell : thumbed->_linksavel; - return; + result.link = (_data->loading() || _data->uploading()) ? thumbed->_linkcancell : thumbed->_linksavel; + return result; } } } else { @@ -4378,25 +4384,24 @@ void HistoryDocument::getState(ClickHandlerPtr &lnk, HistoryCursorState &state, QRect inner(rtlrect(st::msgFilePadding.left(), st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, _width)); if ((_data->loading() || _data->uploading() || !loaded) && inner.contains(x, y)) { - lnk = (_data->loading() || _data->uploading()) ? _cancell : _savel; - return; + result.link = (_data->loading() || _data->uploading()) ? _cancell : _savel; + return result; } } int32 height = _height; if (auto captioned = Get()) { if (y >= bottom) { - bool inText = false; - captioned->_caption.getState(lnk, inText, x - st::msgPadding.left(), y - bottom, _width - st::msgPadding.left() - st::msgPadding.right()); - state = inText ? HistoryInTextCursorState : HistoryDefaultCursorState; - return; + result = captioned->_caption.getState(x - st::msgPadding.left(), y - bottom, _width - st::msgPadding.left() - st::msgPadding.right(), request.forText()); + return result; } height -= captioned->_caption.countHeight(_width - st::msgPadding.left() - st::msgPadding.right()) + st::msgPadding.bottom(); } if (x >= 0 && y >= 0 && x < _width && y < height && !_data->loading() && !_data->uploading() && _data->isValid()) { - lnk = _openl; - return; + result.link = _openl; + return result; } + return result; } const QString HistoryDocument::inDialogsText() const { @@ -4414,7 +4419,7 @@ const QString HistoryDocument::inDialogsText() const { } if (auto captioned = Get()) { if (!captioned->_caption.isEmpty()) { - result.append(' ').append(captioned->_caption.original(0, 0xFFFF, Text::ExpandLinksNone)); + result.append(' ').append(captioned->_caption.original(AllTextSelection, Text::ExpandLinksNone)); } } return result; @@ -4436,7 +4441,7 @@ const QString HistoryDocument::inHistoryText() const { } if (auto captioned = Get()) { if (!captioned->_caption.isEmpty()) { - result.append(qsl(", ")).append(captioned->_caption.original(0, 0xFFFF, Text::ExpandLinksAll)); + result.append(qsl(", ")).append(captioned->_caption.original(AllTextSelection, Text::ExpandLinksAll)); } } return qsl("[ ") + result.append(qsl(" ]")); @@ -4719,11 +4724,13 @@ int HistoryGif::resizeGetHeight(int width) { return _height; } -void HistoryGif::draw(Painter &p, const QRect &r, bool selected, uint64 ms) const { +void HistoryGif::draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const { if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return; _data->automaticLoad(_parent); bool loaded = _data->loaded(), displayLoading = (_parent->id < 0) || _data->displayLoading(); + bool selected = (selection == FullSelection); + if (loaded && !gif() && _gif != BadClipReader && cAutoPlayGif()) { Ui::autoplayMediaInlineAsync(_parent->fullId()); } @@ -4824,15 +4831,17 @@ void HistoryGif::draw(Painter &p, const QRect &r, bool selected, uint64 ms) cons if (!_caption.isEmpty()) { p.setPen(st::black); - _caption.draw(p, st::msgPadding.left(), skipy + height + st::mediaPadding.bottom() + st::mediaCaptionSkip, captionw); + _caption.draw(p, st::msgPadding.left(), skipy + height + st::mediaPadding.bottom() + st::mediaCaptionSkip, captionw, style::al_left, 0, -1, selection); } else if (_parent->getMedia() == this && (_data->uploading() || App::hoveredItem() == _parent)) { int32 fullRight = skipx + width, fullBottom = skipy + height; _parent->drawInfo(p, fullRight, fullBottom, 2 * skipx + width, selected, InfoDisplayOverImage); } } -void HistoryGif::getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const { - if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return; +HistoryTextState HistoryGif::getState(int x, int y, HistoryStateRequest request) const { + HistoryTextState result; + + if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return result; int32 skipx = 0, skipy = 0, width = _width, height = _height; bool bubble = _parent->hasBubble(); @@ -4843,10 +4852,8 @@ void HistoryGif::getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x int32 captionw = width - st::msgPadding.left() - st::msgPadding.right(); height -= _caption.countHeight(captionw) + st::msgPadding.bottom(); if (x >= st::msgPadding.left() && y >= height && x < st::msgPadding.left() + captionw && y < _height) { - bool inText = false; - _caption.getState(lnk, inText, x - st::msgPadding.left(), y - height, captionw); - state = inText ? HistoryInTextCursorState : HistoryDefaultCursorState; - return; + result = _caption.getState(x - st::msgPadding.left(), y - height, captionw, request.forText()); + return result; } height -= st::mediaCaptionSkip; } @@ -4855,27 +4862,28 @@ void HistoryGif::getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x } if (x >= skipx && y >= skipy && x < skipx + width && y < skipy + height) { if (_data->uploading()) { - lnk = _cancell; + result.link = _cancell; } else if (!gif() || !cAutoPlayGif()) { - lnk = _data->loaded() ? _openl : (_data->loading() ? _cancell : _savel); + result.link = _data->loaded() ? _openl : (_data->loading() ? _cancell : _savel); } if (_parent->getMedia() == this) { int32 fullRight = skipx + width, fullBottom = skipy + height; bool inDate = _parent->pointInTime(fullRight, fullBottom, x, y, InfoDisplayOverImage); if (inDate) { - state = HistoryInDateCursorState; + result.cursor = HistoryInDateCursorState; } } - return; + return result; } + return result; } const QString HistoryGif::inDialogsText() const { - return qsl("GIF") + (_caption.isEmpty() ? QString() : (' ' + _caption.original(0, 0xFFFF, Text::ExpandLinksNone))); + return qsl("GIF") + (_caption.isEmpty() ? QString() : (' ' + _caption.original(AllTextSelection, Text::ExpandLinksNone))); } const QString HistoryGif::inHistoryText() const { - return qsl("[ GIF ") + (_caption.isEmpty() ? QString() : (_caption.original(0, 0xFFFF, Text::ExpandLinksAll) + ' ')) + qsl(" ]"); + return qsl("[ GIF ") + (_caption.isEmpty() ? QString() : (_caption.original(AllTextSelection, Text::ExpandLinksAll) + ' ')) + qsl(" ]"); } void HistoryGif::setStatusSize(int32 newSize) const { @@ -5048,11 +5056,12 @@ int HistorySticker::resizeGetHeight(int width) { // return new height return _height; } -void HistorySticker::draw(Painter &p, const QRect &r, bool selected, uint64 ms) const { +void HistorySticker::draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const { if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return; _data->checkSticker(); bool loaded = _data->loaded(); + bool selected = (selection == FullSelection); bool out = _parent->out(), isPost = _parent->isPost(), childmedia = (_parent->getMedia() != this); @@ -5120,8 +5129,9 @@ void HistorySticker::draw(Painter &p, const QRect &r, bool selected, uint64 ms) } } -void HistorySticker::getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const { - if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return; +HistoryTextState HistorySticker::getState(int x, int y, HistoryStateRequest request) const { + HistoryTextState result; + if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return result; bool out = _parent->out(), isPost = _parent->isPost(), childmedia = (_parent->getMedia() != this); @@ -5156,8 +5166,8 @@ void HistorySticker::getState(ClickHandlerPtr &lnk, HistoryCursorState &state, i if (via) { int viah = st::msgReplyPadding.top() + st::msgServiceNameFont->height + (reply ? 0 : st::msgReplyPadding.bottom()); if (x >= rectx && y >= recty && x < rectx + rectw && y < recty + viah) { - lnk = via->_lnk; - return; + result.link = via->_lnk; + return result; } int skip = st::msgServiceNameFont->height + (reply ? 2 * st::msgReplyPadding.top() : 0); recty += skip; @@ -5165,23 +5175,24 @@ void HistorySticker::getState(ClickHandlerPtr &lnk, HistoryCursorState &state, i } if (reply) { if (x >= rectx && y >= recty && x < rectx + rectw && y < recty + recth) { - lnk = reply->replyToLink(); - return; + result.link = reply->replyToLink(); + return result; } } } if (_parent->getMedia() == this) { bool inDate = _parent->pointInTime(usex + usew, _height, x, y, InfoDisplayOverImage); if (inDate) { - state = HistoryInDateCursorState; + result.cursor = HistoryInDateCursorState; } } int pixLeft = usex + (usew - _pixw) / 2, pixTop = (_minh - _pixh) / 2; if (x >= pixLeft && x < pixLeft + _pixw && y >= pixTop && y < pixTop + _pixh) { - lnk = _packLink; - return; + result.link = _packLink; + return result; } + return result; } const QString HistorySticker::inDialogsText() const { @@ -5292,11 +5303,12 @@ void HistoryContact::initDimensions() { _height = _minh; } -void HistoryContact::draw(Painter &p, const QRect &r, bool selected, uint64 ms) const { +void HistoryContact::draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const { if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return; int32 skipx = 0, skipy = 0, width = _width, height = _height; bool out = _parent->out(), isPost = _parent->isPost(), outbg = out && !isPost; + bool selected = (selection == FullSelection); if (width >= _maxw) { width = _maxw; @@ -5345,7 +5357,8 @@ void HistoryContact::draw(Painter &p, const QRect &r, bool selected, uint64 ms) p.drawTextLeft(nameleft, statustop, width, _phone); } -void HistoryContact::getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const { +HistoryTextState HistoryContact::getState(int x, int y, HistoryStateRequest request) const { + HistoryTextState result; bool out = _parent->out(), isPost = _parent->isPost(), outbg = out && !isPost; int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, linktop = 0; @@ -5353,14 +5366,15 @@ void HistoryContact::getState(ClickHandlerPtr &lnk, HistoryCursorState &state, i nameleft = st::msgFileThumbPadding.left() + st::msgFileThumbSize + st::msgFileThumbPadding.right(); linktop = st::msgFileThumbLinkTop; if (rtlrect(nameleft, linktop, _linkw, st::semiboldFont->height, _width).contains(x, y)) { - lnk = _linkl; - return; + result.link = _linkl; + return result; } } if (x >= 0 && y >= 0 && x < _width && y < _height && _contact) { - lnk = _contact->openLink(); - return; + result.link = _contact->openLink(); + return result; } + return result; } const QString HistoryContact::inDialogsText() const { @@ -5670,11 +5684,12 @@ int HistoryWebPage::resizeGetHeight(int width) { return _height; } -void HistoryWebPage::draw(Painter &p, const QRect &r, bool selected, uint64 ms) const { +void HistoryWebPage::draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const { if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return; int32 skipx = 0, skipy = 0, width = _width, height = _height; bool out = _parent->out(), isPost = _parent->isPost(), outbg = out && !isPost; + bool selected = (selection == FullSelection); style::color barfg = (selected ? (outbg ? st::msgOutReplyBarSelColor : st::msgInReplyBarSelColor) : (outbg ? st::msgOutReplyBarColor : st::msgInReplyBarColor)); style::color semibold = (selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg)); @@ -5726,7 +5741,7 @@ void HistoryWebPage::draw(Painter &p, const QRect &r, bool selected, uint64 ms) if (_title.hasSkipBlock()) { endskip = _parent->skipBlockWidth(); } - _title.drawLeftElided(p, lshift, tshift, width, _width, _titleLines, style::al_left, 0, -1, endskip); + _title.drawLeftElided(p, lshift, tshift, width, _width, _titleLines, style::al_left, 0, -1, endskip, false, selection); tshift += _titleLines * _lineHeight; } if (_descriptionLines) { @@ -5735,7 +5750,7 @@ void HistoryWebPage::draw(Painter &p, const QRect &r, bool selected, uint64 ms) if (_description.hasSkipBlock()) { endskip = _parent->skipBlockWidth(); } - _description.drawLeftElided(p, lshift, tshift, width, _width, _descriptionLines, style::al_left, 0, -1, endskip); + _description.drawLeftElided(p, lshift, tshift, width, _width, _descriptionLines, style::al_left, 0, -1, endskip, false, toDescriptionSelection(selection)); tshift += _descriptionLines * _lineHeight; } if (_attach) { @@ -5747,7 +5762,8 @@ void HistoryWebPage::draw(Painter &p, const QRect &r, bool selected, uint64 ms) p.save(); p.translate(attachLeft, attachTop); - _attach->draw(p, r.translated(-attachLeft, -attachTop), selected, ms); + auto attachSelection = selected ? FullSelection : TextSelection{ 0, 0 }; + _attach->draw(p, r.translated(-attachLeft, -attachTop), attachSelection, ms); int32 pixwidth = _attach->currentWidth(), pixheight = _attach->height(); if (_data->type == WebPageVideo) { @@ -5774,8 +5790,10 @@ void HistoryWebPage::draw(Painter &p, const QRect &r, bool selected, uint64 ms) } } -void HistoryWebPage::getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const { - if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return; +HistoryTextState HistoryWebPage::getState(int x, int y, HistoryStateRequest request) const { + HistoryTextState result; + + if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return result; int32 skipx = 0, skipy = 0, width = _width, height = _height; int32 lshift = st::msgPadding.left() + st::webPageLeft, rshift = st::msgPadding.right(), bshift = st::msgPadding.bottom(); @@ -5785,48 +5803,74 @@ void HistoryWebPage::getState(ClickHandlerPtr &lnk, HistoryCursorState &state, i bshift += st::msgDateFont->height; } + bool inThumb = false; if (_asArticle) { int32 pw = qMax(_pixw, int16(_lineHeight)); if (rtlrect(lshift + width - pw, 0, pw, _pixh, _width).contains(x, y)) { - lnk = _openl; - return; + inThumb = true; } width -= pw + st::webPagePhotoDelta; } - int32 tshift = 0; + int tshift = 0, symbolAdd = 0; if (_siteNameWidth) { tshift += _lineHeight; } if (_titleLines) { + if (y >= tshift && y < tshift + _titleLines * _lineHeight) { + Text::StateRequestElided titleRequest = request.forText(); + titleRequest.lines = _titleLines; + result = _title.getStateElidedLeft(x - lshift, y - tshift, width, _width, titleRequest); + } else if (y >= tshift + _titleLines * _lineHeight) { + symbolAdd += _title.length(); + } tshift += _titleLines * _lineHeight; } if (_descriptionLines) { if (y >= tshift && y < tshift + _descriptionLines * _lineHeight) { - bool inText = false; - _description.getStateLeft(lnk, inText, x - lshift, y - tshift, width, _width); - state = inText ? HistoryInTextCursorState : HistoryDefaultCursorState; - return; + Text::StateRequestElided descriptionRequest = request.forText(); + descriptionRequest.lines = _descriptionLines; + result = _description.getStateElidedLeft(x - lshift, y - tshift, width, _width, descriptionRequest); + } else if (y >= tshift + _descriptionLines * _lineHeight) { + symbolAdd += _description.length(); } tshift += _descriptionLines * _lineHeight; } - if (_attach) { + if (inThumb) { + result.link = _openl; + } else if (_attach) { if (tshift) tshift += st::webPagePhotoSkip; if (x >= lshift && x < lshift + width && y >= tshift && y < _height - st::msgPadding.bottom()) { int32 attachLeft = lshift - bubble.left(), attachTop = tshift - bubble.top(); if (rtl()) attachLeft = _width - attachLeft - _attach->currentWidth(); - _attach->getState(lnk, state, x - attachLeft, y - attachTop); - if (lnk && !_data->document && _data->photo) { + result = _attach->getState(x - attachLeft, y - attachTop, request); + + if (result.link && !_data->document && _data->photo) { if (_data->type == WebPageProfile || _data->type == WebPageVideo) { - lnk = _openl; + result.link = _openl; } else if (_data->type == WebPagePhoto || _data->siteName == qstr("Twitter") || _data->siteName == qstr("Facebook")) { // leave photo link } else { - lnk = _openl; + result.link = _openl; } } } } + + result.symbol += symbolAdd; + return result; +} + +TextSelection HistoryWebPage::adjustSelection(TextSelection selection, TextSelectType type) const { + if (!_descriptionLines || selection.to <= _title.length()) { + return _title.adjustSelection(selection, type); + } + auto descriptionSelection = _description.adjustSelection(toDescriptionSelection(selection), type); + if (selection.from >= _title.length()) { + return fromDescriptionSelection(descriptionSelection); + } + auto titleSelection = _title.adjustSelection(selection, type); + return { titleSelection.from, fromDescriptionSelection(descriptionSelection).to }; } void HistoryWebPage::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { @@ -6152,11 +6196,12 @@ int HistoryLocation::resizeGetHeight(int width) { return _height; } -void HistoryLocation::draw(Painter &p, const QRect &r, bool selected, uint64 ms) const { +void HistoryLocation::draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const { if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return; int32 skipx = 0, skipy = 0, width = _width, height = _height; bool bubble = _parent->hasBubble(); bool out = _parent->out(), isPost = _parent->isPost(), outbg = out && !isPost; + bool selected = (selection == FullSelection); if (bubble) { skipx = st::mediaPadding.left(); @@ -6173,11 +6218,11 @@ void HistoryLocation::draw(Painter &p, const QRect &r, bool selected, uint64 ms) p.setPen(st::black); if (!_title.isEmpty()) { - _title.drawLeftElided(p, skipx + st::msgPadding.left(), skipy, textw, _width, 2); + _title.drawLeftElided(p, skipx + st::msgPadding.left(), skipy, textw, _width, 2, style::al_left, 0, -1, 0, false, selection); skipy += qMin(_title.countHeight(textw), 2 * st::webPageTitleFont->height); } if (!_description.isEmpty()) { - _description.drawLeftElided(p, skipx + st::msgPadding.left(), skipy, textw, _width, 3); + _description.drawLeftElided(p, skipx + st::msgPadding.left(), skipy, textw, _width, 3, style::al_left, 0, -1, 0, false, toDescriptionSelection(selection)); skipy += qMin(_description.countHeight(textw), 3 * st::webPageDescriptionFont->height); } if (!_title.isEmpty() || !_description.isEmpty()) { @@ -6216,8 +6261,10 @@ void HistoryLocation::draw(Painter &p, const QRect &r, bool selected, uint64 ms) } } -void HistoryLocation::getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const { - if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return; +HistoryTextState HistoryLocation::getState(int x, int y, HistoryStateRequest request) const { + HistoryTextState result; + + if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return result; int32 skipx = 0, skipy = 0, width = _width, height = _height; bool bubble = _parent->hasBubble(); @@ -6235,10 +6282,21 @@ void HistoryLocation::getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int32 textw = _width - st::msgPadding.left() - st::msgPadding.right(); if (!_title.isEmpty()) { - skipy += qMin(_title.countHeight(textw), 2 * st::webPageTitleFont->height); + auto titleh = qMin(_title.countHeight(textw), 2 * st::webPageTitleFont->height); + if (y >= skipy && y < skipy + titleh) { + result = _title.getStateLeft(x - skipx - st::msgPadding.left(), y - skipy, textw, _width, request.forText()); + return result; + } + skipy += titleh; } if (!_description.isEmpty()) { - skipy += qMin(_description.countHeight(textw), 3 * st::webPageDescriptionFont->height); + auto descriptionh = qMin(_description.countHeight(textw), 3 * st::webPageDescriptionFont->height); + if (y >= skipy && y < skipy + descriptionh) { + result = _description.getStateLeft(x - skipx - st::msgPadding.left(), y - skipy, textw, _width, request.forText()); + if (!_title.isEmpty()) result.symbol += _title.length(); + return result; + } + skipy += descriptionh; } if (!_title.isEmpty() || !_description.isEmpty()) { skipy += st::webPagePhotoSkip; @@ -6246,16 +6304,29 @@ void HistoryLocation::getState(ClickHandlerPtr &lnk, HistoryCursorState &state, height -= skipy + st::mediaPadding.bottom(); } if (x >= skipx && y >= skipy && x < skipx + width && y < skipy + height && _data) { - lnk = _link; + result.link = _link; int32 fullRight = skipx + width, fullBottom = _height - (skipx ? st::mediaPadding.bottom() : 0); bool inDate = _parent->pointInTime(fullRight, fullBottom, x, y, InfoDisplayOverImage); if (inDate) { - state = HistoryInDateCursorState; + result.cursor = HistoryInDateCursorState; } - return; + return result; } + return result; +} + +TextSelection HistoryLocation::adjustSelection(TextSelection selection, TextSelectType type) const { + if (_description.isEmpty() || selection.to <= _title.length()) { + return _title.adjustSelection(selection, type); + } + auto descriptionSelection = _description.adjustSelection(toDescriptionSelection(selection), type); + if (selection.from >= _title.length()) { + return fromDescriptionSelection(descriptionSelection); + } + auto titleSelection = _title.adjustSelection(selection, type); + return { titleSelection.from, fromDescriptionSelection(descriptionSelection).to }; } const QString HistoryLocation::inDialogsText() const { @@ -6972,19 +7043,17 @@ void HistoryMessage::eraseFromOverview() { } } -QString HistoryMessage::selectedText(uint32 selection) const { +QString HistoryMessage::selectedText(TextSelection selection) const { QString result; if (_media && selection == FullSelection) { - QString text = _text.original(0, 0xFFFF, Text::ExpandLinksAll), mediaText = _media->inHistoryText(); + QString text = _text.original(AllTextSelection, Text::ExpandLinksAll), mediaText = _media->inHistoryText(); result = text.isEmpty() ? mediaText : (mediaText.isEmpty() ? text : (text + ' ' + mediaText)); } else { - uint16 selectedFrom = (selection == FullSelection) ? 0 : ((selection >> 16) & 0xFFFF); - uint16 selectedTo = (selection == FullSelection) ? 0xFFFF : (selection & 0xFFFF); - result = _text.original(selectedFrom, selectedTo, Text::ExpandLinksAll); + result = _text.original((selection == FullSelection) ? AllTextSelection : selection, Text::ExpandLinksAll); } if (auto fwd = Get()) { if (selection == FullSelection) { - QString fwdinfo = fwd->_text.original(0, 0xFFFF, Text::ExpandLinksAll), wrapped; + QString fwdinfo = fwd->_text.original(AllTextSelection, Text::ExpandLinksAll), wrapped; wrapped.reserve(fwdinfo.size() + 4 + result.size()); wrapped.append('[').append(fwdinfo).append(qsl("]\n")).append(result); result = wrapped; @@ -7002,7 +7071,7 @@ QString HistoryMessage::selectedText(uint32 selection) const { } QString HistoryMessage::inDialogsText() const { - return emptyText() ? (_media ? _media->inDialogsText() : QString()) : _text.original(0, 0xFFFF, Text::ExpandLinksNone); + return emptyText() ? (_media ? _media->inDialogsText() : QString()) : _text.original(AllTextSelection, Text::ExpandLinksNone); } HistoryMedia *HistoryMessage::getMedia() const { @@ -7224,7 +7293,7 @@ void HistoryMessage::setId(MsgId newId) { } } -void HistoryMessage::draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const { +void HistoryMessage::draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const { bool outbg = out() && !isPost(), bubble = drawBubble(), selected = (selection == FullSelection); int left = 0, width = 0, height = _height; @@ -7317,14 +7386,12 @@ void HistoryMessage::draw(Painter &p, const QRect &r, uint32 selection, uint64 m p.setPen(st::msgColor); p.setFont(st::msgFont); - uint16 selectedFrom = selected ? 0 : ((selection >> 16) & 0xFFFF); - uint16 selectedTo = selected ? 0 : (selection & 0xFFFF); - _text.draw(p, trect.x(), trect.y(), trect.width(), style::al_left, 0, -1, selectedFrom, selectedTo); + _text.draw(p, trect.x(), trect.y(), trect.width(), style::al_left, 0, -1, selection); if (_media && _media->isDisplayed()) { int32 top = height - marginBottom() - _media->height(); p.translate(left, top); - _media->draw(p, r.translated(-left, -top), selected, ms); + _media->draw(p, r.translated(-left, -top), toMediaSelection(selection), ms); p.translate(-left, -top); if (!_media->customInfoLayout()) { HistoryMessage::drawInfo(p, r.x() + r.width(), r.y() + r.height(), 2 * r.x() + r.width(), selected, InfoDisplayDefault); @@ -7335,7 +7402,7 @@ void HistoryMessage::draw(Painter &p, const QRect &r, uint32 selection, uint64 m } else { int32 top = marginTop(); p.translate(left, top); - _media->draw(p, r.translated(-left, -top), selected, ms); + _media->draw(p, r.translated(-left, -top), toMediaSelection(selection), ms); p.translate(-left, -top); } @@ -7537,22 +7604,18 @@ bool HistoryMessage::pointInTime(int32 right, int32 bottom, int x, int y, InfoDi return QRect(dateX, dateY, HistoryMessage::timeWidth(), st::msgDateFont->height).contains(x, y); } -void HistoryMessage::getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const { - lnk.clear(); - state = HistoryDefaultCursorState; +HistoryTextState HistoryMessage::getState(int x, int y, HistoryStateRequest request) const { + HistoryTextState result; int left = 0, width = 0, height = _height; countPositionAndSize(left, width); - if (width < 1) return; + if (width < 1) return result; - if (const ReplyKeyboard *keyboard = inlineReplyKeyboard()) { + auto keyboard = inlineReplyKeyboard(); + if (keyboard) { int h = st::msgBotKbButton.margin + keyboard->naturalHeight(); height -= h; - int top = height + st::msgBotKbButton.margin - marginBottom(); - if (x >= left && x < left + width && y >= top && y < _height - marginBottom()) { - return keyboard->getState(lnk, x - left, y - top); - } } if (drawBubble()) { @@ -7566,12 +7629,12 @@ void HistoryMessage::getState(ClickHandlerPtr &lnk, HistoryCursorState &state, i if (displayFromName()) { if (y >= trect.top() && y < trect.top() + st::msgNameFont->height) { if (x >= trect.left() && x < trect.left() + trect.width() && x < trect.left() + author()->nameText.maxWidth()) { - lnk = author()->openLink(); - return; + result.link = author()->openLink(); + return result; } if (via && !fwd && x >= trect.left() + author()->nameText.maxWidth() + st::msgServiceFont->spacew && x < trect.left() + author()->nameText.maxWidth() + st::msgServiceFont->spacew + via->_width) { - lnk = via->_lnk; - return; + result.link = via->_lnk; + return result; } } trect.setTop(trect.top() + st::msgNameFont->height); @@ -7579,22 +7642,29 @@ void HistoryMessage::getState(ClickHandlerPtr &lnk, HistoryCursorState &state, i if (displayForwardedFrom()) { int32 fwdheight = ((fwd->_text.maxWidth() > trect.width()) ? 2 : 1) * st::semiboldFont->height; if (y >= trect.top() && y < trect.top() + fwdheight) { - bool inText = false; bool breakEverywhere = (fwd->_text.countHeight(trect.width()) > 2 * st::semiboldFont->height); - textstyleSet(&st::inFwdTextStyle); - fwd->_text.getState(lnk, inText, x - trect.left(), y - trect.top(), trect.width(), style::al_left, breakEverywhere); - textstyleRestore(); + auto textRequest = request.forText(); if (breakEverywhere) { - state = HistoryInForwardedCursorState; + textRequest.flags |= Text::StateRequest::Flag::BreakEverywhere; } - return; + textstyleSet(&st::inFwdTextStyle); + result = fwd->_text.getState(x - trect.left(), y - trect.top(), trect.width(), textRequest); + textstyleRestore(); + result.symbol = 0; + result.afterSymbol = false; + if (breakEverywhere) { + result.cursor = HistoryInForwardedCursorState; + } else { + result.cursor = HistoryDefaultCursorState; + } + return result; } trect.setTop(trect.top() + fwdheight); } if (via && !displayFromName() && !displayForwardedFrom()) { if (x >= trect.left() && y >= trect.top() && y < trect.top() + st::msgNameFont->height && x < trect.left() + via->_width) { - lnk = via->_lnk; - return; + result.link = via->_lnk; + return result; } trect.setTop(trect.top() + st::msgNameFont->height); } @@ -7602,84 +7672,59 @@ void HistoryMessage::getState(ClickHandlerPtr &lnk, HistoryCursorState &state, i int32 h = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom(); if (y >= trect.top() && y < trect.top() + h) { if (reply->replyToMsg && y >= trect.top() + st::msgReplyPadding.top() && y < trect.top() + st::msgReplyPadding.top() + st::msgReplyBarSize.height() && x >= trect.left() && x < trect.left() + trect.width()) { - lnk = reply->replyToLink(); + result.link = reply->replyToLink(); } - return; + return result; } trect.setTop(trect.top() + h); } - bool inDate = false; - - if (_media && _media->isDisplayed()) { - if (!_media->customInfoLayout()) { - inDate = HistoryMessage::pointInTime(r.x() + r.width(), r.y() + r.height(), x, y, InfoDisplayDefault); - } - if (y >= r.bottom() - _media->height() && y < r.bottom()) { - _media->getState(lnk, state, x - r.left(), y - (r.bottom() - _media->height())); - if (inDate) state = HistoryInDateCursorState; - return; - } - trect.setBottom(trect.bottom() - _media->height()); - } else { + bool inDate = false, mediaDisplayed = _media && _media->isDisplayed(); + if (!mediaDisplayed || !_media->customInfoLayout()) { inDate = HistoryMessage::pointInTime(r.x() + r.width(), r.y() + r.height(), x, y, InfoDisplayDefault); } - textstyleSet(&((out() && !isPost()) ? st::outTextStyle : st::inTextStyle)); - bool inText = false; - _text.getState(lnk, inText, x - trect.x(), y - trect.y(), trect.width()); - textstyleRestore(); - + if (mediaDisplayed) { + trect.setBottom(trect.bottom() - _media->height()); + if (y >= r.bottom() - _media->height()) { + result = _media->getState(x - r.left(), y - (r.bottom() - _media->height()), request); + result.symbol += _text.length(); + } + } + if (!mediaDisplayed || (y < r.bottom() - _media->height())) { + textstyleSet(&((out() && !isPost()) ? st::outTextStyle : st::inTextStyle)); + result = _text.getState(x - trect.x(), y - trect.y(), trect.width(), request.forText()); + textstyleRestore(); + } if (inDate) { - state = HistoryInDateCursorState; - } else if (inText) { - state = HistoryInTextCursorState; - } else { - state = HistoryDefaultCursorState; + result.cursor = HistoryInDateCursorState; } } else { - _media->getState(lnk, state, x - left, y - marginTop()); + result = _media->getState(x - left, y - marginTop(), request); + result.symbol += _text.length(); } + + if (keyboard) { + int top = height + st::msgBotKbButton.margin - marginBottom(); + if (x >= left && x < left + width && y >= top && y < _height - marginBottom()) { + result.link = keyboard->getState(x - left, y - top); + return result; + } + } + + return result; } -void HistoryMessage::getSymbol(uint16 &symbol, bool &after, bool &upon, int x, int y) const { - symbol = 0; - after = false; - upon = false; - - if (drawBubble()) { - int left = 0, width = 0, height = _height; - countPositionAndSize(left, width); - if (width < 1) return; - - auto fwd = Get(); - auto via = Get(); - auto reply = Get(); - - int top = marginTop(); - QRect r(left, top, width, height - top - marginBottom()); - QRect trect(r.marginsAdded(-st::msgPadding)); - if (displayFromName()) { - trect.setTop(trect.top() + st::msgNameFont->height); - } else if (via && !fwd) { - trect.setTop(trect.top() + st::msgNameFont->height); - } - if (displayForwardedFrom()) { - int32 fwdheight = ((fwd->_text.maxWidth() > trect.width()) ? 2 : 1) * st::semiboldFont->height; - trect.setTop(trect.top() + fwdheight); - } - if (reply) { - int32 h = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom(); - trect.setTop(trect.top() + h); - } - if (_media && _media->isDisplayed()) { - trect.setBottom(trect.bottom() - _media->height()); - } - - textstyleSet(&((out() && !isPost()) ? st::outTextStyle : st::inTextStyle)); - _text.getSymbol(symbol, after, upon, x - trect.x(), y - trect.y(), trect.width()); - textstyleRestore(); +TextSelection HistoryMessage::adjustSelection(TextSelection selection, TextSelectType type) const { + if (!_media || selection.to <= _text.length()) { + return _text.adjustSelection(selection, type); } + auto mediaSelection = _media->adjustSelection(toMediaSelection(selection), type); + if (selection.from >= _text.length()) { + return fromMediaSelection(mediaSelection); + } + auto textSelection = _text.adjustSelection(selection, type); + return { textSelection.from, fromMediaSelection(mediaSelection).to }; } void HistoryMessage::drawInDialog(Painter &p, const QRect &r, bool act, const HistoryItem *&cacheFor, Text &cache) const { @@ -8019,14 +8064,12 @@ void HistoryService::countPositionAndSize(int32 &left, int32 &width) const { width = maxwidth - st::msgServiceMargin.left() - st::msgServiceMargin.left(); } -QString HistoryService::selectedText(uint32 selection) const { - uint16 selectedFrom = (selection == FullSelection) ? 0 : (selection >> 16) & 0xFFFF; - uint16 selectedTo = (selection == FullSelection) ? 0xFFFF : (selection & 0xFFFF); - return _text.original(selectedFrom, selectedTo); +QString HistoryService::selectedText(TextSelection selection) const { + return _text.original((selection == FullSelection) ? AllTextSelection : selection); } QString HistoryService::inDialogsText() const { - return _text.original(0, 0xFFFF, Text::ExpandLinksNone); + return _text.original(AllTextSelection, Text::ExpandLinksNone); } QString HistoryService::inReplyText() const { @@ -8041,7 +8084,7 @@ void HistoryService::setServiceText(const QString &text) { initDimensions(); } -void HistoryService::draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const { +void HistoryService::draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const { int left = 0, width = 0, height = _height - st::msgServiceMargin.top() - st::msgServiceMargin.bottom(); // two small margins countPositionAndSize(left, width); if (width < 1) return; @@ -8085,7 +8128,7 @@ void HistoryService::draw(Painter &p, const QRect &r, uint32 selection, uint64 m height -= st::msgServiceMargin.top() + _media->height(); int32 left = st::msgServiceMargin.left() + (width - _media->maxWidth()) / 2, top = st::msgServiceMargin.top() + height + st::msgServiceMargin.top(); p.translate(left, top); - _media->draw(p, r.translated(-left, -top), selection == FullSelection, ms); + _media->draw(p, r.translated(-left, -top), toMediaSelection(selection), ms); p.translate(-left, -top); } @@ -8102,9 +8145,7 @@ void HistoryService::draw(Painter &p, const QRect &r, uint32 selection, uint64 m p.setBrush(Qt::NoBrush); p.setPen(st::msgServiceColor); p.setFont(st::msgServiceFont); - uint16 selectedFrom = (selection == FullSelection) ? 0 : (selection >> 16) & 0xFFFF; - uint16 selectedTo = (selection == FullSelection) ? 0 : selection & 0xFFFF; - _text.draw(p, trect.x(), trect.y(), trect.width(), Qt::AlignCenter, 0, -1, selectedFrom, selectedTo); + _text.draw(p, trect.x(), trect.y(), trect.width(), Qt::AlignCenter, 0, -1, selection); textstyleRestore(); @@ -8166,13 +8207,12 @@ bool HistoryService::hasPoint(int x, int y) const { return QRect(left, st::msgServiceMargin.top(), width, height).contains(x, y); } -void HistoryService::getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const { - lnk.clear(); - state = HistoryDefaultCursorState; +HistoryTextState HistoryService::getState(int x, int y, HistoryStateRequest request) const { + HistoryTextState result; int left = 0, width = 0, height = _height - st::msgServiceMargin.top() - st::msgServiceMargin.bottom(); // two small margins countPositionAndSize(left, width); - if (width < 1) return; + if (width < 1) return result; if (int dateh = displayedDateHeight()) { y -= dateh; @@ -8190,41 +8230,14 @@ void HistoryService::getState(ClickHandlerPtr &lnk, HistoryCursorState &state, i QRect trect(QRect(left, st::msgServiceMargin.top(), width, height).marginsAdded(-st::msgServicePadding)); if (trect.contains(x, y)) { textstyleSet(&st::serviceTextStyle); - bool inText = false; - _text.getState(lnk, inText, x - trect.x(), y - trect.y(), trect.width(), Qt::AlignCenter); + auto textRequest = request.forText(); + textRequest.align = style::al_center; + result = _text.getState(x - trect.x(), y - trect.y(), trect.width(), textRequest); textstyleRestore(); - state = inText ? HistoryInTextCursorState : HistoryDefaultCursorState; } else if (_media) { - _media->getState(lnk, state, x - st::msgServiceMargin.left() - (width - _media->maxWidth()) / 2, y - st::msgServiceMargin.top() - height - st::msgServiceMargin.top()); + result = _media->getState(x - st::msgServiceMargin.left() - (width - _media->maxWidth()) / 2, y - st::msgServiceMargin.top() - height - st::msgServiceMargin.top(), request); } -} - -void HistoryService::getSymbol(uint16 &symbol, bool &after, bool &upon, int x, int y) const { - symbol = 0; - after = false; - upon = false; - - int left = 0, width = 0, height = _height - st::msgServiceMargin.top() - st::msgServiceMargin.bottom(); // two small margins - countPositionAndSize(left, width); - if (width < 1) return; - - if (int dateh = displayedDateHeight()) { - y -= dateh; - height -= dateh; - } - if (auto unreadbar = Get()) { - int unreadbarh = unreadbar->height(); - y -= unreadbarh; - height -= unreadbarh; - } - - if (_media) { - height -= st::msgServiceMargin.top() + _media->height(); - } - QRect trect(QRect(left, st::msgServiceMargin.top(), width, height).marginsAdded(-st::msgServicePadding)); - textstyleSet(&st::serviceTextStyle); - _text.getSymbol(symbol, after, upon, x - trect.x(), y - trect.y(), trect.width(), Qt::AlignCenter); - textstyleRestore(); + return result; } void HistoryService::drawInDialog(Painter &p, const QRect &r, bool act, const HistoryItem *&cacheFor, Text &cache) const { @@ -8272,13 +8285,12 @@ HistoryGroup::HistoryGroup(History *history, HistoryItem *newItem, const QDateTi , _lnk(new CommentsClickHandler(this)) { } -void HistoryGroup::getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const { - lnk.clear(); - state = HistoryDefaultCursorState; +HistoryTextState HistoryGroup::getState(int x, int y, HistoryStateRequest request) const { + HistoryTextState result; int32 left = 0, width = 0, height = _height - st::msgServiceMargin.top() - st::msgServiceMargin.bottom(); // two small margins countPositionAndSize(left, width); - if (width < 1) return; + if (width < 1) return result; QRect trect(QRect(left, st::msgServiceMargin.top(), width, height).marginsAdded(-st::msgServicePadding)); if (width > _maxw) { @@ -8286,8 +8298,9 @@ void HistoryGroup::getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int width = _maxw; } if (QRect(left, st::msgServiceMargin.top(), width, height).contains(x, y)) { - lnk = _lnk; + result.link = _lnk; } + return result; } void HistoryGroup::uniteWith(MsgId minId, MsgId maxId, int32 count) { @@ -8339,12 +8352,11 @@ HistoryCollapse::HistoryCollapse(History *history, MsgId wasMinId, const QDateTi , _wasMinId(wasMinId) { } -void HistoryCollapse::draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const { +void HistoryCollapse::draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const { } -void HistoryCollapse::getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const { - lnk.clear(); - state = HistoryDefaultCursorState; +HistoryTextState HistoryCollapse::getState(int x, int y, HistoryStateRequest request) const { + return HistoryTextState(); } HistoryJoined::HistoryJoined(History *history, const QDateTime &inviteDate, UserData *inviter, MTPDmessage::Flags flags) diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index ab525f3cb..d60c855f6 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -729,7 +729,7 @@ protected: }; -class HistoryMessage; // dynamic_cast optimize +class HistoryMessage; enum HistoryCursorState { HistoryDefaultCursorState, @@ -738,6 +738,36 @@ enum HistoryCursorState { 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 { InfoDisplayDefault, InfoDisplayOverImage, @@ -936,7 +966,7 @@ public: int naturalHeight() 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 clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed); @@ -1068,7 +1098,7 @@ public: } 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) { } @@ -1216,17 +1246,11 @@ public: virtual bool hasPoint(int x, int y) const { return false; } - virtual void getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const { - lnk.clear(); - state = HistoryDefaultCursorState; - } - virtual void getSymbol(uint16 &symbol, bool &after, bool &upon, int x, int y) const { // from text - upon = hasPoint(x, y); - symbol = upon ? 0xFFFF : 0; - after = false; - } - virtual uint32 adjustSelection(uint16 from, uint16 to, TextSelectType type) const { - return (from << 16) | to; + + virtual HistoryTextState getState(int x, int y, HistoryStateRequest request) const = 0; + + virtual TextSelection adjustSelection(TextSelection selection, TextSelectType type) const { + return selection; } // ClickHandlerHost interface @@ -1251,7 +1275,7 @@ public: } virtual void previousItemChanged(); - virtual QString selectedText(uint32 selection) const { + virtual QString selectedText(TextSelection selection) const { return qsl("[-]"); } virtual QString inDialogsText() const { @@ -1514,6 +1538,13 @@ protected: return const_cast(static_cast(this)->inlineReplyKeyboard()); } + TextSelection toMediaSelection(TextSelection selection) const { + return unshiftSelection(selection, _text); + } + TextSelection fromMediaSelection(TextSelection selection) const { + return shiftSelection(selection, _text); + } + Text _text = { int(st::msgMinWidth) }; int32 _textWidth, _textHeight; @@ -1624,8 +1655,8 @@ public: _width = qMin(width, _maxw); return _height; } - virtual void draw(Painter &p, const QRect &r, bool selected, uint64 ms) const = 0; - virtual void getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const = 0; + virtual void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const = 0; + virtual HistoryTextState getState(int x, int y, HistoryStateRequest request) const = 0; // if we are in selecting items mode perhaps we want to // toggle selection instead of activating the pressed link @@ -1636,6 +1667,10 @@ public: return false; } + virtual TextSelection adjustSelection(TextSelection selection, TextSelectType type) const { + return selection; + } + // if we press and drag this link should we drag the item virtual bool dragItemByHandler(const ClickHandlerPtr &p) const = 0; @@ -1829,8 +1864,12 @@ public: void initDimensions() override; int resizeGetHeight(int width) override; - void draw(Painter &p, const QRect &r, bool selected, uint64 ms) const override; - void getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const override; + void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override; + HistoryTextState getState(int x, int y, HistoryStateRequest request) const override; + + TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override { + return _caption.adjustSelection(selection, type); + } const QString inDialogsText() const override; const QString inHistoryText() const override; @@ -1902,8 +1941,12 @@ public: void initDimensions() override; int resizeGetHeight(int width) override; - void draw(Painter &p, const QRect &r, bool selected, uint64 ms) const override; - void getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const override; + void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override; + HistoryTextState getState(int x, int y, HistoryStateRequest request) const override; + + TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override { + return _caption.adjustSelection(selection, type); + } const QString inDialogsText() const override; const QString inHistoryText() const override; @@ -2015,8 +2058,15 @@ public: void initDimensions() override; int resizeGetHeight(int width) override; - void draw(Painter &p, const QRect &r, bool selected, uint64 ms) const override; - void getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const override; + void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override; + HistoryTextState getState(int x, int y, HistoryStateRequest request) const override; + + TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override { + if (auto captioned = Get()) { + return captioned->_caption.adjustSelection(selection, type); + } + return selection; + } const QString inDialogsText() const override; const QString inHistoryText() const override; @@ -2095,8 +2145,12 @@ public: void initDimensions() override; int resizeGetHeight(int width) override; - void draw(Painter &p, const QRect &r, bool selected, uint64 ms) const override; - void getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const override; + void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override; + HistoryTextState getState(int x, int y, HistoryStateRequest request) const override; + + TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override { + return _caption.adjustSelection(selection, type); + } const QString inDialogsText() const override; const QString inHistoryText() const override; @@ -2183,8 +2237,8 @@ public: void initDimensions() override; int resizeGetHeight(int width) override; - void draw(Painter &p, const QRect &r, bool selected, uint64 ms) const override; - void getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const override; + void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override; + HistoryTextState getState(int x, int y, HistoryStateRequest request) const override; bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override { return true; @@ -2255,8 +2309,8 @@ public: void initDimensions() override; - void draw(Painter &p, const QRect &r, bool selected, uint64 ms) const override; - void getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const override; + void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override; + HistoryTextState getState(int x, int y, HistoryStateRequest request) const override; bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override { return true; @@ -2318,8 +2372,10 @@ public: void initDimensions() override; int resizeGetHeight(int width) override; - void draw(Painter &p, const QRect &r, bool selected, uint64 ms) const override; - void getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const override; + void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) 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 { return _attach && _attach->toggleSelectionByHandlerClick(p); @@ -2376,6 +2432,13 @@ public: ~HistoryWebPage(); private: + TextSelection toDescriptionSelection(TextSelection selection) const { + return unshiftSelection(selection, _title); + } + TextSelection fromDescriptionSelection(TextSelection selection) const { + return shiftSelection(selection, _title); + } + WebPageData *_data; ClickHandlerPtr _openl; HistoryMedia *_attach; @@ -2440,8 +2503,10 @@ public: void initDimensions() override; int resizeGetHeight(int32 width) override; - void draw(Painter &p, const QRect &r, bool selected, uint64 ms) const override; - void getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const override; + void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) 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 { return p == _link; @@ -2467,6 +2532,13 @@ public: } private: + TextSelection toDescriptionSelection(TextSelection selection) const { + return unshiftSelection(selection, _title); + } + TextSelection fromDescriptionSelection(TextSelection selection) const { + return shiftSelection(selection, _title); + } + LocationData *_data; Text _title, _description; ClickHandlerPtr _link; @@ -2538,7 +2610,7 @@ public: void drawInfo(Painter &p, int32 right, int32 bottom, int32 width, bool selected, InfoDisplayType type) const override; void setViewsCount(int32 count) 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; @@ -2547,12 +2619,9 @@ public: bool hasPoint(int x, int y) 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; - uint32 adjustSelection(uint16 from, uint16 to, TextSelectType type) const override { - return _text.adjustSelection(from, to, type); - } + TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override; // ClickHandlerHost interface void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override { @@ -2573,7 +2642,7 @@ public: int32 addToOverview(AddToOverviewMethod method) override; void eraseFromOverview(); - QString selectedText(uint32 selection) const override; + QString selectedText(TextSelection selection) const override; QString inDialogsText() const override; HistoryMedia *getMedia() const override; void setText(const QString &text, const EntitiesInText &entities) override; @@ -2763,12 +2832,12 @@ public: 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; - void getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) 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 { - return _text.adjustSelection(from, to, type); + HistoryTextState getState(int x, int y, HistoryStateRequest request) const override; + + TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override { + return _text.adjustSelection(selection, type); } void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override { @@ -2789,7 +2858,7 @@ public: bool serviceMsg() const override { return true; } - QString selectedText(uint32 selection) const override; + QString selectedText(TextSelection selection) const override; QString inDialogsText() const override; QString inReplyText() const override; @@ -2824,12 +2893,8 @@ public: return _create(history, newItem, date); } - void getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const; - void getSymbol(uint16 &symbol, bool &after, bool &upon, int x, int y) const { - symbol = 0xFFFF; - after = false; - upon = false; - } + HistoryTextState getState(int x, int y, HistoryStateRequest request) const; + QString selectedText(uint32 selection) const { return QString(); } @@ -2877,13 +2942,9 @@ public: return _create(history, wasMinId, date); } - void draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const; - void getState(ClickHandlerPtr &lnk, HistoryCursorState &state, int x, int y) const; - void getSymbol(uint16 &symbol, bool &after, bool &upon, int x, int y) const { - symbol = 0xFFFF; - after = false; - upon = false; - } + void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const; + HistoryTextState getState(int x, int y, HistoryStateRequest request) const; + QString selectedText(uint32 selection) const { return QString(); } diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 73efbe930..2c3aa309d 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -252,11 +252,13 @@ void HistoryInner::paintEvent(QPaintEvent *e) { p.save(); p.translate(0, y); if (r.y() < y + item->height()) while (y < drawToY) { - uint32 sel = 0; + TextSelection sel; 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) { - SelectedItems::const_iterator i = _selected.constFind(item); + auto i = _selected.constFind(item); if (i != selEnd) { sel = i.value(); } @@ -297,11 +299,13 @@ void HistoryInner::paintEvent(QPaintEvent *e) { while (y < drawToY) { int32 h = item->height(); if (historyRect.y() < y + h && hdrawtop < y + h) { - uint32 sel = 0; + TextSelection sel; 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) { - SelectedItems::const_iterator i = _selected.constFind(item); + auto i = _selected.constFind(item); if (i != selEnd) { sel = i.value(); } @@ -588,19 +592,20 @@ void HistoryInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton butt } } if (_dragAction == NoDrag && _dragItem) { - bool afterDragSymbol, uponSymbol; - uint16 symbol; + HistoryTextState dragState; if (_trippleClickTimer.isActive() && (screenPos - _trippleClickPoint).manhattanLength() < QApplication::startDragDistance()) { - _dragItem->getSymbol(symbol, afterDragSymbol, uponSymbol, _dragStartPos.x(), _dragStartPos.y()); - if (uponSymbol) { - uint32 selStatus = (symbol << 16) | symbol; + HistoryStateRequest request; + request.flags = Text::StateRequest::Flag::LookupSymbol; + 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 (!_selected.isEmpty()) { repaintItem(_selected.cbegin().key()); _selected.clear(); } _selected.insert(_dragItem, selStatus); - _dragSymbol = symbol; + _dragSymbol = dragState.symbol; _dragAction = Selecting; _dragSelType = TextSelectParagraphs; dragActionUpdate(_dragPos); @@ -608,12 +613,14 @@ void HistoryInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton butt } } } 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 (App::pressedItem()) { - _dragSymbol = symbol; - bool uponSelected = uponSymbol; + _dragSymbol = dragState.symbol; + bool uponSelected = (dragState.cursor == HistoryInTextCursorState); if (uponSelected) { if (_selected.isEmpty() || _selected.cbegin().value() == FullSelection || @@ -621,7 +628,7 @@ void HistoryInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton butt ) { uponSelected = false; } 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) { uponSelected = false; } @@ -633,8 +640,8 @@ void HistoryInner::dragActionStart(const QPoint &screenPos, Qt::MouseButton butt if (dynamic_cast(App::pressedItem()->getMedia()) || _dragCursorState == HistoryInDateCursorState) { _dragAction = PrepareDrag; // start sticker drag or by-date drag } else { - if (afterDragSymbol) ++_dragSymbol; - uint32 selStatus = (_dragSymbol << 16) | _dragSymbol; + if (dragState.afterSymbol) ++_dragSymbol; + TextSelection selStatus = { _dragSymbol, _dragSymbol }; if (selStatus != FullSelection && (_selected.isEmpty() || _selected.cbegin().value() != FullSelection)) { if (!_selected.isEmpty()) { repaintItem(_selected.cbegin().key()); @@ -675,12 +682,13 @@ void HistoryInner::onDragExec() { bool uponSelected = false; if (_dragItem) { - bool afterDragSymbol; - uint16 symbol; if (!_selected.isEmpty() && _selected.cbegin().value() == FullSelection) { uponSelected = _selected.contains(_dragItem); } 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 (_selected.isEmpty() || _selected.cbegin().value() == FullSelection || @@ -688,8 +696,8 @@ void HistoryInner::onDragExec() { ) { uponSelected = false; } else { - uint16 selFrom = (_selected.cbegin().value() >> 16) & 0xFFFF, selTo = _selected.cbegin().value() & 0xFFFF; - if (symbol < selFrom || symbol >= selTo) { + uint16 selFrom = _selected.cbegin().value().from, selTo = _selected.cbegin().value().to; + if (dragState.symbol < selFrom || dragState.symbol >= selTo) { uponSelected = false; } } @@ -841,8 +849,8 @@ void HistoryInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton but applyDragSelection(); _dragSelFrom = _dragSelTo = 0; } else if (!_selected.isEmpty() && !_dragWasInactive) { - uint32 sel = _selected.cbegin().value(); - if (sel != FullSelection && (sel & 0xFFFF) == ((sel >> 16) & 0xFFFF)) { + auto sel = _selected.cbegin().value(); + if (sel != FullSelection && sel.from == sel.to) { _selected.clear(); if (App::wnd()) App::wnd()->setInnerFocus(); } @@ -867,15 +875,15 @@ void HistoryInner::mouseDoubleClickEvent(QMouseEvent *e) { 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) { - bool afterDragSymbol, uponSelected; - uint16 symbol; - _dragItem->getSymbol(symbol, afterDragSymbol, uponSelected, _dragStartPos.x(), _dragStartPos.y()); - if (uponSelected) { - _dragSymbol = symbol; + HistoryStateRequest request; + request.flags |= Text::StateRequest::Flag::LookupSymbol; + auto dragState = _dragItem->getState(_dragStartPos.x(), _dragStartPos.y(), request); + if (dragState.cursor == HistoryInTextCursorState) { + _dragSymbol = dragState.symbol; _dragSelType = TextSelectWords; if (_dragAction == NoDrag) { _dragAction = Selecting; - uint32 selStatus = (symbol << 16) | symbol; + TextSelection selStatus = { dragState.symbol, dragState.symbol }; if (!_selected.isEmpty()) { repaintItem(_selected.cbegin().key()); _selected.clear(); @@ -915,13 +923,14 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { isUponSelected = -2; } } 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; if (App::mousedItem() && App::mousedItem() == App::hoveredItem()) { QPoint mousePos(mapMouseToItem(mapFromGlobal(_dragPos), App::mousedItem())); - bool afterDragSymbol, uponSymbol; - App::mousedItem()->getSymbol(symbol, afterDragSymbol, uponSymbol, mousePos.x(), mousePos.y()); - if (uponSymbol && symbol >= selFrom && symbol < selTo) { + HistoryStateRequest request; + request.flags |= Text::StateRequest::Flag::LookupSymbol; + auto dragState = App::mousedItem()->getState(mousePos.x(), mousePos.y(), request); + if (dragState.cursor == HistoryInTextCursorState && dragState.symbol >= selFrom && dragState.symbol < selTo) { isUponSelected = 1; } } @@ -1685,57 +1694,13 @@ void HistoryInner::onUpdateSelected() { dragActionCancel(); } - ClickHandlerPtr lnk; + HistoryTextState dragState; ClickHandlerHost *lnkhost = nullptr; - HistoryCursorState cursorState = HistoryDefaultCursorState; + bool selectingText = (item == _dragItem && item == App::hoveredItem() && !_selected.isEmpty() && _selected.cbegin().value() != FullSelection); if (point.y() < _historyOffset) { if (_botAbout && !_botAbout->info->text.isEmpty() && _botAbout->height > 0) { - bool inText = false; - _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); + 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); 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) { if (item != _dragItem || (m - _dragStartPos).manhattanLength() >= QApplication::startDragDistance()) { @@ -1746,19 +1711,68 @@ void HistoryInner::onUpdateSelected() { _dragAction = Selecting; } } + + HistoryStateRequest request; if (_dragAction == Selecting) { - bool canSelectMany = (_history != 0); - if (item == _dragItem && item == App::hoveredItem() && !_selected.isEmpty() && _selected.cbegin().value() != FullSelection) { - bool afterSymbol, uponSymbol; - uint16 second; - _dragItem->getSymbol(second, afterSymbol, uponSymbol, m.x(), m.y()); - if (afterSymbol && _dragSelType == TextSelectLetters) ++second; - uint32 selState = _dragItem->adjustSelection(qMin(second, _dragSymbol), qMax(second, _dragSymbol), _dragSelType); + request.flags |= Text::StateRequest::Flag::LookupSymbol; + } else { + selectingText = false; + } + dragState = item->getState(m.x(), m.y(), request); + lnkhost = item; + 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) { _selected[_dragItem] = selState; repaintItem(_dragItem); } - if (!_wasSelectedText && (selState == FullSelection || (selState & 0xFFFF) != ((selState >> 16) & 0xFFFF))) { + if (!_wasSelectedText && (selState == FullSelection || selState.from != selState.to)) { _wasSelectedText = true; setFocus(); } @@ -2009,7 +2023,7 @@ QString HistoryInner::tooltipText() const { } else if (_dragCursorState == HistoryInForwardedCursorState && _dragAction == NoDrag) { if (App::hoveredItem()) { if (HistoryMessageForwarded *fwd = App::hoveredItem()->Get()) { - return fwd->_text.original(0, 0xFFFF, Text::ExpandLinksNone); + return fwd->_text.original(AllTextSelection, Text::ExpandLinksNone); } } } else if (ClickHandlerPtr lnk = ClickHandler::getActive()) { @@ -2367,11 +2381,10 @@ void BotKeyboard::updateSelected() { QPoint p(mapFromGlobal(_lastMousePos)); int x = rtl() ? st::botKbScroll.width : _st->margin; - ClickHandlerPtr lnk; - _impl->getState(lnk, p.x() - x, p.y() - _st->margin); - if (ClickHandler::setActive(lnk, this)) { + auto link = _impl->getState(p.x() - x, p.y() - _st->margin); + if (ClickHandler::setActive(link, this)) { PopupTooltip::Hide(); - setCursor(lnk ? style::cur_pointer : style::cur_default); + setCursor(link ? style::cur_pointer : style::cur_default); } } @@ -5927,6 +5940,7 @@ void HistoryWidget::inlineBotChanged() { _inlineBotCancel = std_::make_unique(this, st::inlineBotCancel); connect(_inlineBotCancel.get(), SIGNAL(clicked()), this, SLOT(onInlineBotCancel())); _inlineBotCancel->setGeometry(_send.geometry()); + _attachEmoji.raise(); updateFieldSubmitSettings(); updateControlsVisibility(); } else if (!isInlineBot && _inlineBotCancel) { diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h index 99d07a0d9..9e9b77a12 100644 --- a/Telegram/SourceFiles/historywidget.h +++ b/Telegram/SourceFiles/historywidget.h @@ -174,7 +174,7 @@ private: bool _firstLoading = false; style::cursor _cursor = style::cur_default; - typedef QMap SelectedItems; + using SelectedItems = QMap; SelectedItems _selected; void applyDragSelection(); void applyDragSelection(SelectedItems *toItems) const; diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp index 1443e383b..a18ec139a 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp @@ -125,7 +125,7 @@ void DeleteSavedGifClickHandler::onClickImpl() const { 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(); document->automaticLoad(nullptr); @@ -381,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(); float64 over = _a_over.isNull() ? (_active ? 1 : 0) : _a_over.current(); @@ -473,7 +473,7 @@ void Photo::initDimensions() { _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; QSize frame = countFrameSize(); @@ -591,7 +591,7 @@ void Video::initDimensions() { _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; bool withThumb = !content_thumb()->isNull(); @@ -694,7 +694,7 @@ void File::initDimensions() { _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; DocumentData *document = getShownDocument(); @@ -942,7 +942,7 @@ int32 Contact::resizeGetHeight(int32 width) { 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; left = st::msgFileSize + st::inlineThumbSkip; @@ -1051,7 +1051,7 @@ int32 Article::resizeGetHeight(int32 width) { 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; if (_withThumb) { left = st::inlineThumbSize + st::inlineThumbSkip; diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h index b6d769b75..e61c975e3 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h @@ -70,7 +70,7 @@ public: 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; // ClickHandlerHost interface @@ -135,7 +135,7 @@ public: 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; private: @@ -165,7 +165,7 @@ public: } 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; // ClickHandlerHost interface @@ -190,7 +190,7 @@ public: 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; private: @@ -238,7 +238,7 @@ public: 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; // ClickHandlerHost interface @@ -302,7 +302,7 @@ public: void initDimensions() 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; private: @@ -321,7 +321,7 @@ public: void initDimensions() 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; private: diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.h b/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.h index 71284328f..0c091845b 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.h +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.h @@ -58,7 +58,7 @@ public: //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); int32 position() const; diff --git a/Telegram/SourceFiles/layout.h b/Telegram/SourceFiles/layout.h index 7dee8bc15..86e6298e2 100644 --- a/Telegram/SourceFiles/layout.h +++ b/Telegram/SourceFiles/layout.h @@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #pragma once -static const uint32 FullSelection = 0xFFFFFFFF; +static constexpr TextSelection FullSelection = { 0xFFFF, 0xFFFF }; extern TextParseOptions _textNameOptions, _textDlgOptions; extern TextParseOptions _historyTextOptions, _historyBotOptions, _historyTextNoMonoOptions, _historyBotNoMonoOptions; diff --git a/Telegram/SourceFiles/mediaview.cpp b/Telegram/SourceFiles/mediaview.cpp index 16f4b018a..24d0471ac 100644 --- a/Telegram/SourceFiles/mediaview.cpp +++ b/Telegram/SourceFiles/mediaview.cpp @@ -1781,13 +1781,14 @@ bool MediaView::updateOverState(OverState newState) { void MediaView::updateOver(QPoint pos) { ClickHandlerPtr lnk; ClickHandlerHost *lnkhost = nullptr; - bool inText; 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; } 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; } diff --git a/Telegram/SourceFiles/overview/overview_layout.cpp b/Telegram/SourceFiles/overview/overview_layout.cpp index 3a789f3c6..b830e0205 100644 --- a/Telegram/SourceFiles/overview/overview_layout.cpp +++ b/Telegram/SourceFiles/overview/overview_layout.cpp @@ -131,7 +131,7 @@ void Date::initDimensions() { _minh = st::linksDateMargin.top() + st::normalFont->height + st::linksDateMargin.bottom() + st::linksBorder; } -void Date::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const { +void Date::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) const { if (clip.intersects(QRect(0, st::linksDateMargin.top(), _width, st::normalFont->height))) { p.setPen(st::linksDateColor); p.setFont(st::semiboldFont); @@ -159,7 +159,7 @@ int32 Photo::resizeGetHeight(int32 width) { return _height; } -void Photo::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const { +void Photo::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) const { bool good = _data->loaded(); if (!good) { _data->medium->automaticLoad(_parent); @@ -230,7 +230,7 @@ int32 Video::resizeGetHeight(int32 width) { return _height; } -void Video::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const { +void Video::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) const { bool selected = (selection == FullSelection), thumbLoaded = _data->thumb->loaded(); _data->automaticLoad(_parent); @@ -397,7 +397,7 @@ void Voice::initDimensions() { _minh = st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom() + st::lineWidth; } -void Voice::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const { +void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) const { bool selected = (selection == FullSelection); _data->automaticLoad(_parent); @@ -515,9 +515,9 @@ void Voice::getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, i } if (rtlrect(nameleft, statustop, _width - nameleft - nameright, st::normalFont->height, _width).contains(x, y)) { if (_statusSize == FileStatusSizeLoaded || _statusSize == FileStatusSizeReady) { - bool inText = false; - _details.getStateLeft(link, inText, x - nameleft, y - statustop, _width, _width); - cursor = inText ? HistoryInTextCursorState : HistoryDefaultCursorState; + auto textState = _details.getStateLeft(x - nameleft, y - statustop, _width, _width); + link = textState.link; + cursor = textState.uponSymbol ? HistoryInTextCursorState : HistoryDefaultCursorState; } } if (hasPoint(x, y) && !link && !_data->loading()) { @@ -615,7 +615,7 @@ void Document::initDimensions() { } } -void Document::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const { +void Document::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) const { bool selected = (selection == FullSelection); _data->automaticLoad(_parent); @@ -1027,7 +1027,7 @@ int32 Link::resizeGetHeight(int32 width) { return _height; } -void Link::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const { +void Link::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) const { int32 left = st::dlgPhotoSize + st::dlgPhotoPadding, top = st::linksMargin.top() + st::linksBorder, w = _width - left; if (clip.intersects(rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width))) { if (_page && _page->photo) { diff --git a/Telegram/SourceFiles/overview/overview_layout.h b/Telegram/SourceFiles/overview/overview_layout.h index 9a155d01c..ed46ee808 100644 --- a/Telegram/SourceFiles/overview/overview_layout.h +++ b/Telegram/SourceFiles/overview/overview_layout.h @@ -38,7 +38,7 @@ class ItemBase; class AbstractItem : public LayoutItemBase { public: - virtual void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const = 0; + virtual void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) const = 0; virtual ItemBase *toMediaItem() { return nullptr; @@ -164,7 +164,7 @@ public: Date(const QDate &date, bool month); void initDimensions() override; - void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const override; + void paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) const override; private: QDate _date; @@ -178,7 +178,7 @@ public: void initDimensions() override; int32 resizeGetHeight(int32 width) override; - void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const 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: @@ -196,7 +196,7 @@ public: void initDimensions() override; int32 resizeGetHeight(int32 width) override; - void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const 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: @@ -229,7 +229,7 @@ public: Voice(DocumentData *voice, HistoryItem *parent); void initDimensions() override; - void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const 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: @@ -263,7 +263,7 @@ public: Document(DocumentData *document, HistoryItem *parent); void initDimensions() override; - void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const 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 { @@ -308,7 +308,7 @@ public: void initDimensions() override; int32 resizeGetHeight(int32 width) override; - void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const 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: diff --git a/Telegram/SourceFiles/overviewwidget.cpp b/Telegram/SourceFiles/overviewwidget.cpp index 6d4a595be..6a7ffa811 100644 --- a/Telegram/SourceFiles/overviewwidget.cpp +++ b/Telegram/SourceFiles/overviewwidget.cpp @@ -566,8 +566,8 @@ void OverviewInner::dragActionFinish(const QPoint &screenPos, Qt::MouseButton bu if (_dragSelFrom && _dragSelTo) { applyDragSelection(); } else if (!_selected.isEmpty() && !_dragWasInactive) { - uint32 sel = _selected.cbegin().value(); - if (sel != FullSelection && (sel & 0xFFFF) == ((sel >> 16) & 0xFFFF)) { + auto sel = _selected.cbegin().value(); + if (sel != FullSelection && sel.from == sel.to) { _selected.clear(); App::main()->activate(); } @@ -782,7 +782,7 @@ bool OverviewInner::preloadLocal() { return true; } -uint32 OverviewInner::itemSelectedValue(int32 index) const { +TextSelection OverviewInner::itemSelectedValue(int32 index) const { int32 selfrom = -1, selto = -1; if (_dragSelFromIndex >= 0 && _dragSelToIndex >= 0) { selfrom = _dragSelToIndex; @@ -790,7 +790,7 @@ uint32 OverviewInner::itemSelectedValue(int32 index) const { } if (_items.at(index)->toMediaItem()) { // draw item 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()) { SelectedItems::const_iterator j = _selected.constFind(complexMsgId(_items.at(index)->getItem())); if (j != _selected.cend()) { @@ -798,7 +798,7 @@ uint32 OverviewInner::itemSelectedValue(int32 index) const { } } } - return 0; + return { 0, 0 }; } void OverviewInner::paintEvent(QPaintEvent *e) { @@ -1010,7 +1010,7 @@ void OverviewInner::onUpdateSelected() { if (_mousedItem == _dragItem && lnk && !_selected.isEmpty() && _selected.cbegin().value() != FullSelection) { bool afterSymbol = false, uponSymbol = false; uint16 second = 0; - _selected[_dragItem] = 0; + _selected[_dragItem] = { 0, 0 }; updateDragSelection(0, -1, 0, -1, false); } else if (canSelectMany) { bool selectingDown = (_reversed ? (_mousedItemIndex < _dragItemIndex) : (_mousedItemIndex > _dragItemIndex)) || (_mousedItemIndex == _dragItemIndex && ((_type == OverviewPhotos || _type == OverviewVideos) ? (_dragStartPos.x() < m.x()) : (_dragStartPos.y() < m.y()))); @@ -1729,7 +1729,7 @@ void OverviewInner::changingMsgId(HistoryItem *row, MsgId newId) { if (_selectedMsgId == oldId) _selectedMsgId = newId; for (SelectedItems::iterator i = _selected.begin(), e = _selected.end(); i != e; ++i) { if (i.key() == oldId) { - uint32 sel = i.value(); + auto sel = i.value(); _selected.erase(i); _selected.insert(newId, sel); break; diff --git a/Telegram/SourceFiles/overviewwidget.h b/Telegram/SourceFiles/overviewwidget.h index e0c039726..044744006 100644 --- a/Telegram/SourceFiles/overviewwidget.h +++ b/Telegram/SourceFiles/overviewwidget.h @@ -158,7 +158,7 @@ private: ChannelId _channel; bool _selMode; - uint32 itemSelectedValue(int32 index) const; + TextSelection itemSelectedValue(int32 index) const; int32 _rowsLeft, _rowWidth; @@ -209,7 +209,7 @@ private: // selection support, like in HistoryWidget Qt::CursorShape _cursor; HistoryCursorState _cursorState; - typedef QMap SelectedItems; + using SelectedItems = QMap; SelectedItems _selected; enum DragAction { NoDrag = 0x00, diff --git a/Telegram/SourceFiles/profilewidget.cpp b/Telegram/SourceFiles/profilewidget.cpp index ff4d80940..031c2bb27 100644 --- a/Telegram/SourceFiles/profilewidget.cpp +++ b/Telegram/SourceFiles/profilewidget.cpp @@ -1120,9 +1120,9 @@ void ProfileInner::updateSelected() { ClickHandlerPtr lnk; ClickHandlerHost *lnkhost = nullptr; - bool inText = false; 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; } ClickHandler::setActive(lnk, lnkhost); diff --git a/Telegram/SourceFiles/ui/flatlabel.cpp b/Telegram/SourceFiles/ui/flatlabel.cpp index 6daea1251..d170ee92d 100644 --- a/Telegram/SourceFiles/ui/flatlabel.cpp +++ b/Telegram/SourceFiles/ui/flatlabel.cpp @@ -110,10 +110,12 @@ void FlatLabel::updateHover() { QPoint m(mapFromGlobal(_lastMousePos)); 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(); - ClickHandler::setActive(handler, this); + ClickHandler::setActive(state.link, this); } void FlatLabel::setOpacity(float64 o) { diff --git a/Telegram/SourceFiles/ui/text.cpp b/Telegram/SourceFiles/ui/text.cpp index 190da42ce..b47ae3388 100644 --- a/Telegram/SourceFiles/ui/text.cpp +++ b/Telegram/SourceFiles/ui/text.cpp @@ -923,7 +923,7 @@ public: return _blockEnd(t, i, e) - (*i)->from(); } - TextPainter(QPainter *p, const Text *t) : _p(p), _t(t), _elideLast(false), _breakEverywhere(false), _elideRemoveFromEnd(0), _str(0), _elideSavedBlock(0), _lnkResult(0), _inTextFlag(0), _getSymbol(0), _getSymbolAfter(0), _getSymbolUpon(0) { + TextPainter(QPainter *p, const Text *t) : _p(p), _t(t) { } void initNextParagraph(Text::TextBlocks::const_iterator i) { @@ -987,7 +987,7 @@ public: } } - void draw(int32 left, int32 top, int32 w, style::align align, int32 yFrom, int32 yTo, uint16 selectedFrom = 0, uint16 selectedTo = 0) { + void draw(int32 left, int32 top, int32 w, style::align align, int32 yFrom, int32 yTo, TextSelection selection = { 0, 0 }) { if (_t->isEmpty()) return; _blocksSize = _t->_blocks.size(); @@ -1005,8 +1005,7 @@ public: if (_elideLast) { _yToElide = _yTo; } - _selectedFrom = selectedFrom; - _selectedTo = selectedTo; + _selection = selection; _wLeft = _w = w; _str = _t->_text.unicode(); @@ -1173,14 +1172,13 @@ public: if (_lineStart < _t->_text.size()) { if (!drawLine(_t->_text.size(), e, e)) return; } - if (_getSymbol) { - *_getSymbol = _t->_text.size(); - *_getSymbolAfter = false; - *_getSymbolUpon = false; + if (!_p && _lookupSymbol) { + _lookupResult.symbol = _t->_text.size(); + _lookupResult.afterSymbol = false; } } - void drawElided(int32 left, int32 top, int32 w, style::align align, int32 lines, int32 yFrom, int32 yTo, int32 removeFromEnd, bool breakEverywhere) { + void drawElided(int32 left, int32 top, int32 w, style::align align, int32 lines, int32 yFrom, int32 yTo, int32 removeFromEnd, bool breakEverywhere, TextSelection selection) { if (lines <= 0 || _t->isNull()) return; if (yTo < 0 || (lines - 1) * _t->_font->height < yTo) { @@ -1189,48 +1187,45 @@ public: _elideRemoveFromEnd = removeFromEnd; } _breakEverywhere = breakEverywhere; - draw(left, top, w, align, yFrom, yTo); + draw(left, top, w, align, yFrom, yTo, selection); } - const ClickHandlerPtr &link(int32 x, int32 y, int32 w, style::align align) { - static StaticNeverFreedPointer zero(new ClickHandlerPtr()); - - _lnkX = x; - _lnkY = y; - _lnkResult = zero.data(); - if (!_t->isNull() && _lnkX >= 0 && _lnkX < w && _lnkY >= 0) { - draw(0, 0, w, align, _lnkY, _lnkY + 1); - } - return *_lnkResult; - } - - void getState(ClickHandlerPtr &lnk, bool &inText, int32 x, int32 y, int32 w, style::align align, bool breakEverywhere) { - lnk.clear(); - inText = false; - - if (!_t->isNull() && x >= 0 && x < w && y >= 0) { - _lnkX = x; - _lnkY = y; - _lnkResult = &lnk; - _inTextFlag = &inText; - _breakEverywhere = breakEverywhere; - draw(0, 0, w, align, _lnkY, _lnkY + 1); - lnk = *_lnkResult; - } - } - - void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y, int32 w, style::align align) { - symbol = 0; - after = false; - upon = false; + Text::StateResult getState(int x, int y, int w, Text::StateRequest request) { if (!_t->isNull() && y >= 0) { - _lnkX = x; - _lnkY = y; - _getSymbol = &symbol; - _getSymbolAfter = &after; - _getSymbolUpon = &upon; - draw(0, 0, w, align, _lnkY, _lnkY + 1); + _lookupRequest = request; + _lookupX = x; + _lookupY = y; + + _breakEverywhere = (_lookupRequest.flags & Text::StateRequest::Flag::BreakEverywhere); + _lookupSymbol = (_lookupRequest.flags & Text::StateRequest::Flag::LookupSymbol); + _lookupLink = (_lookupRequest.flags & Text::StateRequest::Flag::LookupLink); + if (_lookupSymbol || (_lookupX >= 0 && _lookupX < w)) { + draw(0, 0, w, _lookupRequest.align, _lookupY, _lookupY + 1); + } } + return _lookupResult; + } + + Text::StateResult getStateElided(int x, int y, int w, Text::StateRequestElided request) { + if (!_t->isNull() && y >= 0 && request.lines > 0) { + _lookupRequest = request; + _lookupX = x; + _lookupY = y; + + _breakEverywhere = (_lookupRequest.flags & Text::StateRequest::Flag::BreakEverywhere); + _lookupSymbol = (_lookupRequest.flags & Text::StateRequest::Flag::LookupSymbol); + _lookupLink = (_lookupRequest.flags & Text::StateRequest::Flag::LookupLink); + if (_lookupSymbol || (_lookupX >= 0 && _lookupX < w)) { + int yTo = _lookupY + 1; + if (yTo < 0 || (request.lines - 1) * _t->_font->height < yTo) { + yTo = request.lines * _t->_font->height; + _elideLast = true; + _elideRemoveFromEnd = request.removeFromEnd; + } + draw(0, 0, w, _lookupRequest.align, _lookupY, _lookupY + 1); + } + } + return _lookupResult; } const QPen &blockPen(ITextBlock *block) { @@ -1288,34 +1283,44 @@ public: x += _wLeft; } - if (_getSymbol) { - if (_lnkX < x) { - if (_parDirection == Qt::RightToLeft) { - *_getSymbol = (_lineEnd > _lineStart) ? (_lineEnd - 1) : _lineStart; - *_getSymbolAfter = (_lineEnd > _lineStart) ? true : false; - *_getSymbolUpon = ((_lnkX >= _x) && (_lineEnd < _t->_text.size()) && (!_endBlock || _endBlock->type() != TextBlockTSkip)) ? true : false; - } else { - *_getSymbol = _lineStart; - *_getSymbolAfter = false; - *_getSymbolUpon = ((_lnkX >= _x) && (_lineStart > 0)) ? true : false; + if (!_p) { + if (_lookupX < x) { + if (_lookupSymbol) { + if (_parDirection == Qt::RightToLeft) { + _lookupResult.symbol = (_lineEnd > _lineStart) ? (_lineEnd - 1) : _lineStart; + _lookupResult.afterSymbol = (_lineEnd > _lineStart) ? true : false; +// _lookupResult.uponSymbol = ((_lookupX >= _x) && (_lineEnd < _t->_text.size()) && (!_endBlock || _endBlock->type() != TextBlockTSkip)) ? true : false; + } else { + _lookupResult.symbol = _lineStart; + _lookupResult.afterSymbol = false; +// _lookupResult.uponSymbol = ((_lookupX >= _x) && (_lineStart > 0)) ? true : false; + } } + if (_lookupLink) { + _lookupResult.link.clear(); + } + _lookupResult.uponSymbol = false; return false; - } else if (_lnkX >= x + (_w - _wLeft)) { + } else if (_lookupX >= x + (_w - _wLeft)) { if (_parDirection == Qt::RightToLeft) { - *_getSymbol = _lineStart; - *_getSymbolAfter = false; - *_getSymbolUpon = ((_lnkX < _x + _w) && (_lineStart > 0)) ? true : false; + _lookupResult.symbol = _lineStart; + _lookupResult.afterSymbol = false; +// _lookupResult.uponSymbol = ((_lookupX < _x + _w) && (_lineStart > 0)) ? true : false; } else { - *_getSymbol = (_lineEnd > _lineStart) ? (_lineEnd - 1) : _lineStart; - *_getSymbolAfter = (_lineEnd > _lineStart) ? true : false; - *_getSymbolUpon = ((_lnkX < _x + _w) && (_lineEnd < _t->_text.size()) && (!_endBlock || _endBlock->type() != TextBlockTSkip)) ? true : false; + _lookupResult.symbol = (_lineEnd > _lineStart) ? (_lineEnd - 1) : _lineStart; + _lookupResult.afterSymbol = (_lineEnd > _lineStart) ? true : false; +// _lookupResult.uponSymbol = ((_lookupX < _x + _w) && (_lineEnd < _t->_text.size()) && (!_endBlock || _endBlock->type() != TextBlockTSkip)) ? true : false; } + if (_lookupLink) { + _lookupResult.link.clear(); + } + _lookupResult.uponSymbol = false; return false; } } - bool selectFromStart = (_selectedTo > _lineStart) && (_lineStart > 0) && (_selectedFrom <= _lineStart); - bool selectTillEnd = (_selectedTo >= _lineEnd) && (_lineEnd < _t->_text.size()) && (_selectedFrom < _lineEnd) && (!_endBlock || _endBlock->type() != TextBlockTSkip); + bool selectFromStart = (_selection.to > _lineStart) && (_lineStart > 0) && (_selection.from <= _lineStart); + bool selectTillEnd = (_selection.to >= _lineEnd) && (_lineEnd < _t->_text.size()) && (_selection.from < _lineEnd) && (!_endBlock || _endBlock->type() != TextBlockTSkip); if ((selectFromStart && _parDirection == Qt::LeftToRight) || (selectTillEnd && _parDirection == Qt::RightToLeft)) { if (x > _x) { @@ -1409,52 +1414,48 @@ public: } if (si.analysis.flags >= QScriptAnalysis::TabOrObject) { TextBlockType _type = currentBlock->type(); - if (_lnkResult && _lnkX >= x && _lnkX < x + si.width) { - if (currentBlock->lnkIndex() && _lnkY >= _y + _yDelta && _lnkY < _y + _yDelta + _fontHeight) { - _lnkResult = &_t->_links.at(currentBlock->lnkIndex() - 1); - } - if (_inTextFlag && _type != TextBlockTSkip) { - *_inTextFlag = true; - } - return false; - } else if (_getSymbol && _lnkX >= x && _lnkX < x + si.width) { - if (_type == TextBlockTSkip) { - if (_parDirection == Qt::RightToLeft) { - *_getSymbol = _lineStart; - *_getSymbolAfter = false; - *_getSymbolUpon = false; - } else { - *_getSymbol = (trimmedLineEnd > _lineStart) ? (trimmedLineEnd - 1) : _lineStart; - *_getSymbolAfter = (trimmedLineEnd > _lineStart) ? true : false; - *_getSymbolUpon = false; + if (!_p && _lookupX >= x && _lookupX < x + si.width) { // _lookupRequest + if (_lookupLink) { + if (currentBlock->lnkIndex() && _lookupY >= _y + _yDelta && _lookupY < _y + _yDelta + _fontHeight) { + _lookupResult.link = _t->_links.at(currentBlock->lnkIndex() - 1); } - return false; } - const QChar *chFrom = _str + currentBlock->from(), *chTo = chFrom + ((nextBlock ? nextBlock->from() : _t->_text.size()) - currentBlock->from()); - if (chTo > chFrom && (chTo - 1)->unicode() == QChar::Space) { - if (rtl) { - if (_lnkX < x + (si.width - currentBlock->f_width())) { - *_getSymbol = (chTo - 1 - _str); // up to ending space, included, rtl - *_getSymbolAfter = (_lnkX < x + (si.width - currentBlock->f_width()) / 2) ? true : false; - *_getSymbolUpon = true; - return false; + if (_type != TextBlockTSkip) { + _lookupResult.uponSymbol = true; + } + if (_lookupSymbol) { + if (_type == TextBlockTSkip) { + if (_parDirection == Qt::RightToLeft) { + _lookupResult.symbol = _lineStart; + _lookupResult.afterSymbol = false; + } else { + _lookupResult.symbol = (trimmedLineEnd > _lineStart) ? (trimmedLineEnd - 1) : _lineStart; + _lookupResult.afterSymbol = (trimmedLineEnd > _lineStart) ? true : false; } - } else if (_lnkX >= x + currentBlock->f_width()) { - *_getSymbol = (chTo - 1 - _str); // up to ending space, inclided, ltr - *_getSymbolAfter = (_lnkX >= x + currentBlock->f_width() + (currentBlock->f_rpadding() / 2)) ? true : false; - *_getSymbolUpon = true; return false; } - --chTo; - } - if (_lnkX < x + (rtl ? (si.width - currentBlock->f_width()) : 0) + (currentBlock->f_width() / 2)) { - *_getSymbol = ((rtl && chTo > chFrom) ? (chTo - 1) : chFrom) - _str; - *_getSymbolAfter = (rtl && chTo > chFrom) ? true : false; - *_getSymbolUpon = true; - } else { - *_getSymbol = ((rtl || chTo <= chFrom) ? chFrom : (chTo - 1)) - _str; - *_getSymbolAfter = (rtl || chTo <= chFrom) ? false : true; - *_getSymbolUpon = true; + const QChar *chFrom = _str + currentBlock->from(), *chTo = chFrom + ((nextBlock ? nextBlock->from() : _t->_text.size()) - currentBlock->from()); + if (chTo > chFrom && (chTo - 1)->unicode() == QChar::Space) { + if (rtl) { + if (_lookupX < x + (si.width - currentBlock->f_width())) { + _lookupResult.symbol = (chTo - 1 - _str); // up to ending space, included, rtl + _lookupResult.afterSymbol = (_lookupX < x + (si.width - currentBlock->f_width()) / 2) ? true : false; + return false; + } + } else if (_lookupX >= x + currentBlock->f_width()) { + _lookupResult.symbol = (chTo - 1 - _str); // up to ending space, inclided, ltr + _lookupResult.afterSymbol = (_lookupX >= x + currentBlock->f_width() + (currentBlock->f_rpadding() / 2)) ? true : false; + return false; + } + --chTo; + } + if (_lookupX < x + (rtl ? (si.width - currentBlock->f_width()) : 0) + (currentBlock->f_width() / 2)) { + _lookupResult.symbol = ((rtl && chTo > chFrom) ? (chTo - 1) : chFrom) - _str; + _lookupResult.afterSymbol = (rtl && chTo > chFrom) ? true : false; + } else { + _lookupResult.symbol = ((rtl || chTo <= chFrom) ? chFrom : (chTo - 1)) - _str; + _lookupResult.afterSymbol = (rtl || chTo <= chFrom) ? false : true; + } } return false; } else if (_p && _type == TextBlockTEmoji) { @@ -1462,15 +1463,15 @@ public: if (rtl) { glyphX += (si.width - currentBlock->f_width()); } - if (_localFrom + si.position < _selectedTo) { + if (_localFrom + si.position < _selection.to) { const QChar *chFrom = _str + currentBlock->from(), *chTo = chFrom + ((nextBlock ? nextBlock->from() : _t->_text.size()) - currentBlock->from()); - if (_localFrom + si.position >= _selectedFrom) { // could be without space - if (chTo == chFrom || (chTo - 1)->unicode() != QChar::Space || _selectedTo >= (chTo - _str)) { + if (_localFrom + si.position >= _selection.from) { // could be without space + if (chTo == chFrom || (chTo - 1)->unicode() != QChar::Space || _selection.to >= (chTo - _str)) { _p->fillRect(QRectF(x.toReal(), _y + _yDelta, si.width.toReal(), _fontHeight), _textStyle->selectBg->b); } else { // or with space _p->fillRect(QRectF(glyphX.toReal(), _y + _yDelta, currentBlock->f_width().toReal(), _fontHeight), _textStyle->selectBg->b); } - } else if (chTo > chFrom && (chTo - 1)->unicode() == QChar::Space && (chTo - 1 - _str) >= _selectedFrom) { + } else if (chTo > chFrom && (chTo - 1)->unicode() == QChar::Space && (chTo - 1 - _str) >= _selection.from) { if (rtl) { // rtl space only _p->fillRect(QRectF(x.toReal(), _y + _yDelta, (glyphX - x).toReal(), _fontHeight), _textStyle->selectBg->b); } else { // ltr space only @@ -1504,54 +1505,52 @@ public: for (int g = glyphsStart; g < glyphsEnd; ++g) itemWidth += glyphs.effectiveAdvance(g); - if (_lnkResult && _lnkX >= x && _lnkX < x + itemWidth) { - if (currentBlock->lnkIndex() && _lnkY >= _y + _yDelta && _lnkY < _y + _yDelta + _fontHeight) { - _lnkResult = &_t->_links.at(currentBlock->lnkIndex() - 1); - } - if (_inTextFlag) { - *_inTextFlag = true; - } - return false; - } else if (_getSymbol && _lnkX >= x && _lnkX < x + itemWidth) { - QFixed tmpx = rtl ? (x + itemWidth) : x; - for (int ch = 0, g, itemL = itemEnd - itemStart; ch < itemL;) { - g = logClusters[itemStart - si.position + ch]; - QFixed gwidth = glyphs.effectiveAdvance(g); - // ch2 - glyph end, ch - glyph start, (ch2 - ch) - how much chars it takes - int ch2 = ch + 1; - while ((ch2 < itemL) && (g == logClusters[itemStart - si.position + ch2])) { - ++ch2; + if (!_p && _lookupX >= x && _lookupX < x + itemWidth) { // _lookupRequest + if (_lookupLink) { + if (currentBlock->lnkIndex() && _lookupY >= _y + _yDelta && _lookupY < _y + _yDelta + _fontHeight) { + _lookupResult.link = _t->_links.at(currentBlock->lnkIndex() - 1); } - for (int charsCount = (ch2 - ch); ch < ch2; ++ch) { - QFixed shift1 = QFixed(2 * (charsCount - (ch2 - ch)) + 2) * gwidth / QFixed(2 * charsCount), - shift2 = QFixed(2 * (charsCount - (ch2 - ch)) + 1) * gwidth / QFixed(2 * charsCount); - if ((rtl && _lnkX >= tmpx - shift1) || - (!rtl && _lnkX < tmpx + shift1)) { - *_getSymbol = _localFrom + itemStart + ch; - if ((rtl && _lnkX >= tmpx - shift2) || - (!rtl && _lnkX < tmpx + shift2)) { - *_getSymbolAfter = false; - } else { - *_getSymbolAfter = true; + } + _lookupResult.uponSymbol = true; + if (_lookupSymbol) { + QFixed tmpx = rtl ? (x + itemWidth) : x; + for (int ch = 0, g, itemL = itemEnd - itemStart; ch < itemL;) { + g = logClusters[itemStart - si.position + ch]; + QFixed gwidth = glyphs.effectiveAdvance(g); + // ch2 - glyph end, ch - glyph start, (ch2 - ch) - how much chars it takes + int ch2 = ch + 1; + while ((ch2 < itemL) && (g == logClusters[itemStart - si.position + ch2])) { + ++ch2; + } + for (int charsCount = (ch2 - ch); ch < ch2; ++ch) { + QFixed shift1 = QFixed(2 * (charsCount - (ch2 - ch)) + 2) * gwidth / QFixed(2 * charsCount), + shift2 = QFixed(2 * (charsCount - (ch2 - ch)) + 1) * gwidth / QFixed(2 * charsCount); + if ((rtl && _lookupX >= tmpx - shift1) || + (!rtl && _lookupX < tmpx + shift1)) { + _lookupResult.symbol = _localFrom + itemStart + ch; + if ((rtl && _lookupX >= tmpx - shift2) || + (!rtl && _lookupX < tmpx + shift2)) { + _lookupResult.afterSymbol = false; + } else { + _lookupResult.afterSymbol = true; + } + return false; } - *_getSymbolUpon = true; - return false; + } + if (rtl) { + tmpx -= gwidth; + } else { + tmpx += gwidth; } } - if (rtl) { - tmpx -= gwidth; + if (itemEnd > itemStart) { + _lookupResult.symbol = _localFrom + itemEnd - 1; + _lookupResult.afterSymbol = true; } else { - tmpx += gwidth; + _lookupResult.symbol = _localFrom + itemStart; + _lookupResult.afterSymbol = false; } } - if (itemEnd > itemStart) { - *_getSymbol = _localFrom + itemEnd - 1; - *_getSymbolAfter = true; - } else { - *_getSymbol = _localFrom + itemStart; - *_getSymbolAfter = false; - } - *_getSymbolUpon = true; return false; } else if (_p) { #ifndef TDESKTOP_WINRT // temp @@ -1564,12 +1563,12 @@ public: gf.justified = false; gf.initWithScriptItem(si); #endif // !TDESKTOP_WINRT - if (_localFrom + itemStart < _selectedTo && _localFrom + itemEnd > _selectedFrom) { + if (_localFrom + itemStart < _selection.to && _localFrom + itemEnd > _selection.from) { QFixed selX = x, selWidth = itemWidth; - if (_localFrom + itemEnd > _selectedTo || _localFrom + itemStart < _selectedFrom) { + if (_localFrom + itemEnd > _selection.to || _localFrom + itemStart < _selection.from) { selWidth = 0; int itemL = itemEnd - itemStart; - int selStart = _selectedFrom - (_localFrom + itemStart), selEnd = _selectedTo - (_localFrom + itemStart); + int selStart = _selection.from - (_localFrom + itemStart), selEnd = _selection.to - (_localFrom + itemStart); if (selStart < 0) selStart = 0; if (selEnd > itemL) selEnd = itemL; for (int ch = 0, g; ch < selEnd;) { @@ -1675,6 +1674,7 @@ public: if (_wLeft < si.width) { lineText = lineText.mid(0, currentBlock->from() - _localFrom) + _Elide; lineLength = currentBlock->from() + _Elide.size() - _lineStart; + _selection.to = std::min({ _selection.to, currentBlock->from() }); setElideBidi(currentBlock->from(), _Elide.size()); elideSaveBlock(blockIndex - 1, _endBlock, currentBlock->from(), elideWidth); return; @@ -1706,6 +1706,7 @@ public: if (lineText.size() <= pos || repeat > 3) { lineText += _Elide; lineLength = _localFrom + pos + _Elide.size() - _lineStart; + _selection.to = std::min({ _selection.to, uint16(_localFrom + pos) }); setElideBidi(_localFrom + pos, _Elide.size()); _blocksSize = blockIndex; _endBlock = nextBlock; @@ -1724,7 +1725,8 @@ public: } } - int32 elideStart = _lineStart + lineText.length(); + int32 elideStart = _localFrom + lineText.size(); + _selection.to = std::min({ _selection.to, uint16(elideStart) }); setElideBidi(elideStart, _Elide.size()); lineText += _Elide; @@ -2369,13 +2371,14 @@ private: QPainter *_p; const Text *_t; - bool _elideLast, _breakEverywhere; - int32 _elideRemoveFromEnd; + bool _elideLast = false; + bool _breakEverywhere = false; + int32 _elideRemoveFromEnd = 0; style::align _align; QPen _originalPen; int32 _yFrom, _yTo, _yToElide; - uint16 _selectedFrom, _selectedTo; - const QChar *_str; + TextSelection _selection = { 0, 0 }; + const QChar *_str = nullptr; // current paragraph data Text::TextBlocks::const_iterator _parStartBlock; @@ -2393,18 +2396,18 @@ private: // elided hack support int32 _blocksSize; int32 _elideSavedIndex; - ITextBlock *_elideSavedBlock; + ITextBlock *_elideSavedBlock = nullptr; int32 _lineStart, _localFrom; int32 _lineStartBlock; // link and symbol resolve - QFixed _lnkX; - int32 _lnkY; - const ClickHandlerPtr *_lnkResult; - bool *_inTextFlag; - uint16 *_getSymbol; - bool *_getSymbolAfter, *_getSymbolUpon; + QFixed _lookupX = 0; + int _lookupY = 0; + bool _lookupSymbol = false; + bool _lookupLink = false; + Text::StateRequest _lookupRequest; + Text::StateResult _lookupResult; }; @@ -2935,36 +2938,32 @@ void Text::replaceFont(style::font f) { _font = f; } -void Text::draw(QPainter &painter, int32 left, int32 top, int32 w, style::align align, int32 yFrom, int32 yTo, uint16 selectedFrom, uint16 selectedTo) const { +void Text::draw(QPainter &painter, int32 left, int32 top, int32 w, style::align align, int32 yFrom, int32 yTo, TextSelection selection) const { // painter.fillRect(QRect(left, top, w, countHeight(w)), QColor(0, 0, 0, 32)); // debug TextPainter p(&painter, this); - p.draw(left, top, w, align, yFrom, yTo, selectedFrom, selectedTo); + p.draw(left, top, w, align, yFrom, yTo, selection); } -void Text::drawElided(QPainter &painter, int32 left, int32 top, int32 w, int32 lines, style::align align, int32 yFrom, int32 yTo, int32 removeFromEnd, bool breakEverywhere) const { +void Text::drawElided(QPainter &painter, int32 left, int32 top, int32 w, int32 lines, style::align align, int32 yFrom, int32 yTo, int32 removeFromEnd, bool breakEverywhere, TextSelection selection) const { // painter.fillRect(QRect(left, top, w, countHeight(w)), QColor(0, 0, 0, 32)); // debug TextPainter p(&painter, this); - p.drawElided(left, top, w, align, lines, yFrom, yTo, removeFromEnd, breakEverywhere); + p.drawElided(left, top, w, align, lines, yFrom, yTo, removeFromEnd, breakEverywhere, selection); } -const ClickHandlerPtr &Text::link(int32 x, int32 y, int32 width, style::align align) const { +Text::StateResult Text::getState(int x, int y, int width, StateRequest request) const { TextPainter p(0, this); - return p.link(x, y, width, align); + return p.getState(x, y, width, request); } -void Text::getState(ClickHandlerPtr &lnk, bool &inText, int32 x, int32 y, int32 width, style::align align, bool breakEverywhere) const { +Text::StateResult Text::getStateElided(int x, int y, int width, StateRequestElided request) const { TextPainter p(0, this); - p.getState(lnk, inText, x, y, width, align, breakEverywhere); + return p.getStateElided(x, y, width, request); } -void Text::getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y, int32 width, style::align align) const { - TextPainter p(0, this); - p.getSymbol(symbol, after, upon, x, y, width, align); -} - -uint32 Text::adjustSelection(uint16 from, uint16 to, TextSelectType selectType) const { +TextSelection Text::adjustSelection(TextSelection selection, TextSelectType selectType) const { + uint16 from = selection.from, to = selection.to; if (from < _text.size() && from <= to) { - if (to > _text.size()) to = _text.size() - 1; + if (to > _text.size()) to = _text.size(); if (selectType == TextSelectParagraphs) { if (!chIsParagraphSeparator(_text.at(from))) { while (from > 0 && !chIsParagraphSeparator(_text.at(from - 1))) { @@ -2997,10 +2996,10 @@ uint32 Text::adjustSelection(uint16 from, uint16 to, TextSelectType selectType) } } } - return (from << 16) | to; + return { from, to }; } -QString Text::original(uint16 selectedFrom, uint16 selectedTo, ExpandLinksMode mode) const { +QString Text::original(TextSelection selection, ExpandLinksMode mode) const { QString result, emptyurl; result.reserve(_text.size()); @@ -3013,7 +3012,7 @@ QString Text::original(uint16 selectedFrom, uint16 selectedTo, ExpandLinksMode m const ClickHandlerPtr &lnk(_links.at(lnkIndex - 1)); const QString &url = (mode == ExpandLinksNone || !lnk) ? emptyurl : lnk->text(); - int32 rangeFrom = qMax(int32(selectedFrom), lnkFrom), rangeTo = qMin(blockFrom, int32(selectedTo)); + int32 rangeFrom = qMax(int32(selection.from), lnkFrom), rangeTo = qMin(blockFrom, int32(selection.to)); if (rangeTo > rangeFrom) { QStringRef r = _text.midRef(rangeFrom, rangeTo - rangeFrom); @@ -3043,7 +3042,7 @@ QString Text::original(uint16 selectedFrom, uint16 selectedTo, ExpandLinksMode m if (type == TextBlockTSkip) continue; if (!blockLnkIndex) { - int32 rangeFrom = qMax(selectedFrom, (*i)->from()), rangeTo = qMin(selectedTo, uint16((*i)->from() + TextPainter::_blockLength(this, i, e))); + int32 rangeFrom = qMax(selection.from, (*i)->from()), rangeTo = qMin(selection.to, uint16((*i)->from() + TextPainter::_blockLength(this, i, e))); if (rangeTo > rangeFrom) { result += _text.midRef(rangeFrom, rangeTo - rangeFrom); } diff --git a/Telegram/SourceFiles/ui/text.h b/Telegram/SourceFiles/ui/text.h index c890745f5..6f73c5dae 100644 --- a/Telegram/SourceFiles/ui/text.h +++ b/Telegram/SourceFiles/ui/text.h @@ -344,6 +344,23 @@ enum TextSelectType { TextSelectParagraphs = 0x03, }; +struct TextSelection { + constexpr TextSelection() : from(0), to(0) { + } + constexpr TextSelection(uint16 from, uint16 to) : from(from), to(to) { + } + uint16 from : 16; + uint16 to : 16; +}; +inline bool operator==(TextSelection a, TextSelection b) { + return a.from == b.from && a.to == b.to; +} +inline bool operator!=(TextSelection a, TextSelection b) { + return !(a == b); +} + +static constexpr TextSelection AllTextSelection = { 0, 0xFFFF }; + typedef QPair TextCustomTag; // open str and close str typedef QMap TextCustomTagsMap; @@ -381,34 +398,55 @@ public: void replaceFont(style::font f); // does not recount anything, use at your own risk! - void draw(QPainter &p, int32 left, int32 top, int32 width, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, uint16 selectedFrom = 0, uint16 selectedTo = 0) const; - void drawElided(QPainter &p, int32 left, int32 top, int32 width, int32 lines = 1, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, int32 removeFromEnd = 0, bool breakEverywhere = false) const; - void drawLeft(QPainter &p, int32 left, int32 top, int32 width, int32 outerw, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, uint16 selectedFrom = 0, uint16 selectedTo = 0) const { - draw(p, rtl() ? (outerw - left - width) : left, top, width, align, yFrom, yTo, selectedFrom, selectedTo); + void draw(QPainter &p, int32 left, int32 top, int32 width, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, TextSelection selection = { 0, 0 }) const; + void drawElided(QPainter &p, int32 left, int32 top, int32 width, int32 lines = 1, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, int32 removeFromEnd = 0, bool breakEverywhere = false, TextSelection selection = { 0, 0 }) const; + void drawLeft(QPainter &p, int32 left, int32 top, int32 width, int32 outerw, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, TextSelection selection = { 0, 0 }) const { + draw(p, rtl() ? (outerw - left - width) : left, top, width, align, yFrom, yTo, selection); } - void drawLeftElided(QPainter &p, int32 left, int32 top, int32 width, int32 outerw, int32 lines = 1, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, int32 removeFromEnd = 0, bool breakEverywhere = false) const { - drawElided(p, rtl() ? (outerw - left - width) : left, top, width, lines, align, yFrom, yTo, removeFromEnd, breakEverywhere); + void drawLeftElided(QPainter &p, int32 left, int32 top, int32 width, int32 outerw, int32 lines = 1, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, int32 removeFromEnd = 0, bool breakEverywhere = false, TextSelection selection = { 0, 0 }) const { + drawElided(p, rtl() ? (outerw - left - width) : left, top, width, lines, align, yFrom, yTo, removeFromEnd, breakEverywhere, selection); } - void drawRight(QPainter &p, int32 right, int32 top, int32 width, int32 outerw, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, uint16 selectedFrom = 0, uint16 selectedTo = 0) const { - draw(p, rtl() ? right : (outerw - right - width), top, width, align, yFrom, yTo, selectedFrom, selectedTo); + void drawRight(QPainter &p, int32 right, int32 top, int32 width, int32 outerw, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, TextSelection selection = { 0, 0 }) const { + draw(p, rtl() ? right : (outerw - right - width), top, width, align, yFrom, yTo, selection); } - void drawRightElided(QPainter &p, int32 right, int32 top, int32 width, int32 outerw, int32 lines = 1, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, int32 removeFromEnd = 0, bool breakEverywhere = false) const { - drawElided(p, rtl() ? right : (outerw - right - width), top, width, lines, align, yFrom, yTo, removeFromEnd, breakEverywhere); + void drawRightElided(QPainter &p, int32 right, int32 top, int32 width, int32 outerw, int32 lines = 1, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, int32 removeFromEnd = 0, bool breakEverywhere = false, TextSelection selection = { 0, 0 }) const { + drawElided(p, rtl() ? right : (outerw - right - width), top, width, lines, align, yFrom, yTo, removeFromEnd, breakEverywhere, selection); } - const ClickHandlerPtr &link(int32 x, int32 y, int32 width, style::align align = style::al_left) const; - const ClickHandlerPtr &linkLeft(int32 x, int32 y, int32 width, int32 outerw, style::align align = style::al_left) const { - return link(rtl() ? (outerw - x - width) : x, y, width, align); + struct StateRequest { + enum class Flag { + BreakEverywhere = 0x01, + LookupSymbol = 0x02, + LookupLink = 0x04, + }; + Q_DECLARE_FLAGS(Flags, Flag); + + style::align align = style::al_left; + Flags flags = Flag::LookupLink; + }; + struct StateResult { + ClickHandlerPtr link; + bool uponSymbol = false; + bool afterSymbol = false; + uint16 symbol = 0; + }; + StateResult getState(int x, int y, int width, StateRequest request = StateRequest()) const; + StateResult getStateLeft(int x, int y, int width, int outerw, StateRequest request = StateRequest()) const { + return getState(rtl() ? (outerw - x - width) : x, y, width, request); } - void getState(ClickHandlerPtr &lnk, bool &inText, int32 x, int32 y, int32 width, style::align align = style::al_left, bool breakEverywhere = false) const; - void getStateLeft(ClickHandlerPtr &lnk, bool &inText, int32 x, int32 y, int32 width, int32 outerw, style::align align = style::al_left, bool breakEverywhere = false) const { - return getState(lnk, inText, rtl() ? (outerw - x - width) : x, y, width, align, breakEverywhere); + struct StateRequestElided : public StateRequest { + StateRequestElided() = default; + StateRequestElided(const StateRequest &other) : StateRequest(other) { + } + int lines = 1; + int removeFromEnd = 0; + }; + StateResult getStateElided(int x, int y, int width, StateRequestElided request = StateRequestElided()) const; + StateResult getStateElidedLeft(int x, int y, int width, int outerw, StateRequestElided request = StateRequestElided()) const { + return getStateElided(rtl() ? (outerw - x - width) : x, y, width, request); } - void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y, int32 width, style::align align = style::al_left) const; - void getSymbolLeft(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y, int32 width, int32 outerw, style::align align = style::al_left) const { - return getSymbol(symbol, after, upon, rtl() ? (outerw - x - width) : x, y, width, align); - } - uint32 adjustSelection(uint16 from, uint16 to, TextSelectType selectType) const; + + TextSelection adjustSelection(TextSelection selection, TextSelectType selectType) const; bool isEmpty() const { return _text.isEmpty(); @@ -416,12 +454,15 @@ public: bool isNull() const { return !_font; } + int length() const { + return _text.size(); + } enum ExpandLinksMode { ExpandLinksNone, ExpandLinksShortened, ExpandLinksAll, }; - QString original(uint16 selectedFrom = 0, uint16 selectedTo = 0xFFFF, ExpandLinksMode mode = ExpandLinksShortened) const; + QString original(TextSelection selection = { 0, 0xFFFF }, ExpandLinksMode mode = ExpandLinksShortened) const; EntitiesInText originalEntities() const; bool lastDots(int32 dots, int32 maxdots = 3) { // hack for typing animation @@ -474,6 +515,17 @@ private: friend class TextPainter; }; +inline TextSelection snapSelection(int from, int to) { + return { static_cast(snap(from, 0, 0xFFFF)), static_cast(snap(to, 0, 0xFFFF)) }; +} +inline TextSelection shiftSelection(TextSelection selection, const Text &byText) { + int len = byText.length(); + return snapSelection(int(selection.from) + len, int(selection.to) + len); +} +inline TextSelection unshiftSelection(TextSelection selection, const Text &byText) { + int len = byText.length(); + return snapSelection(int(selection.from) - len, int(selection.to) - len); +} void initLinkSets(); const QSet &validProtocols(); From 68a9a0a12e7023bb963f0ec170a8a8326c55ca29 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 14 Apr 2016 14:00:23 +0300 Subject: [PATCH 05/14] Text copy from HistoryItem/HistoryMedia/combined is done and tested. Moved text module to ui/text/ and split it to several modules. Xcode build currently broken. --- Telegram/SourceFiles/dialogs/dialogs_row.h | 2 +- Telegram/SourceFiles/history.cpp | 198 +- Telegram/SourceFiles/history.h | 56 +- Telegram/SourceFiles/historywidget.cpp | 2 +- .../inline_bots/inline_bot_layout_internal.h | 2 +- .../inline_bots/inline_bot_layout_item.h | 2 +- Telegram/SourceFiles/intro/introwidget.cpp | 2 +- Telegram/SourceFiles/passcodewidget.cpp | 2 +- Telegram/SourceFiles/stdafx.h | 2 +- Telegram/SourceFiles/ui/emoji_config.h | 2 +- Telegram/SourceFiles/ui/popupmenu.h | 2 +- Telegram/SourceFiles/ui/{ => text}/text.cpp | 2087 +---------------- Telegram/SourceFiles/ui/{ => text}/text.h | 398 +--- Telegram/SourceFiles/ui/text/text_block.cpp | 322 +++ Telegram/SourceFiles/ui/text/text_block.h | 214 ++ Telegram/SourceFiles/ui/text/text_entity.cpp | 1919 +++++++++++++++ Telegram/SourceFiles/ui/text/text_entity.h | 85 + Telegram/SourceFiles/ui/toast/toast_widget.h | 2 +- Telegram/Telegram.pro | 8 +- Telegram/Telegram.vcxproj | 8 +- Telegram/Telegram.vcxproj.filters | 27 +- Telegram/Telegram.xcodeproj/project.pbxproj | 4 +- 22 files changed, 2781 insertions(+), 2565 deletions(-) rename Telegram/SourceFiles/ui/{ => text}/text.cpp (58%) rename Telegram/SourceFiles/ui/{ => text}/text.h (51%) create mode 100644 Telegram/SourceFiles/ui/text/text_block.cpp create mode 100644 Telegram/SourceFiles/ui/text/text_block.h create mode 100644 Telegram/SourceFiles/ui/text/text_entity.cpp create mode 100644 Telegram/SourceFiles/ui/text/text_entity.h diff --git a/Telegram/SourceFiles/dialogs/dialogs_row.h b/Telegram/SourceFiles/dialogs/dialogs_row.h index 88dd3ca6f..45180f4ff 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_row.h +++ b/Telegram/SourceFiles/dialogs/dialogs_row.h @@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #pragma once -#include "ui/text.h" +#include "ui/text/text.h" class History; class HistoryItem; diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index 930d7c65e..e4afd330a 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -2944,6 +2944,24 @@ void HistoryMediaPtr::reset(HistoryMedia *p) { } } +namespace internal { + +TextSelection unshiftSelection(TextSelection selection, const Text &byText) { + if (selection == FullSelection) { + return selection; + } + return ::unshiftSelection(selection, byText); +} + +TextSelection shiftSelection(TextSelection selection, const Text &byText) { + if (selection == FullSelection) { + return selection; + } + return ::shiftSelection(selection, byText); +} + +} // namespace internal + HistoryItem::HistoryItem(History *history, MsgId msgId, MTPDmessage::Flags flags, QDateTime msgDate, int32 from) : HistoryElem() , y(0) , id(msgId) @@ -3242,29 +3260,43 @@ void RadialAnimation::draw(Painter &p, const QRect &inner, int32 thickness, cons } namespace { - int32 documentMaxStatusWidth(DocumentData *document) { - int32 result = st::normalFont->width(formatDownloadText(document->size, document->size)); - if (SongData *song = document->song()) { - result = qMax(result, st::normalFont->width(formatPlayedText(song->duration, song->duration))); - result = qMax(result, st::normalFont->width(formatDurationAndSizeText(song->duration, document->size))); - } else if (VoiceData *voice = document->voice()) { - result = qMax(result, st::normalFont->width(formatPlayedText(voice->duration, voice->duration))); - result = qMax(result, st::normalFont->width(formatDurationAndSizeText(voice->duration, document->size))); - } else if (document->isVideo()) { - result = qMax(result, st::normalFont->width(formatDurationAndSizeText(document->duration(), document->size))); - } else { - result = qMax(result, st::normalFont->width(formatSizeText(document->size))); - } - return result; - } - int32 gifMaxStatusWidth(DocumentData *document) { - int32 result = st::normalFont->width(formatDownloadText(document->size, document->size)); - result = qMax(result, st::normalFont->width(formatGifAndSizeText(document->size))); - return result; +int32 documentMaxStatusWidth(DocumentData *document) { + int32 result = st::normalFont->width(formatDownloadText(document->size, document->size)); + if (SongData *song = document->song()) { + result = qMax(result, st::normalFont->width(formatPlayedText(song->duration, song->duration))); + result = qMax(result, st::normalFont->width(formatDurationAndSizeText(song->duration, document->size))); + } else if (VoiceData *voice = document->voice()) { + result = qMax(result, st::normalFont->width(formatPlayedText(voice->duration, voice->duration))); + result = qMax(result, st::normalFont->width(formatDurationAndSizeText(voice->duration, document->size))); + } else if (document->isVideo()) { + result = qMax(result, st::normalFont->width(formatDurationAndSizeText(document->duration(), document->size))); + } else { + result = qMax(result, st::normalFont->width(formatSizeText(document->size))); } + return result; } +int32 gifMaxStatusWidth(DocumentData *document) { + int32 result = st::normalFont->width(formatDownloadText(document->size, document->size)); + result = qMax(result, st::normalFont->width(formatGifAndSizeText(document->size))); + return result; +} + +QString captionedSelectedText(const QString &attachType, const Text &caption, TextSelection selection) { + if (selection != FullSelection) { + return caption.original(selection, Text::ExpandLinksAll); + } + QString result; + result.reserve(5 + attachType.size() + caption.length()); + result.append(qstr("[ ")).append(attachType).append(qstr(" ]")); + if (!caption.isEmpty()) { + result.append(qstr("\n")).append(caption.original(AllTextSelection)); + } + return result; +} +} // namespace + void HistoryFileMedia::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { if (p == _savel || p == _cancell) { if (active && !dataLoaded()) { @@ -3681,12 +3713,12 @@ void HistoryPhoto::detachFromParent() { App::unregPhotoItem(_data, _parent); } -const QString HistoryPhoto::inDialogsText() const { +QString HistoryPhoto::inDialogsText() const { return _caption.isEmpty() ? lang(lng_in_dlg_photo) : _caption.original(AllTextSelection, Text::ExpandLinksNone); } -const QString HistoryPhoto::inHistoryText() const { - return qsl("[ ") + lang(lng_in_dlg_photo) + (_caption.isEmpty() ? QString() : (qsl(", ") + _caption.original(AllTextSelection, Text::ExpandLinksAll))) + qsl(" ]"); +QString HistoryPhoto::selectedText(TextSelection selection) const { + return captionedSelectedText(lang(lng_in_dlg_photo), _caption, selection); } ImagePtr HistoryPhoto::replyPreview() { @@ -3902,7 +3934,7 @@ HistoryTextState HistoryVideo::getState(int x, int y, HistoryStateRequest reques int32 captionw = width - st::msgPadding.left() - st::msgPadding.right(); height -= _caption.countHeight(captionw) + st::msgPadding.bottom(); if (x >= st::msgPadding.left() && y >= height && x < st::msgPadding.left() + captionw && y < _height) { - result = _caption.getState(x - st::msgPadding.left(), y - height, captionw); + result = _caption.getState(x - st::msgPadding.left(), y - height, captionw, request.forText()); } height -= st::mediaCaptionSkip; } @@ -3927,12 +3959,12 @@ void HistoryVideo::setStatusSize(int32 newSize) const { HistoryFileMedia::setStatusSize(newSize, _data->size, _data->duration(), 0); } -const QString HistoryVideo::inDialogsText() const { +QString HistoryVideo::inDialogsText() const { return _caption.isEmpty() ? lang(lng_in_dlg_video) : _caption.original(AllTextSelection, Text::ExpandLinksNone); } -const QString HistoryVideo::inHistoryText() const { - return qsl("[ ") + lang(lng_in_dlg_video) + (_caption.isEmpty() ? QString() : (qsl(", ") + _caption.original(AllTextSelection, Text::ExpandLinksAll))) + qsl(" ]"); +QString HistoryVideo::selectedText(TextSelection selection) const { + return captionedSelectedText(lang(lng_in_dlg_video), _caption, selection); } void HistoryVideo::updateStatusText() const { @@ -4404,7 +4436,7 @@ HistoryTextState HistoryDocument::getState(int x, int y, HistoryStateRequest req return result; } -const QString HistoryDocument::inDialogsText() const { +QString HistoryDocument::inDialogsText() const { QString result; if (Has()) { result = lang(lng_in_dlg_audio); @@ -4425,26 +4457,24 @@ const QString HistoryDocument::inDialogsText() const { return result; } -const QString HistoryDocument::inHistoryText() const { - QString result; +QString HistoryDocument::selectedText(TextSelection selection) const { + const Text emptyCaption; + const Text *caption = &emptyCaption; + if (auto captioned = Get()) { + caption = &captioned->_caption; + } + QString attachType = lang(lng_in_dlg_file); if (Has()) { - result = lang(lng_in_dlg_audio); + attachType = lang(lng_in_dlg_audio); } else if (_data->song()) { - result = lang(lng_in_dlg_audio_file); - } else { - result = lang(lng_in_dlg_file); + attachType = lang(lng_in_dlg_audio_file); } if (auto named = Get()) { if (!named->_name.isEmpty()) { - result.append(qsl(" : ")).append(named->_name); + attachType.append(qstr(" : ")).append(named->_name); } } - if (auto captioned = Get()) { - if (!captioned->_caption.isEmpty()) { - result.append(qsl(", ")).append(captioned->_caption.original(AllTextSelection, Text::ExpandLinksAll)); - } - } - return qsl("[ ") + result.append(qsl(" ]")); + return captionedSelectedText(attachType, *caption, selection); } void HistoryDocument::setStatusSize(int32 newSize, qint64 realDuration) const { @@ -4878,12 +4908,12 @@ HistoryTextState HistoryGif::getState(int x, int y, HistoryStateRequest request) return result; } -const QString HistoryGif::inDialogsText() const { +QString HistoryGif::inDialogsText() const { return qsl("GIF") + (_caption.isEmpty() ? QString() : (' ' + _caption.original(AllTextSelection, Text::ExpandLinksNone))); } -const QString HistoryGif::inHistoryText() const { - return qsl("[ GIF ") + (_caption.isEmpty() ? QString() : (_caption.original(AllTextSelection, Text::ExpandLinksAll) + ' ')) + qsl(" ]"); +QString HistoryGif::selectedText(TextSelection selection) const { + return captionedSelectedText(qsl("GIF"), _caption, selection); } void HistoryGif::setStatusSize(int32 newSize) const { @@ -5195,11 +5225,14 @@ HistoryTextState HistorySticker::getState(int x, int y, HistoryStateRequest requ return result; } -const QString HistorySticker::inDialogsText() const { +QString HistorySticker::inDialogsText() const { return _emoji.isEmpty() ? lang(lng_in_dlg_sticker) : lng_in_dlg_sticker_emoji(lt_emoji, _emoji); } -const QString HistorySticker::inHistoryText() const { +QString HistorySticker::selectedText(TextSelection selection) const { + if (selection != FullSelection) { + return QString(); + } return qsl("[ ") + inDialogsText() + qsl(" ]"); } @@ -5377,12 +5410,15 @@ HistoryTextState HistoryContact::getState(int x, int y, HistoryStateRequest requ return result; } -const QString HistoryContact::inDialogsText() const { +QString HistoryContact::inDialogsText() const { return lang(lng_in_dlg_contact); } -const QString HistoryContact::inHistoryText() const { - return qsl("[ ") + lang(lng_in_dlg_contact) + qsl(" : ") + _name.original() + qsl(", ") + _phone + qsl(" ]"); +QString HistoryContact::selectedText(TextSelection selection) const { + if (selection != FullSelection) { + return QString(); + } + return qsl("[ ") + lang(lng_in_dlg_contact) + qsl(" ]\n") + _name.original() + '\n' + _phone; } void HistoryContact::attachToParent() { @@ -5895,12 +5931,22 @@ void HistoryWebPage::detachFromParent() { if (_attach) _attach->detachFromParent(); } -const QString HistoryWebPage::inDialogsText() const { +QString HistoryWebPage::inDialogsText() const { return QString(); } -const QString HistoryWebPage::inHistoryText() const { - return QString(); +QString HistoryWebPage::selectedText(TextSelection selection) const { + if (selection == FullSelection) { + return QString(); + } + auto titleResult = _title.original(selection, Text::ExpandLinksAll); + auto descriptionResult = _description.original(toDescriptionSelection(selection), Text::ExpandLinksAll); + if (titleResult.isEmpty()) { + return descriptionResult; + } else if (descriptionResult.isEmpty()) { + return titleResult; + } + return titleResult + '\n' + descriptionResult; } ImagePtr HistoryWebPage::replyPreview() { @@ -6263,6 +6309,7 @@ void HistoryLocation::draw(Painter &p, const QRect &r, TextSelection selection, HistoryTextState HistoryLocation::getState(int x, int y, HistoryStateRequest request) const { HistoryTextState result; + auto symbolAdd = 0; if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return result; int32 skipx = 0, skipy = 0, width = _width, height = _height; @@ -6286,6 +6333,8 @@ HistoryTextState HistoryLocation::getState(int x, int y, HistoryStateRequest req if (y >= skipy && y < skipy + titleh) { result = _title.getStateLeft(x - skipx - st::msgPadding.left(), y - skipy, textw, _width, request.forText()); return result; + } else if (y >= skipy + titleh) { + symbolAdd += _title.length(); } skipy += titleh; } @@ -6293,8 +6342,8 @@ HistoryTextState HistoryLocation::getState(int x, int y, HistoryStateRequest req auto descriptionh = qMin(_description.countHeight(textw), 3 * st::webPageDescriptionFont->height); if (y >= skipy && y < skipy + descriptionh) { result = _description.getStateLeft(x - skipx - st::msgPadding.left(), y - skipy, textw, _width, request.forText()); - if (!_title.isEmpty()) result.symbol += _title.length(); - return result; + } else if (y >= skipy + descriptionh) { + symbolAdd += _description.length(); } skipy += descriptionh; } @@ -6311,9 +6360,8 @@ HistoryTextState HistoryLocation::getState(int x, int y, HistoryStateRequest req if (inDate) { result.cursor = HistoryInDateCursorState; } - - return result; } + result.symbol += symbolAdd; return result; } @@ -6329,12 +6377,25 @@ TextSelection HistoryLocation::adjustSelection(TextSelection selection, TextSele return { titleSelection.from, fromDescriptionSelection(descriptionSelection).to }; } -const QString HistoryLocation::inDialogsText() const { - return lang(lng_maps_point); +QString HistoryLocation::inDialogsText() const { + return _title.isEmpty() ? lang(lng_maps_point) : _title.original(AllTextSelection); } -const QString HistoryLocation::inHistoryText() const { - return qsl("[ ") + lang(lng_maps_point) + qsl(" : ") + _link->text() + qsl(" ]"); +QString HistoryLocation::selectedText(TextSelection selection) const { + if (selection == FullSelection) { + auto result = qsl("[ ") + lang(lng_maps_point) + qsl(" ]\n"); + auto info = selectedText(AllTextSelection); + if (!info.isEmpty()) result.append(info).append('\n'); + return result + _link->text(); + } + auto titleResult = _title.original(selection); + auto descriptionResult = _description.original(toDescriptionSelection(selection)); + if (titleResult.isEmpty()) { + return descriptionResult; + } else if (descriptionResult.isEmpty()) { + return titleResult; + } + return titleResult + '\n' + descriptionResult; } int32 HistoryLocation::fullWidth() const { @@ -7044,12 +7105,21 @@ void HistoryMessage::eraseFromOverview() { } QString HistoryMessage::selectedText(TextSelection selection) const { - QString result; - if (_media && selection == FullSelection) { - QString text = _text.original(AllTextSelection, Text::ExpandLinksAll), mediaText = _media->inHistoryText(); - result = text.isEmpty() ? mediaText : (mediaText.isEmpty() ? text : (text + ' ' + mediaText)); + QString result, textResult, mediaResult; + if (selection == FullSelection) { + textResult = _text.original(AllTextSelection, Text::ExpandLinksAll); } else { - result = _text.original((selection == FullSelection) ? AllTextSelection : selection, Text::ExpandLinksAll); + textResult = _text.original(selection, Text::ExpandLinksAll); + } + if (_media) { + mediaResult = _media->selectedText(toMediaSelection(selection)); + } + if (textResult.isEmpty()) { + result = mediaResult; + } else if (mediaResult.isEmpty()) { + result = textResult; + } else { + result = textResult + qstr("\n\n") + mediaResult; } if (auto fwd = Get()) { if (selection == FullSelection) { diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index d60c855f6..68acef5d3 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -1082,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 { public: @@ -1539,10 +1547,10 @@ protected: } TextSelection toMediaSelection(TextSelection selection) const { - return unshiftSelection(selection, _text); + return internal::unshiftSelection(selection, _text); } TextSelection fromMediaSelection(TextSelection selection) const { - return shiftSelection(selection, _text); + return internal::shiftSelection(selection, _text); } Text _text = { int(st::msgMinWidth) }; @@ -1640,8 +1648,8 @@ public: HistoryMedia &operator=(const HistoryMedia &other) = delete; virtual HistoryMediaType type() const = 0; - virtual const QString inDialogsText() const = 0; - virtual const QString inHistoryText() const = 0; + virtual QString inDialogsText() const = 0; + virtual QString selectedText(TextSelection selection) const = 0; bool hasPoint(int x, int y) const { return (x >= 0 && y >= 0 && x < _width && y < _height); @@ -1871,8 +1879,8 @@ public: return _caption.adjustSelection(selection, type); } - const QString inDialogsText() const override; - const QString inHistoryText() const override; + QString inDialogsText() const override; + QString selectedText(TextSelection selection) const override; PhotoData *photo() const { return _data; @@ -1948,8 +1956,8 @@ public: return _caption.adjustSelection(selection, type); } - const QString inDialogsText() const override; - const QString inHistoryText() const override; + QString inDialogsText() const override; + QString selectedText(TextSelection selection) const override; DocumentData *getDocument() override { return _data; @@ -2068,8 +2076,8 @@ public: return selection; } - const QString inDialogsText() const override; - const QString inHistoryText() const override; + QString inDialogsText() const override; + QString selectedText(TextSelection selection) const override; bool uploading() const override { return _data->uploading(); @@ -2152,8 +2160,8 @@ public: return _caption.adjustSelection(selection, type); } - const QString inDialogsText() const override; - const QString inHistoryText() const override; + QString inDialogsText() const override; + QString selectedText(TextSelection selection) const override; bool uploading() const override { return _data->uploading(); @@ -2250,8 +2258,8 @@ public: return true; } - const QString inDialogsText() const override; - const QString inHistoryText() const override; + QString inDialogsText() const override; + QString selectedText(TextSelection selection) const override; DocumentData *getDocument() override { return _data; @@ -2319,8 +2327,8 @@ public: return true; } - const QString inDialogsText() const override; - const QString inHistoryText() const override; + QString inDialogsText() const override; + QString selectedText(TextSelection selection) const override; void attachToParent() override; void detachFromParent() override; @@ -2384,8 +2392,8 @@ public: return _attach && _attach->dragItemByHandler(p); } - const QString inDialogsText() const override; - const QString inHistoryText() const override; + QString inDialogsText() const override; + QString selectedText(TextSelection selection) const override; void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override; void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override; @@ -2433,10 +2441,10 @@ public: private: TextSelection toDescriptionSelection(TextSelection selection) const { - return unshiftSelection(selection, _title); + return internal::unshiftSelection(selection, _title); } TextSelection fromDescriptionSelection(TextSelection selection) const { - return shiftSelection(selection, _title); + return internal::shiftSelection(selection, _title); } WebPageData *_data; @@ -2515,8 +2523,8 @@ public: return p == _link; } - const QString inDialogsText() const override; - const QString inHistoryText() const override; + QString inDialogsText() const override; + QString selectedText(TextSelection selection) const override; bool needsBubble() const override { if (!_title.isEmpty() || !_description.isEmpty()) { @@ -2533,10 +2541,10 @@ public: private: TextSelection toDescriptionSelection(TextSelection selection) const { - return unshiftSelection(selection, _title); + return internal::unshiftSelection(selection, _title); } TextSelection fromDescriptionSelection(TextSelection selection) const { - return shiftSelection(selection, _title); + return internal::shiftSelection(selection, _title); } LocationData *_data; diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 2c3aa309d..c5556bb25 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -1066,7 +1066,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { } } 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); } } diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h index e61c975e3..e36bcc3c5 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h @@ -21,7 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #pragma once #include "inline_bots/inline_bot_layout_item.h" -#include "ui/text.h" +#include "ui/text/text.h" namespace InlineBots { namespace Layout { diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.h b/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.h index 0c091845b..ddd606f62 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.h +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.h @@ -22,7 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "layout.h" #include "structs.h" -#include "ui/text.h" +#include "ui/text/text.h" namespace InlineBots { class Result; diff --git a/Telegram/SourceFiles/intro/introwidget.cpp b/Telegram/SourceFiles/intro/introwidget.cpp index d79f80e0c..5ec5c9ad6 100644 --- a/Telegram/SourceFiles/intro/introwidget.cpp +++ b/Telegram/SourceFiles/intro/introwidget.cpp @@ -33,7 +33,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "mainwidget.h" #include "mainwindow.h" #include "application.h" -#include "ui/text.h" +#include "ui/text/text.h" namespace { IntroWidget *signalEmitOn = 0; diff --git a/Telegram/SourceFiles/passcodewidget.cpp b/Telegram/SourceFiles/passcodewidget.cpp index 95aa4871d..b8e932f0f 100644 --- a/Telegram/SourceFiles/passcodewidget.cpp +++ b/Telegram/SourceFiles/passcodewidget.cpp @@ -27,7 +27,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "passcodewidget.h" #include "mainwindow.h" #include "application.h" -#include "ui/text.h" +#include "ui/text/text.h" PasscodeWidget::PasscodeWidget(QWidget *parent) : TWidget(parent) , _a_show(animation(this, &PasscodeWidget::step_show)) diff --git a/Telegram/SourceFiles/stdafx.h b/Telegram/SourceFiles/stdafx.h index db0521fb8..d8affc31f 100644 --- a/Telegram/SourceFiles/stdafx.h +++ b/Telegram/SourceFiles/stdafx.h @@ -46,7 +46,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "ui/popupmenu.h" #include "ui/scrollarea.h" #include "ui/images.h" -#include "ui/text.h" +#include "ui/text/text.h" #include "ui/flatlabel.h" #include "app.h" diff --git a/Telegram/SourceFiles/ui/emoji_config.h b/Telegram/SourceFiles/ui/emoji_config.h index 90802596f..f7e6c2597 100644 --- a/Telegram/SourceFiles/ui/emoji_config.h +++ b/Telegram/SourceFiles/ui/emoji_config.h @@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #pragma once -#include "ui/text.h" +#include "ui/text/text.h" void emojiInit(); EmojiPtr emojiGet(uint32 code); diff --git a/Telegram/SourceFiles/ui/popupmenu.h b/Telegram/SourceFiles/ui/popupmenu.h index 64ff31fb6..ccc1e8cfb 100644 --- a/Telegram/SourceFiles/ui/popupmenu.h +++ b/Telegram/SourceFiles/ui/popupmenu.h @@ -17,7 +17,7 @@ */ #pragma once -#include "text.h" +#include "ui/text/text.h" class PopupMenu : public TWidget { Q_OBJECT diff --git a/Telegram/SourceFiles/ui/text.cpp b/Telegram/SourceFiles/ui/text/text.cpp similarity index 58% rename from Telegram/SourceFiles/ui/text.cpp rename to Telegram/SourceFiles/ui/text/text.cpp index b47ae3388..ff9915df3 100644 --- a/Telegram/SourceFiles/ui/text.cpp +++ b/Telegram/SourceFiles/ui/text/text.cpp @@ -19,11 +19,12 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #include "stdafx.h" -#include "text.h" +#include "ui/text/text.h" #include #include "core/click_handler_types.h" +#include "ui/text/text_block.h" #include "lang.h" #include "pspecific.h" #include "boxes/confirmbox.h" @@ -31,51 +32,21 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org namespace { - const QRegularExpression _reDomain(QString::fromUtf8("(?|'\"\\[\\]\\{\\}`\\~\\!\\%\\^\\*\\(\\)\\-\\+=\\x10])#[\\w]{2,64}([\\W]|$)"), QRegularExpression::UseUnicodePropertiesOption); - const QRegularExpression _reMention(qsl("(^|[\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\%\\^\\*\\(\\)\\-\\+=\\x10])@[A-Za-z_0-9]{1,32}([\\W]|$)"), QRegularExpression::UseUnicodePropertiesOption); - const QRegularExpression _reBotCommand(qsl("(^|[\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\%\\^\\*\\(\\)\\-\\+=\\x10])/[A-Za-z_0-9]{1,64}(@[A-Za-z_0-9]{5,32})?([\\W]|$)")); - const QRegularExpression _rePre(qsl("(^|[\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\?\\%\\^\\*\\(\\)\\-\\+=\\x10])(````?)[\\s\\S]+?(````?)([\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\?\\%\\^\\*\\(\\)\\-\\+=\\x10]|$)"), QRegularExpression::UseUnicodePropertiesOption); - const QRegularExpression _reCode(qsl("(^|[\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\?\\%\\^\\*\\(\\)\\-\\+=\\x10])(`)[^\\n]+?(`)([\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\?\\%\\^\\*\\(\\)\\-\\+=\\x10]|$)"), QRegularExpression::UseUnicodePropertiesOption); - QSet _validProtocols, _validTopDomains; +const style::textStyle *_textStyle = nullptr; - const style::textStyle *_textStyle = 0; - - void _initDefault() { - _textStyle = &st::defaultTextStyle; - } - - inline int32 _blockHeight(const ITextBlock *b, const style::font &font) { - return (b->type() == TextBlockTSkip) ? static_cast(b)->height() : (_textStyle->lineHeight > font->height) ? _textStyle->lineHeight : font->height; - } - - inline QFixed _blockRBearing(const ITextBlock *b) { - return (b->type() == TextBlockTText) ? static_cast(b)->f_rbearing() : 0; - } +void _initDefault() { + _textStyle = &st::defaultTextStyle; } -const QRegularExpression &reDomain() { - return _reDomain; +inline int32 _blockHeight(const ITextBlock *b, const style::font &font) { + return (b->type() == TextBlockTSkip) ? static_cast(b)->height() : (_textStyle->lineHeight > font->height) ? _textStyle->lineHeight : font->height; } -const QRegularExpression &reMailName() { - return _reMailName; +inline QFixed _blockRBearing(const ITextBlock *b) { + return (b->type() == TextBlockTText) ? static_cast(b)->f_rbearing() : 0; } -const QRegularExpression &reMailStart() { - return _reMailStart; -} - -const QRegularExpression &reHashtag() { - return _reHashtag; -} - -const QRegularExpression &reBotCommand() { - return _reBotCommand; -} +} // namespace const style::textStyle *textstyleCurrent() { return _textStyle; @@ -85,60 +56,6 @@ void textstyleSet(const style::textStyle *style) { _textStyle = style ? style : &st::defaultTextStyle; } -QString textOneLine(const QString &text, bool trim, bool rich) { - QString result(text); - const QChar *s = text.unicode(), *ch = s, *e = text.unicode() + text.size(); - if (trim) { - while (s < e && chIsTrimmed(*s)) { - ++s; - } - while (s < e && chIsTrimmed(*(e - 1))) { - --e; - } - if (e - s != text.size()) { - result = text.mid(s - text.unicode(), e - s); - } - } - for (const QChar *ch = s; ch != e; ++ch) { - if (chIsNewline(*ch)) { - result[int(ch - s)] = QChar::Space; - } - } - return result; -} - -QString textClean(const QString &text) { - QString result(text); - for (const QChar *s = text.unicode(), *ch = s, *e = text.unicode() + text.size(); ch != e; ++ch) { - if (*ch == TextCommand) { - result[int(ch - s)] = QChar::Space; - } - } - return result; -} - -QString textRichPrepare(const QString &text) { - QString result; - result.reserve(text.size()); - const QChar *s = text.constData(), *ch = s; - for (const QChar *e = s + text.size(); ch != e; ++ch) { - if (*ch == TextCommand) { - if (ch > s) result.append(s, ch - s); - result.append(QChar::Space); - s = ch + 1; - continue; - } - if (ch->unicode() == '\\' || ch->unicode() == '[') { - if (ch > s) result.append(s, ch - s); - result.append('\\'); - s = ch; - continue; - } - } - if (ch > s) result.append(s, ch - s); - return result; -} - QString textcmdSkipBlock(ushort w, ushort h) { static QString cmd(5, TextCommand); cmd[1] = QChar(TextCommandSkipBlock); @@ -339,7 +256,7 @@ public: } else if (!original.isEmpty() && original.at(0) == '#') { result = original; fullDisplayed = -2; // hashtag - } else if (_reMailStart.match(original).hasMatch()) { + } else if (reMailStart().match(original).hasMatch()) { result = original; fullDisplayed = -1; // email } else { @@ -2695,6 +2612,10 @@ bool Text::hasLinks() const { return !_links.isEmpty(); } +bool Text::hasSkipBlock() const { + return _blocks.isEmpty() ? false : _blocks.back()->type() == TextBlockTSkip; +} + void Text::setSkipBlock(int32 width, int32 height) { if (!_blocks.isEmpty() && _blocks.back()->type() == TextBlockTSkip) { SkipBlock *block = static_cast(_blocks.back()); @@ -3000,6 +2921,10 @@ TextSelection Text::adjustSelection(TextSelection selection, TextSelectType sele } QString Text::original(TextSelection selection, ExpandLinksMode mode) const { + if (isEmpty() || selection.empty()) { + return QString(); + } + QString result, emptyurl; result.reserve(_text.size()); @@ -3154,1980 +3079,6 @@ void Text::clearFields() { _startDir = Qt::LayoutDirectionAuto; } -// COPIED FROM qtextlayout.cpp AND MODIFIED -namespace { - - struct ScriptLine { - ScriptLine() : length(0), textWidth(0) { - } - - int32 length; - QFixed textWidth; - }; - - struct LineBreakHelper - { - LineBreakHelper() - : glyphCount(0), maxGlyphs(0), currentPosition(0), fontEngine(0), logClusters(0) - { - } - - - ScriptLine tmpData; - ScriptLine spaceData; - - QGlyphLayout glyphs; - - int glyphCount; - int maxGlyphs; - int currentPosition; - glyph_t previousGlyph; - - QFixed rightBearing; - - QFontEngine *fontEngine; - const unsigned short *logClusters; - - inline glyph_t currentGlyph() const - { - Q_ASSERT(currentPosition > 0); - Q_ASSERT(logClusters[currentPosition - 1] < glyphs.numGlyphs); - - return glyphs.glyphs[logClusters[currentPosition - 1]]; - } - - inline void saveCurrentGlyph() - { - previousGlyph = 0; - if (currentPosition > 0 && - logClusters[currentPosition - 1] < glyphs.numGlyphs) { - previousGlyph = currentGlyph(); // needed to calculate right bearing later - } - } - - inline void adjustRightBearing(glyph_t glyph) - { - qreal rb; - fontEngine->getGlyphBearings(glyph, 0, &rb); - rightBearing = qMin(QFixed(), QFixed::fromReal(rb)); - } - - inline void adjustRightBearing() - { - if (currentPosition <= 0) - return; - adjustRightBearing(currentGlyph()); - } - - inline void adjustPreviousRightBearing() - { - if (previousGlyph > 0) - adjustRightBearing(previousGlyph); - } - - }; - - static inline void addNextCluster(int &pos, int end, ScriptLine &line, int &glyphCount, - const QScriptItem ¤t, const unsigned short *logClusters, - const QGlyphLayout &glyphs) - { - int glyphPosition = logClusters[pos]; - do { // got to the first next cluster - ++pos; - ++line.length; - } while (pos < end && logClusters[pos] == glyphPosition); - do { // calculate the textWidth for the rest of the current cluster. - if (!glyphs.attributes[glyphPosition].dontPrint) - line.textWidth += glyphs.advances[glyphPosition]; - ++glyphPosition; - } while (glyphPosition < current.num_glyphs && !glyphs.attributes[glyphPosition].clusterStart); - - Q_ASSERT((pos == end && glyphPosition == current.num_glyphs) || logClusters[pos] == glyphPosition); - - ++glyphCount; - } - -} // anonymous namespace - -class BlockParser { -public: - - BlockParser(QTextEngine *e, TextBlock *b, QFixed minResizeWidth, int32 blockFrom, const QString &str) - : block(b), eng(e), str(str) { - parseWords(minResizeWidth, blockFrom); - } - - void parseWords(QFixed minResizeWidth, int32 blockFrom) { - LineBreakHelper lbh; - - lbh.maxGlyphs = INT_MAX; - - int item = -1; - int newItem = eng->findItem(0); - - style::align alignment = eng->option.alignment(); - - const QCharAttributes *attributes = eng->attributes(); - if (!attributes) - return; - lbh.currentPosition = 0; - int end = 0; - lbh.logClusters = eng->layoutData->logClustersPtr; - lbh.previousGlyph = 0; - - block->_lpadding = 0; - block->_words.clear(); - - int wordStart = lbh.currentPosition; - - bool addingEachGrapheme = false; - int lastGraphemeBoundaryPosition = -1; - ScriptLine lastGraphemeBoundaryLine; - - while (newItem < eng->layoutData->items.size()) { - if (newItem != item) { - item = newItem; - const QScriptItem ¤t = eng->layoutData->items[item]; - if (!current.num_glyphs) { - eng->shape(item); - attributes = eng->attributes(); - if (!attributes) - return; - lbh.logClusters = eng->layoutData->logClustersPtr; - } - lbh.currentPosition = current.position; - end = current.position + eng->length(item); - lbh.glyphs = eng->shapedGlyphs(¤t); - QFontEngine *fontEngine = eng->fontEngine(current); - if (lbh.fontEngine != fontEngine) { - lbh.fontEngine = fontEngine; - } - } - const QScriptItem ¤t = eng->layoutData->items[item]; - - if (attributes[lbh.currentPosition].whiteSpace) { - while (lbh.currentPosition < end && attributes[lbh.currentPosition].whiteSpace) - addNextCluster(lbh.currentPosition, end, lbh.spaceData, lbh.glyphCount, - current, lbh.logClusters, lbh.glyphs); - - if (block->_words.isEmpty()) { - block->_lpadding = lbh.spaceData.textWidth; - } else { - block->_words.back().rpadding += lbh.spaceData.textWidth; - block->_width += lbh.spaceData.textWidth; - } - lbh.spaceData.length = 0; - lbh.spaceData.textWidth = 0; - - wordStart = lbh.currentPosition; - - addingEachGrapheme = false; - lastGraphemeBoundaryPosition = -1; - lastGraphemeBoundaryLine = ScriptLine(); - } else { - do { - addNextCluster(lbh.currentPosition, end, lbh.tmpData, lbh.glyphCount, - current, lbh.logClusters, lbh.glyphs); - - if (lbh.currentPosition >= eng->layoutData->string.length() - || attributes[lbh.currentPosition].whiteSpace - || isLineBreak(attributes, lbh.currentPosition)) { - lbh.adjustRightBearing(); - block->_words.push_back(TextWord(wordStart + blockFrom, lbh.tmpData.textWidth, qMin(QFixed(), lbh.rightBearing))); - block->_width += lbh.tmpData.textWidth; - lbh.tmpData.textWidth = 0; - lbh.tmpData.length = 0; - wordStart = lbh.currentPosition; - break; - } else if (attributes[lbh.currentPosition].graphemeBoundary) { - if (!addingEachGrapheme && lbh.tmpData.textWidth > minResizeWidth) { - if (lastGraphemeBoundaryPosition >= 0) { - lbh.adjustPreviousRightBearing(); - block->_words.push_back(TextWord(wordStart + blockFrom, -lastGraphemeBoundaryLine.textWidth, qMin(QFixed(), lbh.rightBearing))); - block->_width += lastGraphemeBoundaryLine.textWidth; - lbh.tmpData.textWidth -= lastGraphemeBoundaryLine.textWidth; - lbh.tmpData.length -= lastGraphemeBoundaryLine.length; - wordStart = lastGraphemeBoundaryPosition; - } - addingEachGrapheme = true; - } - if (addingEachGrapheme) { - lbh.adjustRightBearing(); - block->_words.push_back(TextWord(wordStart + blockFrom, -lbh.tmpData.textWidth, qMin(QFixed(), lbh.rightBearing))); - block->_width += lbh.tmpData.textWidth; - lbh.tmpData.textWidth = 0; - lbh.tmpData.length = 0; - wordStart = lbh.currentPosition; - } else { - lastGraphemeBoundaryPosition = lbh.currentPosition; - lastGraphemeBoundaryLine = lbh.tmpData; - lbh.saveCurrentGlyph(); - } - } - } while (lbh.currentPosition < end); - } - if (lbh.currentPosition == end) - newItem = item + 1; - } - if (block->_words.isEmpty()) { - block->_rpadding = 0; - } else { - block->_rpadding = block->_words.back().rpadding; - block->_width -= block->_rpadding; - block->_words.squeeze(); - } - } - - bool isLineBreak(const QCharAttributes *attributes, int32 index) { - bool lineBreak = attributes[index].lineBreak; - if (lineBreak && block->lnkIndex() > 0 && index > 0 && str.at(index - 1) == '/') { - return false; // don't break after / in links - } - return lineBreak; - } - -private: - - TextBlock *block; - QTextEngine *eng; - const QString &str; - -}; - -TextBlock::TextBlock(const style::font &font, const QString &str, QFixed minResizeWidth, uint16 from, uint16 length, uchar flags, const style::color &color, uint16 lnkIndex) : ITextBlock(font, str, from, length, flags, color, lnkIndex) { - _flags |= ((TextBlockTText & 0x0F) << 8); - if (length) { - style::font blockFont = font; - if (!flags && lnkIndex) { - // should use textStyle lnkFlags somehow... not supported - } - - if ((flags & TextBlockFPre) || (flags & TextBlockFCode)) { - blockFont = App::monofont(); - if (blockFont->size() != font->size() || blockFont->flags() != font->flags()) { - blockFont = style::font(font->size(), font->flags(), blockFont->family()); - } - } else { - if (flags & TextBlockFBold) { - blockFont = blockFont->bold(); - } - else if (flags & TextBlockFSemibold) { - blockFont = st::semiboldFont; - if (blockFont->size() != font->size() || blockFont->flags() != font->flags()) { - blockFont = style::font(font->size(), font->flags(), blockFont->family()); - } - } - if (flags & TextBlockFItalic) blockFont = blockFont->italic(); - if (flags & TextBlockFUnderline) blockFont = blockFont->underline(); - if (flags & TextBlockFTilde) { // tilde fix in OpenSans - blockFont = st::semiboldFont; - } - } - - QString part = str.mid(_from, length); - QStackTextEngine engine(part, blockFont->f); - engine.itemize(); - - QTextLayout layout(&engine); - layout.beginLayout(); - layout.createLine(); - - bool logCrashString = (rand_value() % 4 == 1); - if (logCrashString) { - SignalHandlers::setCrashAnnotationRef("CrashString", &str); - } - BlockParser parser(&engine, this, minResizeWidth, _from, part); - if (logCrashString) { - SignalHandlers::clearCrashAnnotationRef("CrashString"); - } - - layout.endLayout(); - } -} - -EmojiBlock::EmojiBlock(const style::font &font, const QString &str, uint16 from, uint16 length, uchar flags, const style::color &color, uint16 lnkIndex, const EmojiData *emoji) : ITextBlock(font, str, from, length, flags, color, lnkIndex), emoji(emoji) { - _flags |= ((TextBlockTEmoji & 0x0F) << 8); - _width = int(st::emojiSize + 2 * st::emojiPadding); -} - -SkipBlock::SkipBlock(const style::font &font, const QString &str, uint16 from, int32 w, int32 h, uint16 lnkIndex) : ITextBlock(font, str, from, 1, 0, style::color(), lnkIndex), _height(h) { - _flags |= ((TextBlockTSkip & 0x0F) << 8); - _width = w; -} - -namespace { - void regOneProtocol(const QString &protocol) { - _validProtocols.insert(hashCrc32(protocol.constData(), protocol.size() * sizeof(QChar))); - } - void regOneTopDomain(const QString &domain) { - _validTopDomains.insert(hashCrc32(domain.constData(), domain.size() * sizeof(QChar))); - } -} - -const QSet &validProtocols() { - return _validProtocols; -} -const QSet &validTopDomains() { - return _validTopDomains; -} - -void initLinkSets() { - if (!_validProtocols.isEmpty() || !_validTopDomains.isEmpty()) return; - - regOneProtocol(qsl("itmss")); // itunes - regOneProtocol(qsl("http")); - regOneProtocol(qsl("https")); - regOneProtocol(qsl("ftp")); - regOneProtocol(qsl("tg")); // local urls - - regOneTopDomain(qsl("ac")); - regOneTopDomain(qsl("ad")); - regOneTopDomain(qsl("ae")); - regOneTopDomain(qsl("af")); - regOneTopDomain(qsl("ag")); - regOneTopDomain(qsl("ai")); - regOneTopDomain(qsl("al")); - regOneTopDomain(qsl("am")); - regOneTopDomain(qsl("an")); - regOneTopDomain(qsl("ao")); - regOneTopDomain(qsl("aq")); - regOneTopDomain(qsl("ar")); - regOneTopDomain(qsl("as")); - regOneTopDomain(qsl("at")); - regOneTopDomain(qsl("au")); - regOneTopDomain(qsl("aw")); - regOneTopDomain(qsl("ax")); - regOneTopDomain(qsl("az")); - regOneTopDomain(qsl("ba")); - regOneTopDomain(qsl("bb")); - regOneTopDomain(qsl("bd")); - regOneTopDomain(qsl("be")); - regOneTopDomain(qsl("bf")); - regOneTopDomain(qsl("bg")); - regOneTopDomain(qsl("bh")); - regOneTopDomain(qsl("bi")); - regOneTopDomain(qsl("bj")); - regOneTopDomain(qsl("bm")); - regOneTopDomain(qsl("bn")); - regOneTopDomain(qsl("bo")); - regOneTopDomain(qsl("br")); - regOneTopDomain(qsl("bs")); - regOneTopDomain(qsl("bt")); - regOneTopDomain(qsl("bv")); - regOneTopDomain(qsl("bw")); - regOneTopDomain(qsl("by")); - regOneTopDomain(qsl("bz")); - regOneTopDomain(qsl("ca")); - regOneTopDomain(qsl("cc")); - regOneTopDomain(qsl("cd")); - regOneTopDomain(qsl("cf")); - regOneTopDomain(qsl("cg")); - regOneTopDomain(qsl("ch")); - regOneTopDomain(qsl("ci")); - regOneTopDomain(qsl("ck")); - regOneTopDomain(qsl("cl")); - regOneTopDomain(qsl("cm")); - regOneTopDomain(qsl("cn")); - regOneTopDomain(qsl("co")); - regOneTopDomain(qsl("cr")); - regOneTopDomain(qsl("cu")); - regOneTopDomain(qsl("cv")); - regOneTopDomain(qsl("cx")); - regOneTopDomain(qsl("cy")); - regOneTopDomain(qsl("cz")); - regOneTopDomain(qsl("de")); - regOneTopDomain(qsl("dj")); - regOneTopDomain(qsl("dk")); - regOneTopDomain(qsl("dm")); - regOneTopDomain(qsl("do")); - regOneTopDomain(qsl("dz")); - regOneTopDomain(qsl("ec")); - regOneTopDomain(qsl("ee")); - regOneTopDomain(qsl("eg")); - regOneTopDomain(qsl("eh")); - regOneTopDomain(qsl("er")); - regOneTopDomain(qsl("es")); - regOneTopDomain(qsl("et")); - regOneTopDomain(qsl("eu")); - regOneTopDomain(qsl("fi")); - regOneTopDomain(qsl("fj")); - regOneTopDomain(qsl("fk")); - regOneTopDomain(qsl("fm")); - regOneTopDomain(qsl("fo")); - regOneTopDomain(qsl("fr")); - regOneTopDomain(qsl("ga")); - regOneTopDomain(qsl("gd")); - regOneTopDomain(qsl("ge")); - regOneTopDomain(qsl("gf")); - regOneTopDomain(qsl("gg")); - regOneTopDomain(qsl("gh")); - regOneTopDomain(qsl("gi")); - regOneTopDomain(qsl("gl")); - regOneTopDomain(qsl("gm")); - regOneTopDomain(qsl("gn")); - regOneTopDomain(qsl("gp")); - regOneTopDomain(qsl("gq")); - regOneTopDomain(qsl("gr")); - regOneTopDomain(qsl("gs")); - regOneTopDomain(qsl("gt")); - regOneTopDomain(qsl("gu")); - regOneTopDomain(qsl("gw")); - regOneTopDomain(qsl("gy")); - regOneTopDomain(qsl("hk")); - regOneTopDomain(qsl("hm")); - regOneTopDomain(qsl("hn")); - regOneTopDomain(qsl("hr")); - regOneTopDomain(qsl("ht")); - regOneTopDomain(qsl("hu")); - regOneTopDomain(qsl("id")); - regOneTopDomain(qsl("ie")); - regOneTopDomain(qsl("il")); - regOneTopDomain(qsl("im")); - regOneTopDomain(qsl("in")); - regOneTopDomain(qsl("io")); - regOneTopDomain(qsl("iq")); - regOneTopDomain(qsl("ir")); - regOneTopDomain(qsl("is")); - regOneTopDomain(qsl("it")); - regOneTopDomain(qsl("je")); - regOneTopDomain(qsl("jm")); - regOneTopDomain(qsl("jo")); - regOneTopDomain(qsl("jp")); - regOneTopDomain(qsl("ke")); - regOneTopDomain(qsl("kg")); - regOneTopDomain(qsl("kh")); - regOneTopDomain(qsl("ki")); - regOneTopDomain(qsl("km")); - regOneTopDomain(qsl("kn")); - regOneTopDomain(qsl("kp")); - regOneTopDomain(qsl("kr")); - regOneTopDomain(qsl("kw")); - regOneTopDomain(qsl("ky")); - regOneTopDomain(qsl("kz")); - regOneTopDomain(qsl("la")); - regOneTopDomain(qsl("lb")); - regOneTopDomain(qsl("lc")); - regOneTopDomain(qsl("li")); - regOneTopDomain(qsl("lk")); - regOneTopDomain(qsl("lr")); - regOneTopDomain(qsl("ls")); - regOneTopDomain(qsl("lt")); - regOneTopDomain(qsl("lu")); - regOneTopDomain(qsl("lv")); - regOneTopDomain(qsl("ly")); - regOneTopDomain(qsl("ma")); - regOneTopDomain(qsl("mc")); - regOneTopDomain(qsl("md")); - regOneTopDomain(qsl("me")); - regOneTopDomain(qsl("mg")); - regOneTopDomain(qsl("mh")); - regOneTopDomain(qsl("mk")); - regOneTopDomain(qsl("ml")); - regOneTopDomain(qsl("mm")); - regOneTopDomain(qsl("mn")); - regOneTopDomain(qsl("mo")); - regOneTopDomain(qsl("mp")); - regOneTopDomain(qsl("mq")); - regOneTopDomain(qsl("mr")); - regOneTopDomain(qsl("ms")); - regOneTopDomain(qsl("mt")); - regOneTopDomain(qsl("mu")); - regOneTopDomain(qsl("mv")); - regOneTopDomain(qsl("mw")); - regOneTopDomain(qsl("mx")); - regOneTopDomain(qsl("my")); - regOneTopDomain(qsl("mz")); - regOneTopDomain(qsl("na")); - regOneTopDomain(qsl("nc")); - regOneTopDomain(qsl("ne")); - regOneTopDomain(qsl("nf")); - regOneTopDomain(qsl("ng")); - regOneTopDomain(qsl("ni")); - regOneTopDomain(qsl("nl")); - regOneTopDomain(qsl("no")); - regOneTopDomain(qsl("np")); - regOneTopDomain(qsl("nr")); - regOneTopDomain(qsl("nu")); - regOneTopDomain(qsl("nz")); - regOneTopDomain(qsl("om")); - regOneTopDomain(qsl("pa")); - regOneTopDomain(qsl("pe")); - regOneTopDomain(qsl("pf")); - regOneTopDomain(qsl("pg")); - regOneTopDomain(qsl("ph")); - regOneTopDomain(qsl("pk")); - regOneTopDomain(qsl("pl")); - regOneTopDomain(qsl("pm")); - regOneTopDomain(qsl("pn")); - regOneTopDomain(qsl("pr")); - regOneTopDomain(qsl("ps")); - regOneTopDomain(qsl("pt")); - regOneTopDomain(qsl("pw")); - regOneTopDomain(qsl("py")); - regOneTopDomain(qsl("qa")); - regOneTopDomain(qsl("re")); - regOneTopDomain(qsl("ro")); - regOneTopDomain(qsl("ru")); - regOneTopDomain(qsl("rs")); - regOneTopDomain(qsl("rw")); - regOneTopDomain(qsl("sa")); - regOneTopDomain(qsl("sb")); - regOneTopDomain(qsl("sc")); - regOneTopDomain(qsl("sd")); - regOneTopDomain(qsl("se")); - regOneTopDomain(qsl("sg")); - regOneTopDomain(qsl("sh")); - regOneTopDomain(qsl("si")); - regOneTopDomain(qsl("sj")); - regOneTopDomain(qsl("sk")); - regOneTopDomain(qsl("sl")); - regOneTopDomain(qsl("sm")); - regOneTopDomain(qsl("sn")); - regOneTopDomain(qsl("so")); - regOneTopDomain(qsl("sr")); - regOneTopDomain(qsl("ss")); - regOneTopDomain(qsl("st")); - regOneTopDomain(qsl("su")); - regOneTopDomain(qsl("sv")); - regOneTopDomain(qsl("sx")); - regOneTopDomain(qsl("sy")); - regOneTopDomain(qsl("sz")); - regOneTopDomain(qsl("tc")); - regOneTopDomain(qsl("td")); - regOneTopDomain(qsl("tf")); - regOneTopDomain(qsl("tg")); - regOneTopDomain(qsl("th")); - regOneTopDomain(qsl("tj")); - regOneTopDomain(qsl("tk")); - regOneTopDomain(qsl("tl")); - regOneTopDomain(qsl("tm")); - regOneTopDomain(qsl("tn")); - regOneTopDomain(qsl("to")); - regOneTopDomain(qsl("tp")); - regOneTopDomain(qsl("tr")); - regOneTopDomain(qsl("tt")); - regOneTopDomain(qsl("tv")); - regOneTopDomain(qsl("tw")); - regOneTopDomain(qsl("tz")); - regOneTopDomain(qsl("ua")); - regOneTopDomain(qsl("ug")); - regOneTopDomain(qsl("uk")); - regOneTopDomain(qsl("um")); - regOneTopDomain(qsl("us")); - regOneTopDomain(qsl("uy")); - regOneTopDomain(qsl("uz")); - regOneTopDomain(qsl("va")); - regOneTopDomain(qsl("vc")); - regOneTopDomain(qsl("ve")); - regOneTopDomain(qsl("vg")); - regOneTopDomain(qsl("vi")); - regOneTopDomain(qsl("vn")); - regOneTopDomain(qsl("vu")); - regOneTopDomain(qsl("wf")); - regOneTopDomain(qsl("ws")); - regOneTopDomain(qsl("ye")); - regOneTopDomain(qsl("yt")); - regOneTopDomain(qsl("yu")); - regOneTopDomain(qsl("za")); - regOneTopDomain(qsl("zm")); - regOneTopDomain(qsl("zw")); - regOneTopDomain(qsl("arpa")); - regOneTopDomain(qsl("aero")); - regOneTopDomain(qsl("asia")); - regOneTopDomain(qsl("biz")); - regOneTopDomain(qsl("cat")); - regOneTopDomain(qsl("com")); - regOneTopDomain(qsl("coop")); - regOneTopDomain(qsl("info")); - regOneTopDomain(qsl("int")); - regOneTopDomain(qsl("jobs")); - regOneTopDomain(qsl("mobi")); - regOneTopDomain(qsl("museum")); - regOneTopDomain(qsl("name")); - regOneTopDomain(qsl("net")); - regOneTopDomain(qsl("org")); - regOneTopDomain(qsl("post")); - regOneTopDomain(qsl("pro")); - regOneTopDomain(qsl("tel")); - regOneTopDomain(qsl("travel")); - regOneTopDomain(qsl("xxx")); - regOneTopDomain(qsl("edu")); - regOneTopDomain(qsl("gov")); - regOneTopDomain(qsl("mil")); - regOneTopDomain(qsl("local")); - regOneTopDomain(qsl("xn--lgbbat1ad8j")); - regOneTopDomain(qsl("xn--54b7fta0cc")); - regOneTopDomain(qsl("xn--fiqs8s")); - regOneTopDomain(qsl("xn--fiqz9s")); - regOneTopDomain(qsl("xn--wgbh1c")); - regOneTopDomain(qsl("xn--node")); - regOneTopDomain(qsl("xn--j6w193g")); - regOneTopDomain(qsl("xn--h2brj9c")); - regOneTopDomain(qsl("xn--mgbbh1a71e")); - regOneTopDomain(qsl("xn--fpcrj9c3d")); - regOneTopDomain(qsl("xn--gecrj9c")); - regOneTopDomain(qsl("xn--s9brj9c")); - regOneTopDomain(qsl("xn--xkc2dl3a5ee0h")); - regOneTopDomain(qsl("xn--45brj9c")); - regOneTopDomain(qsl("xn--mgba3a4f16a")); - regOneTopDomain(qsl("xn--mgbayh7gpa")); - regOneTopDomain(qsl("xn--80ao21a")); - regOneTopDomain(qsl("xn--mgbx4cd0ab")); - regOneTopDomain(qsl("xn--l1acc")); - regOneTopDomain(qsl("xn--mgbc0a9azcg")); - regOneTopDomain(qsl("xn--mgb9awbf")); - regOneTopDomain(qsl("xn--mgbai9azgqp6j")); - regOneTopDomain(qsl("xn--ygbi2ammx")); - regOneTopDomain(qsl("xn--wgbl6a")); - regOneTopDomain(qsl("xn--p1ai")); - regOneTopDomain(qsl("xn--mgberp4a5d4ar")); - regOneTopDomain(qsl("xn--90a3ac")); - regOneTopDomain(qsl("xn--yfro4i67o")); - regOneTopDomain(qsl("xn--clchc0ea0b2g2a9gcd")); - regOneTopDomain(qsl("xn--3e0b707e")); - regOneTopDomain(qsl("xn--fzc2c9e2c")); - regOneTopDomain(qsl("xn--xkc2al3hye2a")); - regOneTopDomain(qsl("xn--mgbtf8fl")); - regOneTopDomain(qsl("xn--kprw13d")); - regOneTopDomain(qsl("xn--kpry57d")); - regOneTopDomain(qsl("xn--o3cw4h")); - regOneTopDomain(qsl("xn--pgbs0dh")); - regOneTopDomain(qsl("xn--j1amh")); - regOneTopDomain(qsl("xn--mgbaam7a8h")); - regOneTopDomain(qsl("xn--mgb2ddes")); - regOneTopDomain(qsl("xn--ogbpf8fl")); - regOneTopDomain(QString::fromUtf8("рф")); -} - -namespace { - // accent char list taken from https://github.com/aristus/accent-folding - inline QChar chNoAccent(int32 code) { - switch (code) { - case 7834: return QChar(97); - case 193: return QChar(97); - case 225: return QChar(97); - case 192: return QChar(97); - case 224: return QChar(97); - case 258: return QChar(97); - case 259: return QChar(97); - case 7854: return QChar(97); - case 7855: return QChar(97); - case 7856: return QChar(97); - case 7857: return QChar(97); - case 7860: return QChar(97); - case 7861: return QChar(97); - case 7858: return QChar(97); - case 7859: return QChar(97); - case 194: return QChar(97); - case 226: return QChar(97); - case 7844: return QChar(97); - case 7845: return QChar(97); - case 7846: return QChar(97); - case 7847: return QChar(97); - case 7850: return QChar(97); - case 7851: return QChar(97); - case 7848: return QChar(97); - case 7849: return QChar(97); - case 461: return QChar(97); - case 462: return QChar(97); - case 197: return QChar(97); - case 229: return QChar(97); - case 506: return QChar(97); - case 507: return QChar(97); - case 196: return QChar(97); - case 228: return QChar(97); - case 478: return QChar(97); - case 479: return QChar(97); - case 195: return QChar(97); - case 227: return QChar(97); - case 550: return QChar(97); - case 551: return QChar(97); - case 480: return QChar(97); - case 481: return QChar(97); - case 260: return QChar(97); - case 261: return QChar(97); - case 256: return QChar(97); - case 257: return QChar(97); - case 7842: return QChar(97); - case 7843: return QChar(97); - case 512: return QChar(97); - case 513: return QChar(97); - case 514: return QChar(97); - case 515: return QChar(97); - case 7840: return QChar(97); - case 7841: return QChar(97); - case 7862: return QChar(97); - case 7863: return QChar(97); - case 7852: return QChar(97); - case 7853: return QChar(97); - case 7680: return QChar(97); - case 7681: return QChar(97); - case 570: return QChar(97); - case 11365: return QChar(97); - case 508: return QChar(97); - case 509: return QChar(97); - case 482: return QChar(97); - case 483: return QChar(97); - case 7682: return QChar(98); - case 7683: return QChar(98); - case 7684: return QChar(98); - case 7685: return QChar(98); - case 7686: return QChar(98); - case 7687: return QChar(98); - case 579: return QChar(98); - case 384: return QChar(98); - case 7532: return QChar(98); - case 385: return QChar(98); - case 595: return QChar(98); - case 386: return QChar(98); - case 387: return QChar(98); - case 262: return QChar(99); - case 263: return QChar(99); - case 264: return QChar(99); - case 265: return QChar(99); - case 268: return QChar(99); - case 269: return QChar(99); - case 266: return QChar(99); - case 267: return QChar(99); - case 199: return QChar(99); - case 231: return QChar(99); - case 7688: return QChar(99); - case 7689: return QChar(99); - case 571: return QChar(99); - case 572: return QChar(99); - case 391: return QChar(99); - case 392: return QChar(99); - case 597: return QChar(99); - case 270: return QChar(100); - case 271: return QChar(100); - case 7690: return QChar(100); - case 7691: return QChar(100); - case 7696: return QChar(100); - case 7697: return QChar(100); - case 7692: return QChar(100); - case 7693: return QChar(100); - case 7698: return QChar(100); - case 7699: return QChar(100); - case 7694: return QChar(100); - case 7695: return QChar(100); - case 272: return QChar(100); - case 273: return QChar(100); - case 7533: return QChar(100); - case 393: return QChar(100); - case 598: return QChar(100); - case 394: return QChar(100); - case 599: return QChar(100); - case 395: return QChar(100); - case 396: return QChar(100); - case 545: return QChar(100); - case 240: return QChar(100); - case 201: return QChar(101); - case 399: return QChar(101); - case 398: return QChar(101); - case 477: return QChar(101); - case 233: return QChar(101); - case 200: return QChar(101); - case 232: return QChar(101); - case 276: return QChar(101); - case 277: return QChar(101); - case 202: return QChar(101); - case 234: return QChar(101); - case 7870: return QChar(101); - case 7871: return QChar(101); - case 7872: return QChar(101); - case 7873: return QChar(101); - case 7876: return QChar(101); - case 7877: return QChar(101); - case 7874: return QChar(101); - case 7875: return QChar(101); - case 282: return QChar(101); - case 283: return QChar(101); - case 203: return QChar(101); - case 235: return QChar(101); - case 7868: return QChar(101); - case 7869: return QChar(101); - case 278: return QChar(101); - case 279: return QChar(101); - case 552: return QChar(101); - case 553: return QChar(101); - case 7708: return QChar(101); - case 7709: return QChar(101); - case 280: return QChar(101); - case 281: return QChar(101); - case 274: return QChar(101); - case 275: return QChar(101); - case 7702: return QChar(101); - case 7703: return QChar(101); - case 7700: return QChar(101); - case 7701: return QChar(101); - case 7866: return QChar(101); - case 7867: return QChar(101); - case 516: return QChar(101); - case 517: return QChar(101); - case 518: return QChar(101); - case 519: return QChar(101); - case 7864: return QChar(101); - case 7865: return QChar(101); - case 7878: return QChar(101); - case 7879: return QChar(101); - case 7704: return QChar(101); - case 7705: return QChar(101); - case 7706: return QChar(101); - case 7707: return QChar(101); - case 582: return QChar(101); - case 583: return QChar(101); - case 602: return QChar(101); - case 605: return QChar(101); - case 7710: return QChar(102); - case 7711: return QChar(102); - case 7534: return QChar(102); - case 401: return QChar(102); - case 402: return QChar(102); - case 500: return QChar(103); - case 501: return QChar(103); - case 286: return QChar(103); - case 287: return QChar(103); - case 284: return QChar(103); - case 285: return QChar(103); - case 486: return QChar(103); - case 487: return QChar(103); - case 288: return QChar(103); - case 289: return QChar(103); - case 290: return QChar(103); - case 291: return QChar(103); - case 7712: return QChar(103); - case 7713: return QChar(103); - case 484: return QChar(103); - case 485: return QChar(103); - case 403: return QChar(103); - case 608: return QChar(103); - case 292: return QChar(104); - case 293: return QChar(104); - case 542: return QChar(104); - case 543: return QChar(104); - case 7718: return QChar(104); - case 7719: return QChar(104); - case 7714: return QChar(104); - case 7715: return QChar(104); - case 7720: return QChar(104); - case 7721: return QChar(104); - case 7716: return QChar(104); - case 7717: return QChar(104); - case 7722: return QChar(104); - case 7723: return QChar(104); - case 817: return QChar(104); - case 7830: return QChar(104); - case 294: return QChar(104); - case 295: return QChar(104); - case 11367: return QChar(104); - case 11368: return QChar(104); - case 205: return QChar(105); - case 237: return QChar(105); - case 204: return QChar(105); - case 236: return QChar(105); - case 300: return QChar(105); - case 301: return QChar(105); - case 206: return QChar(105); - case 238: return QChar(105); - case 463: return QChar(105); - case 464: return QChar(105); - case 207: return QChar(105); - case 239: return QChar(105); - case 7726: return QChar(105); - case 7727: return QChar(105); - case 296: return QChar(105); - case 297: return QChar(105); - case 304: return QChar(105); - case 302: return QChar(105); - case 303: return QChar(105); - case 298: return QChar(105); - case 299: return QChar(105); - case 7880: return QChar(105); - case 7881: return QChar(105); - case 520: return QChar(105); - case 521: return QChar(105); - case 522: return QChar(105); - case 523: return QChar(105); - case 7882: return QChar(105); - case 7883: return QChar(105); - case 7724: return QChar(105); - case 7725: return QChar(105); - case 305: return QChar(105); - case 407: return QChar(105); - case 616: return QChar(105); - case 308: return QChar(106); - case 309: return QChar(106); - case 780: return QChar(106); - case 496: return QChar(106); - case 567: return QChar(106); - case 584: return QChar(106); - case 585: return QChar(106); - case 669: return QChar(106); - case 607: return QChar(106); - case 644: return QChar(106); - case 7728: return QChar(107); - case 7729: return QChar(107); - case 488: return QChar(107); - case 489: return QChar(107); - case 310: return QChar(107); - case 311: return QChar(107); - case 7730: return QChar(107); - case 7731: return QChar(107); - case 7732: return QChar(107); - case 7733: return QChar(107); - case 408: return QChar(107); - case 409: return QChar(107); - case 11369: return QChar(107); - case 11370: return QChar(107); - case 313: return QChar(97); - case 314: return QChar(108); - case 317: return QChar(108); - case 318: return QChar(108); - case 315: return QChar(108); - case 316: return QChar(108); - case 7734: return QChar(108); - case 7735: return QChar(108); - case 7736: return QChar(108); - case 7737: return QChar(108); - case 7740: return QChar(108); - case 7741: return QChar(108); - case 7738: return QChar(108); - case 7739: return QChar(108); - case 321: return QChar(108); - case 322: return QChar(108); - case 803: return QChar(108); - case 319: return QChar(108); - case 320: return QChar(108); - case 573: return QChar(108); - case 410: return QChar(108); - case 11360: return QChar(108); - case 11361: return QChar(108); - case 11362: return QChar(108); - case 619: return QChar(108); - case 620: return QChar(108); - case 621: return QChar(108); - case 564: return QChar(108); - case 7742: return QChar(109); - case 7743: return QChar(109); - case 7744: return QChar(109); - case 7745: return QChar(109); - case 7746: return QChar(109); - case 7747: return QChar(109); - case 625: return QChar(109); - case 323: return QChar(110); - case 324: return QChar(110); - case 504: return QChar(110); - case 505: return QChar(110); - case 327: return QChar(110); - case 328: return QChar(110); - case 209: return QChar(110); - case 241: return QChar(110); - case 7748: return QChar(110); - case 7749: return QChar(110); - case 325: return QChar(110); - case 326: return QChar(110); - case 7750: return QChar(110); - case 7751: return QChar(110); - case 7754: return QChar(110); - case 7755: return QChar(110); - case 7752: return QChar(110); - case 7753: return QChar(110); - case 413: return QChar(110); - case 626: return QChar(110); - case 544: return QChar(110); - case 414: return QChar(110); - case 627: return QChar(110); - case 565: return QChar(110); - case 776: return QChar(116); - case 211: return QChar(111); - case 243: return QChar(111); - case 210: return QChar(111); - case 242: return QChar(111); - case 334: return QChar(111); - case 335: return QChar(111); - case 212: return QChar(111); - case 244: return QChar(111); - case 7888: return QChar(111); - case 7889: return QChar(111); - case 7890: return QChar(111); - case 7891: return QChar(111); - case 7894: return QChar(111); - case 7895: return QChar(111); - case 7892: return QChar(111); - case 7893: return QChar(111); - case 465: return QChar(111); - case 466: return QChar(111); - case 214: return QChar(111); - case 246: return QChar(111); - case 554: return QChar(111); - case 555: return QChar(111); - case 336: return QChar(111); - case 337: return QChar(111); - case 213: return QChar(111); - case 245: return QChar(111); - case 7756: return QChar(111); - case 7757: return QChar(111); - case 7758: return QChar(111); - case 7759: return QChar(111); - case 556: return QChar(111); - case 557: return QChar(111); - case 558: return QChar(111); - case 559: return QChar(111); - case 560: return QChar(111); - case 561: return QChar(111); - case 216: return QChar(111); - case 248: return QChar(111); - case 510: return QChar(111); - case 511: return QChar(111); - case 490: return QChar(111); - case 491: return QChar(111); - case 492: return QChar(111); - case 493: return QChar(111); - case 332: return QChar(111); - case 333: return QChar(111); - case 7762: return QChar(111); - case 7763: return QChar(111); - case 7760: return QChar(111); - case 7761: return QChar(111); - case 7886: return QChar(111); - case 7887: return QChar(111); - case 524: return QChar(111); - case 525: return QChar(111); - case 526: return QChar(111); - case 527: return QChar(111); - case 416: return QChar(111); - case 417: return QChar(111); - case 7898: return QChar(111); - case 7899: return QChar(111); - case 7900: return QChar(111); - case 7901: return QChar(111); - case 7904: return QChar(111); - case 7905: return QChar(111); - case 7902: return QChar(111); - case 7903: return QChar(111); - case 7906: return QChar(111); - case 7907: return QChar(111); - case 7884: return QChar(111); - case 7885: return QChar(111); - case 7896: return QChar(111); - case 7897: return QChar(111); - case 415: return QChar(111); - case 629: return QChar(111); - case 7764: return QChar(112); - case 7765: return QChar(112); - case 7766: return QChar(112); - case 7767: return QChar(112); - case 11363: return QChar(112); - case 420: return QChar(112); - case 421: return QChar(112); - case 771: return QChar(112); - case 672: return QChar(113); - case 586: return QChar(113); - case 587: return QChar(113); - case 340: return QChar(114); - case 341: return QChar(114); - case 344: return QChar(114); - case 345: return QChar(114); - case 7768: return QChar(114); - case 7769: return QChar(114); - case 342: return QChar(114); - case 343: return QChar(114); - case 528: return QChar(114); - case 529: return QChar(114); - case 530: return QChar(114); - case 531: return QChar(114); - case 7770: return QChar(114); - case 7771: return QChar(114); - case 7772: return QChar(114); - case 7773: return QChar(114); - case 7774: return QChar(114); - case 7775: return QChar(114); - case 588: return QChar(114); - case 589: return QChar(114); - case 7538: return QChar(114); - case 636: return QChar(114); - case 11364: return QChar(114); - case 637: return QChar(114); - case 638: return QChar(114); - case 7539: return QChar(114); - case 223: return QChar(115); - case 346: return QChar(115); - case 347: return QChar(115); - case 7780: return QChar(115); - case 7781: return QChar(115); - case 348: return QChar(115); - case 349: return QChar(115); - case 352: return QChar(115); - case 353: return QChar(115); - case 7782: return QChar(115); - case 7783: return QChar(115); - case 7776: return QChar(115); - case 7777: return QChar(115); - case 7835: return QChar(115); - case 350: return QChar(115); - case 351: return QChar(115); - case 7778: return QChar(115); - case 7779: return QChar(115); - case 7784: return QChar(115); - case 7785: return QChar(115); - case 536: return QChar(115); - case 537: return QChar(115); - case 642: return QChar(115); - case 809: return QChar(115); - case 222: return QChar(116); - case 254: return QChar(116); - case 356: return QChar(116); - case 357: return QChar(116); - case 7831: return QChar(116); - case 7786: return QChar(116); - case 7787: return QChar(116); - case 354: return QChar(116); - case 355: return QChar(116); - case 7788: return QChar(116); - case 7789: return QChar(116); - case 538: return QChar(116); - case 539: return QChar(116); - case 7792: return QChar(116); - case 7793: return QChar(116); - case 7790: return QChar(116); - case 7791: return QChar(116); - case 358: return QChar(116); - case 359: return QChar(116); - case 574: return QChar(116); - case 11366: return QChar(116); - case 7541: return QChar(116); - case 427: return QChar(116); - case 428: return QChar(116); - case 429: return QChar(116); - case 430: return QChar(116); - case 648: return QChar(116); - case 566: return QChar(116); - case 218: return QChar(117); - case 250: return QChar(117); - case 217: return QChar(117); - case 249: return QChar(117); - case 364: return QChar(117); - case 365: return QChar(117); - case 219: return QChar(117); - case 251: return QChar(117); - case 467: return QChar(117); - case 468: return QChar(117); - case 366: return QChar(117); - case 367: return QChar(117); - case 220: return QChar(117); - case 252: return QChar(117); - case 471: return QChar(117); - case 472: return QChar(117); - case 475: return QChar(117); - case 476: return QChar(117); - case 473: return QChar(117); - case 474: return QChar(117); - case 469: return QChar(117); - case 470: return QChar(117); - case 368: return QChar(117); - case 369: return QChar(117); - case 360: return QChar(117); - case 361: return QChar(117); - case 7800: return QChar(117); - case 7801: return QChar(117); - case 370: return QChar(117); - case 371: return QChar(117); - case 362: return QChar(117); - case 363: return QChar(117); - case 7802: return QChar(117); - case 7803: return QChar(117); - case 7910: return QChar(117); - case 7911: return QChar(117); - case 532: return QChar(117); - case 533: return QChar(117); - case 534: return QChar(117); - case 535: return QChar(117); - case 431: return QChar(117); - case 432: return QChar(117); - case 7912: return QChar(117); - case 7913: return QChar(117); - case 7914: return QChar(117); - case 7915: return QChar(117); - case 7918: return QChar(117); - case 7919: return QChar(117); - case 7916: return QChar(117); - case 7917: return QChar(117); - case 7920: return QChar(117); - case 7921: return QChar(117); - case 7908: return QChar(117); - case 7909: return QChar(117); - case 7794: return QChar(117); - case 7795: return QChar(117); - case 7798: return QChar(117); - case 7799: return QChar(117); - case 7796: return QChar(117); - case 7797: return QChar(117); - case 580: return QChar(117); - case 649: return QChar(117); - case 7804: return QChar(118); - case 7805: return QChar(118); - case 7806: return QChar(118); - case 7807: return QChar(118); - case 434: return QChar(118); - case 651: return QChar(118); - case 7810: return QChar(119); - case 7811: return QChar(119); - case 7808: return QChar(119); - case 7809: return QChar(119); - case 372: return QChar(119); - case 373: return QChar(119); - case 778: return QChar(121); - case 7832: return QChar(119); - case 7812: return QChar(119); - case 7813: return QChar(119); - case 7814: return QChar(119); - case 7815: return QChar(119); - case 7816: return QChar(119); - case 7817: return QChar(119); - case 7820: return QChar(120); - case 7821: return QChar(120); - case 7818: return QChar(120); - case 7819: return QChar(120); - case 221: return QChar(121); - case 253: return QChar(121); - case 7922: return QChar(121); - case 7923: return QChar(121); - case 374: return QChar(121); - case 375: return QChar(121); - case 7833: return QChar(121); - case 376: return QChar(121); - case 255: return QChar(121); - case 7928: return QChar(121); - case 7929: return QChar(121); - case 7822: return QChar(121); - case 7823: return QChar(121); - case 562: return QChar(121); - case 563: return QChar(121); - case 7926: return QChar(121); - case 7927: return QChar(121); - case 7924: return QChar(121); - case 7925: return QChar(121); - case 655: return QChar(121); - case 590: return QChar(121); - case 591: return QChar(121); - case 435: return QChar(121); - case 436: return QChar(121); - case 377: return QChar(122); - case 378: return QChar(122); - case 7824: return QChar(122); - case 7825: return QChar(122); - case 381: return QChar(122); - case 382: return QChar(122); - case 379: return QChar(122); - case 380: return QChar(122); - case 7826: return QChar(122); - case 7827: return QChar(122); - case 7828: return QChar(122); - case 7829: return QChar(122); - case 437: return QChar(122); - case 438: return QChar(122); - case 548: return QChar(122); - case 549: return QChar(122); - case 656: return QChar(122); - case 657: return QChar(122); - case 11371: return QChar(122); - case 11372: return QChar(122); - case 494: return QChar(122); - case 495: return QChar(122); - case 442: return QChar(122); - case 65298: return QChar(50); - case 65302: return QChar(54); - case 65314: return QChar(66); - case 65318: return QChar(70); - case 65322: return QChar(74); - case 65326: return QChar(78); - case 65330: return QChar(82); - case 65334: return QChar(86); - case 65338: return QChar(90); - case 65346: return QChar(98); - case 65350: return QChar(102); - case 65354: return QChar(106); - case 65358: return QChar(110); - case 65362: return QChar(114); - case 65366: return QChar(118); - case 65370: return QChar(122); - case 65297: return QChar(49); - case 65301: return QChar(53); - case 65305: return QChar(57); - case 65313: return QChar(65); - case 65317: return QChar(69); - case 65321: return QChar(73); - case 65325: return QChar(77); - case 65329: return QChar(81); - case 65333: return QChar(85); - case 65337: return QChar(89); - case 65345: return QChar(97); - case 65349: return QChar(101); - case 65353: return QChar(105); - case 65357: return QChar(109); - case 65361: return QChar(113); - case 65365: return QChar(117); - case 65369: return QChar(121); - case 65296: return QChar(48); - case 65300: return QChar(52); - case 65304: return QChar(56); - case 65316: return QChar(68); - case 65320: return QChar(72); - case 65324: return QChar(76); - case 65328: return QChar(80); - case 65332: return QChar(84); - case 65336: return QChar(88); - case 65348: return QChar(100); - case 65352: return QChar(104); - case 65356: return QChar(108); - case 65360: return QChar(112); - case 65364: return QChar(116); - case 65368: return QChar(120); - case 65299: return QChar(51); - case 65303: return QChar(55); - case 65315: return QChar(67); - case 65319: return QChar(71); - case 65323: return QChar(75); - case 65327: return QChar(79); - case 65331: return QChar(83); - case 65335: return QChar(87); - case 65347: return QChar(99); - case 65351: return QChar(103); - case 65355: return QChar(107); - case 65359: return QChar(111); - case 65363: return QChar(115); - case 65367: return QChar(119); - case 1105: return QChar(1077); - default: - break; - } - return QChar(0); - } -} - -QString textAccentFold(const QString &text) { - QString result(text); - bool copying = false; - int32 i = 0; - for (const QChar *s = text.unicode(), *ch = s, *e = text.unicode() + text.size(); ch != e; ++ch, ++i) { - if (ch->unicode() < 128) { - if (copying) result[i] = *ch; - continue; - } - if (chIsDiac(*ch)) { - copying = true; - --i; - continue; - } - if (ch->isHighSurrogate() && ch + 1 < e && (ch + 1)->isLowSurrogate()) { - QChar noAccent = chNoAccent(QChar::surrogateToUcs4(*ch, *(ch + 1))); - if (noAccent.unicode() > 0) { - copying = true; - result[i] = noAccent; - } else { - if (copying) result[i] = *ch; - ++ch, ++i; - if (copying) result[i] = *ch; - } - } else { - QChar noAccent = chNoAccent(ch->unicode()); - if (noAccent.unicode() > 0 && noAccent != *ch) { - result[i] = noAccent; - } else if (copying) { - result[i] = *ch; - } - } - } - return (i < result.size()) ? result.mid(0, i) : result; -} - -QString textSearchKey(const QString &text) { - return textAccentFold(text.trimmed().toLower()); -} - -bool textSplit(QString &sendingText, EntitiesInText &sendingEntities, QString &leftText, EntitiesInText &leftEntities, int32 limit) { - if (leftText.isEmpty() || !limit) return false; - - int32 currentEntity = 0, goodEntity = currentEntity, entityCount = leftEntities.size(); - bool goodInEntity = false, goodCanBreakEntity = false; - - int32 s = 0, half = limit / 2, goodLevel = 0; - for (const QChar *start = leftText.constData(), *ch = start, *end = leftText.constEnd(), *good = ch; ch != end; ++ch, ++s) { - while (currentEntity < entityCount && ch >= start + leftEntities[currentEntity].offset + leftEntities[currentEntity].length) { - ++currentEntity; - } - -#define MARK_GOOD_AS_LEVEL(level) \ -if (goodLevel <= (level)) {\ -goodLevel = (level);\ -good = ch;\ -goodEntity = currentEntity;\ -goodInEntity = inEntity;\ -goodCanBreakEntity = canBreakEntity;\ -} - - if (s > half) { - bool inEntity = (currentEntity < entityCount) && (ch > start + leftEntities[currentEntity].offset) && (ch < start + leftEntities[currentEntity].offset + leftEntities[currentEntity].length); - EntityInTextType entityType = (currentEntity < entityCount) ? leftEntities[currentEntity].type : EntityInTextBold; - bool canBreakEntity = (entityType == EntityInTextPre || entityType == EntityInTextCode); - int32 noEntityLevel = inEntity ? 0 : 1; - if (inEntity && !canBreakEntity) { - MARK_GOOD_AS_LEVEL(0); - } else { - if (chIsNewline(*ch)) { - if (inEntity) { - if (ch + 1 < end && chIsNewline(*(ch + 1))) { - MARK_GOOD_AS_LEVEL(12); - } else { - MARK_GOOD_AS_LEVEL(11); - } - } else if (ch + 1 < end && chIsNewline(*(ch + 1))) { - MARK_GOOD_AS_LEVEL(15); - } else if (currentEntity < entityCount && ch + 1 == start + leftEntities[currentEntity].offset && leftEntities[currentEntity].type == EntityInTextPre) { - MARK_GOOD_AS_LEVEL(14); - } else if (currentEntity > 0 && ch == start + leftEntities[currentEntity - 1].offset + leftEntities[currentEntity - 1].length && leftEntities[currentEntity - 1].type == EntityInTextPre) { - MARK_GOOD_AS_LEVEL(14); - } else { - MARK_GOOD_AS_LEVEL(13); - } - } else if (chIsSpace(*ch)) { - if (chIsSentenceEnd(*(ch - 1))) { - MARK_GOOD_AS_LEVEL(9 + noEntityLevel); - } else if (chIsSentencePartEnd(*(ch - 1))) { - MARK_GOOD_AS_LEVEL(7 + noEntityLevel); - } else { - MARK_GOOD_AS_LEVEL(5 + noEntityLevel); - } - } else if (chIsWordSeparator(*(ch - 1))) { - MARK_GOOD_AS_LEVEL(3 + noEntityLevel); - } else { - MARK_GOOD_AS_LEVEL(1 + noEntityLevel); - } - } - } - -#undef MARK_GOOD_AS_LEVEL - - int elen = 0; - if (EmojiPtr e = emojiFromText(ch, end, &elen)) { - for (int i = 0; i < elen; ++i, ++ch, ++s) { - if (ch->isHighSurrogate() && i + 1 < elen && (ch + 1)->isLowSurrogate()) { - ++ch; - ++i; - } - } - --ch; - --s; - } else if (ch->isHighSurrogate() && ch + 1 < end && (ch + 1)->isLowSurrogate()) { - ++ch; - } - if (s >= limit) { - sendingText = leftText.mid(0, good - start); - leftText = leftText.mid(good - start); - if (goodInEntity) { - if (goodCanBreakEntity) { - sendingEntities = leftEntities.mid(0, goodEntity + 1); - sendingEntities.back().length = good - start - sendingEntities.back().offset; - leftEntities = leftEntities.mid(goodEntity); - for (EntitiesInText::iterator i = leftEntities.begin(), e = leftEntities.end(); i != e; ++i) { - i->offset -= good - start; - if (i->offset < 0) { - i->length += i->offset; - i->offset = 0; - } - } - } else { - sendingEntities = leftEntities.mid(0, goodEntity); - leftEntities = leftEntities.mid(goodEntity + 1); - } - } else { - sendingEntities = leftEntities.mid(0, goodEntity); - leftEntities = leftEntities.mid(goodEntity); - for (EntitiesInText::iterator i = leftEntities.begin(), e = leftEntities.end(); i != e; ++i) { - i->offset -= good - start; - } - } - return true; - } - } - sendingText = leftText; - leftText = QString(); - sendingEntities = leftEntities; - leftEntities = EntitiesInText(); - return true; -} - -bool textcmdStartsLink(const QChar *start, int32 len, int32 commandOffset) { - if (commandOffset + 2 < len) { - if (*(start + commandOffset + 1) == TextCommandLinkIndex) { - return (*(start + commandOffset + 2) != 0); - } - return (*(start + commandOffset + 1) != TextCommandLinkText); - } - return false; -} - -bool checkTagStartInCommand(const QChar *start, int32 len, int32 tagStart, int32 &commandOffset, bool &commandIsLink, bool &inLink) { - bool inCommand = false; - const QChar *commandEnd = start + commandOffset; - while (commandOffset < len && tagStart > commandOffset) { // skip commands, evaluating are we in link or not - commandEnd = textSkipCommand(start + commandOffset, start + len); - if (commandEnd > start + commandOffset) { - if (tagStart < (commandEnd - start)) { - inCommand = true; - break; - } - for (commandOffset = commandEnd - start; commandOffset < len; ++commandOffset) { - if (*(start + commandOffset) == TextCommand) { - inLink = commandIsLink; - commandIsLink = textcmdStartsLink(start, len, commandOffset); - break; - } - } - if (commandOffset >= len) { - inLink = commandIsLink; - commandIsLink = false; - } - } else { - break; - } - } - if (inCommand) { - commandOffset = commandEnd - start; - } - return inCommand; -} - -EntitiesInText textParseEntities(QString &text, int32 flags, bool rich) { // some code is duplicated in flattextarea.cpp! - EntitiesInText result, mono; - - bool withHashtags = (flags & TextParseHashtags); - bool withMentions = (flags & TextParseMentions); - bool withBotCommands = (flags & TextParseBotCommands); - bool withMono = (flags & TextParseMono); - - if (withMono) { // parse mono entities (code and pre) - QString newText; - - int32 offset = 0, matchOffset = offset, len = text.size(), commandOffset = rich ? 0 : len; - bool inLink = false, commandIsLink = false; - const QChar *start = text.constData(); - for (; matchOffset < len;) { - if (commandOffset <= matchOffset) { - for (commandOffset = matchOffset; commandOffset < len; ++commandOffset) { - if (*(start + commandOffset) == TextCommand) { - inLink = commandIsLink; - commandIsLink = textcmdStartsLink(start, len, commandOffset); - break; - } - } - if (commandOffset >= len) { - inLink = commandIsLink; - commandIsLink = false; - } - } - QRegularExpressionMatch mPre = _rePre.match(text, matchOffset); - QRegularExpressionMatch mCode = _reCode.match(text, matchOffset), mTag; - if (!mPre.hasMatch() && !mCode.hasMatch()) break; - - int32 preStart = mPre.hasMatch() ? mPre.capturedStart() : INT_MAX, - preEnd = mPre.hasMatch() ? mPre.capturedEnd() : INT_MAX, - codeStart = mCode.hasMatch() ? mCode.capturedStart() : INT_MAX, - codeEnd = mCode.hasMatch() ? mCode.capturedEnd() : INT_MAX, - tagStart, tagEnd; - if (mPre.hasMatch()) { - if (!mPre.capturedRef(1).isEmpty()) { - ++preStart; - } - if (!mPre.capturedRef(4).isEmpty()) { - --preEnd; - } - } - if (mCode.hasMatch()) { - if (!mCode.capturedRef(1).isEmpty()) { - ++codeStart; - } - if (!mCode.capturedRef(4).isEmpty()) { - --codeEnd; - } - } - - bool pre = (preStart <= codeStart); - if (pre) { - tagStart = preStart; - tagEnd = preEnd; - mTag = mPre; - } else { - tagStart = codeStart; - tagEnd = codeEnd; - mTag = mCode; - } - - bool inCommand = checkTagStartInCommand(start, len, tagStart, commandOffset, commandIsLink, inLink); - if (inCommand || inLink) { - matchOffset = commandOffset; - continue; - } - - if (newText.isEmpty()) newText.reserve(text.size()); - - bool addNewlineBefore = false, addNewlineAfter = false; - int32 outerStart = tagStart, outerEnd = tagEnd; - int32 innerStart = tagStart + mTag.capturedLength(2), innerEnd = tagEnd - mTag.capturedLength(3); - if (pre) { - while (outerStart > 0 && chIsSpace(*(start + outerStart - 1), rich) && !chIsNewline(*(start + outerStart - 1))) { - --outerStart; - } - addNewlineBefore = (outerStart > 0 && !chIsNewline(*(start + outerStart - 1))); - - for (int32 testInnerStart = innerStart; testInnerStart < innerEnd; ++testInnerStart) { - if (chIsNewline(*(start + testInnerStart))) { - innerStart = testInnerStart + 1; - break; - } else if (!chIsSpace(*(start + testInnerStart))) { - break; - } - } - for (int32 testInnerEnd = innerEnd; innerStart < testInnerEnd;) { - --testInnerEnd; - if (chIsNewline(*(start + testInnerEnd))) { - innerEnd = testInnerEnd; - break; - } else if (!chIsSpace(*(start + testInnerEnd))) { - break; - } - } - - while (outerEnd < len && chIsSpace(*(start + outerEnd)) && !chIsNewline(*(start + outerEnd))) { - ++outerEnd; - } - addNewlineAfter = (outerEnd < len && !chIsNewline(*(start + outerEnd))); - } - if (outerStart > offset) newText.append(start + offset, outerStart - offset); - if (addNewlineBefore) newText.append('\n'); - - int32 tagLength = innerEnd - innerStart; - mono.push_back(EntityInText(pre ? EntityInTextPre : EntityInTextCode, newText.size(), tagLength)); - - newText.append(start + innerStart, tagLength); - if (addNewlineAfter) newText.append('\n'); - - offset = matchOffset = outerEnd; - } - if (!newText.isEmpty()) { - newText.append(start + offset, len - offset); - text = newText; - } - } - int32 monoEntity = 0, monoCount = mono.size(), monoTill = 0; - - initLinkSets(); - int32 len = text.size(), commandOffset = rich ? 0 : len; - bool inLink = false, commandIsLink = false; - const QChar *start = text.constData(), *end = start + text.size(); - for (int32 offset = 0, matchOffset = offset, mentionSkip = 0; offset < len;) { - if (commandOffset <= offset) { - for (commandOffset = offset; commandOffset < len; ++commandOffset) { - if (*(start + commandOffset) == TextCommand) { - inLink = commandIsLink; - commandIsLink = textcmdStartsLink(start, len, commandOffset); - break; - } - } - } - QRegularExpressionMatch mDomain = _reDomain.match(text, matchOffset); - QRegularExpressionMatch mExplicitDomain = _reExplicitDomain.match(text, matchOffset); - QRegularExpressionMatch mHashtag = withHashtags ? _reHashtag.match(text, matchOffset) : QRegularExpressionMatch(); - QRegularExpressionMatch mMention = withMentions ? _reMention.match(text, qMax(mentionSkip, matchOffset)) : QRegularExpressionMatch(); - QRegularExpressionMatch mBotCommand = withBotCommands ? _reBotCommand.match(text, matchOffset) : QRegularExpressionMatch(); - - EntityInTextType lnkType = EntityInTextUrl; - int32 lnkStart = 0, lnkLength = 0; - int32 domainStart = mDomain.hasMatch() ? mDomain.capturedStart() : INT_MAX, - domainEnd = mDomain.hasMatch() ? mDomain.capturedEnd() : INT_MAX, - explicitDomainStart = mExplicitDomain.hasMatch() ? mExplicitDomain.capturedStart() : INT_MAX, - explicitDomainEnd = mExplicitDomain.hasMatch() ? mExplicitDomain.capturedEnd() : INT_MAX, - hashtagStart = mHashtag.hasMatch() ? mHashtag.capturedStart() : INT_MAX, - hashtagEnd = mHashtag.hasMatch() ? mHashtag.capturedEnd() : INT_MAX, - mentionStart = mMention.hasMatch() ? mMention.capturedStart() : INT_MAX, - mentionEnd = mMention.hasMatch() ? mMention.capturedEnd() : INT_MAX, - botCommandStart = mBotCommand.hasMatch() ? mBotCommand.capturedStart() : INT_MAX, - botCommandEnd = mBotCommand.hasMatch() ? mBotCommand.capturedEnd() : INT_MAX; - if (mHashtag.hasMatch()) { - if (!mHashtag.capturedRef(1).isEmpty()) { - ++hashtagStart; - } - if (!mHashtag.capturedRef(2).isEmpty()) { - --hashtagEnd; - } - } - while (mMention.hasMatch()) { - if (!mMention.capturedRef(1).isEmpty()) { - ++mentionStart; - } - if (!mMention.capturedRef(2).isEmpty()) { - --mentionEnd; - } - if (!(start + mentionStart + 1)->isLetter() || !(start + mentionEnd - 1)->isLetterOrNumber()) { - mentionSkip = mentionEnd; - mMention = _reMention.match(text, qMax(mentionSkip, matchOffset)); - if (mMention.hasMatch()) { - mentionStart = mMention.capturedStart(); - mentionEnd = mMention.capturedEnd(); - } else { - mentionStart = INT_MAX; - mentionEnd = INT_MAX; - } - } else { - break; - } - } - if (mBotCommand.hasMatch()) { - if (!mBotCommand.capturedRef(1).isEmpty()) { - ++botCommandStart; - } - if (!mBotCommand.capturedRef(3).isEmpty()) { - --botCommandEnd; - } - } - if (!mDomain.hasMatch() && !mExplicitDomain.hasMatch() && !mHashtag.hasMatch() && !mMention.hasMatch() && !mBotCommand.hasMatch()) { - break; - } - - if (explicitDomainStart < domainStart) { - domainStart = explicitDomainStart; - domainEnd = explicitDomainEnd; - mDomain = mExplicitDomain; - } - if (mentionStart < hashtagStart && mentionStart < domainStart && mentionStart < botCommandStart) { - bool inCommand = checkTagStartInCommand(start, len, mentionStart, commandOffset, commandIsLink, inLink); - if (inCommand || inLink) { - offset = matchOffset = commandOffset; - continue; - } - - lnkType = EntityInTextMention; - lnkStart = mentionStart; - lnkLength = mentionEnd - mentionStart; - } else if (hashtagStart < domainStart && hashtagStart < botCommandStart) { - bool inCommand = checkTagStartInCommand(start, len, hashtagStart, commandOffset, commandIsLink, inLink); - if (inCommand || inLink) { - offset = matchOffset = commandOffset; - continue; - } - - lnkType = EntityInTextHashtag; - lnkStart = hashtagStart; - lnkLength = hashtagEnd - hashtagStart; - } else if (botCommandStart < domainStart) { - bool inCommand = checkTagStartInCommand(start, len, botCommandStart, commandOffset, commandIsLink, inLink); - if (inCommand || inLink) { - offset = matchOffset = commandOffset; - continue; - } - - lnkType = EntityInTextBotCommand; - lnkStart = botCommandStart; - lnkLength = botCommandEnd - botCommandStart; - } else { - bool inCommand = checkTagStartInCommand(start, len, domainStart, commandOffset, commandIsLink, inLink); - if (inCommand || inLink) { - offset = matchOffset = commandOffset; - continue; - } - - QString protocol = mDomain.captured(1).toLower(); - QString topDomain = mDomain.captured(3).toLower(); - - bool isProtocolValid = protocol.isEmpty() || _validProtocols.contains(hashCrc32(protocol.constData(), protocol.size() * sizeof(QChar))); - bool isTopDomainValid = !protocol.isEmpty() || _validTopDomains.contains(hashCrc32(topDomain.constData(), topDomain.size() * sizeof(QChar))); - - if (protocol.isEmpty() && domainStart > offset + 1 && *(start + domainStart - 1) == QChar('@')) { - QString forMailName = text.mid(offset, domainStart - offset - 1); - QRegularExpressionMatch mMailName = _reMailName.match(forMailName); - if (mMailName.hasMatch()) { - int32 mailStart = offset + mMailName.capturedStart(); - if (mailStart < offset) { - mailStart = offset; - } - lnkType = EntityInTextEmail; - lnkStart = mailStart; - lnkLength = domainEnd - mailStart; - } - } - if (lnkType == EntityInTextUrl && !lnkLength) { - if (!isProtocolValid || !isTopDomainValid) { - matchOffset = domainEnd; - continue; - } - lnkStart = domainStart; - - QStack parenth; - const QChar *domainEnd = start + mDomain.capturedEnd(), *p = domainEnd; - for (; p < end; ++p) { - QChar ch(*p); - if (chIsLinkEnd(ch)) break; // link finished - if (chIsAlmostLinkEnd(ch)) { - const QChar *endTest = p + 1; - while (endTest < end && chIsAlmostLinkEnd(*endTest)) { - ++endTest; - } - if (endTest >= end || chIsLinkEnd(*endTest)) { - break; // link finished at p - } - p = endTest; - ch = *p; - } - if (ch == '(' || ch == '[' || ch == '{' || ch == '<') { - parenth.push(p); - } else if (ch == ')' || ch == ']' || ch == '}' || ch == '>') { - if (parenth.isEmpty()) break; - const QChar *q = parenth.pop(), open(*q); - if ((ch == ')' && open != '(') || (ch == ']' && open != '[') || (ch == '}' && open != '{') || (ch == '>' && open != '<')) { - p = q; - break; - } - } - } - if (p > domainEnd) { // check, that domain ended - if (domainEnd->unicode() != '/' && domainEnd->unicode() != '?') { - matchOffset = domainEnd - start; - continue; - } - } - lnkLength = (p - start) - lnkStart; - } - } - for (; monoEntity < monoCount && mono[monoEntity].offset <= lnkStart; ++monoEntity) { - monoTill = qMax(monoTill, mono[monoEntity].offset + mono[monoEntity].length); - result.push_back(mono[monoEntity]); - } - if (lnkStart >= monoTill) { - result.push_back(EntityInText(lnkType, lnkStart, lnkLength)); - } - - offset = matchOffset = lnkStart + lnkLength; - } - for (; monoEntity < monoCount; ++monoEntity) { - monoTill = qMax(monoTill, mono[monoEntity].offset + mono[monoEntity].length); - result.push_back(mono[monoEntity]); - } - - return result; -} - -QString textApplyEntities(const QString &text, const EntitiesInText &entities) { - if (entities.isEmpty()) return text; - - QMultiMap closingTags; - QString code(qsl("`")), pre(qsl("```")); - - QString result; - int32 size = text.size(); - const QChar *b = text.constData(), *already = b, *e = b + size; - EntitiesInText::const_iterator entity = entities.cbegin(), end = entities.cend(); - while (entity != end && ((entity->type != EntityInTextCode && entity->type != EntityInTextPre) || entity->length <= 0 || entity->offset >= size)) { - ++entity; - } - while (entity != end || !closingTags.isEmpty()) { - int32 nextOpenEntity = (entity == end) ? (size + 1) : entity->offset; - int32 nextCloseEntity = closingTags.isEmpty() ? (size + 1) : closingTags.cbegin().key(); - if (nextOpenEntity <= nextCloseEntity) { - QString tag = (entity->type == EntityInTextCode) ? code : pre; - if (result.isEmpty()) result.reserve(text.size() + entities.size() * pre.size() * 2); - - const QChar *offset = b + nextOpenEntity; - if (offset > already) { - result.append(already, offset - already); - already = offset; - } - result.append(tag); - closingTags.insert(qMin(entity->offset + entity->length, size), tag); - - ++entity; - while (entity != end && ((entity->type != EntityInTextCode && entity->type != EntityInTextPre) || entity->length <= 0 || entity->offset >= size)) { - ++entity; - } - } else { - const QChar *offset = b + nextCloseEntity; - if (offset > already) { - result.append(already, offset - already); - already = offset; - } - result.append(closingTags.cbegin().value()); - closingTags.erase(closingTags.begin()); - } - } - if (result.isEmpty()) { - return text; - } - const QChar *offset = b + size; - if (offset > already) { - result.append(already, offset - already); - } - return result; -} - void emojiDraw(QPainter &p, EmojiPtr e, int x, int y) { p.drawPixmap(QPoint(x, y), App::emoji(), QRect(e->x * ESize, e->y * ESize, ESize, ESize)); } - -void replaceStringWithEntities(const QLatin1String &from, QChar to, QString &result, EntitiesInText &entities, bool checkSpace = false) { - int32 len = from.size(), s = result.size(), offset = 0, length = 0; - EntitiesInText::iterator i = entities.begin(), e = entities.end(); - for (QChar *start = result.data(); offset < s;) { - int32 nextOffset = result.indexOf(from, offset); - if (nextOffset < 0) { - moveStringPart(start, length, offset, s - offset, entities); - break; - } - - if (checkSpace) { - bool spaceBefore = (nextOffset > 0) && (start + nextOffset - 1)->isSpace(); - bool spaceAfter = (nextOffset + len < s) && (start + nextOffset + len)->isSpace(); - if (!spaceBefore && !spaceAfter) { - moveStringPart(start, length, offset, nextOffset - offset + len + 1, entities); - continue; - } - } - - bool skip = false; - for (; i != e; ++i) { // find and check next finishing entity - if (i->offset + i->length > nextOffset) { - skip = (i->offset < nextOffset + len); - break; - } - } - if (skip) { - moveStringPart(start, length, offset, nextOffset - offset + len, entities); - continue; - } - - moveStringPart(start, length, offset, nextOffset - offset, entities); - - *(start + length) = to; - ++length; - offset += len; - } - if (length < s) result.resize(length); -} - -QString prepareTextWithEntities(QString result, EntitiesInText &entities, int32 flags) { - cleanTextWithEntities(result, entities); - - if (flags) { - entities = textParseEntities(result, flags); - } - - replaceStringWithEntities(qstr("--"), QChar(8212), result, entities, true); - replaceStringWithEntities(qstr("<<"), QChar(171), result, entities); - replaceStringWithEntities(qstr(">>"), QChar(187), result, entities); - - if (cReplaceEmojis()) { - result = replaceEmojis(result, entities); - } - - trimTextWithEntities(result, entities); - - return result; -} diff --git a/Telegram/SourceFiles/ui/text.h b/Telegram/SourceFiles/ui/text/text.h similarity index 51% rename from Telegram/SourceFiles/ui/text.h rename to Telegram/SourceFiles/ui/text/text.h index 6f73c5dae..0c9cf24e3 100644 --- a/Telegram/SourceFiles/ui/text.h +++ b/Telegram/SourceFiles/ui/text/text.h @@ -20,296 +20,11 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #pragma once -#include "core/click_handler.h" - -enum EntityInTextType { - EntityInTextUrl, - EntityInTextCustomUrl, - EntityInTextEmail, - EntityInTextHashtag, - EntityInTextMention, - EntityInTextBotCommand, - - EntityInTextBold, - EntityInTextItalic, - EntityInTextCode, // inline - EntityInTextPre, // block -}; -struct EntityInText { - EntityInText(EntityInTextType type, int offset, int length, const QString &text = QString()) : type(type), offset(offset), length(length), text(text) { - } - EntityInTextType type; - int offset, length; - QString text; -}; -typedef QList EntitiesInText; - -// text preprocess -QString textClean(const QString &text); -QString textRichPrepare(const QString &text); -QString textOneLine(const QString &text, bool trim = true, bool rich = false); -QString textAccentFold(const QString &text); -QString textSearchKey(const QString &text); -bool textSplit(QString &sendingText, EntitiesInText &sendingEntities, QString &leftText, EntitiesInText &leftEntities, int32 limit); - -enum { - TextParseMultiline = 0x001, - TextParseLinks = 0x002, - TextParseRichText = 0x004, - TextParseMentions = 0x008, - TextParseHashtags = 0x010, - TextParseBotCommands = 0x020, - TextParseMono = 0x040, - - TextTwitterMentions = 0x100, - TextTwitterHashtags = 0x200, - TextInstagramMentions = 0x400, - TextInstagramHashtags = 0x800, -}; - -inline EntitiesInText entitiesFromMTP(const QVector &entities) { - EntitiesInText result; - if (!entities.isEmpty()) { - result.reserve(entities.size()); - for (int32 i = 0, l = entities.size(); i != l; ++i) { - const auto &e(entities.at(i)); - switch (e.type()) { - case mtpc_messageEntityUrl: { const auto &d(e.c_messageEntityUrl()); result.push_back(EntityInText(EntityInTextUrl, d.voffset.v, d.vlength.v)); } break; - case mtpc_messageEntityTextUrl: { const auto &d(e.c_messageEntityTextUrl()); result.push_back(EntityInText(EntityInTextCustomUrl, d.voffset.v, d.vlength.v, textClean(qs(d.vurl)))); } break; - case mtpc_messageEntityEmail: { const auto &d(e.c_messageEntityEmail()); result.push_back(EntityInText(EntityInTextEmail, d.voffset.v, d.vlength.v)); } break; - case mtpc_messageEntityHashtag: { const auto &d(e.c_messageEntityHashtag()); result.push_back(EntityInText(EntityInTextHashtag, d.voffset.v, d.vlength.v)); } break; - case mtpc_messageEntityMention: { const auto &d(e.c_messageEntityMention()); result.push_back(EntityInText(EntityInTextMention, d.voffset.v, d.vlength.v)); } break; - case mtpc_messageEntityBotCommand: { const auto &d(e.c_messageEntityBotCommand()); result.push_back(EntityInText(EntityInTextBotCommand, d.voffset.v, d.vlength.v)); } break; - case mtpc_messageEntityBold: { const auto &d(e.c_messageEntityBold()); result.push_back(EntityInText(EntityInTextBold, d.voffset.v, d.vlength.v)); } break; - case mtpc_messageEntityItalic: { const auto &d(e.c_messageEntityItalic()); result.push_back(EntityInText(EntityInTextItalic, d.voffset.v, d.vlength.v)); } break; - case mtpc_messageEntityCode: { const auto &d(e.c_messageEntityCode()); result.push_back(EntityInText(EntityInTextCode, d.voffset.v, d.vlength.v)); } break; - case mtpc_messageEntityPre: { const auto &d(e.c_messageEntityPre()); result.push_back(EntityInText(EntityInTextPre, d.voffset.v, d.vlength.v, textClean(qs(d.vlanguage)))); } break; - } - } - } - return result; -} -inline MTPVector linksToMTP(const EntitiesInText &links, bool sending = false) { - MTPVector result(MTP_vector(0)); - QVector &v(result._vector().v); - for (int32 i = 0, s = links.size(); i != s; ++i) { - const EntityInText &l(links.at(i)); - if (l.length <= 0 || (sending && l.type != EntityInTextCode && l.type != EntityInTextPre)) continue; - - switch (l.type) { - case EntityInTextUrl: v.push_back(MTP_messageEntityUrl(MTP_int(l.offset), MTP_int(l.length))); break; - case EntityInTextCustomUrl: v.push_back(MTP_messageEntityTextUrl(MTP_int(l.offset), MTP_int(l.length), MTP_string(l.text))); break; - case EntityInTextEmail: v.push_back(MTP_messageEntityEmail(MTP_int(l.offset), MTP_int(l.length))); break; - case EntityInTextHashtag: v.push_back(MTP_messageEntityHashtag(MTP_int(l.offset), MTP_int(l.length))); break; - case EntityInTextMention: v.push_back(MTP_messageEntityMention(MTP_int(l.offset), MTP_int(l.length))); break; - case EntityInTextBotCommand: v.push_back(MTP_messageEntityBotCommand(MTP_int(l.offset), MTP_int(l.length))); break; - case EntityInTextBold: v.push_back(MTP_messageEntityBold(MTP_int(l.offset), MTP_int(l.length))); break; - case EntityInTextItalic: v.push_back(MTP_messageEntityItalic(MTP_int(l.offset), MTP_int(l.length))); break; - case EntityInTextCode: v.push_back(MTP_messageEntityCode(MTP_int(l.offset), MTP_int(l.length))); break; - case EntityInTextPre: v.push_back(MTP_messageEntityPre(MTP_int(l.offset), MTP_int(l.length), MTP_string(l.text))); break; - } - } - return result; -} -EntitiesInText textParseEntities(QString &text, int32 flags, bool rich = false); // changes text if (flags & TextParseMono) -QString textApplyEntities(const QString &text, const EntitiesInText &entities); - -#include "ui/emoji_config.h" - -void emojiDraw(QPainter &p, EmojiPtr e, int x, int y); - #include "../../../QtStatic/qtbase/src/gui/text/qfontengine_p.h" -enum TextBlockType { - TextBlockTNewline = 0x01, - TextBlockTText = 0x02, - TextBlockTEmoji = 0x03, - TextBlockTSkip = 0x04, -}; - -enum TextBlockFlags { - TextBlockFBold = 0x01, - TextBlockFItalic = 0x02, - TextBlockFUnderline = 0x04, - TextBlockFTilde = 0x08, // tilde fix in OpenSans - TextBlockFSemibold = 0x10, - TextBlockFCode = 0x20, - TextBlockFPre = 0x40, -}; - -class ITextBlock { -public: - - ITextBlock(const style::font &font, const QString &str, uint16 from, uint16 length, uchar flags, const style::color &color, uint16 lnkIndex) : _from(from), _flags((flags & 0xFF) | ((lnkIndex & 0xFFFF) << 12))/*, _color(color)*/, _lpadding(0) { - if (length) { - if (str.at(_from + length - 1).unicode() == QChar::Space) { - _rpadding = font->spacew; - } - if (length > 1 && str.at(0).unicode() == QChar::Space) { - _lpadding = font->spacew; - } - } - } - - uint16 from() const { - return _from; - } - int32 width() const { - return _width.toInt(); - } - int32 lpadding() const { - return _lpadding.toInt(); - } - int32 rpadding() const { - return _rpadding.toInt(); - } - QFixed f_width() const { - return _width; - } - QFixed f_lpadding() const { - return _lpadding; - } - QFixed f_rpadding() const { - return _rpadding; - } - - uint16 lnkIndex() const { - return (_flags >> 12) & 0xFFFF; - } - void setLnkIndex(uint16 lnkIndex) { - _flags = (_flags & ~(0xFFFF << 12)) | (lnkIndex << 12); - } - - TextBlockType type() const { - return TextBlockType((_flags >> 8) & 0x0F); - } - int32 flags() const { - return (_flags & 0xFF); - } - const style::color &color() const { - static style::color tmp; - return tmp;//_color; - } - - virtual ITextBlock *clone() const = 0; - virtual ~ITextBlock() { - } - -protected: - - uint16 _from; - - uint32 _flags; // 4 bits empty, 16 bits lnkIndex, 4 bits type, 8 bits flags - - QFixed _width, _lpadding, _rpadding; - -}; - -class NewlineBlock : public ITextBlock { -public: - - Qt::LayoutDirection nextDirection() const { - return _nextDir; - } - - ITextBlock *clone() const { - return new NewlineBlock(*this); - } - -private: - - NewlineBlock(const style::font &font, const QString &str, uint16 from, uint16 length) : ITextBlock(font, str, from, length, 0, st::transparent, 0), _nextDir(Qt::LayoutDirectionAuto) { - _flags |= ((TextBlockTNewline & 0x0F) << 8); - } - - Qt::LayoutDirection _nextDir; - - friend class Text; - friend class TextParser; - - friend class TextPainter; -}; - -struct TextWord { - TextWord() { - } - TextWord(uint16 from, QFixed width, QFixed rbearing, QFixed rpadding = 0) : from(from), - _rbearing(rbearing.value() > 0x7FFF ? 0x7FFF : (rbearing.value() < -0x7FFF ? -0x7FFF : rbearing.value())), width(width), rpadding(rpadding) { - } - QFixed f_rbearing() const { - return QFixed::fromFixed(_rbearing); - } - uint16 from; - int16 _rbearing; - QFixed width, rpadding; -}; - -class TextBlock : public ITextBlock { -public: - - QFixed f_rbearing() const { - return _words.isEmpty() ? 0 : _words.back().f_rbearing(); - } - - ITextBlock *clone() const { - return new TextBlock(*this); - } - -private: - - TextBlock(const style::font &font, const QString &str, QFixed minResizeWidth, uint16 from, uint16 length, uchar flags, const style::color &color, uint16 lnkIndex); - - typedef QVector TextWords; - TextWords _words; - - friend class Text; - friend class TextParser; - - friend class BlockParser; - friend class TextPainter; -}; - -class EmojiBlock : public ITextBlock { -public: - - ITextBlock *clone() const { - return new EmojiBlock(*this); - } - -private: - - EmojiBlock(const style::font &font, const QString &str, uint16 from, uint16 length, uchar flags, const style::color &color, uint16 lnkIndex, const EmojiData *emoji); - - const EmojiData *emoji; - - friend class Text; - friend class TextParser; - - friend class TextPainter; -}; - -class SkipBlock : public ITextBlock { -public: - - int32 height() const { - return _height; - } - - ITextBlock *clone() const { - return new SkipBlock(*this); - } - -private: - - SkipBlock(const style::font &font, const QString &str, uint16 from, int32 w, int32 h, uint16 lnkIndex); - - int32 _height; - - friend class Text; - friend class TextParser; - - friend class TextPainter; -}; +#include "core/click_handler.h" +#include "ui/text/text_entity.h" +#include "ui/emoji_config.h" static const QChar TextCommand(0x0010); enum TextCommands { @@ -349,6 +64,9 @@ struct TextSelection { } constexpr TextSelection(uint16 from, uint16 to) : from(from), to(to) { } + constexpr bool empty() const { + return from == to; + } uint16 from : 16; uint16 to : 16; }; @@ -364,6 +82,7 @@ static constexpr TextSelection AllTextSelection = { 0, 0xFFFF }; typedef QPair TextCustomTag; // open str and close str typedef QMap TextCustomTagsMap; +class ITextBlock; class Text { public: @@ -383,9 +102,7 @@ public: void setLink(uint16 lnkIndex, const ClickHandlerPtr &lnk); bool hasLinks() const; - bool hasSkipBlock() const { - return _blocks.isEmpty() ? false : _blocks.back()->type() == TextBlockTSkip; - } + bool hasSkipBlock() const; void setSkipBlock(int32 width, int32 height); void removeSkipBlock(); @@ -462,7 +179,7 @@ public: ExpandLinksShortened, ExpandLinksAll, }; - QString original(TextSelection selection = { 0, 0xFFFF }, ExpandLinksMode mode = ExpandLinksShortened) const; + QString original(TextSelection selection = AllTextSelection, ExpandLinksMode mode = ExpandLinksShortened) const; EntitiesInText originalEntities() const; bool lastDots(int32 dots, int32 maxdots = 3) { // hack for typing animation @@ -539,9 +256,8 @@ const QRegularExpression &reBotCommand(); // text style const style::textStyle *textstyleCurrent(); void textstyleSet(const style::textStyle *style); - inline void textstyleRestore() { - textstyleSet(0); + textstyleSet(nullptr); } // textcmd @@ -681,96 +397,4 @@ inline QString myUrlDecode(const QString &enc) { return QUrl::fromPercentEncoding(enc.toUtf8()); } -QString prepareTextWithEntities(QString result, EntitiesInText &entities, int32 flags); - -inline QString prepareText(QString result, bool checkLinks = false) { - EntitiesInText entities; - return prepareTextWithEntities(result, entities, checkLinks ? (TextParseLinks | TextParseMentions | TextParseHashtags | TextParseBotCommands) : 0); -} - -inline void moveStringPart(QChar *start, int32 &to, int32 &from, int32 count, EntitiesInText &entities) { - if (count > 0) { - if (to < from) { - memmove(start + to, start + from, count * sizeof(QChar)); - for (EntitiesInText::iterator i = entities.begin(), e = entities.end(); i != e; ++i) { - if (i->offset >= from + count) break; - if (i->offset + i->length < from) continue; - if (i->offset >= from) { - i->offset -= (from - to); - i->length += (from - to); - } - if (i->offset + i->length < from + count) { - i->length -= (from - to); - } - } - } - to += count; - from += count; - } -} - -// replace bad symbols with space and remove \r -inline void cleanTextWithEntities(QString &result, EntitiesInText &entities) { - result = result.replace('\t', qstr(" ")); - int32 len = result.size(), to = 0, from = 0; - QChar *start = result.data(); - for (QChar *ch = start, *end = start + len; ch < end; ++ch) { - if (ch->unicode() == '\r') { - moveStringPart(start, to, from, (ch - start) - from, entities); - ++from; - } else if (chReplacedBySpace(*ch)) { - *ch = ' '; - } - } - moveStringPart(start, to, from, len - from, entities); - if (to < len) result.resize(to); -} - -inline void trimTextWithEntities(QString &result, EntitiesInText &entities) { - bool foundNotTrimmed = false; - for (QChar *s = result.data(), *e = s + result.size(), *ch = e; ch != s;) { // rtrim - --ch; - if (!chIsTrimmed(*ch)) { - if (ch + 1 < e) { - int32 l = ch + 1 - s; - for (EntitiesInText::iterator i = entities.begin(), e = entities.end(); i != e; ++i) { - if (i->offset > l) { - i->offset = l; - i->length = 0; - } else if (i->offset + i->length > l) { - i->length = l - i->offset; - } - } - result.resize(l); - } - foundNotTrimmed = true; - break; - } - } - if (!foundNotTrimmed) { - result.clear(); - entities.clear(); - return; - } - - for (QChar *s = result.data(), *ch = s, *e = s + result.size(); ch != e; ++ch) { // ltrim - if (!chIsTrimmed(*ch)) { - if (ch > s) { - int32 l = ch - s; - for (EntitiesInText::iterator i = entities.begin(), e = entities.end(); i != e; ++i) { - if (i->offset + i->length <= l) { - i->length = 0; - i->offset = 0; - } else if (i->offset < l) { - i->length = i->offset + i->length - l; - i->offset = 0; - } else { - i->offset -= l; - } - } - result = result.mid(l); - } - break; - } - } -} +void emojiDraw(QPainter &p, EmojiPtr e, int x, int y); diff --git a/Telegram/SourceFiles/ui/text/text_block.cpp b/Telegram/SourceFiles/ui/text/text_block.cpp new file mode 100644 index 000000000..0505636b5 --- /dev/null +++ b/Telegram/SourceFiles/ui/text/text_block.cpp @@ -0,0 +1,322 @@ +/* +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 "ui/text/text_block.h" + +// COPIED FROM qtextlayout.cpp AND MODIFIED +namespace { + +struct ScriptLine { + ScriptLine() : length(0), textWidth(0) { + } + + int32 length; + QFixed textWidth; +}; + +struct LineBreakHelper +{ + LineBreakHelper() + : glyphCount(0), maxGlyphs(0), currentPosition(0), fontEngine(0), logClusters(0) + { + } + + + ScriptLine tmpData; + ScriptLine spaceData; + + QGlyphLayout glyphs; + + int glyphCount; + int maxGlyphs; + int currentPosition; + glyph_t previousGlyph; + + QFixed rightBearing; + + QFontEngine *fontEngine; + const unsigned short *logClusters; + + inline glyph_t currentGlyph() const + { + Q_ASSERT(currentPosition > 0); + Q_ASSERT(logClusters[currentPosition - 1] < glyphs.numGlyphs); + + return glyphs.glyphs[logClusters[currentPosition - 1]]; + } + + inline void saveCurrentGlyph() + { + previousGlyph = 0; + if (currentPosition > 0 && + logClusters[currentPosition - 1] < glyphs.numGlyphs) { + previousGlyph = currentGlyph(); // needed to calculate right bearing later + } + } + + inline void adjustRightBearing(glyph_t glyph) + { + qreal rb; + fontEngine->getGlyphBearings(glyph, 0, &rb); + rightBearing = qMin(QFixed(), QFixed::fromReal(rb)); + } + + inline void adjustRightBearing() + { + if (currentPosition <= 0) + return; + adjustRightBearing(currentGlyph()); + } + + inline void adjustPreviousRightBearing() + { + if (previousGlyph > 0) + adjustRightBearing(previousGlyph); + } + +}; + +static inline void addNextCluster(int &pos, int end, ScriptLine &line, int &glyphCount, + const QScriptItem ¤t, const unsigned short *logClusters, + const QGlyphLayout &glyphs) +{ + int glyphPosition = logClusters[pos]; + do { // got to the first next cluster + ++pos; + ++line.length; + } while (pos < end && logClusters[pos] == glyphPosition); + do { // calculate the textWidth for the rest of the current cluster. + if (!glyphs.attributes[glyphPosition].dontPrint) + line.textWidth += glyphs.advances[glyphPosition]; + ++glyphPosition; + } while (glyphPosition < current.num_glyphs && !glyphs.attributes[glyphPosition].clusterStart); + + Q_ASSERT((pos == end && glyphPosition == current.num_glyphs) || logClusters[pos] == glyphPosition); + + ++glyphCount; +} + +} // anonymous namespace + +class BlockParser { +public: + + BlockParser(QTextEngine *e, TextBlock *b, QFixed minResizeWidth, int32 blockFrom, const QString &str) + : block(b), eng(e), str(str) { + parseWords(minResizeWidth, blockFrom); + } + + void parseWords(QFixed minResizeWidth, int32 blockFrom) { + LineBreakHelper lbh; + + lbh.maxGlyphs = INT_MAX; + + int item = -1; + int newItem = eng->findItem(0); + + style::align alignment = eng->option.alignment(); + + const QCharAttributes *attributes = eng->attributes(); + if (!attributes) + return; + lbh.currentPosition = 0; + int end = 0; + lbh.logClusters = eng->layoutData->logClustersPtr; + lbh.previousGlyph = 0; + + block->_lpadding = 0; + block->_words.clear(); + + int wordStart = lbh.currentPosition; + + bool addingEachGrapheme = false; + int lastGraphemeBoundaryPosition = -1; + ScriptLine lastGraphemeBoundaryLine; + + while (newItem < eng->layoutData->items.size()) { + if (newItem != item) { + item = newItem; + const QScriptItem ¤t = eng->layoutData->items[item]; + if (!current.num_glyphs) { + eng->shape(item); + attributes = eng->attributes(); + if (!attributes) + return; + lbh.logClusters = eng->layoutData->logClustersPtr; + } + lbh.currentPosition = current.position; + end = current.position + eng->length(item); + lbh.glyphs = eng->shapedGlyphs(¤t); + QFontEngine *fontEngine = eng->fontEngine(current); + if (lbh.fontEngine != fontEngine) { + lbh.fontEngine = fontEngine; + } + } + const QScriptItem ¤t = eng->layoutData->items[item]; + + if (attributes[lbh.currentPosition].whiteSpace) { + while (lbh.currentPosition < end && attributes[lbh.currentPosition].whiteSpace) + addNextCluster(lbh.currentPosition, end, lbh.spaceData, lbh.glyphCount, + current, lbh.logClusters, lbh.glyphs); + + if (block->_words.isEmpty()) { + block->_lpadding = lbh.spaceData.textWidth; + } else { + block->_words.back().rpadding += lbh.spaceData.textWidth; + block->_width += lbh.spaceData.textWidth; + } + lbh.spaceData.length = 0; + lbh.spaceData.textWidth = 0; + + wordStart = lbh.currentPosition; + + addingEachGrapheme = false; + lastGraphemeBoundaryPosition = -1; + lastGraphemeBoundaryLine = ScriptLine(); + } else { + do { + addNextCluster(lbh.currentPosition, end, lbh.tmpData, lbh.glyphCount, + current, lbh.logClusters, lbh.glyphs); + + if (lbh.currentPosition >= eng->layoutData->string.length() + || attributes[lbh.currentPosition].whiteSpace + || isLineBreak(attributes, lbh.currentPosition)) { + lbh.adjustRightBearing(); + block->_words.push_back(TextWord(wordStart + blockFrom, lbh.tmpData.textWidth, qMin(QFixed(), lbh.rightBearing))); + block->_width += lbh.tmpData.textWidth; + lbh.tmpData.textWidth = 0; + lbh.tmpData.length = 0; + wordStart = lbh.currentPosition; + break; + } else if (attributes[lbh.currentPosition].graphemeBoundary) { + if (!addingEachGrapheme && lbh.tmpData.textWidth > minResizeWidth) { + if (lastGraphemeBoundaryPosition >= 0) { + lbh.adjustPreviousRightBearing(); + block->_words.push_back(TextWord(wordStart + blockFrom, -lastGraphemeBoundaryLine.textWidth, qMin(QFixed(), lbh.rightBearing))); + block->_width += lastGraphemeBoundaryLine.textWidth; + lbh.tmpData.textWidth -= lastGraphemeBoundaryLine.textWidth; + lbh.tmpData.length -= lastGraphemeBoundaryLine.length; + wordStart = lastGraphemeBoundaryPosition; + } + addingEachGrapheme = true; + } + if (addingEachGrapheme) { + lbh.adjustRightBearing(); + block->_words.push_back(TextWord(wordStart + blockFrom, -lbh.tmpData.textWidth, qMin(QFixed(), lbh.rightBearing))); + block->_width += lbh.tmpData.textWidth; + lbh.tmpData.textWidth = 0; + lbh.tmpData.length = 0; + wordStart = lbh.currentPosition; + } else { + lastGraphemeBoundaryPosition = lbh.currentPosition; + lastGraphemeBoundaryLine = lbh.tmpData; + lbh.saveCurrentGlyph(); + } + } + } while (lbh.currentPosition < end); + } + if (lbh.currentPosition == end) + newItem = item + 1; + } + if (block->_words.isEmpty()) { + block->_rpadding = 0; + } else { + block->_rpadding = block->_words.back().rpadding; + block->_width -= block->_rpadding; + block->_words.squeeze(); + } + } + + bool isLineBreak(const QCharAttributes *attributes, int32 index) { + bool lineBreak = attributes[index].lineBreak; + if (lineBreak && block->lnkIndex() > 0 && index > 0 && str.at(index - 1) == '/') { + return false; // don't break after / in links + } + return lineBreak; + } + +private: + + TextBlock *block; + QTextEngine *eng; + const QString &str; + +}; + +TextBlock::TextBlock(const style::font &font, const QString &str, QFixed minResizeWidth, uint16 from, uint16 length, uchar flags, const style::color &color, uint16 lnkIndex) : ITextBlock(font, str, from, length, flags, color, lnkIndex) { + _flags |= ((TextBlockTText & 0x0F) << 8); + if (length) { + style::font blockFont = font; + if (!flags && lnkIndex) { + // should use textStyle lnkFlags somehow... not supported + } + + if ((flags & TextBlockFPre) || (flags & TextBlockFCode)) { + blockFont = App::monofont(); + if (blockFont->size() != font->size() || blockFont->flags() != font->flags()) { + blockFont = style::font(font->size(), font->flags(), blockFont->family()); + } + } else { + if (flags & TextBlockFBold) { + blockFont = blockFont->bold(); + } else if (flags & TextBlockFSemibold) { + blockFont = st::semiboldFont; + if (blockFont->size() != font->size() || blockFont->flags() != font->flags()) { + blockFont = style::font(font->size(), font->flags(), blockFont->family()); + } + } + if (flags & TextBlockFItalic) blockFont = blockFont->italic(); + if (flags & TextBlockFUnderline) blockFont = blockFont->underline(); + if (flags & TextBlockFTilde) { // tilde fix in OpenSans + blockFont = st::semiboldFont; + } + } + + QString part = str.mid(_from, length); + QStackTextEngine engine(part, blockFont->f); + engine.itemize(); + + QTextLayout layout(&engine); + layout.beginLayout(); + layout.createLine(); + + bool logCrashString = (rand_value() % 4 == 1); + if (logCrashString) { + SignalHandlers::setCrashAnnotationRef("CrashString", &str); + } + BlockParser parser(&engine, this, minResizeWidth, _from, part); + if (logCrashString) { + SignalHandlers::clearCrashAnnotationRef("CrashString"); + } + + layout.endLayout(); + } +} + +EmojiBlock::EmojiBlock(const style::font &font, const QString &str, uint16 from, uint16 length, uchar flags, const style::color &color, uint16 lnkIndex, const EmojiData *emoji) : ITextBlock(font, str, from, length, flags, color, lnkIndex), emoji(emoji) { + _flags |= ((TextBlockTEmoji & 0x0F) << 8); + _width = int(st::emojiSize + 2 * st::emojiPadding); +} + +SkipBlock::SkipBlock(const style::font &font, const QString &str, uint16 from, int32 w, int32 h, uint16 lnkIndex) : ITextBlock(font, str, from, 1, 0, style::color(), lnkIndex), _height(h) { + _flags |= ((TextBlockTSkip & 0x0F) << 8); + _width = w; +} diff --git a/Telegram/SourceFiles/ui/text/text_block.h b/Telegram/SourceFiles/ui/text/text_block.h new file mode 100644 index 000000000..c5afc4485 --- /dev/null +++ b/Telegram/SourceFiles/ui/text/text_block.h @@ -0,0 +1,214 @@ +/* +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 "../../../QtStatic/qtbase/src/gui/text/qfontengine_p.h" + +enum TextBlockType { + TextBlockTNewline = 0x01, + TextBlockTText = 0x02, + TextBlockTEmoji = 0x03, + TextBlockTSkip = 0x04, +}; + +enum TextBlockFlags { + TextBlockFBold = 0x01, + TextBlockFItalic = 0x02, + TextBlockFUnderline = 0x04, + TextBlockFTilde = 0x08, // tilde fix in OpenSans + TextBlockFSemibold = 0x10, + TextBlockFCode = 0x20, + TextBlockFPre = 0x40, +}; + +class ITextBlock { +public: + + ITextBlock(const style::font &font, const QString &str, uint16 from, uint16 length, uchar flags, const style::color &color, uint16 lnkIndex) : _from(from), _flags((flags & 0xFF) | ((lnkIndex & 0xFFFF) << 12))/*, _color(color)*/, _lpadding(0) { + if (length) { + if (str.at(_from + length - 1).unicode() == QChar::Space) { + _rpadding = font->spacew; + } + if (length > 1 && str.at(0).unicode() == QChar::Space) { + _lpadding = font->spacew; + } + } + } + + uint16 from() const { + return _from; + } + int32 width() const { + return _width.toInt(); + } + int32 lpadding() const { + return _lpadding.toInt(); + } + int32 rpadding() const { + return _rpadding.toInt(); + } + QFixed f_width() const { + return _width; + } + QFixed f_lpadding() const { + return _lpadding; + } + QFixed f_rpadding() const { + return _rpadding; + } + + uint16 lnkIndex() const { + return (_flags >> 12) & 0xFFFF; + } + void setLnkIndex(uint16 lnkIndex) { + _flags = (_flags & ~(0xFFFF << 12)) | (lnkIndex << 12); + } + + TextBlockType type() const { + return TextBlockType((_flags >> 8) & 0x0F); + } + int32 flags() const { + return (_flags & 0xFF); + } + const style::color &color() const { + static style::color tmp; + return tmp;//_color; + } + + virtual ITextBlock *clone() const = 0; + virtual ~ITextBlock() { + } + +protected: + + uint16 _from; + + uint32 _flags; // 4 bits empty, 16 bits lnkIndex, 4 bits type, 8 bits flags + + QFixed _width, _lpadding, _rpadding; + +}; + +class NewlineBlock : public ITextBlock { +public: + + Qt::LayoutDirection nextDirection() const { + return _nextDir; + } + + ITextBlock *clone() const { + return new NewlineBlock(*this); + } + +private: + + NewlineBlock(const style::font &font, const QString &str, uint16 from, uint16 length) : ITextBlock(font, str, from, length, 0, st::transparent, 0), _nextDir(Qt::LayoutDirectionAuto) { + _flags |= ((TextBlockTNewline & 0x0F) << 8); + } + + Qt::LayoutDirection _nextDir; + + friend class Text; + friend class TextParser; + + friend class TextPainter; +}; + +struct TextWord { + TextWord() { + } + TextWord(uint16 from, QFixed width, QFixed rbearing, QFixed rpadding = 0) : from(from), + _rbearing(rbearing.value() > 0x7FFF ? 0x7FFF : (rbearing.value() < -0x7FFF ? -0x7FFF : rbearing.value())), width(width), rpadding(rpadding) { + } + QFixed f_rbearing() const { + return QFixed::fromFixed(_rbearing); + } + uint16 from; + int16 _rbearing; + QFixed width, rpadding; +}; + +class TextBlock : public ITextBlock { +public: + + QFixed f_rbearing() const { + return _words.isEmpty() ? 0 : _words.back().f_rbearing(); + } + + ITextBlock *clone() const { + return new TextBlock(*this); + } + +private: + + TextBlock(const style::font &font, const QString &str, QFixed minResizeWidth, uint16 from, uint16 length, uchar flags, const style::color &color, uint16 lnkIndex); + + typedef QVector TextWords; + TextWords _words; + + friend class Text; + friend class TextParser; + + friend class BlockParser; + friend class TextPainter; +}; + +class EmojiBlock : public ITextBlock { +public: + + ITextBlock *clone() const { + return new EmojiBlock(*this); + } + +private: + + EmojiBlock(const style::font &font, const QString &str, uint16 from, uint16 length, uchar flags, const style::color &color, uint16 lnkIndex, const EmojiData *emoji); + + const EmojiData *emoji; + + friend class Text; + friend class TextParser; + + friend class TextPainter; +}; + +class SkipBlock : public ITextBlock { +public: + + int32 height() const { + return _height; + } + + ITextBlock *clone() const { + return new SkipBlock(*this); + } + +private: + + SkipBlock(const style::font &font, const QString &str, uint16 from, int32 w, int32 h, uint16 lnkIndex); + + int32 _height; + + friend class Text; + friend class TextParser; + + friend class TextPainter; +}; diff --git a/Telegram/SourceFiles/ui/text/text_entity.cpp b/Telegram/SourceFiles/ui/text/text_entity.cpp new file mode 100644 index 000000000..bc241a950 --- /dev/null +++ b/Telegram/SourceFiles/ui/text/text_entity.cpp @@ -0,0 +1,1919 @@ +/* +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 "ui/text/text_entity.h" + +namespace { + +const QRegularExpression _reDomain(QString::fromUtf8("(?|'\"\\[\\]\\{\\}`\\~\\!\\%\\^\\*\\(\\)\\-\\+=\\x10])#[\\w]{2,64}([\\W]|$)"), QRegularExpression::UseUnicodePropertiesOption); +const QRegularExpression _reMention(qsl("(^|[\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\%\\^\\*\\(\\)\\-\\+=\\x10])@[A-Za-z_0-9]{1,32}([\\W]|$)"), QRegularExpression::UseUnicodePropertiesOption); +const QRegularExpression _reBotCommand(qsl("(^|[\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\%\\^\\*\\(\\)\\-\\+=\\x10])/[A-Za-z_0-9]{1,64}(@[A-Za-z_0-9]{5,32})?([\\W]|$)")); +const QRegularExpression _rePre(qsl("(^|[\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\?\\%\\^\\*\\(\\)\\-\\+=\\x10])(````?)[\\s\\S]+?(````?)([\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\?\\%\\^\\*\\(\\)\\-\\+=\\x10]|$)"), QRegularExpression::UseUnicodePropertiesOption); +const QRegularExpression _reCode(qsl("(^|[\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\?\\%\\^\\*\\(\\)\\-\\+=\\x10])(`)[^\\n]+?(`)([\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\?\\%\\^\\*\\(\\)\\-\\+=\\x10]|$)"), QRegularExpression::UseUnicodePropertiesOption); +QSet _validProtocols, _validTopDomains; + +} // namespace + +const QRegularExpression &reDomain() { + return _reDomain; +} + +const QRegularExpression &reMailName() { + return _reMailName; +} + +const QRegularExpression &reMailStart() { + return _reMailStart; +} + +const QRegularExpression &reHashtag() { + return _reHashtag; +} + +const QRegularExpression &reBotCommand() { + return _reBotCommand; +} + +namespace { + +void regOneProtocol(const QString &protocol) { + _validProtocols.insert(hashCrc32(protocol.constData(), protocol.size() * sizeof(QChar))); +} + +void regOneTopDomain(const QString &domain) { + _validTopDomains.insert(hashCrc32(domain.constData(), domain.size() * sizeof(QChar))); +} + +} // namespace + +const QSet &validProtocols() { + return _validProtocols; +} +const QSet &validTopDomains() { + return _validTopDomains; +} + +void initLinkSets() { + if (!_validProtocols.isEmpty() || !_validTopDomains.isEmpty()) return; + + regOneProtocol(qsl("itmss")); // itunes + regOneProtocol(qsl("http")); + regOneProtocol(qsl("https")); + regOneProtocol(qsl("ftp")); + regOneProtocol(qsl("tg")); // local urls + + regOneTopDomain(qsl("ac")); + regOneTopDomain(qsl("ad")); + regOneTopDomain(qsl("ae")); + regOneTopDomain(qsl("af")); + regOneTopDomain(qsl("ag")); + regOneTopDomain(qsl("ai")); + regOneTopDomain(qsl("al")); + regOneTopDomain(qsl("am")); + regOneTopDomain(qsl("an")); + regOneTopDomain(qsl("ao")); + regOneTopDomain(qsl("aq")); + regOneTopDomain(qsl("ar")); + regOneTopDomain(qsl("as")); + regOneTopDomain(qsl("at")); + regOneTopDomain(qsl("au")); + regOneTopDomain(qsl("aw")); + regOneTopDomain(qsl("ax")); + regOneTopDomain(qsl("az")); + regOneTopDomain(qsl("ba")); + regOneTopDomain(qsl("bb")); + regOneTopDomain(qsl("bd")); + regOneTopDomain(qsl("be")); + regOneTopDomain(qsl("bf")); + regOneTopDomain(qsl("bg")); + regOneTopDomain(qsl("bh")); + regOneTopDomain(qsl("bi")); + regOneTopDomain(qsl("bj")); + regOneTopDomain(qsl("bm")); + regOneTopDomain(qsl("bn")); + regOneTopDomain(qsl("bo")); + regOneTopDomain(qsl("br")); + regOneTopDomain(qsl("bs")); + regOneTopDomain(qsl("bt")); + regOneTopDomain(qsl("bv")); + regOneTopDomain(qsl("bw")); + regOneTopDomain(qsl("by")); + regOneTopDomain(qsl("bz")); + regOneTopDomain(qsl("ca")); + regOneTopDomain(qsl("cc")); + regOneTopDomain(qsl("cd")); + regOneTopDomain(qsl("cf")); + regOneTopDomain(qsl("cg")); + regOneTopDomain(qsl("ch")); + regOneTopDomain(qsl("ci")); + regOneTopDomain(qsl("ck")); + regOneTopDomain(qsl("cl")); + regOneTopDomain(qsl("cm")); + regOneTopDomain(qsl("cn")); + regOneTopDomain(qsl("co")); + regOneTopDomain(qsl("cr")); + regOneTopDomain(qsl("cu")); + regOneTopDomain(qsl("cv")); + regOneTopDomain(qsl("cx")); + regOneTopDomain(qsl("cy")); + regOneTopDomain(qsl("cz")); + regOneTopDomain(qsl("de")); + regOneTopDomain(qsl("dj")); + regOneTopDomain(qsl("dk")); + regOneTopDomain(qsl("dm")); + regOneTopDomain(qsl("do")); + regOneTopDomain(qsl("dz")); + regOneTopDomain(qsl("ec")); + regOneTopDomain(qsl("ee")); + regOneTopDomain(qsl("eg")); + regOneTopDomain(qsl("eh")); + regOneTopDomain(qsl("er")); + regOneTopDomain(qsl("es")); + regOneTopDomain(qsl("et")); + regOneTopDomain(qsl("eu")); + regOneTopDomain(qsl("fi")); + regOneTopDomain(qsl("fj")); + regOneTopDomain(qsl("fk")); + regOneTopDomain(qsl("fm")); + regOneTopDomain(qsl("fo")); + regOneTopDomain(qsl("fr")); + regOneTopDomain(qsl("ga")); + regOneTopDomain(qsl("gd")); + regOneTopDomain(qsl("ge")); + regOneTopDomain(qsl("gf")); + regOneTopDomain(qsl("gg")); + regOneTopDomain(qsl("gh")); + regOneTopDomain(qsl("gi")); + regOneTopDomain(qsl("gl")); + regOneTopDomain(qsl("gm")); + regOneTopDomain(qsl("gn")); + regOneTopDomain(qsl("gp")); + regOneTopDomain(qsl("gq")); + regOneTopDomain(qsl("gr")); + regOneTopDomain(qsl("gs")); + regOneTopDomain(qsl("gt")); + regOneTopDomain(qsl("gu")); + regOneTopDomain(qsl("gw")); + regOneTopDomain(qsl("gy")); + regOneTopDomain(qsl("hk")); + regOneTopDomain(qsl("hm")); + regOneTopDomain(qsl("hn")); + regOneTopDomain(qsl("hr")); + regOneTopDomain(qsl("ht")); + regOneTopDomain(qsl("hu")); + regOneTopDomain(qsl("id")); + regOneTopDomain(qsl("ie")); + regOneTopDomain(qsl("il")); + regOneTopDomain(qsl("im")); + regOneTopDomain(qsl("in")); + regOneTopDomain(qsl("io")); + regOneTopDomain(qsl("iq")); + regOneTopDomain(qsl("ir")); + regOneTopDomain(qsl("is")); + regOneTopDomain(qsl("it")); + regOneTopDomain(qsl("je")); + regOneTopDomain(qsl("jm")); + regOneTopDomain(qsl("jo")); + regOneTopDomain(qsl("jp")); + regOneTopDomain(qsl("ke")); + regOneTopDomain(qsl("kg")); + regOneTopDomain(qsl("kh")); + regOneTopDomain(qsl("ki")); + regOneTopDomain(qsl("km")); + regOneTopDomain(qsl("kn")); + regOneTopDomain(qsl("kp")); + regOneTopDomain(qsl("kr")); + regOneTopDomain(qsl("kw")); + regOneTopDomain(qsl("ky")); + regOneTopDomain(qsl("kz")); + regOneTopDomain(qsl("la")); + regOneTopDomain(qsl("lb")); + regOneTopDomain(qsl("lc")); + regOneTopDomain(qsl("li")); + regOneTopDomain(qsl("lk")); + regOneTopDomain(qsl("lr")); + regOneTopDomain(qsl("ls")); + regOneTopDomain(qsl("lt")); + regOneTopDomain(qsl("lu")); + regOneTopDomain(qsl("lv")); + regOneTopDomain(qsl("ly")); + regOneTopDomain(qsl("ma")); + regOneTopDomain(qsl("mc")); + regOneTopDomain(qsl("md")); + regOneTopDomain(qsl("me")); + regOneTopDomain(qsl("mg")); + regOneTopDomain(qsl("mh")); + regOneTopDomain(qsl("mk")); + regOneTopDomain(qsl("ml")); + regOneTopDomain(qsl("mm")); + regOneTopDomain(qsl("mn")); + regOneTopDomain(qsl("mo")); + regOneTopDomain(qsl("mp")); + regOneTopDomain(qsl("mq")); + regOneTopDomain(qsl("mr")); + regOneTopDomain(qsl("ms")); + regOneTopDomain(qsl("mt")); + regOneTopDomain(qsl("mu")); + regOneTopDomain(qsl("mv")); + regOneTopDomain(qsl("mw")); + regOneTopDomain(qsl("mx")); + regOneTopDomain(qsl("my")); + regOneTopDomain(qsl("mz")); + regOneTopDomain(qsl("na")); + regOneTopDomain(qsl("nc")); + regOneTopDomain(qsl("ne")); + regOneTopDomain(qsl("nf")); + regOneTopDomain(qsl("ng")); + regOneTopDomain(qsl("ni")); + regOneTopDomain(qsl("nl")); + regOneTopDomain(qsl("no")); + regOneTopDomain(qsl("np")); + regOneTopDomain(qsl("nr")); + regOneTopDomain(qsl("nu")); + regOneTopDomain(qsl("nz")); + regOneTopDomain(qsl("om")); + regOneTopDomain(qsl("pa")); + regOneTopDomain(qsl("pe")); + regOneTopDomain(qsl("pf")); + regOneTopDomain(qsl("pg")); + regOneTopDomain(qsl("ph")); + regOneTopDomain(qsl("pk")); + regOneTopDomain(qsl("pl")); + regOneTopDomain(qsl("pm")); + regOneTopDomain(qsl("pn")); + regOneTopDomain(qsl("pr")); + regOneTopDomain(qsl("ps")); + regOneTopDomain(qsl("pt")); + regOneTopDomain(qsl("pw")); + regOneTopDomain(qsl("py")); + regOneTopDomain(qsl("qa")); + regOneTopDomain(qsl("re")); + regOneTopDomain(qsl("ro")); + regOneTopDomain(qsl("ru")); + regOneTopDomain(qsl("rs")); + regOneTopDomain(qsl("rw")); + regOneTopDomain(qsl("sa")); + regOneTopDomain(qsl("sb")); + regOneTopDomain(qsl("sc")); + regOneTopDomain(qsl("sd")); + regOneTopDomain(qsl("se")); + regOneTopDomain(qsl("sg")); + regOneTopDomain(qsl("sh")); + regOneTopDomain(qsl("si")); + regOneTopDomain(qsl("sj")); + regOneTopDomain(qsl("sk")); + regOneTopDomain(qsl("sl")); + regOneTopDomain(qsl("sm")); + regOneTopDomain(qsl("sn")); + regOneTopDomain(qsl("so")); + regOneTopDomain(qsl("sr")); + regOneTopDomain(qsl("ss")); + regOneTopDomain(qsl("st")); + regOneTopDomain(qsl("su")); + regOneTopDomain(qsl("sv")); + regOneTopDomain(qsl("sx")); + regOneTopDomain(qsl("sy")); + regOneTopDomain(qsl("sz")); + regOneTopDomain(qsl("tc")); + regOneTopDomain(qsl("td")); + regOneTopDomain(qsl("tf")); + regOneTopDomain(qsl("tg")); + regOneTopDomain(qsl("th")); + regOneTopDomain(qsl("tj")); + regOneTopDomain(qsl("tk")); + regOneTopDomain(qsl("tl")); + regOneTopDomain(qsl("tm")); + regOneTopDomain(qsl("tn")); + regOneTopDomain(qsl("to")); + regOneTopDomain(qsl("tp")); + regOneTopDomain(qsl("tr")); + regOneTopDomain(qsl("tt")); + regOneTopDomain(qsl("tv")); + regOneTopDomain(qsl("tw")); + regOneTopDomain(qsl("tz")); + regOneTopDomain(qsl("ua")); + regOneTopDomain(qsl("ug")); + regOneTopDomain(qsl("uk")); + regOneTopDomain(qsl("um")); + regOneTopDomain(qsl("us")); + regOneTopDomain(qsl("uy")); + regOneTopDomain(qsl("uz")); + regOneTopDomain(qsl("va")); + regOneTopDomain(qsl("vc")); + regOneTopDomain(qsl("ve")); + regOneTopDomain(qsl("vg")); + regOneTopDomain(qsl("vi")); + regOneTopDomain(qsl("vn")); + regOneTopDomain(qsl("vu")); + regOneTopDomain(qsl("wf")); + regOneTopDomain(qsl("ws")); + regOneTopDomain(qsl("ye")); + regOneTopDomain(qsl("yt")); + regOneTopDomain(qsl("yu")); + regOneTopDomain(qsl("za")); + regOneTopDomain(qsl("zm")); + regOneTopDomain(qsl("zw")); + regOneTopDomain(qsl("arpa")); + regOneTopDomain(qsl("aero")); + regOneTopDomain(qsl("asia")); + regOneTopDomain(qsl("biz")); + regOneTopDomain(qsl("cat")); + regOneTopDomain(qsl("com")); + regOneTopDomain(qsl("coop")); + regOneTopDomain(qsl("info")); + regOneTopDomain(qsl("int")); + regOneTopDomain(qsl("jobs")); + regOneTopDomain(qsl("mobi")); + regOneTopDomain(qsl("museum")); + regOneTopDomain(qsl("name")); + regOneTopDomain(qsl("net")); + regOneTopDomain(qsl("org")); + regOneTopDomain(qsl("post")); + regOneTopDomain(qsl("pro")); + regOneTopDomain(qsl("tel")); + regOneTopDomain(qsl("travel")); + regOneTopDomain(qsl("xxx")); + regOneTopDomain(qsl("edu")); + regOneTopDomain(qsl("gov")); + regOneTopDomain(qsl("mil")); + regOneTopDomain(qsl("local")); + regOneTopDomain(qsl("xn--lgbbat1ad8j")); + regOneTopDomain(qsl("xn--54b7fta0cc")); + regOneTopDomain(qsl("xn--fiqs8s")); + regOneTopDomain(qsl("xn--fiqz9s")); + regOneTopDomain(qsl("xn--wgbh1c")); + regOneTopDomain(qsl("xn--node")); + regOneTopDomain(qsl("xn--j6w193g")); + regOneTopDomain(qsl("xn--h2brj9c")); + regOneTopDomain(qsl("xn--mgbbh1a71e")); + regOneTopDomain(qsl("xn--fpcrj9c3d")); + regOneTopDomain(qsl("xn--gecrj9c")); + regOneTopDomain(qsl("xn--s9brj9c")); + regOneTopDomain(qsl("xn--xkc2dl3a5ee0h")); + regOneTopDomain(qsl("xn--45brj9c")); + regOneTopDomain(qsl("xn--mgba3a4f16a")); + regOneTopDomain(qsl("xn--mgbayh7gpa")); + regOneTopDomain(qsl("xn--80ao21a")); + regOneTopDomain(qsl("xn--mgbx4cd0ab")); + regOneTopDomain(qsl("xn--l1acc")); + regOneTopDomain(qsl("xn--mgbc0a9azcg")); + regOneTopDomain(qsl("xn--mgb9awbf")); + regOneTopDomain(qsl("xn--mgbai9azgqp6j")); + regOneTopDomain(qsl("xn--ygbi2ammx")); + regOneTopDomain(qsl("xn--wgbl6a")); + regOneTopDomain(qsl("xn--p1ai")); + regOneTopDomain(qsl("xn--mgberp4a5d4ar")); + regOneTopDomain(qsl("xn--90a3ac")); + regOneTopDomain(qsl("xn--yfro4i67o")); + regOneTopDomain(qsl("xn--clchc0ea0b2g2a9gcd")); + regOneTopDomain(qsl("xn--3e0b707e")); + regOneTopDomain(qsl("xn--fzc2c9e2c")); + regOneTopDomain(qsl("xn--xkc2al3hye2a")); + regOneTopDomain(qsl("xn--mgbtf8fl")); + regOneTopDomain(qsl("xn--kprw13d")); + regOneTopDomain(qsl("xn--kpry57d")); + regOneTopDomain(qsl("xn--o3cw4h")); + regOneTopDomain(qsl("xn--pgbs0dh")); + regOneTopDomain(qsl("xn--j1amh")); + regOneTopDomain(qsl("xn--mgbaam7a8h")); + regOneTopDomain(qsl("xn--mgb2ddes")); + regOneTopDomain(qsl("xn--ogbpf8fl")); + regOneTopDomain(QString::fromUtf8("\xd1\x80\xd1\x84")); +} + +namespace { +// accent char list taken from https://github.com/aristus/accent-folding +inline QChar chNoAccent(int32 code) { + switch (code) { + case 7834: return QChar(97); + case 193: return QChar(97); + case 225: return QChar(97); + case 192: return QChar(97); + case 224: return QChar(97); + case 258: return QChar(97); + case 259: return QChar(97); + case 7854: return QChar(97); + case 7855: return QChar(97); + case 7856: return QChar(97); + case 7857: return QChar(97); + case 7860: return QChar(97); + case 7861: return QChar(97); + case 7858: return QChar(97); + case 7859: return QChar(97); + case 194: return QChar(97); + case 226: return QChar(97); + case 7844: return QChar(97); + case 7845: return QChar(97); + case 7846: return QChar(97); + case 7847: return QChar(97); + case 7850: return QChar(97); + case 7851: return QChar(97); + case 7848: return QChar(97); + case 7849: return QChar(97); + case 461: return QChar(97); + case 462: return QChar(97); + case 197: return QChar(97); + case 229: return QChar(97); + case 506: return QChar(97); + case 507: return QChar(97); + case 196: return QChar(97); + case 228: return QChar(97); + case 478: return QChar(97); + case 479: return QChar(97); + case 195: return QChar(97); + case 227: return QChar(97); + case 550: return QChar(97); + case 551: return QChar(97); + case 480: return QChar(97); + case 481: return QChar(97); + case 260: return QChar(97); + case 261: return QChar(97); + case 256: return QChar(97); + case 257: return QChar(97); + case 7842: return QChar(97); + case 7843: return QChar(97); + case 512: return QChar(97); + case 513: return QChar(97); + case 514: return QChar(97); + case 515: return QChar(97); + case 7840: return QChar(97); + case 7841: return QChar(97); + case 7862: return QChar(97); + case 7863: return QChar(97); + case 7852: return QChar(97); + case 7853: return QChar(97); + case 7680: return QChar(97); + case 7681: return QChar(97); + case 570: return QChar(97); + case 11365: return QChar(97); + case 508: return QChar(97); + case 509: return QChar(97); + case 482: return QChar(97); + case 483: return QChar(97); + case 7682: return QChar(98); + case 7683: return QChar(98); + case 7684: return QChar(98); + case 7685: return QChar(98); + case 7686: return QChar(98); + case 7687: return QChar(98); + case 579: return QChar(98); + case 384: return QChar(98); + case 7532: return QChar(98); + case 385: return QChar(98); + case 595: return QChar(98); + case 386: return QChar(98); + case 387: return QChar(98); + case 262: return QChar(99); + case 263: return QChar(99); + case 264: return QChar(99); + case 265: return QChar(99); + case 268: return QChar(99); + case 269: return QChar(99); + case 266: return QChar(99); + case 267: return QChar(99); + case 199: return QChar(99); + case 231: return QChar(99); + case 7688: return QChar(99); + case 7689: return QChar(99); + case 571: return QChar(99); + case 572: return QChar(99); + case 391: return QChar(99); + case 392: return QChar(99); + case 597: return QChar(99); + case 270: return QChar(100); + case 271: return QChar(100); + case 7690: return QChar(100); + case 7691: return QChar(100); + case 7696: return QChar(100); + case 7697: return QChar(100); + case 7692: return QChar(100); + case 7693: return QChar(100); + case 7698: return QChar(100); + case 7699: return QChar(100); + case 7694: return QChar(100); + case 7695: return QChar(100); + case 272: return QChar(100); + case 273: return QChar(100); + case 7533: return QChar(100); + case 393: return QChar(100); + case 598: return QChar(100); + case 394: return QChar(100); + case 599: return QChar(100); + case 395: return QChar(100); + case 396: return QChar(100); + case 545: return QChar(100); + case 240: return QChar(100); + case 201: return QChar(101); + case 399: return QChar(101); + case 398: return QChar(101); + case 477: return QChar(101); + case 233: return QChar(101); + case 200: return QChar(101); + case 232: return QChar(101); + case 276: return QChar(101); + case 277: return QChar(101); + case 202: return QChar(101); + case 234: return QChar(101); + case 7870: return QChar(101); + case 7871: return QChar(101); + case 7872: return QChar(101); + case 7873: return QChar(101); + case 7876: return QChar(101); + case 7877: return QChar(101); + case 7874: return QChar(101); + case 7875: return QChar(101); + case 282: return QChar(101); + case 283: return QChar(101); + case 203: return QChar(101); + case 235: return QChar(101); + case 7868: return QChar(101); + case 7869: return QChar(101); + case 278: return QChar(101); + case 279: return QChar(101); + case 552: return QChar(101); + case 553: return QChar(101); + case 7708: return QChar(101); + case 7709: return QChar(101); + case 280: return QChar(101); + case 281: return QChar(101); + case 274: return QChar(101); + case 275: return QChar(101); + case 7702: return QChar(101); + case 7703: return QChar(101); + case 7700: return QChar(101); + case 7701: return QChar(101); + case 7866: return QChar(101); + case 7867: return QChar(101); + case 516: return QChar(101); + case 517: return QChar(101); + case 518: return QChar(101); + case 519: return QChar(101); + case 7864: return QChar(101); + case 7865: return QChar(101); + case 7878: return QChar(101); + case 7879: return QChar(101); + case 7704: return QChar(101); + case 7705: return QChar(101); + case 7706: return QChar(101); + case 7707: return QChar(101); + case 582: return QChar(101); + case 583: return QChar(101); + case 602: return QChar(101); + case 605: return QChar(101); + case 7710: return QChar(102); + case 7711: return QChar(102); + case 7534: return QChar(102); + case 401: return QChar(102); + case 402: return QChar(102); + case 500: return QChar(103); + case 501: return QChar(103); + case 286: return QChar(103); + case 287: return QChar(103); + case 284: return QChar(103); + case 285: return QChar(103); + case 486: return QChar(103); + case 487: return QChar(103); + case 288: return QChar(103); + case 289: return QChar(103); + case 290: return QChar(103); + case 291: return QChar(103); + case 7712: return QChar(103); + case 7713: return QChar(103); + case 484: return QChar(103); + case 485: return QChar(103); + case 403: return QChar(103); + case 608: return QChar(103); + case 292: return QChar(104); + case 293: return QChar(104); + case 542: return QChar(104); + case 543: return QChar(104); + case 7718: return QChar(104); + case 7719: return QChar(104); + case 7714: return QChar(104); + case 7715: return QChar(104); + case 7720: return QChar(104); + case 7721: return QChar(104); + case 7716: return QChar(104); + case 7717: return QChar(104); + case 7722: return QChar(104); + case 7723: return QChar(104); + case 817: return QChar(104); + case 7830: return QChar(104); + case 294: return QChar(104); + case 295: return QChar(104); + case 11367: return QChar(104); + case 11368: return QChar(104); + case 205: return QChar(105); + case 237: return QChar(105); + case 204: return QChar(105); + case 236: return QChar(105); + case 300: return QChar(105); + case 301: return QChar(105); + case 206: return QChar(105); + case 238: return QChar(105); + case 463: return QChar(105); + case 464: return QChar(105); + case 207: return QChar(105); + case 239: return QChar(105); + case 7726: return QChar(105); + case 7727: return QChar(105); + case 296: return QChar(105); + case 297: return QChar(105); + case 304: return QChar(105); + case 302: return QChar(105); + case 303: return QChar(105); + case 298: return QChar(105); + case 299: return QChar(105); + case 7880: return QChar(105); + case 7881: return QChar(105); + case 520: return QChar(105); + case 521: return QChar(105); + case 522: return QChar(105); + case 523: return QChar(105); + case 7882: return QChar(105); + case 7883: return QChar(105); + case 7724: return QChar(105); + case 7725: return QChar(105); + case 305: return QChar(105); + case 407: return QChar(105); + case 616: return QChar(105); + case 308: return QChar(106); + case 309: return QChar(106); + case 780: return QChar(106); + case 496: return QChar(106); + case 567: return QChar(106); + case 584: return QChar(106); + case 585: return QChar(106); + case 669: return QChar(106); + case 607: return QChar(106); + case 644: return QChar(106); + case 7728: return QChar(107); + case 7729: return QChar(107); + case 488: return QChar(107); + case 489: return QChar(107); + case 310: return QChar(107); + case 311: return QChar(107); + case 7730: return QChar(107); + case 7731: return QChar(107); + case 7732: return QChar(107); + case 7733: return QChar(107); + case 408: return QChar(107); + case 409: return QChar(107); + case 11369: return QChar(107); + case 11370: return QChar(107); + case 313: return QChar(97); + case 314: return QChar(108); + case 317: return QChar(108); + case 318: return QChar(108); + case 315: return QChar(108); + case 316: return QChar(108); + case 7734: return QChar(108); + case 7735: return QChar(108); + case 7736: return QChar(108); + case 7737: return QChar(108); + case 7740: return QChar(108); + case 7741: return QChar(108); + case 7738: return QChar(108); + case 7739: return QChar(108); + case 321: return QChar(108); + case 322: return QChar(108); + case 803: return QChar(108); + case 319: return QChar(108); + case 320: return QChar(108); + case 573: return QChar(108); + case 410: return QChar(108); + case 11360: return QChar(108); + case 11361: return QChar(108); + case 11362: return QChar(108); + case 619: return QChar(108); + case 620: return QChar(108); + case 621: return QChar(108); + case 564: return QChar(108); + case 7742: return QChar(109); + case 7743: return QChar(109); + case 7744: return QChar(109); + case 7745: return QChar(109); + case 7746: return QChar(109); + case 7747: return QChar(109); + case 625: return QChar(109); + case 323: return QChar(110); + case 324: return QChar(110); + case 504: return QChar(110); + case 505: return QChar(110); + case 327: return QChar(110); + case 328: return QChar(110); + case 209: return QChar(110); + case 241: return QChar(110); + case 7748: return QChar(110); + case 7749: return QChar(110); + case 325: return QChar(110); + case 326: return QChar(110); + case 7750: return QChar(110); + case 7751: return QChar(110); + case 7754: return QChar(110); + case 7755: return QChar(110); + case 7752: return QChar(110); + case 7753: return QChar(110); + case 413: return QChar(110); + case 626: return QChar(110); + case 544: return QChar(110); + case 414: return QChar(110); + case 627: return QChar(110); + case 565: return QChar(110); + case 776: return QChar(116); + case 211: return QChar(111); + case 243: return QChar(111); + case 210: return QChar(111); + case 242: return QChar(111); + case 334: return QChar(111); + case 335: return QChar(111); + case 212: return QChar(111); + case 244: return QChar(111); + case 7888: return QChar(111); + case 7889: return QChar(111); + case 7890: return QChar(111); + case 7891: return QChar(111); + case 7894: return QChar(111); + case 7895: return QChar(111); + case 7892: return QChar(111); + case 7893: return QChar(111); + case 465: return QChar(111); + case 466: return QChar(111); + case 214: return QChar(111); + case 246: return QChar(111); + case 554: return QChar(111); + case 555: return QChar(111); + case 336: return QChar(111); + case 337: return QChar(111); + case 213: return QChar(111); + case 245: return QChar(111); + case 7756: return QChar(111); + case 7757: return QChar(111); + case 7758: return QChar(111); + case 7759: return QChar(111); + case 556: return QChar(111); + case 557: return QChar(111); + case 558: return QChar(111); + case 559: return QChar(111); + case 560: return QChar(111); + case 561: return QChar(111); + case 216: return QChar(111); + case 248: return QChar(111); + case 510: return QChar(111); + case 511: return QChar(111); + case 490: return QChar(111); + case 491: return QChar(111); + case 492: return QChar(111); + case 493: return QChar(111); + case 332: return QChar(111); + case 333: return QChar(111); + case 7762: return QChar(111); + case 7763: return QChar(111); + case 7760: return QChar(111); + case 7761: return QChar(111); + case 7886: return QChar(111); + case 7887: return QChar(111); + case 524: return QChar(111); + case 525: return QChar(111); + case 526: return QChar(111); + case 527: return QChar(111); + case 416: return QChar(111); + case 417: return QChar(111); + case 7898: return QChar(111); + case 7899: return QChar(111); + case 7900: return QChar(111); + case 7901: return QChar(111); + case 7904: return QChar(111); + case 7905: return QChar(111); + case 7902: return QChar(111); + case 7903: return QChar(111); + case 7906: return QChar(111); + case 7907: return QChar(111); + case 7884: return QChar(111); + case 7885: return QChar(111); + case 7896: return QChar(111); + case 7897: return QChar(111); + case 415: return QChar(111); + case 629: return QChar(111); + case 7764: return QChar(112); + case 7765: return QChar(112); + case 7766: return QChar(112); + case 7767: return QChar(112); + case 11363: return QChar(112); + case 420: return QChar(112); + case 421: return QChar(112); + case 771: return QChar(112); + case 672: return QChar(113); + case 586: return QChar(113); + case 587: return QChar(113); + case 340: return QChar(114); + case 341: return QChar(114); + case 344: return QChar(114); + case 345: return QChar(114); + case 7768: return QChar(114); + case 7769: return QChar(114); + case 342: return QChar(114); + case 343: return QChar(114); + case 528: return QChar(114); + case 529: return QChar(114); + case 530: return QChar(114); + case 531: return QChar(114); + case 7770: return QChar(114); + case 7771: return QChar(114); + case 7772: return QChar(114); + case 7773: return QChar(114); + case 7774: return QChar(114); + case 7775: return QChar(114); + case 588: return QChar(114); + case 589: return QChar(114); + case 7538: return QChar(114); + case 636: return QChar(114); + case 11364: return QChar(114); + case 637: return QChar(114); + case 638: return QChar(114); + case 7539: return QChar(114); + case 223: return QChar(115); + case 346: return QChar(115); + case 347: return QChar(115); + case 7780: return QChar(115); + case 7781: return QChar(115); + case 348: return QChar(115); + case 349: return QChar(115); + case 352: return QChar(115); + case 353: return QChar(115); + case 7782: return QChar(115); + case 7783: return QChar(115); + case 7776: return QChar(115); + case 7777: return QChar(115); + case 7835: return QChar(115); + case 350: return QChar(115); + case 351: return QChar(115); + case 7778: return QChar(115); + case 7779: return QChar(115); + case 7784: return QChar(115); + case 7785: return QChar(115); + case 536: return QChar(115); + case 537: return QChar(115); + case 642: return QChar(115); + case 809: return QChar(115); + case 222: return QChar(116); + case 254: return QChar(116); + case 356: return QChar(116); + case 357: return QChar(116); + case 7831: return QChar(116); + case 7786: return QChar(116); + case 7787: return QChar(116); + case 354: return QChar(116); + case 355: return QChar(116); + case 7788: return QChar(116); + case 7789: return QChar(116); + case 538: return QChar(116); + case 539: return QChar(116); + case 7792: return QChar(116); + case 7793: return QChar(116); + case 7790: return QChar(116); + case 7791: return QChar(116); + case 358: return QChar(116); + case 359: return QChar(116); + case 574: return QChar(116); + case 11366: return QChar(116); + case 7541: return QChar(116); + case 427: return QChar(116); + case 428: return QChar(116); + case 429: return QChar(116); + case 430: return QChar(116); + case 648: return QChar(116); + case 566: return QChar(116); + case 218: return QChar(117); + case 250: return QChar(117); + case 217: return QChar(117); + case 249: return QChar(117); + case 364: return QChar(117); + case 365: return QChar(117); + case 219: return QChar(117); + case 251: return QChar(117); + case 467: return QChar(117); + case 468: return QChar(117); + case 366: return QChar(117); + case 367: return QChar(117); + case 220: return QChar(117); + case 252: return QChar(117); + case 471: return QChar(117); + case 472: return QChar(117); + case 475: return QChar(117); + case 476: return QChar(117); + case 473: return QChar(117); + case 474: return QChar(117); + case 469: return QChar(117); + case 470: return QChar(117); + case 368: return QChar(117); + case 369: return QChar(117); + case 360: return QChar(117); + case 361: return QChar(117); + case 7800: return QChar(117); + case 7801: return QChar(117); + case 370: return QChar(117); + case 371: return QChar(117); + case 362: return QChar(117); + case 363: return QChar(117); + case 7802: return QChar(117); + case 7803: return QChar(117); + case 7910: return QChar(117); + case 7911: return QChar(117); + case 532: return QChar(117); + case 533: return QChar(117); + case 534: return QChar(117); + case 535: return QChar(117); + case 431: return QChar(117); + case 432: return QChar(117); + case 7912: return QChar(117); + case 7913: return QChar(117); + case 7914: return QChar(117); + case 7915: return QChar(117); + case 7918: return QChar(117); + case 7919: return QChar(117); + case 7916: return QChar(117); + case 7917: return QChar(117); + case 7920: return QChar(117); + case 7921: return QChar(117); + case 7908: return QChar(117); + case 7909: return QChar(117); + case 7794: return QChar(117); + case 7795: return QChar(117); + case 7798: return QChar(117); + case 7799: return QChar(117); + case 7796: return QChar(117); + case 7797: return QChar(117); + case 580: return QChar(117); + case 649: return QChar(117); + case 7804: return QChar(118); + case 7805: return QChar(118); + case 7806: return QChar(118); + case 7807: return QChar(118); + case 434: return QChar(118); + case 651: return QChar(118); + case 7810: return QChar(119); + case 7811: return QChar(119); + case 7808: return QChar(119); + case 7809: return QChar(119); + case 372: return QChar(119); + case 373: return QChar(119); + case 778: return QChar(121); + case 7832: return QChar(119); + case 7812: return QChar(119); + case 7813: return QChar(119); + case 7814: return QChar(119); + case 7815: return QChar(119); + case 7816: return QChar(119); + case 7817: return QChar(119); + case 7820: return QChar(120); + case 7821: return QChar(120); + case 7818: return QChar(120); + case 7819: return QChar(120); + case 221: return QChar(121); + case 253: return QChar(121); + case 7922: return QChar(121); + case 7923: return QChar(121); + case 374: return QChar(121); + case 375: return QChar(121); + case 7833: return QChar(121); + case 376: return QChar(121); + case 255: return QChar(121); + case 7928: return QChar(121); + case 7929: return QChar(121); + case 7822: return QChar(121); + case 7823: return QChar(121); + case 562: return QChar(121); + case 563: return QChar(121); + case 7926: return QChar(121); + case 7927: return QChar(121); + case 7924: return QChar(121); + case 7925: return QChar(121); + case 655: return QChar(121); + case 590: return QChar(121); + case 591: return QChar(121); + case 435: return QChar(121); + case 436: return QChar(121); + case 377: return QChar(122); + case 378: return QChar(122); + case 7824: return QChar(122); + case 7825: return QChar(122); + case 381: return QChar(122); + case 382: return QChar(122); + case 379: return QChar(122); + case 380: return QChar(122); + case 7826: return QChar(122); + case 7827: return QChar(122); + case 7828: return QChar(122); + case 7829: return QChar(122); + case 437: return QChar(122); + case 438: return QChar(122); + case 548: return QChar(122); + case 549: return QChar(122); + case 656: return QChar(122); + case 657: return QChar(122); + case 11371: return QChar(122); + case 11372: return QChar(122); + case 494: return QChar(122); + case 495: return QChar(122); + case 442: return QChar(122); + case 65298: return QChar(50); + case 65302: return QChar(54); + case 65314: return QChar(66); + case 65318: return QChar(70); + case 65322: return QChar(74); + case 65326: return QChar(78); + case 65330: return QChar(82); + case 65334: return QChar(86); + case 65338: return QChar(90); + case 65346: return QChar(98); + case 65350: return QChar(102); + case 65354: return QChar(106); + case 65358: return QChar(110); + case 65362: return QChar(114); + case 65366: return QChar(118); + case 65370: return QChar(122); + case 65297: return QChar(49); + case 65301: return QChar(53); + case 65305: return QChar(57); + case 65313: return QChar(65); + case 65317: return QChar(69); + case 65321: return QChar(73); + case 65325: return QChar(77); + case 65329: return QChar(81); + case 65333: return QChar(85); + case 65337: return QChar(89); + case 65345: return QChar(97); + case 65349: return QChar(101); + case 65353: return QChar(105); + case 65357: return QChar(109); + case 65361: return QChar(113); + case 65365: return QChar(117); + case 65369: return QChar(121); + case 65296: return QChar(48); + case 65300: return QChar(52); + case 65304: return QChar(56); + case 65316: return QChar(68); + case 65320: return QChar(72); + case 65324: return QChar(76); + case 65328: return QChar(80); + case 65332: return QChar(84); + case 65336: return QChar(88); + case 65348: return QChar(100); + case 65352: return QChar(104); + case 65356: return QChar(108); + case 65360: return QChar(112); + case 65364: return QChar(116); + case 65368: return QChar(120); + case 65299: return QChar(51); + case 65303: return QChar(55); + case 65315: return QChar(67); + case 65319: return QChar(71); + case 65323: return QChar(75); + case 65327: return QChar(79); + case 65331: return QChar(83); + case 65335: return QChar(87); + case 65347: return QChar(99); + case 65351: return QChar(103); + case 65355: return QChar(107); + case 65359: return QChar(111); + case 65363: return QChar(115); + case 65367: return QChar(119); + case 1105: return QChar(1077); + default: + break; + } + return QChar(0); +} +} + +QString textClean(const QString &text) { + QString result(text); + for (const QChar *s = text.unicode(), *ch = s, *e = text.unicode() + text.size(); ch != e; ++ch) { + if (*ch == TextCommand) { + result[int(ch - s)] = QChar::Space; + } + } + return result; +} + +QString textRichPrepare(const QString &text) { + QString result; + result.reserve(text.size()); + const QChar *s = text.constData(), *ch = s; + for (const QChar *e = s + text.size(); ch != e; ++ch) { + if (*ch == TextCommand) { + if (ch > s) result.append(s, ch - s); + result.append(QChar::Space); + s = ch + 1; + continue; + } + if (ch->unicode() == '\\' || ch->unicode() == '[') { + if (ch > s) result.append(s, ch - s); + result.append('\\'); + s = ch; + continue; + } + } + if (ch > s) result.append(s, ch - s); + return result; +} + +QString textOneLine(const QString &text, bool trim, bool rich) { + QString result(text); + const QChar *s = text.unicode(), *ch = s, *e = text.unicode() + text.size(); + if (trim) { + while (s < e && chIsTrimmed(*s)) { + ++s; + } + while (s < e && chIsTrimmed(*(e - 1))) { + --e; + } + if (e - s != text.size()) { + result = text.mid(s - text.unicode(), e - s); + } + } + for (const QChar *ch = s; ch != e; ++ch) { + if (chIsNewline(*ch)) { + result[int(ch - s)] = QChar::Space; + } + } + return result; +} + +QString textAccentFold(const QString &text) { + QString result(text); + bool copying = false; + int32 i = 0; + for (const QChar *s = text.unicode(), *ch = s, *e = text.unicode() + text.size(); ch != e; ++ch, ++i) { + if (ch->unicode() < 128) { + if (copying) result[i] = *ch; + continue; + } + if (chIsDiac(*ch)) { + copying = true; + --i; + continue; + } + if (ch->isHighSurrogate() && ch + 1 < e && (ch + 1)->isLowSurrogate()) { + QChar noAccent = chNoAccent(QChar::surrogateToUcs4(*ch, *(ch + 1))); + if (noAccent.unicode() > 0) { + copying = true; + result[i] = noAccent; + } else { + if (copying) result[i] = *ch; + ++ch, ++i; + if (copying) result[i] = *ch; + } + } else { + QChar noAccent = chNoAccent(ch->unicode()); + if (noAccent.unicode() > 0 && noAccent != *ch) { + result[i] = noAccent; + } else if (copying) { + result[i] = *ch; + } + } + } + return (i < result.size()) ? result.mid(0, i) : result; +} + +QString textSearchKey(const QString &text) { + return textAccentFold(text.trimmed().toLower()); +} + +bool textSplit(QString &sendingText, EntitiesInText &sendingEntities, QString &leftText, EntitiesInText &leftEntities, int32 limit) { + if (leftText.isEmpty() || !limit) return false; + + int32 currentEntity = 0, goodEntity = currentEntity, entityCount = leftEntities.size(); + bool goodInEntity = false, goodCanBreakEntity = false; + + int32 s = 0, half = limit / 2, goodLevel = 0; + for (const QChar *start = leftText.constData(), *ch = start, *end = leftText.constEnd(), *good = ch; ch != end; ++ch, ++s) { + while (currentEntity < entityCount && ch >= start + leftEntities[currentEntity].offset + leftEntities[currentEntity].length) { + ++currentEntity; + } + +#define MARK_GOOD_AS_LEVEL(level) \ +if (goodLevel <= (level)) {\ +goodLevel = (level);\ +good = ch;\ +goodEntity = currentEntity;\ +goodInEntity = inEntity;\ +goodCanBreakEntity = canBreakEntity;\ +} + + if (s > half) { + bool inEntity = (currentEntity < entityCount) && (ch > start + leftEntities[currentEntity].offset) && (ch < start + leftEntities[currentEntity].offset + leftEntities[currentEntity].length); + EntityInTextType entityType = (currentEntity < entityCount) ? leftEntities[currentEntity].type : EntityInTextBold; + bool canBreakEntity = (entityType == EntityInTextPre || entityType == EntityInTextCode); + int32 noEntityLevel = inEntity ? 0 : 1; + if (inEntity && !canBreakEntity) { + MARK_GOOD_AS_LEVEL(0); + } else { + if (chIsNewline(*ch)) { + if (inEntity) { + if (ch + 1 < end && chIsNewline(*(ch + 1))) { + MARK_GOOD_AS_LEVEL(12); + } else { + MARK_GOOD_AS_LEVEL(11); + } + } else if (ch + 1 < end && chIsNewline(*(ch + 1))) { + MARK_GOOD_AS_LEVEL(15); + } else if (currentEntity < entityCount && ch + 1 == start + leftEntities[currentEntity].offset && leftEntities[currentEntity].type == EntityInTextPre) { + MARK_GOOD_AS_LEVEL(14); + } else if (currentEntity > 0 && ch == start + leftEntities[currentEntity - 1].offset + leftEntities[currentEntity - 1].length && leftEntities[currentEntity - 1].type == EntityInTextPre) { + MARK_GOOD_AS_LEVEL(14); + } else { + MARK_GOOD_AS_LEVEL(13); + } + } else if (chIsSpace(*ch)) { + if (chIsSentenceEnd(*(ch - 1))) { + MARK_GOOD_AS_LEVEL(9 + noEntityLevel); + } else if (chIsSentencePartEnd(*(ch - 1))) { + MARK_GOOD_AS_LEVEL(7 + noEntityLevel); + } else { + MARK_GOOD_AS_LEVEL(5 + noEntityLevel); + } + } else if (chIsWordSeparator(*(ch - 1))) { + MARK_GOOD_AS_LEVEL(3 + noEntityLevel); + } else { + MARK_GOOD_AS_LEVEL(1 + noEntityLevel); + } + } + } + +#undef MARK_GOOD_AS_LEVEL + + int elen = 0; + if (EmojiPtr e = emojiFromText(ch, end, &elen)) { + for (int i = 0; i < elen; ++i, ++ch, ++s) { + if (ch->isHighSurrogate() && i + 1 < elen && (ch + 1)->isLowSurrogate()) { + ++ch; + ++i; + } + } + --ch; + --s; + } else if (ch->isHighSurrogate() && ch + 1 < end && (ch + 1)->isLowSurrogate()) { + ++ch; + } + if (s >= limit) { + sendingText = leftText.mid(0, good - start); + leftText = leftText.mid(good - start); + if (goodInEntity) { + if (goodCanBreakEntity) { + sendingEntities = leftEntities.mid(0, goodEntity + 1); + sendingEntities.back().length = good - start - sendingEntities.back().offset; + leftEntities = leftEntities.mid(goodEntity); + for (EntitiesInText::iterator i = leftEntities.begin(), e = leftEntities.end(); i != e; ++i) { + i->offset -= good - start; + if (i->offset < 0) { + i->length += i->offset; + i->offset = 0; + } + } + } else { + sendingEntities = leftEntities.mid(0, goodEntity); + leftEntities = leftEntities.mid(goodEntity + 1); + } + } else { + sendingEntities = leftEntities.mid(0, goodEntity); + leftEntities = leftEntities.mid(goodEntity); + for (EntitiesInText::iterator i = leftEntities.begin(), e = leftEntities.end(); i != e; ++i) { + i->offset -= good - start; + } + } + return true; + } + } + sendingText = leftText; + leftText = QString(); + sendingEntities = leftEntities; + leftEntities = EntitiesInText(); + return true; +} + +bool textcmdStartsLink(const QChar *start, int32 len, int32 commandOffset) { + if (commandOffset + 2 < len) { + if (*(start + commandOffset + 1) == TextCommandLinkIndex) { + return (*(start + commandOffset + 2) != 0); + } + return (*(start + commandOffset + 1) != TextCommandLinkText); + } + return false; +} + +bool checkTagStartInCommand(const QChar *start, int32 len, int32 tagStart, int32 &commandOffset, bool &commandIsLink, bool &inLink) { + bool inCommand = false; + const QChar *commandEnd = start + commandOffset; + while (commandOffset < len && tagStart > commandOffset) { // skip commands, evaluating are we in link or not + commandEnd = textSkipCommand(start + commandOffset, start + len); + if (commandEnd > start + commandOffset) { + if (tagStart < (commandEnd - start)) { + inCommand = true; + break; + } + for (commandOffset = commandEnd - start; commandOffset < len; ++commandOffset) { + if (*(start + commandOffset) == TextCommand) { + inLink = commandIsLink; + commandIsLink = textcmdStartsLink(start, len, commandOffset); + break; + } + } + if (commandOffset >= len) { + inLink = commandIsLink; + commandIsLink = false; + } + } else { + break; + } + } + if (inCommand) { + commandOffset = commandEnd - start; + } + return inCommand; +} + +EntitiesInText entitiesFromMTP(const QVector &entities) { + EntitiesInText result; + if (!entities.isEmpty()) { + result.reserve(entities.size()); + for_const (const auto &entity, entities) { + switch (entity.type()) { + case mtpc_messageEntityUrl: { const auto &d(entity.c_messageEntityUrl()); result.push_back(EntityInText(EntityInTextUrl, d.voffset.v, d.vlength.v)); } break; + case mtpc_messageEntityTextUrl: { const auto &d(entity.c_messageEntityTextUrl()); result.push_back(EntityInText(EntityInTextCustomUrl, d.voffset.v, d.vlength.v, textClean(qs(d.vurl)))); } break; + case mtpc_messageEntityEmail: { const auto &d(entity.c_messageEntityEmail()); result.push_back(EntityInText(EntityInTextEmail, d.voffset.v, d.vlength.v)); } break; + case mtpc_messageEntityHashtag: { const auto &d(entity.c_messageEntityHashtag()); result.push_back(EntityInText(EntityInTextHashtag, d.voffset.v, d.vlength.v)); } break; + case mtpc_messageEntityMention: { const auto &d(entity.c_messageEntityMention()); result.push_back(EntityInText(EntityInTextMention, d.voffset.v, d.vlength.v)); } break; + case mtpc_messageEntityBotCommand: { const auto &d(entity.c_messageEntityBotCommand()); result.push_back(EntityInText(EntityInTextBotCommand, d.voffset.v, d.vlength.v)); } break; + case mtpc_messageEntityBold: { const auto &d(entity.c_messageEntityBold()); result.push_back(EntityInText(EntityInTextBold, d.voffset.v, d.vlength.v)); } break; + case mtpc_messageEntityItalic: { const auto &d(entity.c_messageEntityItalic()); result.push_back(EntityInText(EntityInTextItalic, d.voffset.v, d.vlength.v)); } break; + case mtpc_messageEntityCode: { const auto &d(entity.c_messageEntityCode()); result.push_back(EntityInText(EntityInTextCode, d.voffset.v, d.vlength.v)); } break; + case mtpc_messageEntityPre: { const auto &d(entity.c_messageEntityPre()); result.push_back(EntityInText(EntityInTextPre, d.voffset.v, d.vlength.v, textClean(qs(d.vlanguage)))); } break; + } + } + } + return result; +} + +MTPVector linksToMTP(const EntitiesInText &links, bool sending) { + MTPVector result(MTP_vector(0)); + auto &v = result._vector().v; + for_const (const auto &link, links) { + if (link.length <= 0) continue; + if (sending && link.type != EntityInTextCode && link.type != EntityInTextPre) continue; + + auto offset = MTP_int(link.offset), length = MTP_int(link.length); + switch (link.type) { + case EntityInTextUrl: v.push_back(MTP_messageEntityUrl(offset, length)); break; + case EntityInTextCustomUrl: v.push_back(MTP_messageEntityTextUrl(offset, length, MTP_string(link.text))); break; + case EntityInTextEmail: v.push_back(MTP_messageEntityEmail(offset, length)); break; + case EntityInTextHashtag: v.push_back(MTP_messageEntityHashtag(offset, length)); break; + case EntityInTextMention: v.push_back(MTP_messageEntityMention(offset, length)); break; + case EntityInTextBotCommand: v.push_back(MTP_messageEntityBotCommand(offset, length)); break; + case EntityInTextBold: v.push_back(MTP_messageEntityBold(offset, length)); break; + case EntityInTextItalic: v.push_back(MTP_messageEntityItalic(offset, length)); break; + case EntityInTextCode: v.push_back(MTP_messageEntityCode(offset, length)); break; + case EntityInTextPre: v.push_back(MTP_messageEntityPre(offset, length, MTP_string(link.text))); break; + } + } + return result; +} + +EntitiesInText textParseEntities(QString &text, int32 flags, bool rich) { // some code is duplicated in flattextarea.cpp! + EntitiesInText result, mono; + + bool withHashtags = (flags & TextParseHashtags); + bool withMentions = (flags & TextParseMentions); + bool withBotCommands = (flags & TextParseBotCommands); + bool withMono = (flags & TextParseMono); + + if (withMono) { // parse mono entities (code and pre) + QString newText; + + int32 offset = 0, matchOffset = offset, len = text.size(), commandOffset = rich ? 0 : len; + bool inLink = false, commandIsLink = false; + const QChar *start = text.constData(); + for (; matchOffset < len;) { + if (commandOffset <= matchOffset) { + for (commandOffset = matchOffset; commandOffset < len; ++commandOffset) { + if (*(start + commandOffset) == TextCommand) { + inLink = commandIsLink; + commandIsLink = textcmdStartsLink(start, len, commandOffset); + break; + } + } + if (commandOffset >= len) { + inLink = commandIsLink; + commandIsLink = false; + } + } + auto mPre = _rePre.match(text, matchOffset); + auto mCode = _reCode.match(text, matchOffset); + if (!mPre.hasMatch() && !mCode.hasMatch()) break; + + int32 preStart = mPre.hasMatch() ? mPre.capturedStart() : INT_MAX, + preEnd = mPre.hasMatch() ? mPre.capturedEnd() : INT_MAX, + codeStart = mCode.hasMatch() ? mCode.capturedStart() : INT_MAX, + codeEnd = mCode.hasMatch() ? mCode.capturedEnd() : INT_MAX, + tagStart, tagEnd; + if (mPre.hasMatch()) { + if (!mPre.capturedRef(1).isEmpty()) { + ++preStart; + } + if (!mPre.capturedRef(4).isEmpty()) { + --preEnd; + } + } + if (mCode.hasMatch()) { + if (!mCode.capturedRef(1).isEmpty()) { + ++codeStart; + } + if (!mCode.capturedRef(4).isEmpty()) { + --codeEnd; + } + } + + bool pre = (preStart <= codeStart); + auto mTag = pre ? mPre : mCode; + if (pre) { + tagStart = preStart; + tagEnd = preEnd; + } else { + tagStart = codeStart; + tagEnd = codeEnd; + } + + bool inCommand = checkTagStartInCommand(start, len, tagStart, commandOffset, commandIsLink, inLink); + if (inCommand || inLink) { + matchOffset = commandOffset; + continue; + } + + if (newText.isEmpty()) newText.reserve(text.size()); + + bool addNewlineBefore = false, addNewlineAfter = false; + int32 outerStart = tagStart, outerEnd = tagEnd; + int32 innerStart = tagStart + mTag.capturedLength(2), innerEnd = tagEnd - mTag.capturedLength(3); + if (pre) { + while (outerStart > 0 && chIsSpace(*(start + outerStart - 1), rich) && !chIsNewline(*(start + outerStart - 1))) { + --outerStart; + } + addNewlineBefore = (outerStart > 0 && !chIsNewline(*(start + outerStart - 1))); + + for (int32 testInnerStart = innerStart; testInnerStart < innerEnd; ++testInnerStart) { + if (chIsNewline(*(start + testInnerStart))) { + innerStart = testInnerStart + 1; + break; + } else if (!chIsSpace(*(start + testInnerStart))) { + break; + } + } + for (int32 testInnerEnd = innerEnd; innerStart < testInnerEnd;) { + --testInnerEnd; + if (chIsNewline(*(start + testInnerEnd))) { + innerEnd = testInnerEnd; + break; + } else if (!chIsSpace(*(start + testInnerEnd))) { + break; + } + } + + while (outerEnd < len && chIsSpace(*(start + outerEnd)) && !chIsNewline(*(start + outerEnd))) { + ++outerEnd; + } + addNewlineAfter = (outerEnd < len && !chIsNewline(*(start + outerEnd))); + } + if (outerStart > offset) newText.append(start + offset, outerStart - offset); + if (addNewlineBefore) newText.append('\n'); + + int32 tagLength = innerEnd - innerStart; + mono.push_back(EntityInText(pre ? EntityInTextPre : EntityInTextCode, newText.size(), tagLength)); + + newText.append(start + innerStart, tagLength); + if (addNewlineAfter) newText.append('\n'); + + offset = matchOffset = outerEnd; + } + if (!newText.isEmpty()) { + newText.append(start + offset, len - offset); + text = newText; + } + } + int32 monoEntity = 0, monoCount = mono.size(), monoTill = 0; + + initLinkSets(); + int32 len = text.size(), commandOffset = rich ? 0 : len; + bool inLink = false, commandIsLink = false; + const QChar *start = text.constData(), *end = start + text.size(); + for (int32 offset = 0, matchOffset = offset, mentionSkip = 0; offset < len;) { + if (commandOffset <= offset) { + for (commandOffset = offset; commandOffset < len; ++commandOffset) { + if (*(start + commandOffset) == TextCommand) { + inLink = commandIsLink; + commandIsLink = textcmdStartsLink(start, len, commandOffset); + break; + } + } + } + QRegularExpressionMatch mDomain = _reDomain.match(text, matchOffset); + QRegularExpressionMatch mExplicitDomain = _reExplicitDomain.match(text, matchOffset); + QRegularExpressionMatch mHashtag = withHashtags ? _reHashtag.match(text, matchOffset) : QRegularExpressionMatch(); + QRegularExpressionMatch mMention = withMentions ? _reMention.match(text, qMax(mentionSkip, matchOffset)) : QRegularExpressionMatch(); + QRegularExpressionMatch mBotCommand = withBotCommands ? _reBotCommand.match(text, matchOffset) : QRegularExpressionMatch(); + + EntityInTextType lnkType = EntityInTextUrl; + int32 lnkStart = 0, lnkLength = 0; + int32 domainStart = mDomain.hasMatch() ? mDomain.capturedStart() : INT_MAX, + domainEnd = mDomain.hasMatch() ? mDomain.capturedEnd() : INT_MAX, + explicitDomainStart = mExplicitDomain.hasMatch() ? mExplicitDomain.capturedStart() : INT_MAX, + explicitDomainEnd = mExplicitDomain.hasMatch() ? mExplicitDomain.capturedEnd() : INT_MAX, + hashtagStart = mHashtag.hasMatch() ? mHashtag.capturedStart() : INT_MAX, + hashtagEnd = mHashtag.hasMatch() ? mHashtag.capturedEnd() : INT_MAX, + mentionStart = mMention.hasMatch() ? mMention.capturedStart() : INT_MAX, + mentionEnd = mMention.hasMatch() ? mMention.capturedEnd() : INT_MAX, + botCommandStart = mBotCommand.hasMatch() ? mBotCommand.capturedStart() : INT_MAX, + botCommandEnd = mBotCommand.hasMatch() ? mBotCommand.capturedEnd() : INT_MAX; + if (mHashtag.hasMatch()) { + if (!mHashtag.capturedRef(1).isEmpty()) { + ++hashtagStart; + } + if (!mHashtag.capturedRef(2).isEmpty()) { + --hashtagEnd; + } + } + while (mMention.hasMatch()) { + if (!mMention.capturedRef(1).isEmpty()) { + ++mentionStart; + } + if (!mMention.capturedRef(2).isEmpty()) { + --mentionEnd; + } + if (!(start + mentionStart + 1)->isLetter() || !(start + mentionEnd - 1)->isLetterOrNumber()) { + mentionSkip = mentionEnd; + mMention = _reMention.match(text, qMax(mentionSkip, matchOffset)); + if (mMention.hasMatch()) { + mentionStart = mMention.capturedStart(); + mentionEnd = mMention.capturedEnd(); + } else { + mentionStart = INT_MAX; + mentionEnd = INT_MAX; + } + } else { + break; + } + } + if (mBotCommand.hasMatch()) { + if (!mBotCommand.capturedRef(1).isEmpty()) { + ++botCommandStart; + } + if (!mBotCommand.capturedRef(3).isEmpty()) { + --botCommandEnd; + } + } + if (!mDomain.hasMatch() && !mExplicitDomain.hasMatch() && !mHashtag.hasMatch() && !mMention.hasMatch() && !mBotCommand.hasMatch()) { + break; + } + + if (explicitDomainStart < domainStart) { + domainStart = explicitDomainStart; + domainEnd = explicitDomainEnd; + mDomain = mExplicitDomain; + } + if (mentionStart < hashtagStart && mentionStart < domainStart && mentionStart < botCommandStart) { + bool inCommand = checkTagStartInCommand(start, len, mentionStart, commandOffset, commandIsLink, inLink); + if (inCommand || inLink) { + offset = matchOffset = commandOffset; + continue; + } + + lnkType = EntityInTextMention; + lnkStart = mentionStart; + lnkLength = mentionEnd - mentionStart; + } else if (hashtagStart < domainStart && hashtagStart < botCommandStart) { + bool inCommand = checkTagStartInCommand(start, len, hashtagStart, commandOffset, commandIsLink, inLink); + if (inCommand || inLink) { + offset = matchOffset = commandOffset; + continue; + } + + lnkType = EntityInTextHashtag; + lnkStart = hashtagStart; + lnkLength = hashtagEnd - hashtagStart; + } else if (botCommandStart < domainStart) { + bool inCommand = checkTagStartInCommand(start, len, botCommandStart, commandOffset, commandIsLink, inLink); + if (inCommand || inLink) { + offset = matchOffset = commandOffset; + continue; + } + + lnkType = EntityInTextBotCommand; + lnkStart = botCommandStart; + lnkLength = botCommandEnd - botCommandStart; + } else { + bool inCommand = checkTagStartInCommand(start, len, domainStart, commandOffset, commandIsLink, inLink); + if (inCommand || inLink) { + offset = matchOffset = commandOffset; + continue; + } + + QString protocol = mDomain.captured(1).toLower(); + QString topDomain = mDomain.captured(3).toLower(); + + bool isProtocolValid = protocol.isEmpty() || _validProtocols.contains(hashCrc32(protocol.constData(), protocol.size() * sizeof(QChar))); + bool isTopDomainValid = !protocol.isEmpty() || _validTopDomains.contains(hashCrc32(topDomain.constData(), topDomain.size() * sizeof(QChar))); + + if (protocol.isEmpty() && domainStart > offset + 1 && *(start + domainStart - 1) == QChar('@')) { + QString forMailName = text.mid(offset, domainStart - offset - 1); + QRegularExpressionMatch mMailName = _reMailName.match(forMailName); + if (mMailName.hasMatch()) { + int32 mailStart = offset + mMailName.capturedStart(); + if (mailStart < offset) { + mailStart = offset; + } + lnkType = EntityInTextEmail; + lnkStart = mailStart; + lnkLength = domainEnd - mailStart; + } + } + if (lnkType == EntityInTextUrl && !lnkLength) { + if (!isProtocolValid || !isTopDomainValid) { + matchOffset = domainEnd; + continue; + } + lnkStart = domainStart; + + QStack parenth; + const QChar *domainEnd = start + mDomain.capturedEnd(), *p = domainEnd; + for (; p < end; ++p) { + QChar ch(*p); + if (chIsLinkEnd(ch)) break; // link finished + if (chIsAlmostLinkEnd(ch)) { + const QChar *endTest = p + 1; + while (endTest < end && chIsAlmostLinkEnd(*endTest)) { + ++endTest; + } + if (endTest >= end || chIsLinkEnd(*endTest)) { + break; // link finished at p + } + p = endTest; + ch = *p; + } + if (ch == '(' || ch == '[' || ch == '{' || ch == '<') { + parenth.push(p); + } else if (ch == ')' || ch == ']' || ch == '}' || ch == '>') { + if (parenth.isEmpty()) break; + const QChar *q = parenth.pop(), open(*q); + if ((ch == ')' && open != '(') || (ch == ']' && open != '[') || (ch == '}' && open != '{') || (ch == '>' && open != '<')) { + p = q; + break; + } + } + } + if (p > domainEnd) { // check, that domain ended + if (domainEnd->unicode() != '/' && domainEnd->unicode() != '?') { + matchOffset = domainEnd - start; + continue; + } + } + lnkLength = (p - start) - lnkStart; + } + } + for (; monoEntity < monoCount && mono[monoEntity].offset <= lnkStart; ++monoEntity) { + monoTill = qMax(monoTill, mono[monoEntity].offset + mono[monoEntity].length); + result.push_back(mono[monoEntity]); + } + if (lnkStart >= monoTill) { + result.push_back(EntityInText(lnkType, lnkStart, lnkLength)); + } + + offset = matchOffset = lnkStart + lnkLength; + } + for (; monoEntity < monoCount; ++monoEntity) { + monoTill = qMax(monoTill, mono[monoEntity].offset + mono[monoEntity].length); + result.push_back(mono[monoEntity]); + } + + return result; +} + +QString textApplyEntities(const QString &text, const EntitiesInText &entities) { + if (entities.isEmpty()) return text; + + QMultiMap closingTags; + QString code(qsl("`")), pre(qsl("```")); + + QString result; + int32 size = text.size(); + const QChar *b = text.constData(), *already = b, *e = b + size; + EntitiesInText::const_iterator entity = entities.cbegin(), end = entities.cend(); + while (entity != end && ((entity->type != EntityInTextCode && entity->type != EntityInTextPre) || entity->length <= 0 || entity->offset >= size)) { + ++entity; + } + while (entity != end || !closingTags.isEmpty()) { + int32 nextOpenEntity = (entity == end) ? (size + 1) : entity->offset; + int32 nextCloseEntity = closingTags.isEmpty() ? (size + 1) : closingTags.cbegin().key(); + if (nextOpenEntity <= nextCloseEntity) { + QString tag = (entity->type == EntityInTextCode) ? code : pre; + if (result.isEmpty()) result.reserve(text.size() + entities.size() * pre.size() * 2); + + const QChar *offset = b + nextOpenEntity; + if (offset > already) { + result.append(already, offset - already); + already = offset; + } + result.append(tag); + closingTags.insert(qMin(entity->offset + entity->length, size), tag); + + ++entity; + while (entity != end && ((entity->type != EntityInTextCode && entity->type != EntityInTextPre) || entity->length <= 0 || entity->offset >= size)) { + ++entity; + } + } else { + const QChar *offset = b + nextCloseEntity; + if (offset > already) { + result.append(already, offset - already); + already = offset; + } + result.append(closingTags.cbegin().value()); + closingTags.erase(closingTags.begin()); + } + } + if (result.isEmpty()) { + return text; + } + const QChar *offset = b + size; + if (offset > already) { + result.append(already, offset - already); + } + return result; +} + +void replaceStringWithEntities(const QLatin1String &from, QChar to, QString &result, EntitiesInText &entities, bool checkSpace = false) { + int32 len = from.size(), s = result.size(), offset = 0, length = 0; + EntitiesInText::iterator i = entities.begin(), e = entities.end(); + for (QChar *start = result.data(); offset < s;) { + int32 nextOffset = result.indexOf(from, offset); + if (nextOffset < 0) { + moveStringPart(start, length, offset, s - offset, entities); + break; + } + + if (checkSpace) { + bool spaceBefore = (nextOffset > 0) && (start + nextOffset - 1)->isSpace(); + bool spaceAfter = (nextOffset + len < s) && (start + nextOffset + len)->isSpace(); + if (!spaceBefore && !spaceAfter) { + moveStringPart(start, length, offset, nextOffset - offset + len + 1, entities); + continue; + } + } + + bool skip = false; + for (; i != e; ++i) { // find and check next finishing entity + if (i->offset + i->length > nextOffset) { + skip = (i->offset < nextOffset + len); + break; + } + } + if (skip) { + moveStringPart(start, length, offset, nextOffset - offset + len, entities); + continue; + } + + moveStringPart(start, length, offset, nextOffset - offset, entities); + + *(start + length) = to; + ++length; + offset += len; + } + if (length < s) result.resize(length); +} + +QString prepareTextWithEntities(QString result, EntitiesInText &entities, int32 flags) { + cleanTextWithEntities(result, entities); + + if (flags) { + entities = textParseEntities(result, flags); + } + + replaceStringWithEntities(qstr("--"), QChar(8212), result, entities, true); + replaceStringWithEntities(qstr("<<"), QChar(171), result, entities); + replaceStringWithEntities(qstr(">>"), QChar(187), result, entities); + + if (cReplaceEmojis()) { + result = replaceEmojis(result, entities); + } + + trimTextWithEntities(result, entities); + + return result; +} + +void moveStringPart(QChar *start, int32 &to, int32 &from, int32 count, EntitiesInText &entities) { + if (count > 0) { + if (to < from) { + memmove(start + to, start + from, count * sizeof(QChar)); + for (auto &entity : entities) { + if (entity.offset >= from + count) break; + if (entity.offset + entity.length < from) continue; + if (entity.offset >= from) { + entity.offset -= (from - to); + entity.length += (from - to); + } + if (entity.offset + entity.length < from + count) { + entity.length -= (from - to); + } + } + } + to += count; + from += count; + } +} + +// replace bad symbols with space and remove \r +void cleanTextWithEntities(QString &result, EntitiesInText &entities) { + result = result.replace('\t', qstr(" ")); + int32 len = result.size(), to = 0, from = 0; + QChar *start = result.data(); + for (QChar *ch = start, *end = start + len; ch < end; ++ch) { + if (ch->unicode() == '\r') { + moveStringPart(start, to, from, (ch - start) - from, entities); + ++from; + } else if (chReplacedBySpace(*ch)) { + *ch = ' '; + } + } + moveStringPart(start, to, from, len - from, entities); + if (to < len) result.resize(to); +} + +void trimTextWithEntities(QString &result, EntitiesInText &entities) { + bool foundNotTrimmed = false; + for (QChar *s = result.data(), *e = s + result.size(), *ch = e; ch != s;) { // rtrim + --ch; + if (!chIsTrimmed(*ch)) { + if (ch + 1 < e) { + int32 l = ch + 1 - s; + for (EntitiesInText::iterator i = entities.begin(), e = entities.end(); i != e; ++i) { + if (i->offset > l) { + i->offset = l; + i->length = 0; + } else if (i->offset + i->length > l) { + i->length = l - i->offset; + } + } + result.resize(l); + } + foundNotTrimmed = true; + break; + } + } + if (!foundNotTrimmed) { + result.clear(); + entities.clear(); + return; + } + + for (QChar *s = result.data(), *ch = s, *e = s + result.size(); ch != e; ++ch) { // ltrim + if (!chIsTrimmed(*ch)) { + if (ch > s) { + int32 l = ch - s; + for (EntitiesInText::iterator i = entities.begin(), e = entities.end(); i != e; ++i) { + if (i->offset + i->length <= l) { + i->length = 0; + i->offset = 0; + } else if (i->offset < l) { + i->length = i->offset + i->length - l; + i->offset = 0; + } else { + i->offset -= l; + } + } + result = result.mid(l); + } + break; + } + } +} diff --git a/Telegram/SourceFiles/ui/text/text_entity.h b/Telegram/SourceFiles/ui/text/text_entity.h new file mode 100644 index 000000000..aaf9406f6 --- /dev/null +++ b/Telegram/SourceFiles/ui/text/text_entity.h @@ -0,0 +1,85 @@ +/* +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 EntityInTextType { + EntityInTextUrl, + EntityInTextCustomUrl, + EntityInTextEmail, + EntityInTextHashtag, + EntityInTextMention, + EntityInTextBotCommand, + + EntityInTextBold, + EntityInTextItalic, + EntityInTextCode, // inline + EntityInTextPre, // block +}; +struct EntityInText { + EntityInText(EntityInTextType type, int offset, int length, const QString &text = QString()) : type(type), offset(offset), length(length), text(text) { + } + EntityInTextType type; + int offset, length; + QString text; +}; +typedef QList EntitiesInText; + +// text preprocess +QString textClean(const QString &text); +QString textRichPrepare(const QString &text); +QString textOneLine(const QString &text, bool trim = true, bool rich = false); +QString textAccentFold(const QString &text); +QString textSearchKey(const QString &text); +bool textSplit(QString &sendingText, EntitiesInText &sendingEntities, QString &leftText, EntitiesInText &leftEntities, int32 limit); + +enum { + TextParseMultiline = 0x001, + TextParseLinks = 0x002, + TextParseRichText = 0x004, + TextParseMentions = 0x008, + TextParseHashtags = 0x010, + TextParseBotCommands = 0x020, + TextParseMono = 0x040, + + TextTwitterMentions = 0x100, + TextTwitterHashtags = 0x200, + TextInstagramMentions = 0x400, + TextInstagramHashtags = 0x800, +}; + +EntitiesInText entitiesFromMTP(const QVector &entities); +MTPVector linksToMTP(const EntitiesInText &links, bool sending = false); + +EntitiesInText textParseEntities(QString &text, int32 flags, bool rich = false); // changes text if (flags & TextParseMono) +QString textApplyEntities(const QString &text, const EntitiesInText &entities); + +QString prepareTextWithEntities(QString result, EntitiesInText &entities, int32 flags); + +inline QString prepareText(QString result, bool checkLinks = false) { + EntitiesInText entities; + return prepareTextWithEntities(result, entities, checkLinks ? (TextParseLinks | TextParseMentions | TextParseHashtags | TextParseBotCommands) : 0); +} + +void moveStringPart(QChar *start, int32 &to, int32 &from, int32 count, EntitiesInText &entities); + +// replace bad symbols with space and remove \r +void cleanTextWithEntities(QString &result, EntitiesInText &entities); +void trimTextWithEntities(QString &result, EntitiesInText &entities); \ No newline at end of file diff --git a/Telegram/SourceFiles/ui/toast/toast_widget.h b/Telegram/SourceFiles/ui/toast/toast_widget.h index 4ee46f599..1d255e2c1 100644 --- a/Telegram/SourceFiles/ui/toast/toast_widget.h +++ b/Telegram/SourceFiles/ui/toast/toast_widget.h @@ -22,7 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "ui/toast/toast.h" #include "ui/twidget.h" -#include "ui/text.h" +#include "ui/text/text.h" namespace Ui { namespace Toast { diff --git a/Telegram/Telegram.pro b/Telegram/Telegram.pro index ff1580fb4..b33c46f6f 100644 --- a/Telegram/Telegram.pro +++ b/Telegram/Telegram.pro @@ -129,6 +129,9 @@ SOURCES += \ ./SourceFiles/mtproto/scheme_auto.cpp \ ./SourceFiles/mtproto/session.cpp \ ./SourceFiles/ui/buttons/peer_avatar_button.cpp \ + ./SourceFiles/ui/text/text.cpp \ + ./SourceFiles/ui/text/text_block.cpp \ + ./SourceFiles/ui/text/text_entity.cpp \ ./SourceFiles/ui/toast/toast.cpp \ ./SourceFiles/ui/toast/toast_manager.cpp \ ./SourceFiles/ui/toast/toast_widget.cpp \ @@ -147,7 +150,6 @@ SOURCES += \ ./SourceFiles/ui/images.cpp \ ./SourceFiles/ui/scrollarea.cpp \ ./SourceFiles/ui/style_core.cpp \ - ./SourceFiles/ui/text.cpp \ ./SourceFiles/ui/twidget.cpp \ ./GeneratedFiles/lang_auto.cpp \ ./GeneratedFiles/style_auto.cpp \ @@ -238,6 +240,9 @@ HEADERS += \ ./SourceFiles/mtproto/session.h \ ./SourceFiles/pspecific.h \ ./SourceFiles/ui/buttons/peer_avatar_button.h \ + ./SourceFiles/ui/text/text.h \ + ./SourceFiles/ui/text/text_block.h \ + ./SourceFiles/ui/text/text_entity.h \ ./SourceFiles/ui/toast/toast.h \ ./SourceFiles/ui/toast/toast_manager.h \ ./SourceFiles/ui/toast/toast_widget.h \ @@ -257,7 +262,6 @@ HEADERS += \ ./SourceFiles/ui/scrollarea.h \ ./SourceFiles/ui/style.h \ ./SourceFiles/ui/style_core.h \ - ./SourceFiles/ui/text.h \ ./SourceFiles/ui/twidget.h \ ./GeneratedFiles/lang_auto.h \ ./GeneratedFiles/style_auto.h \ diff --git a/Telegram/Telegram.vcxproj b/Telegram/Telegram.vcxproj index 1fb2d8faf..dc2676a0b 100644 --- a/Telegram/Telegram.vcxproj +++ b/Telegram/Telegram.vcxproj @@ -1170,7 +1170,9 @@ - + + + @@ -1509,7 +1511,6 @@ - $(QTDIR)\bin\moc.exe;%(FullPath) Moc%27ing twidget.h... @@ -1524,6 +1525,9 @@ .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/ui/twidget.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\openssl\Release\include" "-I.\..\..\Libraries\ffmpeg" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I.\..\..\Libraries\breakpad\src" "-I.\ThirdParty\minizip" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.1\QtGui" + + + $(QTDIR)\bin\moc.exe;%(FullPath) diff --git a/Telegram/Telegram.vcxproj.filters b/Telegram/Telegram.vcxproj.filters index 86772f8db..0b17e3c99 100644 --- a/Telegram/Telegram.vcxproj.filters +++ b/Telegram/Telegram.vcxproj.filters @@ -79,6 +79,9 @@ {ddcc5634-90e7-4815-ba86-a3db539f4774} + + {850c3d13-024a-4ef3-a6b7-b546e67cca48} + @@ -972,9 +975,6 @@ ui - - ui - ui @@ -1068,6 +1068,15 @@ overview + + ui\text + + + ui\text + + + ui\text + @@ -1175,9 +1184,6 @@ ui - - ui - ui\toast @@ -1220,6 +1226,15 @@ overview + + ui\text + + + ui\text + + + ui\text + diff --git a/Telegram/Telegram.xcodeproj/project.pbxproj b/Telegram/Telegram.xcodeproj/project.pbxproj index fe744af85..c994beee8 100644 --- a/Telegram/Telegram.xcodeproj/project.pbxproj +++ b/Telegram/Telegram.xcodeproj/project.pbxproj @@ -457,7 +457,7 @@ 111BBEE3D1432C3B517FD539 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qdds.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qdds.pri"; sourceTree = ""; }; 120EBCD9A37DB9A36BFE58C0 /* contactsbox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = contactsbox.h; path = SourceFiles/boxes/contactsbox.h; sourceTree = ""; }; 1292B92B4848460640F6A391 /* telegram.qrc */ = {isa = PBXFileReference; lastKnownFileType = text; name = telegram.qrc; path = Resources/telegram.qrc; sourceTree = ""; }; - 135FD3715BFDC50AD7B00E04 /* text.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = text.cpp; path = SourceFiles/ui/text.cpp; sourceTree = ""; }; + 135FD3715BFDC50AD7B00E04 /* text.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = text.cpp; path = SourceFiles/ui/text/text.cpp; sourceTree = ""; }; 143405635D04698F421A12EA /* aboutbox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = aboutbox.h; path = SourceFiles/boxes/aboutbox.h; sourceTree = ""; }; 14437BFDCD58FF1742EF1B35 /* photocropbox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = photocropbox.h; path = SourceFiles/boxes/photocropbox.h; sourceTree = ""; }; 152B8D1BCECEB7B0C77E073C /* introwidget.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = introwidget.h; path = SourceFiles/intro/introwidget.h; sourceTree = ""; }; @@ -570,7 +570,7 @@ 6D50D70712776D7ED3B00E5C /* facade.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = facade.cpp; path = SourceFiles/mtproto/facade.cpp; sourceTree = ""; }; 6E1859D714E4471E053D90C9 /* scrollarea.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = scrollarea.cpp; path = SourceFiles/ui/scrollarea.cpp; sourceTree = ""; }; 6E67D23B15FC4B628DB2E0B2 /* /usr/local/Qt-5.5.1/mkspecs/qdevice.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/qdevice.pri"; sourceTree = ""; }; - 6E8FD0ED1B60D43929944CD2 /* text.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = text.h; path = SourceFiles/ui/text.h; sourceTree = ""; }; + 6E8FD0ED1B60D43929944CD2 /* text.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = text.h; path = SourceFiles/ui/text/text.h; sourceTree = ""; }; 710C982FC773400941B3AFBC /* dropdown.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = dropdown.cpp; path = SourceFiles/dropdown.cpp; sourceTree = ""; }; 723F90793B2C195E2CCB2233 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 73737DC91E390C4AB18FB595 /* pspecific_mac_p.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = pspecific_mac_p.mm; path = SourceFiles/pspecific_mac_p.mm; sourceTree = ""; }; From 291f483671de6eba929798d6c632235d045071f8 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 14 Apr 2016 15:00:44 +0300 Subject: [PATCH 06/14] Allowing to choose bots in appoint supergroup admin box. Better naturalHeight() for bot keyboards. We try to make all the buttons in the row have equal size (size of the largest button). --- Telegram/SourceFiles/boxes/contactsbox.cpp | 1 - Telegram/SourceFiles/history.cpp | 23 ++++++++++------------ 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/Telegram/SourceFiles/boxes/contactsbox.cpp b/Telegram/SourceFiles/boxes/contactsbox.cpp index 326c94bef..92540758a 100644 --- a/Telegram/SourceFiles/boxes/contactsbox.cpp +++ b/Telegram/SourceFiles/boxes/contactsbox.cpp @@ -957,7 +957,6 @@ void ContactsInner::peopleReceived(const QString &query, const QVector if (p->asUser()->botInfo->cantJoinGroups) continue; } if (_channel) { - if (_channel->isMegagroup() && _membersFilter == MembersFilterAdmins) continue; if (!_channel->isMegagroup() && _membersFilter != MembersFilterAdmins) continue; } } diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index e4afd330a..ec27218e1 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -2626,10 +2626,10 @@ void ReplyKeyboard::resize(int width, int height) { } bool ReplyKeyboard::isEnoughSpace(int width, const style::botKeyboardButton &st) const { - for_const (const ButtonRow &row, _rows) { + for_const (const auto &row, _rows) { int s = row.size(); int widthLeft = width - ((s - 1) * st.margin + s * 2 * st.padding); - for_const (const Button &button, row) { + for_const (const auto &button, row) { widthLeft -= qMax(button.text.maxWidth(), 1); if (widthLeft < 0) { if (row.size() > 3) { @@ -2648,18 +2648,15 @@ void ReplyKeyboard::setStyle(StylePtr &&st) { } int ReplyKeyboard::naturalWidth() const { - int result = 0; + auto result = 0; + for_const (const auto &row, _rows) { + auto rowMaxButtonWidth = 0; + for_const (const auto &button, row) { + accumulate_max(rowMaxButtonWidth, qMax(button.text.maxWidth(), 1) + _st->minButtonWidth(button.type)); + } - auto markup = _item->Get(); - for_const (const ButtonRow &row, _rows) { - int rowSize = row.size(); - int rowWidth = (rowSize - 1) * _st->buttonSkip(); - for_const (const Button &button, row) { - rowWidth += qMax(button.text.maxWidth(), 1) + _st->minButtonWidth(button.type); - } - if (rowWidth > result) { - result = rowWidth; - } + auto rowSize = row.size(); + accumulate_max(result, rowSize * rowMaxButtonWidth + (rowSize - 1) * _st->buttonSkip()); } return result; } From 246e39adb1b686aa4e3ab317e3460e2b7378958c Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 14 Apr 2016 16:03:03 +0300 Subject: [PATCH 07/14] Fixed Xcode build, improved project folders (similar to MSVC), warnings fixed. --- Telegram/SourceFiles/history.h | 14 +- Telegram/SourceFiles/mainwidget.h | 7 +- Telegram/SourceFiles/pspecific_mac_p.mm | 1 + Telegram/SourceFiles/stdafx.h | 19 +- Telegram/SourceFiles/ui/flatinput.h | 36 +- Telegram/SourceFiles/ui/flattextarea.h | 28 +- Telegram/SourceFiles/ui/text/text.h | 3 + Telegram/SourceFiles/ui/twidget.h | 3 +- Telegram/Telegram.xcodeproj/project.pbxproj | 426 +++++------------- Telegram/Telegram.xcodeproj/qt_preprocess.mak | 30 +- 10 files changed, 195 insertions(+), 372 deletions(-) diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index 68acef5d3..de909ffd0 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -2901,12 +2901,12 @@ public: return _create(history, newItem, date); } - HistoryTextState getState(int x, int y, HistoryStateRequest request) const; + HistoryTextState getState(int x, int y, HistoryStateRequest request) const override; - QString selectedText(uint32 selection) const { + QString selectedText(TextSelection selection) const override { return QString(); } - HistoryItemType type() const { + HistoryItemType type() const override { return HistoryItemGroup; } void uniteWith(MsgId minId, MsgId maxId, int32 count); @@ -2950,13 +2950,13 @@ public: return _create(history, wasMinId, date); } - void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const; - HistoryTextState getState(int x, int y, HistoryStateRequest request) const; + void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override; + HistoryTextState getState(int x, int y, HistoryStateRequest request) const override; - QString selectedText(uint32 selection) const { + QString selectedText(TextSelection selection) const override { return QString(); } - HistoryItemType type() const { + HistoryItemType type() const override { return HistoryItemCollapse; } MsgId wasMinId() const { diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index 18c214d5a..dafb651b8 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -37,7 +37,6 @@ class TopBarWidget; class MainWindow; class ApiWrap; -class MainWidget; class ConfirmBox; class DialogsWidget; class HistoryWidget; @@ -550,12 +549,12 @@ private: ChildWidget _dialogs; ChildWidget _history; - ChildWidget _profile = nullptr; - ChildWidget _overview = nullptr; + ChildWidget _profile = { nullptr }; + ChildWidget _overview = { nullptr }; ChildWidget _player; ChildWidget _topBar; ConfirmBox *_forwardConfirm = nullptr; // for single column layout - ChildWidget _hider = nullptr; + ChildWidget _hider = { nullptr }; StackItems _stack; PeerData *_peerInStack = nullptr; MsgId _msgIdInStack = 0; diff --git a/Telegram/SourceFiles/pspecific_mac_p.mm b/Telegram/SourceFiles/pspecific_mac_p.mm index 4e3c1998f..392acfd00 100644 --- a/Telegram/SourceFiles/pspecific_mac_p.mm +++ b/Telegram/SourceFiles/pspecific_mac_p.mm @@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "mainwindow.h" #include "mainwidget.h" #include "application.h" +#include "playerwidget.h" #include "lang.h" diff --git a/Telegram/SourceFiles/stdafx.h b/Telegram/SourceFiles/stdafx.h index d8affc31f..e1e8bc5c7 100644 --- a/Telegram/SourceFiles/stdafx.h +++ b/Telegram/SourceFiles/stdafx.h @@ -21,13 +21,30 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #define NOMINMAX // no min() and max() macro declarations #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 #include +// False positive warning in clang for QMap member function value: +// const T QMap::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 + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif // __clang__ + #include #include diff --git a/Telegram/SourceFiles/ui/flatinput.h b/Telegram/SourceFiles/ui/flatinput.h index 6a1789292..0de17a883 100644 --- a/Telegram/SourceFiles/ui/flatinput.h +++ b/Telegram/SourceFiles/ui/flatinput.h @@ -31,14 +31,14 @@ public: 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 paintEvent(QPaintEvent *e); - void focusInEvent(QFocusEvent *e); - void focusOutEvent(QFocusEvent *e); - void keyPressEvent(QKeyEvent *e); - void resizeEvent(QResizeEvent *e); - void contextMenuEvent(QContextMenuEvent *e); + void paintEvent(QPaintEvent *e) override; + void focusInEvent(QFocusEvent *e) override; + void focusOutEvent(QFocusEvent *e) override; + void keyPressEvent(QKeyEvent *e) override; + void resizeEvent(QResizeEvent *e) override; + void contextMenuEvent(QContextMenuEvent *e) override; void notaBene(); @@ -52,8 +52,8 @@ public: void step_appearance(float64 ms, bool timer); - QSize sizeHint() const; - QSize minimumSizeHint() const; + QSize sizeHint() const override; + QSize minimumSizeHint() const override; void customUpDown(bool isCustom); const QString &getLastText() const { @@ -507,14 +507,14 @@ public: 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 paintEvent(QPaintEvent *e); - void focusInEvent(QFocusEvent *e); - void focusOutEvent(QFocusEvent *e); - void keyPressEvent(QKeyEvent *e); - void resizeEvent(QResizeEvent *e); - void contextMenuEvent(QContextMenuEvent *e); + void paintEvent(QPaintEvent *e) override; + void focusInEvent(QFocusEvent *e) override; + void focusOutEvent(QFocusEvent *e) override; + void keyPressEvent(QKeyEvent *e) override; + void resizeEvent(QResizeEvent *e) override; + void contextMenuEvent(QContextMenuEvent *e) override; void showError(); @@ -528,8 +528,8 @@ public: void step_placeholderShift(float64 ms, bool timer); void step_border(float64 ms, bool timer); - QSize sizeHint() const; - QSize minimumSizeHint() const; + QSize sizeHint() const override; + QSize minimumSizeHint() const override; void customUpDown(bool isCustom); const QString &getLastText() const { diff --git a/Telegram/SourceFiles/ui/flattextarea.h b/Telegram/SourceFiles/ui/flattextarea.h index 2a115107a..8c9235eea 100644 --- a/Telegram/SourceFiles/ui/flattextarea.h +++ b/Telegram/SourceFiles/ui/flattextarea.h @@ -35,16 +35,16 @@ public: 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 paintEvent(QPaintEvent *e); - void focusInEvent(QFocusEvent *e); - void focusOutEvent(QFocusEvent *e); - void keyPressEvent(QKeyEvent *e); - void resizeEvent(QResizeEvent *e); - void mousePressEvent(QMouseEvent *e); - void dropEvent(QDropEvent *e); - void contextMenuEvent(QContextMenuEvent *e); + void paintEvent(QPaintEvent *e) override; + void focusInEvent(QFocusEvent *e) override; + void focusOutEvent(QFocusEvent *e) override; + void keyPressEvent(QKeyEvent *e) override; + void resizeEvent(QResizeEvent *e) override; + void mousePressEvent(QMouseEvent *e) override; + void dropEvent(QDropEvent *e) override; + void contextMenuEvent(QContextMenuEvent *e) override; void setMaxLength(int32 maxLength); void setMinHeight(int32 minHeight); @@ -62,8 +62,8 @@ public: void step_appearance(float64 ms, bool timer); - QSize sizeHint() const; - QSize minimumSizeHint() const; + QSize sizeHint() const override; + QSize minimumSizeHint() const override; EmojiPtr getSingleEmoji() const; QString getMentionHashtagBotCommandPart(bool &start) const; @@ -82,9 +82,9 @@ public: void parseLinks(); QStringList linksList() const; - void insertFromMimeData(const QMimeData *source); + void insertFromMimeData(const QMimeData *source) override; - QMimeData *createMimeDataFromSelection() const; + QMimeData *createMimeDataFromSelection() const override; enum class SubmitSettings { None, @@ -125,7 +125,7 @@ protected: void insertEmoji(EmojiPtr emoji, QTextCursor c); - QVariant loadResource(int type, const QUrl &name); + QVariant loadResource(int type, const QUrl &name) override; void checkContentHeight(); diff --git a/Telegram/SourceFiles/ui/text/text.h b/Telegram/SourceFiles/ui/text/text.h index 0c9cf24e3..84f8ace9a 100644 --- a/Telegram/SourceFiles/ui/text/text.h +++ b/Telegram/SourceFiles/ui/text/text.h @@ -138,6 +138,9 @@ public: }; Q_DECLARE_FLAGS(Flags, Flag); + StateRequest() { + } + style::align align = style::al_left; Flags flags = Flag::LookupLink; }; diff --git a/Telegram/SourceFiles/ui/twidget.h b/Telegram/SourceFiles/ui/twidget.h index 9d4b5468f..cec138a84 100644 --- a/Telegram/SourceFiles/ui/twidget.h +++ b/Telegram/SourceFiles/ui/twidget.h @@ -174,7 +174,7 @@ class TWidget : public QWidget { public: TWidget(QWidget *parent = nullptr) : QWidget(parent) { } - bool event(QEvent *e) { + bool event(QEvent *e) override { return QWidget::event(e); } virtual void grabStart() { @@ -233,6 +233,7 @@ class ChildWidget { public: ChildWidget(std::nullptr_t) : _widget(nullptr) { } + // No default constructor, but constructors with at least // one argument are simply make functions. template diff --git a/Telegram/Telegram.xcodeproj/project.pbxproj b/Telegram/Telegram.xcodeproj/project.pbxproj index c994beee8..82df9ffb8 100644 --- a/Telegram/Telegram.xcodeproj/project.pbxproj +++ b/Telegram/Telegram.xcodeproj/project.pbxproj @@ -66,6 +66,13 @@ 075FEBEC1C82336D0003ECA3 /* shortcuts.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 075FEBEA1C82336D0003ECA3 /* shortcuts.cpp */; }; 0764D55A1ABAD6F900FBFEED /* apiwrap.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 0764D5581ABAD6F900FBFEED /* apiwrap.cpp */; }; 0764D55D1ABAD71B00FBFEED /* moc_apiwrap.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 0764D55C1ABAD71B00FBFEED /* moc_apiwrap.cpp */; }; + 076B1C4D1CBFBF59002C0BC2 /* text_block.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 076B1C491CBFBF59002C0BC2 /* text_block.cpp */; }; + 076B1C4E1CBFBF59002C0BC2 /* text_entity.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 076B1C4B1CBFBF59002C0BC2 /* text_entity.cpp */; }; + 076B1C541CBFC6F2002C0BC2 /* click_handler_types.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 076B1C501CBFC6F2002C0BC2 /* click_handler_types.cpp */; }; + 076B1C551CBFC6F2002C0BC2 /* click_handler.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 076B1C521CBFC6F2002C0BC2 /* click_handler.cpp */; }; + 076B1C5B1CBFC8F1002C0BC2 /* top_bar_widget.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 076B1C591CBFC8F1002C0BC2 /* top_bar_widget.cpp */; }; + 076B1C5F1CBFC98F002C0BC2 /* overview_layout.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 076B1C5D1CBFC98F002C0BC2 /* overview_layout.cpp */; }; + 076B1C631CBFCC53002C0BC2 /* moc_top_bar_widget.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 076B1C621CBFCC53002C0BC2 /* moc_top_bar_widget.cpp */; }; 077A4AF71CA41C38002188D2 /* connection_abstract.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 077A4AEC1CA41C38002188D2 /* connection_abstract.cpp */; }; 077A4AF81CA41C38002188D2 /* connection_auto.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 077A4AEE1CA41C38002188D2 /* connection_auto.cpp */; }; 077A4AF91CA41C38002188D2 /* connection_http.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 077A4AF01CA41C38002188D2 /* connection_http.cpp */; }; @@ -289,7 +296,6 @@ 032C1BF3E727B450A4851D48 /* emojibox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = emojibox.h; path = SourceFiles/boxes/emojibox.h; sourceTree = ""; }; 04391BE7A8B9D811E255100A /* Qt5Gui */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = Qt5Gui; path = "/usr/local/Qt-5.5.1/lib/libQt5Gui$(QT_LIBRARY_SUFFIX).a"; sourceTree = ""; }; 047DAFB0A7DE92C63033A43C /* mainwidget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = mainwidget.cpp; path = SourceFiles/mainwidget.cpp; sourceTree = ""; }; - 060A694B42A4555240009936 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtga.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtga.pri"; sourceTree = ""; }; 06E379415713F34B83F99C35 /* app.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = app.cpp; path = SourceFiles/app.cpp; sourceTree = ""; }; 0702E9A11CB8D2A8007A7495 /* serialize_common.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = serialize_common.cpp; path = SourceFiles/serialize/serialize_common.cpp; sourceTree = SOURCE_ROOT; }; 0702E9A21CB8D2A8007A7495 /* serialize_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = serialize_common.h; path = SourceFiles/serialize/serialize_common.h; sourceTree = SOURCE_ROOT; }; @@ -333,13 +339,26 @@ 0755AEDA1AD12A80004D738A /* moc_abstractbox.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = moc_abstractbox.cpp; path = GeneratedFiles/Debug/moc_abstractbox.cpp; sourceTree = SOURCE_ROOT; }; 0755AEDB1AD12A80004D738A /* moc_intropwdcheck.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = moc_intropwdcheck.cpp; path = GeneratedFiles/Debug/moc_intropwdcheck.cpp; sourceTree = SOURCE_ROOT; }; 0755AEDC1AD12A80004D738A /* moc_sessionsbox.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = moc_sessionsbox.cpp; path = GeneratedFiles/Debug/moc_sessionsbox.cpp; sourceTree = SOURCE_ROOT; }; - 075EB50EB07CF69FD62FB8DF /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_sql_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_sql_private.pri"; sourceTree = ""; }; 075F99A91A45EEF200915C72 /* lang_es.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = lang_es.strings; path = Resources/langs/lang_es.strings; sourceTree = SOURCE_ROOT; }; 075FEBEA1C82336D0003ECA3 /* shortcuts.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = shortcuts.cpp; path = SourceFiles/shortcuts.cpp; sourceTree = SOURCE_ROOT; }; 075FEBEB1C82336D0003ECA3 /* shortcuts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = shortcuts.h; path = SourceFiles/shortcuts.h; sourceTree = SOURCE_ROOT; }; 0764D5581ABAD6F900FBFEED /* apiwrap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = apiwrap.cpp; path = SourceFiles/apiwrap.cpp; sourceTree = SOURCE_ROOT; }; 0764D5591ABAD6F900FBFEED /* apiwrap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = apiwrap.h; path = SourceFiles/apiwrap.h; sourceTree = SOURCE_ROOT; }; 0764D55C1ABAD71B00FBFEED /* moc_apiwrap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = moc_apiwrap.cpp; path = GeneratedFiles/Debug/moc_apiwrap.cpp; sourceTree = SOURCE_ROOT; }; + 076B1C491CBFBF59002C0BC2 /* text_block.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = text_block.cpp; path = SourceFiles/ui/text/text_block.cpp; sourceTree = SOURCE_ROOT; }; + 076B1C4A1CBFBF59002C0BC2 /* text_block.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = text_block.h; path = SourceFiles/ui/text/text_block.h; sourceTree = SOURCE_ROOT; }; + 076B1C4B1CBFBF59002C0BC2 /* text_entity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = text_entity.cpp; path = SourceFiles/ui/text/text_entity.cpp; sourceTree = SOURCE_ROOT; }; + 076B1C4C1CBFBF59002C0BC2 /* text_entity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = text_entity.h; path = SourceFiles/ui/text/text_entity.h; sourceTree = SOURCE_ROOT; }; + 076B1C501CBFC6F2002C0BC2 /* click_handler_types.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = click_handler_types.cpp; path = SourceFiles/core/click_handler_types.cpp; sourceTree = SOURCE_ROOT; }; + 076B1C511CBFC6F2002C0BC2 /* click_handler_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = click_handler_types.h; path = SourceFiles/core/click_handler_types.h; sourceTree = SOURCE_ROOT; }; + 076B1C521CBFC6F2002C0BC2 /* click_handler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = click_handler.cpp; path = SourceFiles/core/click_handler.cpp; sourceTree = SOURCE_ROOT; }; + 076B1C531CBFC6F2002C0BC2 /* click_handler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = click_handler.h; path = SourceFiles/core/click_handler.h; sourceTree = SOURCE_ROOT; }; + 076B1C571CBFC8D9002C0BC2 /* history_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = history_common.h; path = SourceFiles/history/history_common.h; sourceTree = SOURCE_ROOT; }; + 076B1C591CBFC8F1002C0BC2 /* top_bar_widget.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = top_bar_widget.cpp; path = SourceFiles/window/top_bar_widget.cpp; sourceTree = SOURCE_ROOT; }; + 076B1C5A1CBFC8F1002C0BC2 /* top_bar_widget.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = top_bar_widget.h; path = SourceFiles/window/top_bar_widget.h; sourceTree = SOURCE_ROOT; }; + 076B1C5D1CBFC98F002C0BC2 /* overview_layout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = overview_layout.cpp; path = SourceFiles/overview/overview_layout.cpp; sourceTree = SOURCE_ROOT; }; + 076B1C5E1CBFC98F002C0BC2 /* overview_layout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = overview_layout.h; path = SourceFiles/overview/overview_layout.h; sourceTree = SOURCE_ROOT; }; + 076B1C621CBFCC53002C0BC2 /* moc_top_bar_widget.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = moc_top_bar_widget.cpp; path = GeneratedFiles/Debug/moc_top_bar_widget.cpp; sourceTree = SOURCE_ROOT; }; 0771C4C94B623FC34BF62983 /* introwidget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = introwidget.cpp; path = SourceFiles/intro/introwidget.cpp; sourceTree = ""; }; 077A4AEC1CA41C38002188D2 /* connection_abstract.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = connection_abstract.cpp; path = SourceFiles/mtproto/connection_abstract.cpp; sourceTree = SOURCE_ROOT; }; 077A4AED1CA41C38002188D2 /* connection_abstract.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = connection_abstract.h; path = SourceFiles/mtproto/connection_abstract.h; sourceTree = SOURCE_ROOT; }; @@ -445,7 +464,6 @@ 08A7682548FB7E671FF03822 /* boxshadow.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = boxshadow.cpp; path = SourceFiles/ui/boxshadow.cpp; sourceTree = ""; }; 098EA7CE256AAFAE4A17EB77 /* introcode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = introcode.h; path = SourceFiles/intro/introcode.h; sourceTree = ""; }; 09FD01F2BD652EB838A296D8 /* application.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = application.h; path = SourceFiles/application.h; sourceTree = ""; }; - 0ABCEA8D0DD45589040B0AF2 /* /usr/local/Qt-5.5.1/mkspecs/common/unix.conf */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/common/unix.conf"; sourceTree = ""; }; 0BDE09020E45EFA57DCB2E25 /* photosendbox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = photosendbox.h; path = SourceFiles/boxes/photosendbox.h; sourceTree = ""; }; 0C0DC15EB416789673526AA5 /* moc_emojibox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_emojibox.cpp; path = GeneratedFiles/Debug/moc_emojibox.cpp; sourceTree = ""; }; 0CAA815FFFEDCD84808E11F5 /* logs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = logs.h; path = SourceFiles/logs.h; sourceTree = ""; }; @@ -454,14 +472,12 @@ 0FBED3C6654EA3753EB39831 /* session.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = session.cpp; path = SourceFiles/mtproto/session.cpp; sourceTree = ""; }; 0FC38EE7F29EF895925A2C49 /* style_core.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = style_core.h; path = SourceFiles/ui/style_core.h; sourceTree = ""; }; 1080B6D395843B8F76A2E45E /* moc_title.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_title.cpp; path = GeneratedFiles/Debug/moc_title.cpp; sourceTree = ""; }; - 111BBEE3D1432C3B517FD539 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qdds.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qdds.pri"; sourceTree = ""; }; 120EBCD9A37DB9A36BFE58C0 /* contactsbox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = contactsbox.h; path = SourceFiles/boxes/contactsbox.h; sourceTree = ""; }; 1292B92B4848460640F6A391 /* telegram.qrc */ = {isa = PBXFileReference; lastKnownFileType = text; name = telegram.qrc; path = Resources/telegram.qrc; sourceTree = ""; }; 135FD3715BFDC50AD7B00E04 /* text.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = text.cpp; path = SourceFiles/ui/text/text.cpp; sourceTree = ""; }; 143405635D04698F421A12EA /* aboutbox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = aboutbox.h; path = SourceFiles/boxes/aboutbox.h; sourceTree = ""; }; 14437BFDCD58FF1742EF1B35 /* photocropbox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = photocropbox.h; path = SourceFiles/boxes/photocropbox.h; sourceTree = ""; }; 152B8D1BCECEB7B0C77E073C /* introwidget.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = introwidget.h; path = SourceFiles/intro/introwidget.h; sourceTree = ""; }; - 16DD53E17C65AC8B450CC6C3 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_quick.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_quick.pri"; sourceTree = ""; }; 186D09F4CB713AD4B8BDD260 /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = /System/Library/Frameworks/AudioUnit.framework; sourceTree = ""; }; 19618554524B8D928F13940D /* emoji_config.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = emoji_config.h; path = SourceFiles/ui/emoji_config.h; sourceTree = ""; }; 1A4C47331E186344291B8178 /* dropdown.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = dropdown.h; path = SourceFiles/dropdown.h; sourceTree = ""; }; @@ -470,42 +486,27 @@ 1DC02F674A7192FF8BE391A7 /* basic_types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = basic_types.h; path = SourceFiles/core/basic_types.h; sourceTree = ""; }; 1DEFC0760BB9340529F582F7 /* confirmbox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = confirmbox.h; path = SourceFiles/boxes/confirmbox.h; sourceTree = ""; }; 1E5EEB5782B6357057356F9E /* moc_flatinput.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_flatinput.cpp; path = GeneratedFiles/Debug/moc_flatinput.cpp; sourceTree = ""; }; - 1FAE75C970AA73F2DEDDB508 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qavfcamera.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qavfcamera.pri"; sourceTree = ""; }; 1FE45A67215BEA2434F588E8 /* moc_layerwidget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_layerwidget.cpp; path = GeneratedFiles/Debug/moc_layerwidget.cpp; sourceTree = ""; }; 205259EEEE2BADA5E64741E3 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = /System/Library/Frameworks/Security.framework; sourceTree = ""; }; 206B4F5CBD5354BCE19FF32F /* countries.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = countries.h; path = SourceFiles/countries.h; sourceTree = ""; }; 2181F5E34DE0A4B2F811E2E2 /* moc_flatlabel.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_flatlabel.cpp; path = GeneratedFiles/Debug/moc_flatlabel.cpp; sourceTree = ""; }; 21F907AB8D19BD779147A085 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = /System/Library/Frameworks/AVFoundation.framework; sourceTree = ""; }; 220B97F8F62C720E6059A64B /* profilewidget.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = profilewidget.h; path = SourceFiles/profilewidget.h; sourceTree = ""; }; - 23BC8B0FC3279421D41CA268 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_gui.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_gui.pri"; sourceTree = ""; }; - 2440CD1D4CEF80443BCA1B8B /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qgenericbearer.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qgenericbearer.pri"; sourceTree = ""; }; - 247D8DF3B1DDB665B80BBA25 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtaccessiblequick.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtaccessiblequick.pri"; sourceTree = ""; }; - 24B6929EE3952310F2DAECB1 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtaudio_coreaudio.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtaudio_coreaudio.pri"; sourceTree = ""; }; 24F7D3E789E91B10E422C116 /* config.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = config.h; path = SourceFiles/config.h; sourceTree = ""; }; 25CA12A22B83B0B038C5B5DE /* langloaderplain.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = langloaderplain.h; path = SourceFiles/langloaderplain.h; sourceTree = ""; }; 26083D8E535AFF927591E1A5 /* moc_contactsbox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_contactsbox.cpp; path = GeneratedFiles/Debug/moc_contactsbox.cpp; sourceTree = ""; }; 26B83A58EE268598E703875D /* history.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = history.cpp; path = SourceFiles/history.cpp; sourceTree = ""; }; 27E7471A4EC90E84353AA16F /* core_types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = core_types.h; path = SourceFiles/mtproto/core_types.h; sourceTree = ""; }; - 28BD0D10214709D95B161E24 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_multimediawidgets.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_multimediawidgets.pri"; sourceTree = ""; }; - 293C8DEEE270847AC20E70F9 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_network.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_network.pri"; sourceTree = ""; }; 2BB2A1BB8DB0993F78F4E3C7 /* title.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = title.cpp; path = SourceFiles/title.cpp; sourceTree = ""; }; 2C540BAEABD7F9B5FA11008E /* moc_dcenter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_dcenter.cpp; path = GeneratedFiles/Debug/moc_dcenter.cpp; sourceTree = ""; }; 2C99425D7670941EAF07B453 /* moc_historywidget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_historywidget.cpp; path = GeneratedFiles/Debug/moc_historywidget.cpp; sourceTree = ""; }; - 2E48BB382B895A5ACD79AF9F /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_bluetooth_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_bluetooth_private.pri"; sourceTree = ""; }; - 2E6D9B1D2743D24E31B0B284 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_xmlpatterns.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_xmlpatterns.pri"; sourceTree = ""; }; 2EA58EF6CDF368B0132BAEB9 /* settings.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = settings.h; path = SourceFiles/settings.h; sourceTree = ""; }; 301BB513F2F5D447B3BF22DF /* mainwindow.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mainwindow.h; path = SourceFiles/mainwindow.h; sourceTree = ""; }; - 311004331A04F3D69C98643C /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_serialport_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_serialport_private.pri"; sourceTree = ""; }; 31120EDB269DFF13E1D49847 /* qicns */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = qicns; path = "/usr/local/Qt-5.5.1/plugins/imageformats/libqicns$(QT_LIBRARY_SUFFIX).a"; sourceTree = ""; }; 315C7FACB4A9E18AA95486CA /* dcenter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = dcenter.cpp; path = SourceFiles/mtproto/dcenter.cpp; sourceTree = ""; }; - 33F165B1DB8CBF182C56FAB5 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_macextras_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_macextras_private.pri"; sourceTree = ""; }; - 346287C9E754E7C458153F03 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qwbmp.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qwbmp.pri"; sourceTree = ""; }; 34E1DF19219C52D7DB20224A /* flatlabel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = flatlabel.h; path = SourceFiles/ui/flatlabel.h; sourceTree = ""; }; - 360D4B3ED25D126430DE27D4 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_enginio.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_enginio.pri"; sourceTree = ""; }; - 3685604BDB64DD6E92169B73 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qdeclarativeview.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qdeclarativeview.pri"; sourceTree = ""; }; 36BDA5D01BED543A92886669 /* Telegram.pro */ = {isa = PBXFileReference; lastKnownFileType = text; path = Telegram.pro; sourceTree = ""; }; 36F718DC72345A84987DB0F6 /* flatbutton.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = flatbutton.h; path = SourceFiles/ui/flatbutton.h; sourceTree = ""; }; - 382E89A91A34F7898C25FD0D /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_network_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_network_private.pri"; sourceTree = ""; }; 39C1ADF085370E033CB7E7E1 /* style_classes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = style_classes.h; path = GeneratedFiles/style_classes.h; sourceTree = ""; }; 3A220FD1AE5AD9FE3DC073A4 /* moc_mainwidget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_mainwidget.cpp; path = GeneratedFiles/Debug/moc_mainwidget.cpp; sourceTree = ""; }; 3B3ED09AB00290D78CF1181B /* moc_dialogswidget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_dialogswidget.cpp; path = GeneratedFiles/Debug/moc_dialogswidget.cpp; sourceTree = ""; }; @@ -514,29 +515,23 @@ 3C44131FDCFEF4396B9EA2BA /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = /System/Library/Frameworks/AudioToolbox.framework; sourceTree = ""; }; 3D54A9F3266BB8739520E3FB /* moc_fileuploader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_fileuploader.cpp; path = GeneratedFiles/Debug/moc_fileuploader.cpp; sourceTree = ""; }; 3E329D4547CC23585307FA32 /* countryinput.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = countryinput.cpp; path = SourceFiles/ui/countryinput.cpp; sourceTree = ""; }; - 3F08D430CEC8D2117735CCB4 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qmldbg_tcp_qtdeclarative.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qmldbg_tcp_qtdeclarative.pri"; sourceTree = ""; }; 420A06A32B66D250142B4B6D /* style_core.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = style_core.cpp; path = SourceFiles/ui/style_core.cpp; sourceTree = ""; }; - 45B95DB3B70B47A910FC847B /* /usr/local/Qt-5.5.1/mkspecs/common/gcc-base.conf */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/common/gcc-base.conf"; sourceTree = ""; }; - 45DB132B756499D4DF38430E /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qjp2.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qjp2.pri"; sourceTree = ""; }; 4604687EBA85611C9E8A9CDF /* button.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = button.h; path = SourceFiles/ui/button.h; sourceTree = ""; }; 46292F489228B60010794CE4 /* moc_button.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_button.cpp; path = GeneratedFiles/Debug/moc_button.cpp; sourceTree = ""; }; 4689C06178B60B84E7F3A3B7 /* Qt5Widgets */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = Qt5Widgets; path = "/usr/local/Qt-5.5.1/lib/libQt5Widgets$(QT_LIBRARY_SUFFIX).a"; sourceTree = ""; }; 48003469151B9DDE82E851FB /* moc_profilewidget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_profilewidget.cpp; path = GeneratedFiles/Debug/moc_profilewidget.cpp; sourceTree = ""; }; 4AF15B5A0A43EB62D6DAF211 /* libexif.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libexif.a; path = "../../Libraries/libexif-0.6.20/libexif/.libs/libexif.a"; sourceTree = ""; }; - 4C6C71914B1926119120DACD /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_enginio_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_enginio_private.pri"; sourceTree = ""; }; 4D1099F2D3696E8A0E17D37D /* session.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = session.h; path = SourceFiles/mtproto/session.h; sourceTree = ""; }; 4D504A849F15EB58E53A4E5F /* title.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = title.h; path = SourceFiles/title.h; sourceTree = ""; }; 4D55B83DFDFE3D492CDBD27A /* button.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = button.cpp; path = SourceFiles/ui/button.cpp; sourceTree = ""; }; 4D765E1B1EA6C757220C63E7 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = ""; }; 4E4D06EC4D2C82C7D6E079A2 /* flatinput.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = flatinput.h; path = SourceFiles/ui/flatinput.h; sourceTree = ""; }; - 4FB6657DA22BC68B819B64B3 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_qmldevtools_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_qmldevtools_private.pri"; sourceTree = ""; }; 5059175BDCEC77B7246DE1B9 /* flatcheckbox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = flatcheckbox.h; path = SourceFiles/ui/flatcheckbox.h; sourceTree = ""; }; 507CCEEC4CBA3E3BD6EEDED1 /* twidget.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = twidget.h; path = SourceFiles/ui/twidget.h; sourceTree = ""; }; 51355181C0E6689B0B764543 /* connectionbox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = connectionbox.cpp; path = SourceFiles/boxes/connectionbox.cpp; sourceTree = ""; }; 5271C394C1E7646D117CE67E /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = main.cpp; path = SourceFiles/main.cpp; sourceTree = ""; }; 547CCADBD1CC5050167EF948 /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = /System/Library/Frameworks/CoreMedia.framework; sourceTree = ""; }; 5591A965D1DC024FBDB40151 /* moc_file_download.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_file_download.cpp; path = GeneratedFiles/Debug/moc_file_download.cpp; sourceTree = ""; }; - 5597304BEC94BFB9EAAEBC4B /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_openglextensions_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_openglextensions_private.pri"; sourceTree = ""; }; 55A654A2EE8554FF062742B8 /* moc_twidget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_twidget.cpp; path = GeneratedFiles/Debug/moc_twidget.cpp; sourceTree = ""; }; 55B4A93DD455EED91C899A8E /* dialogswidget.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = dialogswidget.h; path = SourceFiles/dialogswidget.h; sourceTree = ""; }; 58A7114F60E7D09E73283983 /* moc_introsignup.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_introsignup.cpp; path = GeneratedFiles/Debug/moc_introsignup.cpp; sourceTree = ""; }; @@ -546,93 +541,58 @@ 5A7F88F9C7F08D3DDE6EEF6B /* localimageloader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = localimageloader.cpp; path = SourceFiles/localimageloader.cpp; sourceTree = ""; }; 5A80A1907B6CFFB524C1E57D /* Qt5Core */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = Qt5Core; path = "/usr/local/Qt-5.5.1/lib/libQt5Core$(QT_LIBRARY_SUFFIX).a"; sourceTree = ""; }; 5A9B4C6C59856143F3D0DE53 /* layerwidget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = layerwidget.cpp; path = SourceFiles/layerwidget.cpp; sourceTree = ""; }; - 5B22E9E4EE9AAE42ABC24AB3 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_qtmultimediaquicktools_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_qtmultimediaquicktools_private.pri"; sourceTree = ""; }; 5C7FD422BBEDA858D7237AE9 /* flattextarea.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = flattextarea.cpp; path = SourceFiles/ui/flattextarea.cpp; sourceTree = ""; }; - 5CEA7A2DB2136425A88D1254 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_opengl.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_opengl.pri"; sourceTree = ""; }; - 5F781C7FD8422D359EA1D2FE /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_core_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_core_private.pri"; sourceTree = ""; }; 6011DDB120E1B2D4803E129A /* stdafx.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = stdafx.h; path = SourceFiles/stdafx.h; sourceTree = ""; }; - 6102C69805B6398AF6FA5BEB /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_qml_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_qml_private.pri"; sourceTree = ""; }; 61C679D8B4B332026BD34200 /* introphone.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = introphone.cpp; path = SourceFiles/intro/introphone.cpp; sourceTree = ""; }; 62807F13DBD204D0716143AD /* Telegram.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Telegram.app; sourceTree = BUILT_PRODUCTS_DIR; }; 63AF8520023B4EA40306CB03 /* moc_session.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_session.cpp; path = GeneratedFiles/Debug/moc_session.cpp; sourceTree = ""; }; - 63E722139886C87BC82DBDF5 /* /usr/local/Qt-5.5.1/mkspecs/macx-clang/qmake.conf */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/macx-clang/qmake.conf"; sourceTree = ""; }; 6532A0DC7EFE446967682E83 /* moc_downloadpathbox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_downloadpathbox.cpp; path = GeneratedFiles/Debug/moc_downloadpathbox.cpp; sourceTree = ""; }; 6610564B876E47D289A596DB /* confirmbox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = confirmbox.cpp; path = SourceFiles/boxes/confirmbox.cpp; sourceTree = ""; }; - 669FB007C4A3D58424D85EC8 /* /usr/local/Qt-5.5.1/mkspecs/common/shell-unix.conf */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/common/shell-unix.conf"; sourceTree = ""; }; 6700DD555BF1C0FC338FB959 /* Qt5Network */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = Qt5Network; path = "/usr/local/Qt-5.5.1/lib/libQt5Network$(QT_LIBRARY_SUFFIX).a"; sourceTree = ""; }; 6868ADA9E9A9801B2BA92B97 /* countryinput.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = countryinput.h; path = SourceFiles/ui/countryinput.h; sourceTree = ""; }; - 69347C39E4D922E94D0860BF /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_designercomponents_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_designercomponents_private.pri"; sourceTree = ""; }; 6A510365F9F6367ECB0DB065 /* images.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = images.cpp; path = SourceFiles/ui/images.cpp; sourceTree = ""; }; 6B46A0EE3C3B9D3B5A24946E /* moc_mainwindow.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_mainwindow.cpp; path = GeneratedFiles/Debug/moc_mainwindow.cpp; sourceTree = ""; }; 6B90F69947805586A6FAE80E /* sysbuttons.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = sysbuttons.cpp; path = SourceFiles/sysbuttons.cpp; sourceTree = ""; }; - 6C08BFC27C4C303A3A5181DB /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_printsupport.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_printsupport.pri"; sourceTree = ""; }; 6C86B6E6AB1857B735B720D6 /* layerwidget.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = layerwidget.h; path = SourceFiles/layerwidget.h; sourceTree = ""; }; 6D50D70712776D7ED3B00E5C /* facade.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = facade.cpp; path = SourceFiles/mtproto/facade.cpp; sourceTree = ""; }; 6E1859D714E4471E053D90C9 /* scrollarea.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = scrollarea.cpp; path = SourceFiles/ui/scrollarea.cpp; sourceTree = ""; }; - 6E67D23B15FC4B628DB2E0B2 /* /usr/local/Qt-5.5.1/mkspecs/qdevice.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/qdevice.pri"; sourceTree = ""; }; 6E8FD0ED1B60D43929944CD2 /* text.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = text.h; path = SourceFiles/ui/text/text.h; sourceTree = ""; }; 710C982FC773400941B3AFBC /* dropdown.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = dropdown.cpp; path = SourceFiles/dropdown.cpp; sourceTree = ""; }; 723F90793B2C195E2CCB2233 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 73737DC91E390C4AB18FB595 /* pspecific_mac_p.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = pspecific_mac_p.mm; path = SourceFiles/pspecific_mac_p.mm; sourceTree = ""; }; 74772222DA764BE4623EAC5D /* moc_pspecific_mac.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_pspecific_mac.cpp; path = GeneratedFiles/Debug/moc_pspecific_mac.cpp; sourceTree = ""; }; 748F1BCCBEEB3675768960FB /* auth_key.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = auth_key.h; path = SourceFiles/mtproto/auth_key.h; sourceTree = ""; }; - 74C1C232DFAA71028A0412CA /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtmultimedia_m3u.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtmultimedia_m3u.pri"; sourceTree = ""; }; 763ED3C6815ED6C89E352652 /* flatlabel.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = flatlabel.cpp; path = SourceFiles/ui/flatlabel.cpp; sourceTree = ""; }; - 77FF486B1F9BCD55A8A3F35D /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_concurrent.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_concurrent.pri"; sourceTree = ""; }; - 7A94C7168B3FCBE5F04A013B /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_declarative.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_declarative.pri"; sourceTree = ""; }; - 7C2F42B222EE88E26A6FED62 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_designer_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_designer_private.pri"; sourceTree = ""; }; 7CA6945B22800A0F30B75DA5 /* addcontactbox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = addcontactbox.cpp; path = SourceFiles/boxes/addcontactbox.cpp; sourceTree = ""; }; 7CDE9D7CB2C729BC3612372B /* addcontactbox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = addcontactbox.h; path = SourceFiles/boxes/addcontactbox.h; sourceTree = ""; }; 7D075A915E8739C1B6BC5F43 /* basic_types.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = basic_types.cpp; path = SourceFiles/core/basic_types.cpp; sourceTree = ""; }; - 7D28E9003CE64D8A7F2E292E /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_concurrent_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_concurrent_private.pri"; sourceTree = ""; }; 7DBFC0B5EAF874BA10E3D603 /* scheme_auto.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = scheme_auto.h; path = SourceFiles/mtproto/scheme_auto.h; sourceTree = ""; }; - 7DE30A90667C03C4F91A2A91 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_sql.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_sql.pri"; sourceTree = ""; }; 7EC00404ACD5AB0E97726B0E /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = /System/Library/Frameworks/QuartzCore.framework; sourceTree = ""; }; - 7ECCC1F9442988B4F2707CC1 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_core.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_core.pri"; sourceTree = ""; }; 81780025807318AEA3B8A6FF /* moc_addcontactbox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_addcontactbox.cpp; path = GeneratedFiles/Debug/moc_addcontactbox.cpp; sourceTree = ""; }; - 817A0F5A41B553A6DE67FDEB /* /usr/local/Qt-5.5.1/mkspecs/common/macx.conf */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/common/macx.conf"; sourceTree = ""; }; - 82E7DCFD95559532D8FC6CDD /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_quickparticles_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_quickparticles_private.pri"; sourceTree = ""; }; 83728F60A64483E0AA933D76 /* pspecific.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = pspecific.h; path = SourceFiles/pspecific.h; sourceTree = ""; }; 83A36F229E897566E011B79E /* scrollarea.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = scrollarea.h; path = SourceFiles/ui/scrollarea.h; sourceTree = ""; }; 83D37373949868693FB7816D /* qmng */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = qmng; path = "/usr/local/Qt-5.5.1/plugins/imageformats/libqmng$(QT_LIBRARY_SUFFIX).a"; sourceTree = ""; }; - 85061B1DA49D125991117950 /* /usr/local/Qt-5.5.1/mkspecs/macx-xcode/qmake.conf */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/macx-xcode/qmake.conf"; sourceTree = ""; }; - 85B6936EDBE61D9BB8F8B33B /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_sensors.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_sensors.pri"; sourceTree = ""; }; 85FABD67716E36CD8B3CA4FA /* animation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = animation.h; path = SourceFiles/ui/animation.h; sourceTree = ""; }; - 87A4C1983FD641360BF80A02 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtaccessiblewidgets.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtaccessiblewidgets.pri"; sourceTree = ""; }; - 87EEF25EE25CF21572D1438C /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_websockets_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_websockets_private.pri"; sourceTree = ""; }; - 8849E60AEC7DB97A475C17EA /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_testlib_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_testlib_private.pri"; sourceTree = ""; }; 8880067F9BFD46108777E134 /* facade.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = facade.h; path = SourceFiles/mtproto/facade.h; sourceTree = ""; }; 8918F4B71ED5FC138AFD3F70 /* moc_scrollarea.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_scrollarea.cpp; path = GeneratedFiles/Debug/moc_scrollarea.cpp; sourceTree = ""; }; - 892D36BEF797BA4AF48D378A /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtsensors_dummy.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtsensors_dummy.pri"; sourceTree = ""; }; - 89863CCAF1D29037AE95755D /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_declarative_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_declarative_private.pri"; sourceTree = ""; }; 89F92B278CA31C393E245056 /* rpc_sender.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = rpc_sender.cpp; path = SourceFiles/mtproto/rpc_sender.cpp; sourceTree = ""; }; - 8A04A4A3625204D12A1207F6 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_nfc.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_nfc.pri"; sourceTree = ""; }; 8A28F7789408AA839F48A5F2 /* settings.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = settings.cpp; path = SourceFiles/settings.cpp; sourceTree = ""; }; 8A9D926C08392F7A9BC83B0C /* fileuploader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = fileuploader.h; path = SourceFiles/fileuploader.h; sourceTree = ""; }; - 8B4BB4E74F8A4442EF563D7D /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtsensorgestures_shakeplugin.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtsensorgestures_shakeplugin.pri"; sourceTree = ""; }; 8B98A212C068D6CC7CE73CAA /* moc_introcode.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_introcode.cpp; path = GeneratedFiles/Debug/moc_introcode.cpp; sourceTree = ""; }; - 8C31D89BDFCDF466DAED19A0 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_quick_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_quick_private.pri"; sourceTree = ""; }; - 8C5164D4E37556D40C5E6AA2 /* /usr/local/Qt-5.5.1/mkspecs/common/clang.conf */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/common/clang.conf"; sourceTree = ""; }; 8C800AAC9549E6E9E7046BED /* contactsbox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = contactsbox.cpp; path = SourceFiles/boxes/contactsbox.cpp; sourceTree = ""; }; 8CCCACE96535180FEB557712 /* settingswidget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = settingswidget.cpp; path = SourceFiles/settingswidget.cpp; sourceTree = ""; }; 8CF51323544B886B8F4A2232 /* qwbmp */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = qwbmp; path = "/usr/local/Qt-5.5.1/plugins/imageformats/libqwbmp$(QT_LIBRARY_SUFFIX).a"; sourceTree = ""; }; 8D9815BDB5BD9F90D2BC05C5 /* AGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AGL.framework; path = /System/Library/Frameworks/AGL.framework; sourceTree = ""; }; - 8DDE1D26B3206CDB8B57FABE /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_svg_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_svg_private.pri"; sourceTree = ""; }; 8DF456E9A416E4C3C2D6946C /* downloadpathbox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = downloadpathbox.cpp; path = SourceFiles/boxes/downloadpathbox.cpp; sourceTree = ""; }; - 8E9136256AFFBA6EF048AA55 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_widgets_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_widgets_private.pri"; sourceTree = ""; }; 8EB83A4D34226609E79A613A /* connectionbox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = connectionbox.h; path = SourceFiles/boxes/connectionbox.h; sourceTree = ""; }; 8F500B5166907B6D9A7C3E3D /* qico */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = qico; path = "/usr/local/Qt-5.5.1/plugins/imageformats/libqico$(QT_LIBRARY_SUFFIX).a"; sourceTree = ""; }; - 8F572030CE9AB8CC5F672201 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_platformsupport_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_platformsupport_private.pri"; sourceTree = ""; }; - 8F97C9CAE38CA3AFAC0B3953 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_websockets.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_websockets.pri"; sourceTree = ""; }; 924D4939FD169BB4B8AEB1C9 /* moc_facade.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_facade.cpp; path = GeneratedFiles/Debug/moc_facade.cpp; sourceTree = ""; }; 93AFE74928551FC3D7E8390B /* moc_settingswidget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_settingswidget.cpp; path = GeneratedFiles/Debug/moc_settingswidget.cpp; sourceTree = ""; }; - 946BEA667170DC1A7A8F9DB0 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qmng.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qmng.pri"; sourceTree = ""; }; 963123025C466CB8DD9CF4AF /* connection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = connection.h; path = SourceFiles/mtproto/connection.h; sourceTree = ""; }; 96ACDDE3DCB798B97F9EA2F4 /* file_download.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = file_download.h; path = SourceFiles/mtproto/file_download.h; sourceTree = ""; }; 9742F24EE18EA44D52824F1E /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = /System/Library/Frameworks/CoreServices.framework; sourceTree = ""; }; 974DB34EEB8F83B91614C0B0 /* logs.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = logs.cpp; path = SourceFiles/logs.cpp; sourceTree = ""; }; 99B8D38F7F5858601230911E /* style_auto.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = style_auto.cpp; path = GeneratedFiles/style_auto.cpp; sourceTree = ""; }; - 9A0BDF67E013BB4FFB8685B0 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qqt7engine.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qqt7engine.pri"; sourceTree = ""; }; 9A55B8F7C143D66AD9EAE304 /* qgenericbearer */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = qgenericbearer; path = "/usr/local/Qt-5.5.1/plugins/bearer/libqgenericbearer$(QT_LIBRARY_SUFFIX).a"; sourceTree = ""; }; 9A69B711DE4B9C89BA803750 /* moc_aboutbox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_aboutbox.cpp; path = GeneratedFiles/Debug/moc_aboutbox.cpp; sourceTree = ""; }; 9AB1479D7D63386FD2046620 /* flatinput.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = flatinput.cpp; path = SourceFiles/ui/flatinput.cpp; sourceTree = ""; }; @@ -643,131 +603,70 @@ 9E0704DE8650D7952DC6B7AE /* moc_photosendbox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_photosendbox.cpp; path = GeneratedFiles/Debug/moc_photosendbox.cpp; sourceTree = ""; }; 9EFD7CB36012BFC00CC79434 /* style_auto.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = style_auto.h; path = GeneratedFiles/style_auto.h; sourceTree = ""; }; A0090709DE1B155085362C36 /* introcode.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = introcode.cpp; path = SourceFiles/intro/introcode.cpp; sourceTree = ""; }; - A022AF919D1977534CA66BB8 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_widgets.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_widgets.pri"; sourceTree = ""; }; A1479F94376F9732B57C69DB /* moc_animation.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_animation.cpp; path = GeneratedFiles/Debug/moc_animation.cpp; sourceTree = ""; }; A1A67BEAA744704B29168D39 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = ""; }; A3622760CEC6D6827A25E710 /* rsa_public_key.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = rsa_public_key.h; path = SourceFiles/mtproto/rsa_public_key.h; sourceTree = ""; }; A37C7E516201B0264A4CDA38 /* moc_introwidget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_introwidget.cpp; path = GeneratedFiles/Debug/moc_introwidget.cpp; sourceTree = ""; }; - A4D8AC60897F435C1C3B9D02 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtsensors_generic.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtsensors_generic.pri"; sourceTree = ""; }; - A59F74CD76FDC2B4B9910E18 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_scripttools_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_scripttools_private.pri"; sourceTree = ""; }; - A5B17ABEFBA1C2F43443D644 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_macextras.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_macextras.pri"; sourceTree = ""; }; A7782E2B07CB2D1D14F431B0 /* qtaccessiblewidgets */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = qtaccessiblewidgets; path = "/usr/local/Qt-5.5.1/plugins/accessible/libqtaccessiblewidgets$(QT_LIBRARY_SUFFIX).a"; sourceTree = ""; }; A83D2C19F756D3371E5999A8 /* historywidget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = historywidget.cpp; path = SourceFiles/historywidget.cpp; sourceTree = ""; }; - A9E30FA27827990C5F182223 /* /usr/local/Qt-5.5.1/mkspecs/common/gcc-base-mac.conf */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/common/gcc-base-mac.conf"; sourceTree = ""; }; A9FF4818C6775109B3DBFA18 /* introsignup.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = introsignup.cpp; path = SourceFiles/intro/introsignup.cpp; sourceTree = ""; }; AA5379CB06E908AC80BE7B82 /* Qt5OpenGL */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = Qt5OpenGL; path = "/usr/local/Qt-5.5.1/lib/libQt5OpenGL$(QT_LIBRARY_SUFFIX).a"; sourceTree = ""; }; - AA73DC3C2901E2979FE8AD5B /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_xml.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_xml.pri"; sourceTree = ""; }; - AB1C02DDBD8E88DD9A9AFDDD /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtsensorgestures_plugin.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtsensorgestures_plugin.pri"; sourceTree = ""; }; - AB745978DF0F41D1801ABDA6 /* .qmake.stash */ = {isa = PBXFileReference; lastKnownFileType = file; path = .qmake.stash; sourceTree = ""; }; - ABA9AB4619F09DCFD2D4A27F /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_qmltest_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_qmltest_private.pri"; sourceTree = ""; }; AC9B5F6FB4B984C8D76F7AE2 /* moc_dropdown.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_dropdown.cpp; path = GeneratedFiles/Debug/moc_dropdown.cpp; sourceTree = ""; }; - ACC8A73268E5D9AF64E97AF4 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_bluetooth.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_bluetooth.pri"; sourceTree = ""; }; AD0C395D671BC024083A5FC7 /* localimageloader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = localimageloader.h; path = SourceFiles/localimageloader.h; sourceTree = ""; }; AD90723EF02EAD016FD49CC9 /* introstart.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = introstart.h; path = SourceFiles/intro/introstart.h; sourceTree = ""; }; ADC6308023253CEA51F86E21 /* qwebp */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = qwebp; path = "/usr/local/Qt-5.5.1/plugins/imageformats/libqwebp$(QT_LIBRARY_SUFFIX).a"; sourceTree = ""; }; - ADFC79902C14A612AE93A89A /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_svg.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_svg.pri"; sourceTree = ""; }; AEA456A2F75ED9F5CDA7BCBE /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; AF4585F593B1C9D0D4FD061C /* flatcheckbox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = flatcheckbox.cpp; path = SourceFiles/ui/flatcheckbox.cpp; sourceTree = ""; }; AF5776B0652744978B7DF6D3 /* langloaderplain.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = langloaderplain.cpp; path = SourceFiles/langloaderplain.cpp; sourceTree = ""; }; AF61D864B8C444ADD4E1B391 /* moc_photocropbox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_photocropbox.cpp; path = GeneratedFiles/Debug/moc_photocropbox.cpp; sourceTree = ""; }; - AFD721AA33A2F785E77B1698 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qcocoa.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qcocoa.pri"; sourceTree = ""; }; - B064BF3B496A7BF7A449CA1E /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qsqlite.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qsqlite.pri"; sourceTree = ""; }; - B2246267D4C0D789259A86B0 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_quickwidgets_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_quickwidgets_private.pri"; sourceTree = ""; }; - B26239063A068F800A2C95F4 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qwebp.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qwebp.pri"; sourceTree = ""; }; B3062303CE8F4EB9325CB3DC /* emoji_config.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = emoji_config.cpp; path = SourceFiles/ui/emoji_config.cpp; sourceTree = ""; }; - B382B645B34234E451AE5D94 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_qml.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_qml.pri"; sourceTree = ""; }; B3D42654F18B1FE49512C404 /* dcenter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = dcenter.h; path = SourceFiles/mtproto/dcenter.h; sourceTree = ""; }; - B518DA4EE7376002AFC71FD5 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_uitools_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_uitools_private.pri"; sourceTree = ""; }; - B51B01657BFE9EAEF5590561 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_nfc_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_nfc_private.pri"; sourceTree = ""; }; - B678DA730B4ECE863AD631AE /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qminimal.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qminimal.pri"; sourceTree = ""; }; B714EA71A09A832FAA846A0A /* moc_connection.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_connection.cpp; path = GeneratedFiles/Debug/moc_connection.cpp; sourceTree = ""; }; - B8525798C5AA7D7C6D68E1B3 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qmldbg_qtquick2.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qmldbg_qtquick2.pri"; sourceTree = ""; }; B88236FC554B694F618D848C /* moc_sysbuttons.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_sysbuttons.cpp; path = GeneratedFiles/Debug/moc_sysbuttons.cpp; sourceTree = ""; }; - B8C1F6C965A7A14FBA8D4518 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtmedia_audioengine.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtmedia_audioengine.pri"; sourceTree = ""; }; B8D9AFA42E8633154A9817A2 /* connection.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = connection.cpp; path = SourceFiles/mtproto/connection.cpp; sourceTree = ""; }; B97D4DB97FE881648644211A /* downloadpathbox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = downloadpathbox.h; path = SourceFiles/boxes/downloadpathbox.h; sourceTree = ""; }; BB1602EA641643DE565005B1 /* twidget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = twidget.cpp; path = SourceFiles/ui/twidget.cpp; sourceTree = ""; }; - BD22EFEFCC02644B1883CE19 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtiff.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtiff.pri"; sourceTree = ""; }; - BD4D97801B547471B37A4CDC /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_bootstrap_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_bootstrap_private.pri"; sourceTree = ""; }; BDAB6725B830DEE896DC0F55 /* boxshadow.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = boxshadow.h; path = SourceFiles/ui/boxshadow.h; sourceTree = ""; }; - BDC9ECADEE40D11E3C2EA93F /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_sensors_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_sensors_private.pri"; sourceTree = ""; }; BEF9DFDA6822604126A7E233 /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = /System/Library/Frameworks/CoreAudio.framework; sourceTree = ""; }; - BFF0C38FB0EC140C5F0304AE /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_serialport.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_serialport.pri"; sourceTree = ""; }; C194EDD00F76216057D48A5C /* aboutbox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = aboutbox.cpp; path = SourceFiles/boxes/aboutbox.cpp; sourceTree = ""; }; C19DF71B273A4843553518F2 /* app.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = app.h; path = SourceFiles/app.h; sourceTree = ""; }; C20F9DD8C7B031B8E20D5653 /* application.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = application.cpp; path = SourceFiles/application.cpp; sourceTree = ""; }; C34459FA465B57DF4DB80D12 /* introstart.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = introstart.cpp; path = SourceFiles/intro/introstart.cpp; sourceTree = ""; }; - C4295BE59CCEBCDD16268349 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qico.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qico.pri"; sourceTree = ""; }; - C505A18319B9B63C63877858 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_script_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_script_private.pri"; sourceTree = ""; }; C63C6D083EBEB13A60256DF3 /* historywidget.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = historywidget.h; path = SourceFiles/historywidget.h; sourceTree = ""; }; - C84546C18DCBB04166195DCF /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtposition_positionpoll.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtposition_positionpoll.pri"; sourceTree = ""; }; C913E6A1001E07EE7C13CE93 /* style.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = style.h; path = SourceFiles/ui/style.h; sourceTree = ""; }; C9FFCCE4FCB845744636795F /* moc_flatbutton.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_flatbutton.cpp; path = GeneratedFiles/Debug/moc_flatbutton.cpp; sourceTree = ""; }; CA56ACFB53D87637192CC9B2 /* mainwindow.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = mainwindow.cpp; path = SourceFiles/mainwindow.cpp; sourceTree = ""; }; - CCF75CFFB857487FB18F99F9 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qoffscreen.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qoffscreen.pri"; sourceTree = ""; }; CE0D5EFE401BF9815FACE579 /* pspecific_mac.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = pspecific_mac.h; path = SourceFiles/pspecific_mac.h; sourceTree = ""; }; CE7FFE194127BD789A2C877A /* moc_confirmbox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_confirmbox.cpp; path = GeneratedFiles/Debug/moc_confirmbox.cpp; sourceTree = ""; }; - CE829DD126DD2B97E8D70A7A /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_scripttools.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_scripttools.pri"; sourceTree = ""; }; CF1690B68F3B278E78823DB9 /* history.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = history.h; path = SourceFiles/history.h; sourceTree = ""; }; CF32DF59C7823E4F3397EF3C /* profilewidget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = profilewidget.cpp; path = SourceFiles/profilewidget.cpp; sourceTree = ""; }; - CF86CD5BB01B9011E6B6FD3E /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_clucene_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_clucene_private.pri"; sourceTree = ""; }; - CFCB992BEC24B71BFB8A2F30 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_script.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_script.pri"; sourceTree = ""; }; - CFFBE05DB004895080314289 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qsvgicon.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qsvgicon.pri"; sourceTree = ""; }; - D0CDC87DAFDA7F18A7AF450F /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_printsupport_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_printsupport_private.pri"; sourceTree = ""; }; D12A6BD8EE80B8B308E481AD /* moc_flattextarea.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_flattextarea.cpp; path = GeneratedFiles/Debug/moc_flattextarea.cpp; sourceTree = ""; }; D1C9C77F1318F5A55C9BF289 /* photosendbox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = photosendbox.cpp; path = SourceFiles/boxes/photosendbox.cpp; sourceTree = ""; }; - D1FA7CAB5ACC09D563AE569F /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_multimediawidgets_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_multimediawidgets_private.pri"; sourceTree = ""; }; - D2FE4D909926A0D1656068C4 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_multimedia.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_multimedia.pri"; sourceTree = ""; }; D3D1BE0BEA3AEE0551AD39AC /* qdds */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = qdds; path = "/usr/local/Qt-5.5.1/plugins/imageformats/libqdds$(QT_LIBRARY_SUFFIX).a"; sourceTree = ""; }; D3FE9C29B6A61D7C3C4B731B /* animation.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = animation.cpp; path = SourceFiles/ui/animation.cpp; sourceTree = ""; }; D4B32C2222F82AC56BADEB21 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = ""; }; - D4DE537C1FBBD48BD989FAD1 /* /usr/local/Qt-5.5.1/mkspecs/qconfig.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/qconfig.pri"; sourceTree = ""; }; - D5141F795670589C8CC41CBC /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_cocoaprintersupport.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_cocoaprintersupport.pri"; sourceTree = ""; }; D53D8E6A188E05078A114294 /* qcocoa */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = qcocoa; path = "/usr/local/Qt-5.5.1/plugins/platforms/libqcocoa$(QT_LIBRARY_SUFFIX).a"; sourceTree = ""; }; D6193B79CECC9DD0142D1200 /* qtharfbuzzng */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = qtharfbuzzng; path = "/usr/local/Qt-5.5.1/lib/libqtharfbuzzng$(QT_LIBRARY_SUFFIX).a"; sourceTree = ""; }; D6FF6676816C4E374D374060 /* qrc_telegram.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = qrc_telegram.cpp; path = GeneratedFiles/qrc_telegram.cpp; sourceTree = ""; }; - D7A0618DE39A427EBF41940E /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_help_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_help_private.pri"; sourceTree = ""; }; - D81E3D9A18202BE8EC3D0E2C /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_gui_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_gui_private.pri"; sourceTree = ""; }; - D948D4D8F949D45158F8DE35 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_quickwidgets.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_quickwidgets.pri"; sourceTree = ""; }; - DB0A26DDC377B2004F61BFE3 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_testlib.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_testlib.pri"; sourceTree = ""; }; DBF506D10449BFABD45B82DA /* Qt5PrintSupport */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = Qt5PrintSupport; path = "/usr/local/Qt-5.5.1/lib/libQt5PrintSupport$(QT_LIBRARY_SUFFIX).a"; sourceTree = ""; }; DC23E0B79FF53F35BA8F76A1 /* introsignup.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = introsignup.h; path = SourceFiles/intro/introsignup.h; sourceTree = ""; }; DCEFD9167C239650120B0145 /* qtga */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = qtga; path = "/usr/local/Qt-5.5.1/plugins/imageformats/libqtga$(QT_LIBRARY_SUFFIX).a"; sourceTree = ""; }; DE4C0E3685DDAE58F9397B13 /* filedialog.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = filedialog.cpp; path = SourceFiles/ui/filedialog.cpp; sourceTree = ""; }; - DF8188E30892A4654B984221 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_qmltest.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_qmltest.pri"; sourceTree = ""; }; DFD7912080BC557230093752 /* ApplicationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ApplicationServices.framework; path = /System/Library/Frameworks/ApplicationServices.framework; sourceTree = ""; }; - E0F4563EA350EB65112A0EF4 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_opengl_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_opengl_private.pri"; sourceTree = ""; }; E181C525E21A16F2D4396CA7 /* moc_application.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_application.cpp; path = GeneratedFiles/Debug/moc_application.cpp; sourceTree = ""; }; - E37365B4489B4918BEBB707D /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_xml_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_xml_private.pri"; sourceTree = ""; }; - E432DA897A5F027987342E8F /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_openglextensions.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_openglextensions.pri"; sourceTree = ""; }; E466873F01ABA1E55E914489 /* dialogswidget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = dialogswidget.cpp; path = SourceFiles/dialogswidget.cpp; sourceTree = ""; }; - E50FA73B8A23BC179A642B27 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_uitools.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_uitools.pri"; sourceTree = ""; }; - E66B9EC81C285CA9A7FB6A2E /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_positioning_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_positioning_private.pri"; sourceTree = ""; }; E7B2F248E3F7970788F35BF5 /* Qt5PlatformSupport */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = Qt5PlatformSupport; path = "/usr/local/Qt-5.5.1/lib/libQt5PlatformSupport$(QT_LIBRARY_SUFFIX).a"; sourceTree = ""; }; - E7D67CB158408BB7DEA74764 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_multimedia_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_multimedia_private.pri"; sourceTree = ""; }; E908A6C86F93FA27DF70866C /* photocropbox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = photocropbox.cpp; path = SourceFiles/boxes/photocropbox.cpp; sourceTree = ""; }; - EA5D4FF9DE4AC4215D7DCE0D /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qcorewlanbearer.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qcorewlanbearer.pri"; sourceTree = ""; }; - EB1F99FD112917157F3C3F6E /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qicns.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qicns.pri"; sourceTree = ""; }; - EB29AC635054C09EFA749AE1 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qmldbg_tcp.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qmldbg_tcp.pri"; sourceTree = ""; }; - EBD39B69F368CEEAC360A16D /* /usr/local/Qt-5.5.1/mkspecs/common/mac.conf */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/common/mac.conf"; sourceTree = ""; }; EE03BC5CA4628A6D6BEB0122 /* qcorewlanbearer */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = qcorewlanbearer; path = "/usr/local/Qt-5.5.1/plugins/bearer/libqcorewlanbearer$(QT_LIBRARY_SUFFIX).a"; sourceTree = ""; }; EF1AD6A66D0C28A6A15E2C30 /* introphone.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = introphone.h; path = SourceFiles/intro/introphone.h; sourceTree = ""; }; F0681BC551FC8A2B132FC646 /* qjp2 */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = qjp2; path = "/usr/local/Qt-5.5.1/plugins/imageformats/libqjp2$(QT_LIBRARY_SUFFIX).a"; sourceTree = ""; }; - F0A58515945747E36783CC21 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qmldbg_inspector.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qmldbg_inspector.pri"; sourceTree = ""; }; F1A04BDB750C2AE652797B04 /* flatbutton.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = flatbutton.cpp; path = SourceFiles/ui/flatbutton.cpp; sourceTree = ""; }; F2453BA07315EB9F34F1CD57 /* qtiff */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = qtiff; path = "/usr/local/Qt-5.5.1/plugins/imageformats/libqtiff$(QT_LIBRARY_SUFFIX).a"; sourceTree = ""; }; F26998DF735BCE5F975508ED /* CoreWLAN.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreWLAN.framework; path = /System/Library/Frameworks/CoreWLAN.framework; sourceTree = ""; }; - F2F823087EA182CCBD5748B8 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_designer.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_designer.pri"; sourceTree = ""; }; - F33BE16353DD1557A9AB3558 /* /usr/local/Qt-5.5.1/mkspecs/common/clang-mac.conf */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/common/clang-mac.conf"; sourceTree = ""; }; - F4EB01857048DCFCFFAAC4D0 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qavfmediaplayer.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qavfmediaplayer.pri"; sourceTree = ""; }; F4EECA1187A744AEF5165243 /* pspecific_mac.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = pspecific_mac.cpp; path = SourceFiles/pspecific_mac.cpp; sourceTree = ""; }; - F7ADBF552F6B9A5982915164 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_positioning.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_positioning.pri"; sourceTree = ""; }; F80095A026AF9453E9C2B8BD /* settingswidget.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = settingswidget.h; path = SourceFiles/settingswidget.h; sourceTree = ""; }; - F83F87F8A60C9DF666911D42 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qsvg.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qsvg.pri"; sourceTree = ""; }; - F9BEAA743A908603687DA204 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_xmlpatterns_private.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_xmlpatterns_private.pri"; sourceTree = ""; }; FB61F72601D91BF3AC730D20 /* rpc_sender.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = rpc_sender.h; path = SourceFiles/mtproto/rpc_sender.h; sourceTree = ""; }; FCC237CA5AD60B9BA4447615 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; - FD944B80F033DFE737D401A2 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_help.pri */ = {isa = PBXFileReference; lastKnownFileType = text; path = "/usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_help.pri"; sourceTree = ""; }; FE8FD20832B4C226E345CFBA /* mainwidget.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mainwidget.h; path = SourceFiles/mainwidget.h; sourceTree = ""; }; FEC58F9D8A0963E5A9D4BE6F /* moc_connectionbox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = moc_connectionbox.cpp; path = GeneratedFiles/Debug/moc_connectionbox.cpp; sourceTree = ""; }; FF5BDAB0076F3391B219EA52 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = /System/Library/Frameworks/SystemConfiguration.framework; sourceTree = ""; }; @@ -877,6 +776,74 @@ name = langs; sourceTree = ""; }; + 076B1C471CBFBEB4002C0BC2 /* text */ = { + isa = PBXGroup; + children = ( + 076B1C491CBFBF59002C0BC2 /* text_block.cpp */, + 076B1C4A1CBFBF59002C0BC2 /* text_block.h */, + 076B1C4B1CBFBF59002C0BC2 /* text_entity.cpp */, + 076B1C4C1CBFBF59002C0BC2 /* text_entity.h */, + 135FD3715BFDC50AD7B00E04 /* text.cpp */, + 6E8FD0ED1B60D43929944CD2 /* text.h */, + ); + name = text; + sourceTree = ""; + }; + 076B1C4F1CBFC6DC002C0BC2 /* core */ = { + isa = PBXGroup; + children = ( + 7D075A915E8739C1B6BC5F43 /* basic_types.cpp */, + 1DC02F674A7192FF8BE391A7 /* basic_types.h */, + 076B1C501CBFC6F2002C0BC2 /* click_handler_types.cpp */, + 076B1C511CBFC6F2002C0BC2 /* click_handler_types.h */, + 076B1C521CBFC6F2002C0BC2 /* click_handler.cpp */, + 076B1C531CBFC6F2002C0BC2 /* click_handler.h */, + ); + name = core; + sourceTree = ""; + }; + 076B1C561CBFC8C9002C0BC2 /* history */ = { + isa = PBXGroup; + children = ( + 076B1C571CBFC8D9002C0BC2 /* history_common.h */, + ); + name = history; + sourceTree = ""; + }; + 076B1C581CBFC8DF002C0BC2 /* window */ = { + isa = PBXGroup; + children = ( + 076B1C591CBFC8F1002C0BC2 /* top_bar_widget.cpp */, + 076B1C5A1CBFC8F1002C0BC2 /* top_bar_widget.h */, + ); + name = window; + sourceTree = ""; + }; + 076B1C5C1CBFC97D002C0BC2 /* overview */ = { + isa = PBXGroup; + children = ( + 076B1C5D1CBFC98F002C0BC2 /* overview_layout.cpp */, + 076B1C5E1CBFC98F002C0BC2 /* overview_layout.h */, + ); + name = overview; + sourceTree = ""; + }; + 076B1C611CBFCC0F002C0BC2 /* Resources */ = { + isa = PBXGroup; + children = ( + 074968CB1A44D0B800394F46 /* langs */, + 07D7EABC1A597DD000838BA2 /* Localizable.strings */, + 07C3AF24194335ED0016CFF1 /* Images.xcassets */, + 07080BCB1A4357F300741A51 /* lang.strings */, + 07C3AF2919433ABF0016CFF1 /* style_classes.txt */, + 07C3AF2A19433ABF0016CFF1 /* style.txt */, + 07AF95F71AFD03C80060B057 /* telegram_emojis.qrc */, + 07AF95F81AFD03C80060B057 /* telegram_mac.qrc */, + 1292B92B4848460640F6A391 /* telegram.qrc */, + ); + name = Resources; + sourceTree = ""; + }; 07B816FF1CB9A219006F7869 /* dialogs */ = { isa = PBXGroup; children = ( @@ -929,19 +896,6 @@ name = buttons; sourceTree = ""; }; - 130BDDB6FC4D60CF394D95AF /* GeneratedFiles */ = { - isa = PBXGroup; - children = ( - 07DC429F1B5EA15300B6B888 /* numbers.cpp */, - 07080BCD1A43588C00741A51 /* lang_auto.cpp */, - 07080BCE1A43588C00741A51 /* lang_auto.h */, - 99B8D38F7F5858601230911E /* style_auto.cpp */, - 9EFD7CB36012BFC00CC79434 /* style_auto.h */, - 39C1ADF085370E033CB7E7E1 /* style_classes.h */, - ); - name = GeneratedFiles; - sourceTree = ""; - }; 1A6AA22F4A758C4B5F5138FB /* mtproto */ = { isa = PBXGroup; children = ( @@ -979,33 +933,27 @@ name = mtproto; sourceTree = ""; }; - 25B08E2869634E9BCBA333A2 /* Generated Sources */ = { + 25B08E2869634E9BCBA333A2 /* GeneratedFiles */ = { isa = PBXGroup; children = ( - D0B536A85E53302E4F66CE23 /* GeneratedFiles */, + 801973D3334D0FCA849CF485 /* Debug */, + 07DC429F1B5EA15300B6B888 /* numbers.cpp */, + 07080BCD1A43588C00741A51 /* lang_auto.cpp */, + 07080BCE1A43588C00741A51 /* lang_auto.h */, + 07AF95F21AFD03B90060B057 /* qrc_telegram_emojis.cpp */, + 07AF95F31AFD03B90060B057 /* qrc_telegram_mac.cpp */, + D6FF6676816C4E374D374060 /* qrc_telegram.cpp */, + 99B8D38F7F5858601230911E /* style_auto.cpp */, + 9EFD7CB36012BFC00CC79434 /* style_auto.h */, + 39C1ADF085370E033CB7E7E1 /* style_classes.h */, ); - name = "Generated Sources"; - sourceTree = ""; - }; - 2EB56BE3C2D93CDAB0C52E67 /* Sources */ = { - isa = PBXGroup; - children = ( - 73F2E45FDEB381A085D37A49 /* SourceFiles */, - 130BDDB6FC4D60CF394D95AF /* GeneratedFiles */, - ); - name = Sources; - sourceTree = ""; - }; - 370997172D3BAEED157B8E70 /* SourceFiles */ = { - isa = PBXGroup; - children = ( - ); - name = SourceFiles; + name = GeneratedFiles; sourceTree = ""; }; 579DA7AEF5751DF4988869A0 /* ui */ = { isa = PBXGroup; children = ( + 076B1C471CBFBEB4002C0BC2 /* text */, 07E373901CBBBFDE00934F77 /* buttons */, 07C8FE071CB80884007A8702 /* toast */, D3FE9C29B6A61D7C3C4B731B /* animation.cpp */, @@ -1038,8 +986,6 @@ 83A36F229E897566E011B79E /* scrollarea.h */, 420A06A32B66D250142B4B6D /* style_core.cpp */, 0FC38EE7F29EF895925A2C49 /* style_core.h */, - 135FD3715BFDC50AD7B00E04 /* text.cpp */, - 6E8FD0ED1B60D43929944CD2 /* text.h */, BB1602EA641643DE565005B1 /* twidget.cpp */, 507CCEEC4CBA3E3BD6EEDED1 /* twidget.h */, ); @@ -1069,13 +1015,16 @@ isa = PBXGroup; children = ( ADC8DBF4C6F26E14C77F68B4 /* boxes */, + 076B1C4F1CBFC6DC002C0BC2 /* core */, 07B816FF1CB9A219006F7869 /* dialogs */, + 076B1C561CBFC8C9002C0BC2 /* history */, 07C8FDF81CB66D80007A8702 /* inline_bots */, 5E35A03E5F2C51353EBCBF00 /* intro */, - 074968CB1A44D0B800394F46 /* langs */, 1A6AA22F4A758C4B5F5138FB /* mtproto */, + 076B1C5C1CBFC97D002C0BC2 /* overview */, 0702E99F1CB8D290007A7495 /* serialize */, 579DA7AEF5751DF4988869A0 /* ui */, + 076B1C581CBFC8DF002C0BC2 /* window */, 0764D5581ABAD6F900FBFEED /* apiwrap.cpp */, 0764D5591ABAD6F900FBFEED /* apiwrap.h */, 06E379415713F34B83F99C35 /* app.cpp */, @@ -1086,8 +1035,6 @@ 07D7034A19B8755A00C4EED2 /* audio.h */, 07C7596D1B1F7E0000662169 /* autoupdater.cpp */, 07C7596E1B1F7E0000662169 /* autoupdater.h */, - 7D075A915E8739C1B6BC5F43 /* basic_types.cpp */, - 1DC02F674A7192FF8BE391A7 /* basic_types.h */, 206B4F5CBD5354BCE19FF32F /* countries.h */, E466873F01ABA1E55E914489 /* dialogswidget.cpp */, 55B4A93DD455EED91C899A8E /* dialogswidget.h */, @@ -1156,140 +1103,18 @@ name = SourceFiles; sourceTree = ""; }; - 74B182DB50CB5611B5C1C297 /* Supporting Files */ = { + 74B182DB50CB5611B5C1C297 /* Version */ = { isa = PBXGroup; children = ( 36BDA5D01BED543A92886669 /* Telegram.pro */, - 6E67D23B15FC4B628DB2E0B2 /* /usr/local/Qt-5.5.1/mkspecs/qdevice.pri */, - 669FB007C4A3D58424D85EC8 /* /usr/local/Qt-5.5.1/mkspecs/common/shell-unix.conf */, - 0ABCEA8D0DD45589040B0AF2 /* /usr/local/Qt-5.5.1/mkspecs/common/unix.conf */, - EBD39B69F368CEEAC360A16D /* /usr/local/Qt-5.5.1/mkspecs/common/mac.conf */, - 817A0F5A41B553A6DE67FDEB /* /usr/local/Qt-5.5.1/mkspecs/common/macx.conf */, - 45B95DB3B70B47A910FC847B /* /usr/local/Qt-5.5.1/mkspecs/common/gcc-base.conf */, - A9E30FA27827990C5F182223 /* /usr/local/Qt-5.5.1/mkspecs/common/gcc-base-mac.conf */, - 8C5164D4E37556D40C5E6AA2 /* /usr/local/Qt-5.5.1/mkspecs/common/clang.conf */, - F33BE16353DD1557A9AB3558 /* /usr/local/Qt-5.5.1/mkspecs/common/clang-mac.conf */, - D4DE537C1FBBD48BD989FAD1 /* /usr/local/Qt-5.5.1/mkspecs/qconfig.pri */, - ACC8A73268E5D9AF64E97AF4 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_bluetooth.pri */, - 2E48BB382B895A5ACD79AF9F /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_bluetooth_private.pri */, - BD4D97801B547471B37A4CDC /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_bootstrap_private.pri */, - CF86CD5BB01B9011E6B6FD3E /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_clucene_private.pri */, - 77FF486B1F9BCD55A8A3F35D /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_concurrent.pri */, - 7D28E9003CE64D8A7F2E292E /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_concurrent_private.pri */, - 7ECCC1F9442988B4F2707CC1 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_core.pri */, - 5F781C7FD8422D359EA1D2FE /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_core_private.pri */, - 7A94C7168B3FCBE5F04A013B /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_declarative.pri */, - 89863CCAF1D29037AE95755D /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_declarative_private.pri */, - F2F823087EA182CCBD5748B8 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_designer.pri */, - 7C2F42B222EE88E26A6FED62 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_designer_private.pri */, - 69347C39E4D922E94D0860BF /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_designercomponents_private.pri */, - 360D4B3ED25D126430DE27D4 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_enginio.pri */, - 4C6C71914B1926119120DACD /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_enginio_private.pri */, - 23BC8B0FC3279421D41CA268 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_gui.pri */, - D81E3D9A18202BE8EC3D0E2C /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_gui_private.pri */, - FD944B80F033DFE737D401A2 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_help.pri */, - D7A0618DE39A427EBF41940E /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_help_private.pri */, - A5B17ABEFBA1C2F43443D644 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_macextras.pri */, - 33F165B1DB8CBF182C56FAB5 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_macextras_private.pri */, - D2FE4D909926A0D1656068C4 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_multimedia.pri */, - E7D67CB158408BB7DEA74764 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_multimedia_private.pri */, - 28BD0D10214709D95B161E24 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_multimediawidgets.pri */, - D1FA7CAB5ACC09D563AE569F /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_multimediawidgets_private.pri */, - 293C8DEEE270847AC20E70F9 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_network.pri */, - 382E89A91A34F7898C25FD0D /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_network_private.pri */, - 8A04A4A3625204D12A1207F6 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_nfc.pri */, - B51B01657BFE9EAEF5590561 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_nfc_private.pri */, - 5CEA7A2DB2136425A88D1254 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_opengl.pri */, - E0F4563EA350EB65112A0EF4 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_opengl_private.pri */, - E432DA897A5F027987342E8F /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_openglextensions.pri */, - 5597304BEC94BFB9EAAEBC4B /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_openglextensions_private.pri */, - 8F572030CE9AB8CC5F672201 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_platformsupport_private.pri */, - F7ADBF552F6B9A5982915164 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_positioning.pri */, - E66B9EC81C285CA9A7FB6A2E /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_positioning_private.pri */, - 6C08BFC27C4C303A3A5181DB /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_printsupport.pri */, - D0CDC87DAFDA7F18A7AF450F /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_printsupport_private.pri */, - B382B645B34234E451AE5D94 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_qml.pri */, - 6102C69805B6398AF6FA5BEB /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_qml_private.pri */, - 4FB6657DA22BC68B819B64B3 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_qmldevtools_private.pri */, - DF8188E30892A4654B984221 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_qmltest.pri */, - ABA9AB4619F09DCFD2D4A27F /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_qmltest_private.pri */, - 5B22E9E4EE9AAE42ABC24AB3 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_qtmultimediaquicktools_private.pri */, - 16DD53E17C65AC8B450CC6C3 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_quick.pri */, - 8C31D89BDFCDF466DAED19A0 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_quick_private.pri */, - 82E7DCFD95559532D8FC6CDD /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_quickparticles_private.pri */, - D948D4D8F949D45158F8DE35 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_quickwidgets.pri */, - B2246267D4C0D789259A86B0 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_quickwidgets_private.pri */, - CFCB992BEC24B71BFB8A2F30 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_script.pri */, - C505A18319B9B63C63877858 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_script_private.pri */, - CE829DD126DD2B97E8D70A7A /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_scripttools.pri */, - A59F74CD76FDC2B4B9910E18 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_scripttools_private.pri */, - 85B6936EDBE61D9BB8F8B33B /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_sensors.pri */, - BDC9ECADEE40D11E3C2EA93F /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_sensors_private.pri */, - BFF0C38FB0EC140C5F0304AE /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_serialport.pri */, - 311004331A04F3D69C98643C /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_serialport_private.pri */, - 7DE30A90667C03C4F91A2A91 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_sql.pri */, - 075EB50EB07CF69FD62FB8DF /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_sql_private.pri */, - ADFC79902C14A612AE93A89A /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_svg.pri */, - 8DDE1D26B3206CDB8B57FABE /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_svg_private.pri */, - DB0A26DDC377B2004F61BFE3 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_testlib.pri */, - 8849E60AEC7DB97A475C17EA /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_testlib_private.pri */, - E50FA73B8A23BC179A642B27 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_uitools.pri */, - B518DA4EE7376002AFC71FD5 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_uitools_private.pri */, - 8F97C9CAE38CA3AFAC0B3953 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_websockets.pri */, - 87EEF25EE25CF21572D1438C /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_websockets_private.pri */, - A022AF919D1977534CA66BB8 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_widgets.pri */, - 8E9136256AFFBA6EF048AA55 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_widgets_private.pri */, - AA73DC3C2901E2979FE8AD5B /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_xml.pri */, - E37365B4489B4918BEBB707D /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_xml_private.pri */, - 2E6D9B1D2743D24E31B0B284 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_xmlpatterns.pri */, - F9BEAA743A908603687DA204 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_lib_xmlpatterns_private.pri */, - D5141F795670589C8CC41CBC /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_cocoaprintersupport.pri */, - 1FAE75C970AA73F2DEDDB508 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qavfcamera.pri */, - F4EB01857048DCFCFFAAC4D0 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qavfmediaplayer.pri */, - AFD721AA33A2F785E77B1698 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qcocoa.pri */, - EA5D4FF9DE4AC4215D7DCE0D /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qcorewlanbearer.pri */, - 111BBEE3D1432C3B517FD539 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qdds.pri */, - 3685604BDB64DD6E92169B73 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qdeclarativeview.pri */, - 2440CD1D4CEF80443BCA1B8B /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qgenericbearer.pri */, - EB1F99FD112917157F3C3F6E /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qicns.pri */, - C4295BE59CCEBCDD16268349 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qico.pri */, - 45DB132B756499D4DF38430E /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qjp2.pri */, - B678DA730B4ECE863AD631AE /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qminimal.pri */, - F0A58515945747E36783CC21 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qmldbg_inspector.pri */, - B8525798C5AA7D7C6D68E1B3 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qmldbg_qtquick2.pri */, - EB29AC635054C09EFA749AE1 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qmldbg_tcp.pri */, - 3F08D430CEC8D2117735CCB4 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qmldbg_tcp_qtdeclarative.pri */, - 946BEA667170DC1A7A8F9DB0 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qmng.pri */, - CCF75CFFB857487FB18F99F9 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qoffscreen.pri */, - 9A0BDF67E013BB4FFB8685B0 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qqt7engine.pri */, - B064BF3B496A7BF7A449CA1E /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qsqlite.pri */, - F83F87F8A60C9DF666911D42 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qsvg.pri */, - CFFBE05DB004895080314289 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qsvgicon.pri */, - 247D8DF3B1DDB665B80BBA25 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtaccessiblequick.pri */, - 87A4C1983FD641360BF80A02 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtaccessiblewidgets.pri */, - 24B6929EE3952310F2DAECB1 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtaudio_coreaudio.pri */, - 060A694B42A4555240009936 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtga.pri */, - BD22EFEFCC02644B1883CE19 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtiff.pri */, - B8C1F6C965A7A14FBA8D4518 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtmedia_audioengine.pri */, - 74C1C232DFAA71028A0412CA /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtmultimedia_m3u.pri */, - C84546C18DCBB04166195DCF /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtposition_positionpoll.pri */, - AB1C02DDBD8E88DD9A9AFDDD /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtsensorgestures_plugin.pri */, - 8B4BB4E74F8A4442EF563D7D /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtsensorgestures_shakeplugin.pri */, - 892D36BEF797BA4AF48D378A /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtsensors_dummy.pri */, - A4D8AC60897F435C1C3B9D02 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qtsensors_generic.pri */, - 346287C9E754E7C458153F03 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qwbmp.pri */, - B26239063A068F800A2C95F4 /* /usr/local/Qt-5.5.1/mkspecs/modules/qt_plugin_qwebp.pri */, - 63E722139886C87BC82DBDF5 /* /usr/local/Qt-5.5.1/mkspecs/macx-clang/qmake.conf */, - 85061B1DA49D125991117950 /* /usr/local/Qt-5.5.1/mkspecs/macx-xcode/qmake.conf */, - AB745978DF0F41D1801ABDA6 /* .qmake.stash */, - 370997172D3BAEED157B8E70 /* SourceFiles */, ); - name = "Supporting Files"; + name = Version; sourceTree = ""; }; 801973D3334D0FCA849CF485 /* Debug */ = { isa = PBXGroup; children = ( + 076B1C621CBFCC53002C0BC2 /* moc_top_bar_widget.cpp */, 07C8FE111CB80915007A8702 /* moc_toast_manager.cpp */, 077A4AFF1CA41EE2002188D2 /* moc_connection_abstract.cpp */, 077A4B001CA41EE2002188D2 /* moc_connection_auto.cpp */, @@ -1456,35 +1281,17 @@ name = Frameworks; sourceTree = ""; }; - D0B536A85E53302E4F66CE23 /* GeneratedFiles */ = { - isa = PBXGroup; - children = ( - 07AF95F21AFD03B90060B057 /* qrc_telegram_emojis.cpp */, - 07AF95F31AFD03B90060B057 /* qrc_telegram_mac.cpp */, - D6FF6676816C4E374D374060 /* qrc_telegram.cpp */, - 801973D3334D0FCA849CF485 /* Debug */, - ); - name = GeneratedFiles; - sourceTree = ""; - }; E8C543AB96796ECAA2E65C57 /* Telegram */ = { isa = PBXGroup; children = ( - 07D7EABC1A597DD000838BA2 /* Localizable.strings */, 07084684195445A600B5AE3A /* Updater.xcodeproj */, - 2EB56BE3C2D93CDAB0C52E67 /* Sources */, - 25B08E2869634E9BCBA333A2 /* Generated Sources */, + 25B08E2869634E9BCBA333A2 /* GeneratedFiles */, + 73F2E45FDEB381A085D37A49 /* SourceFiles */, 071AD8691C5E8504008C9E90 /* ThirdParty */, - 74B182DB50CB5611B5C1C297 /* Supporting Files */, + 74B182DB50CB5611B5C1C297 /* Version */, AF39DD055C3EF8226FBE929D /* Frameworks */, FE0A091FDBFB3E9C31B7A1BD /* Products */, - 07C3AF24194335ED0016CFF1 /* Images.xcassets */, - 07080BCB1A4357F300741A51 /* lang.strings */, - 07C3AF2919433ABF0016CFF1 /* style_classes.txt */, - 07C3AF2A19433ABF0016CFF1 /* style.txt */, - 07AF95F71AFD03C80060B057 /* telegram_emojis.qrc */, - 07AF95F81AFD03C80060B057 /* telegram_mac.qrc */, - 1292B92B4848460640F6A391 /* telegram.qrc */, + 076B1C611CBFCC0F002C0BC2 /* Resources */, ); name = Telegram; sourceTree = ""; @@ -1687,6 +1494,7 @@ 02F93BF511880983D3C57B84 /* dialogswidget.cpp in Compile Sources */, 07DE92A81AA4925B00A18F6F /* passcodebox.cpp in Compile Sources */, 074968D21A44D1DF00394F46 /* moc_languagebox.cpp in Compile Sources */, + 076B1C5F1CBFC98F002C0BC2 /* overview_layout.cpp in Compile Sources */, 6EF5A4ECC0EF19EA016EBA3E /* dropdown.cpp in Compile Sources */, 6E4DB0CBEF415196AFD4149F /* fileuploader.cpp in Compile Sources */, 700925F3B2C6163D38140CEA /* history.cpp in Compile Sources */, @@ -1701,6 +1509,7 @@ 113AA97DEE7847C7D2DCFF71 /* logs.cpp in Compile Sources */, E3194392BD6D0726F75FA72E /* mainwidget.cpp in Compile Sources */, DF36EA42D67ED39E58CB7DF9 /* settings.cpp in Compile Sources */, + 076B1C541CBFC6F2002C0BC2 /* click_handler_types.cpp in Compile Sources */, 077A4B031CA41EE2002188D2 /* moc_connection_abstract.cpp in Compile Sources */, B99CCE43EEFCD3E18F6D16D1 /* settingswidget.cpp in Compile Sources */, B8DA82DA1B195A933A0805E7 /* sysbuttons.cpp in Compile Sources */, @@ -1709,6 +1518,7 @@ 4078D5D614EB3ECF7F1848C7 /* basic_types.cpp in Compile Sources */, 68FFEB7CA30BF0149161B809 /* mainwindow.cpp in Compile Sources */, 0CB7DE9A54CC9BF86FB7B5CA /* facade.cpp in Compile Sources */, + 076B1C5B1CBFC8F1002C0BC2 /* top_bar_widget.cpp in Compile Sources */, DF259E9677CC63AF8754032B /* connection.cpp in Compile Sources */, 074FCB9119D36E60004C6EB2 /* moc_popupmenu.cpp in Compile Sources */, B6346B66B0A2228A91D8A5D9 /* dcenter.cpp in Compile Sources */, @@ -1742,6 +1552,7 @@ 07129D6A1C16D230002DC495 /* auth_key.cpp in Compile Sources */, 90085DF442550A0845D5AF37 /* style_core.cpp in Compile Sources */, 074FCB8E19D36851004C6EB2 /* popupmenu.cpp in Compile Sources */, + 076B1C4D1CBFBF59002C0BC2 /* text_block.cpp in Compile Sources */, 3AA6E7264581F82856FB37F7 /* text.cpp in Compile Sources */, 077A4B061CA41EE2002188D2 /* moc_connection_tcp.cpp in Compile Sources */, FCE6518C548DF7BC82228A4A /* twidget.cpp in Compile Sources */, @@ -1766,6 +1577,7 @@ 9357E7B12AD6D88B157ACA05 /* introcode.cpp in Compile Sources */, 4BF3F8D0797BC8A0C1FAD13C /* introphone.cpp in Compile Sources */, 4978DE680549639AE9AA9CA6 /* introsignup.cpp in Compile Sources */, + 076B1C551CBFC6F2002C0BC2 /* click_handler.cpp in Compile Sources */, 8B22E794EFF0EAFF964A3043 /* introstart.cpp in Compile Sources */, 74343521EECC740F777DAFE6 /* pspecific_mac.cpp in Compile Sources */, 26A81090DC8B5BCF7278FDFF /* qrc_telegram.cpp in Compile Sources */, @@ -1808,6 +1620,7 @@ 07A6933519927B160099CB9F /* moc_mediaview.cpp in Compile Sources */, 07A69332199277BA0099CB9F /* mediaview.cpp in Compile Sources */, 9A523F51135FD4E2464673A6 /* moc_session.cpp in Compile Sources */, + 076B1C631CBFCC53002C0BC2 /* moc_top_bar_widget.cpp in Compile Sources */, C329997D36D34D568CE16C9A /* moc_animation.cpp in Compile Sources */, B2F5B08BFFBBE7E37D3863BB /* moc_button.cpp in Compile Sources */, 6A8BC88AB464B92706EFE6FF /* moc_countryinput.cpp in Compile Sources */, @@ -1819,6 +1632,7 @@ 565F748438E6CE0148C54AFE /* moc_flatinput.cpp in Compile Sources */, 8B71D1C7BB9DCEE6511219C2 /* moc_flatlabel.cpp in Compile Sources */, 0710C9FE1B0B9376001B4272 /* stickersetbox.cpp in Compile Sources */, + 076B1C4E1CBFBF59002C0BC2 /* text_entity.cpp in Compile Sources */, 0764D55D1ABAD71B00FBFEED /* moc_apiwrap.cpp in Compile Sources */, 0752F8701C2C84470026D0BC /* layout.cpp in Compile Sources */, 07DE92AD1AA4928B00A18F6F /* moc_passcodebox.cpp in Compile Sources */, diff --git a/Telegram/Telegram.xcodeproj/qt_preprocess.mak b/Telegram/Telegram.xcodeproj/qt_preprocess.mak index 4e0c0fabc..610300e3e 100644 --- a/Telegram/Telegram.xcodeproj/qt_preprocess.mak +++ b/Telegram/Telegram.xcodeproj/qt_preprocess.mak @@ -52,6 +52,7 @@ compilers: GeneratedFiles/qrc_telegram.cpp\ GeneratedFiles/Debug/moc_localimageloader.cpp\ GeneratedFiles/Debug/moc_localstorage.cpp\ GeneratedFiles/Debug/moc_mainwidget.cpp\ + GeneratedFiles/Debug/moc_top_bar_widget.cpp\ GeneratedFiles/Debug/moc_settingswidget.cpp\ GeneratedFiles/Debug/moc_sysbuttons.cpp\ GeneratedFiles/Debug/moc_title.cpp\ @@ -177,6 +178,7 @@ compiler_moc_header_make_all: GeneratedFiles/Debug/moc_apiwrap.cpp\ GeneratedFiles/Debug/moc_localimageloader.cpp\ GeneratedFiles/Debug/moc_localstorage.cpp\ GeneratedFiles/Debug/moc_mainwidget.cpp\ + GeneratedFiles/Debug/moc_top_bar_widget.cpp\ GeneratedFiles/Debug/moc_settingswidget.cpp\ GeneratedFiles/Debug/moc_sysbuttons.cpp\ GeneratedFiles/Debug/moc_title.cpp\ @@ -245,6 +247,7 @@ compiler_moc_header_clean: GeneratedFiles/Debug/moc_localimageloader.cpp\ GeneratedFiles/Debug/moc_localstorage.cpp\ GeneratedFiles/Debug/moc_mainwidget.cpp\ + GeneratedFiles/Debug/moc_top_bar_widget.cpp\ GeneratedFiles/Debug/moc_settingswidget.cpp\ GeneratedFiles/Debug/moc_sysbuttons.cpp\ GeneratedFiles/Debug/moc_title.cpp\ @@ -387,30 +390,15 @@ GeneratedFiles/Debug/moc_localimageloader.cpp: SourceFiles/localimageloader.h GeneratedFiles/Debug/moc_localstorage.cpp: SourceFiles/localstorage.h /usr/local/Qt-5.5.1/bin/moc $(DEFINES) -D__APPLE__ -D__GNUC__=4 -I/usr/local/Qt-5.5.1/mkspecs/macx-clang -I. -I/usr/local/Qt-5.5.1/include/QtGui/5.5.1/QtGui -I/usr/local/Qt-5.5.1/include/QtCore/5.5.1/QtCore -I/usr/local/Qt-5.5.1/include -I./SourceFiles -I./GeneratedFiles -I../../Libraries/lzma/C -I../../Libraries/libexif-0.6.20 -I/usr/local/Qt-5.5.1/include -I/usr/local/Qt-5.5.1/include/QtMultimedia -I/usr/local/Qt-5.5.1/include/QtWidgets -I/usr/local/Qt-5.5.1/include/QtNetwork -I/usr/local/Qt-5.5.1/include/QtGui -I/usr/local/Qt-5.5.1/include/QtCore -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1 -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1/backward -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/5.1/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include SourceFiles/localstorage.h -o GeneratedFiles/Debug/moc_localstorage.cpp -GeneratedFiles/Debug/moc_mainwidget.cpp: ../../Libraries/QtStatic/qtbase/include/QtWidgets/QWidget \ - SourceFiles/ui/flatbutton.h \ - SourceFiles/ui/button.h \ - SourceFiles/ui/twidget.h \ - SourceFiles/ui/flatcheckbox.h \ - SourceFiles/ui/animation.h \ - SourceFiles/core/basic_types.h \ - ../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \ - SourceFiles/logs.h \ - ../../Libraries/QtStatic/qtbase/include/QtCore/QTimer \ - ../../Libraries/QtStatic/qtbase/include/QtGui/QColor \ - SourceFiles/ui/style.h \ - GeneratedFiles/style_classes.h \ - GeneratedFiles/style_auto.h \ - SourceFiles/dialogswidget.h \ - SourceFiles/historywidget.h \ - SourceFiles/localimageloader.h \ - SourceFiles/ui/boxshadow.h \ - SourceFiles/dropdown.h \ - SourceFiles/overviewwidget.h \ - SourceFiles/profilewidget.h \ +GeneratedFiles/Debug/moc_mainwidget.cpp: SourceFiles/localimageloader.h \ + SourceFiles/history/history_common.h \ SourceFiles/mainwidget.h /usr/local/Qt-5.5.1/bin/moc $(DEFINES) -D__APPLE__ -D__GNUC__=4 -I/usr/local/Qt-5.5.1/mkspecs/macx-clang -I. -I/usr/local/Qt-5.5.1/include/QtGui/5.5.1/QtGui -I/usr/local/Qt-5.5.1/include/QtCore/5.5.1/QtCore -I/usr/local/Qt-5.5.1/include -I./SourceFiles -I./GeneratedFiles -I../../Libraries/lzma/C -I../../Libraries/libexif-0.6.20 -I/usr/local/Qt-5.5.1/include -I/usr/local/Qt-5.5.1/include/QtMultimedia -I/usr/local/Qt-5.5.1/include/QtWidgets -I/usr/local/Qt-5.5.1/include/QtNetwork -I/usr/local/Qt-5.5.1/include/QtGui -I/usr/local/Qt-5.5.1/include/QtCore -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1 -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1/backward -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/5.1/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include SourceFiles/mainwidget.h -o GeneratedFiles/Debug/moc_mainwidget.cpp +GeneratedFiles/Debug/moc_top_bar_widget.cpp: SourceFiles/ui/twidget.h \ + SourceFiles/window/top_bar_widget.h + /usr/local/Qt-5.5.1/bin/moc $(DEFINES) -D__APPLE__ -D__GNUC__=4 -I/usr/local/Qt-5.5.1/mkspecs/macx-clang -I. -I/usr/local/Qt-5.5.1/include/QtGui/5.5.1/QtGui -I/usr/local/Qt-5.5.1/include/QtCore/5.5.1/QtCore -I/usr/local/Qt-5.5.1/include -I./SourceFiles -I./GeneratedFiles -I../../Libraries/lzma/C -I../../Libraries/libexif-0.6.20 -I/usr/local/Qt-5.5.1/include -I/usr/local/Qt-5.5.1/include/QtMultimedia -I/usr/local/Qt-5.5.1/include/QtWidgets -I/usr/local/Qt-5.5.1/include/QtNetwork -I/usr/local/Qt-5.5.1/include/QtGui -I/usr/local/Qt-5.5.1/include/QtCore -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1 -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1/backward -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/5.1/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include SourceFiles/window/top_bar_widget.h -o GeneratedFiles/Debug/moc_top_bar_widget.cpp + GeneratedFiles/Debug/moc_settingswidget.cpp: SourceFiles/ui/flatbutton.h \ SourceFiles/ui/button.h \ ../../Libraries/QtStatic/qtbase/include/QtWidgets/QWidget \ From acc7e08a54b37c5b053829ffa821ad88e82d7390 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 14 Apr 2016 16:06:36 +0300 Subject: [PATCH 08/14] Remove -flto in Linux 32bit (it fails Release link: virtual memory exhausted) --- Telegram/Telegram.pro | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Telegram/Telegram.pro b/Telegram/Telegram.pro index b33c46f6f..fc8b609ca 100644 --- a/Telegram/Telegram.pro +++ b/Telegram/Telegram.pro @@ -339,6 +339,15 @@ CONFIG(release, debug|release) { QMAKE_LFLAGS_RELEASE -= -O1 QMAKE_LFLAGS_RELEASE += -Ofast -flto -g -rdynamic } +# Linux 32bit fails Release link with Link-Time Optimization: virtual memory exhausted +unix { + !contains(QMAKE_TARGET.arch, x86_64) { + CONFIG(release, debug|release) { + QMAKE_CXXFLAGS_RELEASE -= -flto + QMAKE_LFLAGS_RELEASE -= -flto + } + } +} CONFIG(debug, debug|release) { QMAKE_LFLAGS_DEBUG += -g -rdynamic } From d80850a439eacf2811f68002eac4e2c06db7a022 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 14 Apr 2016 17:30:47 +0300 Subject: [PATCH 09/14] Fixed QtCreator build. --- Telegram/SourceFiles/ui/text/text.h | 7 +- Telegram/Telegram.pro | 161 +++++++++++++++------------- 2 files changed, 89 insertions(+), 79 deletions(-) diff --git a/Telegram/SourceFiles/ui/text/text.h b/Telegram/SourceFiles/ui/text/text.h index 84f8ace9a..13eca1805 100644 --- a/Telegram/SourceFiles/ui/text/text.h +++ b/Telegram/SourceFiles/ui/text/text.h @@ -155,12 +155,13 @@ public: return getState(rtl() ? (outerw - x - width) : x, y, width, request); } struct StateRequestElided : public StateRequest { - StateRequestElided() = default; - StateRequestElided(const StateRequest &other) : StateRequest(other) { + StateRequestElided() { + } + StateRequestElided(const StateRequest &other) : StateRequest(other) { } int lines = 1; int removeFromEnd = 0; - }; + }; StateResult getStateElided(int x, int y, int width, StateRequestElided request = StateRequestElided()) const; StateResult getStateElidedLeft(int x, int y, int width, int outerw, StateRequestElided request = StateRequestElided()) const { return getStateElided(rtl() ? (outerw - x - width) : x, y, width, request); diff --git a/Telegram/Telegram.pro b/Telegram/Telegram.pro index fc8b609ca..7b69fedb8 100644 --- a/Telegram/Telegram.pro +++ b/Telegram/Telegram.pro @@ -80,6 +80,9 @@ unix { } SOURCES += \ + ./GeneratedFiles/lang_auto.cpp \ + ./GeneratedFiles/style_auto.cpp \ + ./GeneratedFiles/numbers.cpp \ ./SourceFiles/main.cpp \ ./SourceFiles/stdafx.cpp \ ./SourceFiles/apiwrap.cpp \ @@ -112,8 +115,40 @@ SOURCES += \ ./SourceFiles/structs.cpp \ ./SourceFiles/sysbuttons.cpp \ ./SourceFiles/title.cpp \ - ./SourceFiles/basic_types.cpp \ - ./SourceFiles/window.cpp \ + ./SourceFiles/mainwindow.cpp \ + ./SourceFiles/boxes/aboutbox.cpp \ + ./SourceFiles/boxes/abstractbox.cpp \ + ./SourceFiles/boxes/addcontactbox.cpp \ + ./SourceFiles/boxes/autolockbox.cpp \ + ./SourceFiles/boxes/backgroundbox.cpp \ + ./SourceFiles/boxes/confirmbox.cpp \ + ./SourceFiles/boxes/connectionbox.cpp \ + ./SourceFiles/boxes/contactsbox.cpp \ + ./SourceFiles/boxes/downloadpathbox.cpp \ + ./SourceFiles/boxes/emojibox.cpp \ + ./SourceFiles/boxes/languagebox.cpp \ + ./SourceFiles/boxes/passcodebox.cpp \ + ./SourceFiles/boxes/photocropbox.cpp \ + ./SourceFiles/boxes/photosendbox.cpp \ + ./SourceFiles/boxes/sessionsbox.cpp \ + ./SourceFiles/boxes/stickersetbox.cpp \ + ./SourceFiles/boxes/usernamebox.cpp \ + ./SourceFiles/core/basic_types.cpp \ + ./SourceFiles/core/click_handler.cpp \ + ./SourceFiles/core/click_handler_types.cpp \ + ./SourceFiles/dialogs/dialogs_indexed_list.cpp \ + ./SourceFiles/dialogs/dialogs_layout.cpp \ + ./SourceFiles/dialogs/dialogs_list.cpp \ + ./SourceFiles/inline_bots/inline_bot_layout_internal.cpp \ + ./SourceFiles/inline_bots/inline_bot_layout_item.cpp \ + ./SourceFiles/inline_bots/inline_bot_result.cpp \ + ./SourceFiles/inline_bots/inline_bot_send_data.cpp \ + ./SourceFiles/intro/introwidget.cpp \ + ./SourceFiles/intro/introcode.cpp \ + ./SourceFiles/intro/introphone.cpp \ + ./SourceFiles/intro/intropwdcheck.cpp \ + ./SourceFiles/intro/introsignup.cpp \ + ./SourceFiles/intro/introstart.cpp \ ./SourceFiles/mtproto/facade.cpp \ ./SourceFiles/mtproto/auth_key.cpp \ ./SourceFiles/mtproto/connection.cpp \ @@ -128,6 +163,9 @@ SOURCES += \ ./SourceFiles/mtproto/rpc_sender.cpp \ ./SourceFiles/mtproto/scheme_auto.cpp \ ./SourceFiles/mtproto/session.cpp \ + ./SourceFiles/overview/overview_layout.cpp \ + ./SourceFiles/serialize/serialize_common.cpp \ + ./SourceFiles/serialize/serialize_document.cpp \ ./SourceFiles/ui/buttons/peer_avatar_button.cpp \ ./SourceFiles/ui/text/text.cpp \ ./SourceFiles/ui/text/text_block.cpp \ @@ -151,43 +189,12 @@ SOURCES += \ ./SourceFiles/ui/scrollarea.cpp \ ./SourceFiles/ui/style_core.cpp \ ./SourceFiles/ui/twidget.cpp \ - ./GeneratedFiles/lang_auto.cpp \ - ./GeneratedFiles/style_auto.cpp \ - ./GeneratedFiles/numbers.cpp \ - ./SourceFiles/boxes/aboutbox.cpp \ - ./SourceFiles/boxes/abstractbox.cpp \ - ./SourceFiles/boxes/addcontactbox.cpp \ - ./SourceFiles/boxes/autolockbox.cpp \ - ./SourceFiles/boxes/backgroundbox.cpp \ - ./SourceFiles/boxes/confirmbox.cpp \ - ./SourceFiles/boxes/connectionbox.cpp \ - ./SourceFiles/boxes/contactsbox.cpp \ - ./SourceFiles/boxes/downloadpathbox.cpp \ - ./SourceFiles/boxes/emojibox.cpp \ - ./SourceFiles/boxes/languagebox.cpp \ - ./SourceFiles/boxes/passcodebox.cpp \ - ./SourceFiles/boxes/photocropbox.cpp \ - ./SourceFiles/boxes/photosendbox.cpp \ - ./SourceFiles/boxes/sessionsbox.cpp \ - ./SourceFiles/boxes/stickersetbox.cpp \ - ./SourceFiles/boxes/usernamebox.cpp \ - ./SourceFiles/dialogs/dialogs_indexed_list.cpp \ - ./SourceFiles/dialogs/dialogs_layout.cpp \ - ./SourceFiles/dialogs/dialogs_list.cpp \ - ./SourceFiles/inline_bots/inline_bot_layout_internal.cpp \ - ./SourceFiles/inline_bots/inline_bot_layout_item.cpp \ - ./SourceFiles/inline_bots/inline_bot_result.cpp \ - ./SourceFiles/inline_bots/inline_bot_send_data.cpp \ - ./SourceFiles/serialize/serialize_common.cpp \ - ./SourceFiles/serialize/serialize_document.cpp \ - ./SourceFiles/intro/introwidget.cpp \ - ./SourceFiles/intro/introcode.cpp \ - ./SourceFiles/intro/introphone.cpp \ - ./SourceFiles/intro/intropwdcheck.cpp \ - ./SourceFiles/intro/introsignup.cpp \ - ./SourceFiles/intro/introstart.cpp + ./SourceFiles/window/top_bar_widget.cpp HEADERS += \ + ./GeneratedFiles/lang_auto.h \ + ./GeneratedFiles/style_auto.h \ + ./GeneratedFiles/style_classes.h \ ./SourceFiles/stdafx.h \ ./SourceFiles/apiwrap.h \ ./SourceFiles/app.h \ @@ -222,8 +229,43 @@ HEADERS += \ ./SourceFiles/structs.h \ ./SourceFiles/sysbuttons.h \ ./SourceFiles/title.h \ - ./SourceFiles/basic_types.h \ - ./SourceFiles/window.h \ + ./SourceFiles/mainwindow.h \ + ./SourceFiles/boxes/aboutbox.h \ + ./SourceFiles/boxes/abstractbox.h \ + ./SourceFiles/boxes/addcontactbox.h \ + ./SourceFiles/boxes/autolockbox.h \ + ./SourceFiles/boxes/backgroundbox.h \ + ./SourceFiles/boxes/confirmbox.h \ + ./SourceFiles/boxes/connectionbox.h \ + ./SourceFiles/boxes/contactsbox.h \ + ./SourceFiles/boxes/downloadpathbox.h \ + ./SourceFiles/boxes/emojibox.h \ + ./SourceFiles/boxes/languagebox.h \ + ./SourceFiles/boxes/passcodebox.h \ + ./SourceFiles/boxes/photocropbox.h \ + ./SourceFiles/boxes/photosendbox.h \ + ./SourceFiles/boxes/sessionsbox.h \ + ./SourceFiles/boxes/stickersetbox.h \ + ./SourceFiles/boxes/usernamebox.h \ + ./SourceFiles/core/basic_types.h \ + ./SourceFiles/core/click_handler.h \ + ./SourceFiles/core/click_handler_types.h \ + ./SourceFiles/dialogs/dialogs_common.h \ + ./SourceFiles/dialogs/dialogs_indexed_list.h \ + ./SourceFiles/dialogs/dialogs_layout.h \ + ./SourceFiles/dialogs/dialogs_list.h \ + ./SourceFiles/dialogs/dialogs_row.h \ + ./SourceFiles/history/history_common.h \ + ./SourceFiles/inline_bots/inline_bot_layout_internal.h \ + ./SourceFiles/inline_bots/inline_bot_layout_item.h \ + ./SourceFiles/inline_bots/inline_bot_result.h \ + ./SourceFiles/inline_bots/inline_bot_send_data.h \ + ./SourceFiles/intro/introwidget.h \ + ./SourceFiles/intro/introcode.h \ + ./SourceFiles/intro/introphone.h \ + ./SourceFiles/intro/intropwdcheck.h \ + ./SourceFiles/intro/introsignup.h \ + ./SourceFiles/intro/introstart.h \ ./SourceFiles/mtproto/facade.h \ ./SourceFiles/mtproto/auth_key.h \ ./SourceFiles/mtproto/connection.h \ @@ -238,7 +280,10 @@ HEADERS += \ ./SourceFiles/mtproto/rpc_sender.h \ ./SourceFiles/mtproto/scheme_auto.h \ ./SourceFiles/mtproto/session.h \ + ./SourceFiles/overview/overview_layout.h \ ./SourceFiles/pspecific.h \ + ./SourceFiles/serialize/serialize_common.h \ + ./SourceFiles/serialize/serialize_document.h \ ./SourceFiles/ui/buttons/peer_avatar_button.h \ ./SourceFiles/ui/text/text.h \ ./SourceFiles/ui/text/text_block.h \ @@ -263,43 +308,7 @@ HEADERS += \ ./SourceFiles/ui/style.h \ ./SourceFiles/ui/style_core.h \ ./SourceFiles/ui/twidget.h \ - ./GeneratedFiles/lang_auto.h \ - ./GeneratedFiles/style_auto.h \ - ./GeneratedFiles/style_classes.h \ - ./SourceFiles/boxes/aboutbox.h \ - ./SourceFiles/boxes/abstractbox.h \ - ./SourceFiles/boxes/addcontactbox.h \ - ./SourceFiles/boxes/autolockbox.h \ - ./SourceFiles/boxes/backgroundbox.h \ - ./SourceFiles/boxes/confirmbox.h \ - ./SourceFiles/boxes/connectionbox.h \ - ./SourceFiles/boxes/contactsbox.h \ - ./SourceFiles/boxes/downloadpathbox.h \ - ./SourceFiles/boxes/emojibox.h \ - ./SourceFiles/boxes/languagebox.h \ - ./SourceFiles/boxes/passcodebox.h \ - ./SourceFiles/boxes/photocropbox.h \ - ./SourceFiles/boxes/photosendbox.h \ - ./SourceFiles/boxes/sessionsbox.h \ - ./SourceFiles/boxes/stickersetbox.h \ - ./SourceFiles/boxes/usernamebox.h \ - ./SourceFiles/dialogs/dialogs_common.h \ - ./SourceFiles/dialogs/dialogs_indexed_list.h \ - ./SourceFiles/dialogs/dialogs_layout.h \ - ./SourceFiles/dialogs/dialogs_list.h \ - ./SourceFiles/dialogs/dialogs_row.h \ - ./SourceFiles/inline_bots/inline_bot_layout_internal.h \ - ./SourceFiles/inline_bots/inline_bot_layout_item.h \ - ./SourceFiles/inline_bots/inline_bot_result.h \ - ./SourceFiles/inline_bots/inline_bot_send_data.h \ - ./SourceFiles/serialize/serialize_common.h \ - ./SourceFiles/serialize/serialize_document.h \ - ./SourceFiles/intro/introwidget.h \ - ./SourceFiles/intro/introcode.h \ - ./SourceFiles/intro/introphone.h \ - ./SourceFiles/intro/intropwdcheck.h \ - ./SourceFiles/intro/introsignup.h \ - ./SourceFiles/intro/introstart.h + ./SourceFiles/window/top_bar_widget.h win32 { SOURCES += \ From fdead263d6a751156247dd1f755649b4b4b91e83 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 14 Apr 2016 19:08:36 +0300 Subject: [PATCH 10/14] Media shortcuts now are enabled only when in-app player is opened. --- Telegram/SourceFiles/mainwidget.cpp | 54 +- Telegram/SourceFiles/mainwidget.h | 3 +- Telegram/SourceFiles/playerwidget.cpp | 57 +- Telegram/SourceFiles/playerwidget.h | 48 +- Telegram/SourceFiles/shortcuts.cpp | 791 ++++++++++++++------------ Telegram/SourceFiles/shortcuts.h | 6 + 6 files changed, 520 insertions(+), 439 deletions(-) diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index d3d478f0b..bc0e86d6b 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -100,7 +100,7 @@ MainWidget::MainWidget(MainWindow *window) : TWidget(window) App::wnd()->getTitle()->updateBackButton(); _topBar->hide(); - _player->hide(); + _player->hidePlayer(); orderWidgets(); @@ -1558,12 +1558,14 @@ void MainWidget::documentPlayProgress(const SongMsgId &songId) { if (playing == songId) { _player->updateState(playing, playingState, playingPosition, playingDuration, playingFrequency); - if (!(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing && !_a_show.animating()) { - if (_player->isHidden()) { - _player->clearSelection(); - _player->show(); - _playerHeight = _contentScrollAddToY = _player->height(); - resizeEvent(0); + if (!(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) { + if (!_player->isOpened()) { + _player->openPlayer(); + if (_player->isHidden() && !_a_show.animating()) { + _player->showPlayer(); + _playerHeight = _contentScrollAddToY = _player->height(); + resizeEvent(0); + } } } } @@ -1578,12 +1580,15 @@ void MainWidget::documentPlayProgress(const SongMsgId &songId) { } } -void MainWidget::hidePlayer() { - if (!_player->isHidden()) { - _player->hide(); - _contentScrollAddToY = -_player->height(); - _playerHeight = 0; - resizeEvent(0); +void MainWidget::closePlayer() { + if (_player->isOpened()) { + _player->closePlayer(); + if (!_player->isHidden() && !_a_show.animating()) { + _player->hidePlayer(); + _contentScrollAddToY = -_player->height(); + _playerHeight = 0; + resizeEvent(0); + } } } @@ -2477,8 +2482,10 @@ void MainWidget::hideAll() { } _topBar->hide(); _mediaType->hide(); - _player->hide(); - _playerHeight = 0; + if (_player->isOpened() && !_player->isHidden()) { + _player->hidePlayer(); + _playerHeight = 0; + } } void MainWidget::showAll() { @@ -2538,20 +2545,9 @@ void MainWidget::showAll() { _topBar->show(); } } - if (audioPlayer()) { - SongMsgId playing; - AudioPlayerState playingState = AudioPlayerStopped; - int64 playingPosition = 0, playingDuration = 0; - int32 playingFrequency = 0; - audioPlayer()->currentState(&playing, &playingState, &playingPosition, &playingDuration, &playingFrequency); - if (playing) { - _player->updateState(playing, playingState, playingPosition, playingDuration, playingFrequency); - if (!(playingState & AudioPlayerStoppedMask) && playingState != AudioPlayerFinishing) { - _player->clearSelection(); - _player->show(); - _playerHeight = _player->height(); - } - } + if (_player->isOpened() && _player->isHidden()) { + _player->showPlayer(); + _playerHeight = _player->height(); } resizeEvent(0); diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index dafb651b8..d080355c0 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -372,6 +372,8 @@ public: bool isItemVisible(HistoryItem *item); + void closePlayer(); + void app_sendBotCallback(const HistoryMessageReplyMarkup::Button *button, const HistoryItem *msg, int row, int col); void ui_repaintHistoryItem(const HistoryItem *item); @@ -422,7 +424,6 @@ public slots: void documentPlayProgress(const SongMsgId &songId); void inlineResultLoadProgress(FileLoader *loader); void inlineResultLoadFailed(FileLoader *loader, bool started); - void hidePlayer(); void dialogsCancelled(); diff --git a/Telegram/SourceFiles/playerwidget.cpp b/Telegram/SourceFiles/playerwidget.cpp index 454763a2e..876ecd4a6 100644 --- a/Telegram/SourceFiles/playerwidget.cpp +++ b/Telegram/SourceFiles/playerwidget.cpp @@ -19,41 +19,21 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org */ #include "stdafx.h" +#include "playerwidget.h" + +#include "shortcuts.h" #include "ui/style.h" #include "lang.h" - #include "boxes/addcontactbox.h" #include "application.h" #include "mainwindow.h" #include "playerwidget.h" #include "mainwidget.h" - #include "localstorage.h" - #include "audio.h" 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)) -, _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)) , _sideShadow(this, st::shadowColor) { resize(st::wndMinWidth, st::playerHeight); @@ -372,6 +352,29 @@ bool PlayerWidget::seekingSong(const SongMsgId &song) const { 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) { for (StateAnimations::iterator i = _stateAnimations.begin(); i != _stateAnimations.cend();) { int32 over = qAbs(i.key()); @@ -463,7 +466,7 @@ void PlayerWidget::mouseReleaseEvent(QMouseEvent *e) { } update(); } else if (_down == OverClose && _over == OverClose) { - stopPressed(); + closePressed(); } _down = OverNone; } @@ -545,7 +548,11 @@ void PlayerWidget::stopPressed() { if (!_song || isHidden()) return; audioPlayer()->stop(OverviewFiles); - if (App::main()) App::main()->hidePlayer(); +} + +void PlayerWidget::closePressed() { + stopPressed(); + if (App::main()) App::main()->closePlayer(); } void PlayerWidget::resizeEvent(QResizeEvent *e) { diff --git a/Telegram/SourceFiles/playerwidget.h b/Telegram/SourceFiles/playerwidget.h index 3c5cffbd3..c5286fca5 100644 --- a/Telegram/SourceFiles/playerwidget.h +++ b/Telegram/SourceFiles/playerwidget.h @@ -42,6 +42,7 @@ public: void prevPressed(); void nextPressed(); void stopPressed(); + void closePressed(); void step_progress(float64 ms, bool timer); void step_state(uint64 ms, bool timer); @@ -55,12 +56,23 @@ public: bool seekingSong(const SongMsgId &song) const; + void openPlayer(); + bool isOpened() const; + void closePlayer(); + + void showPlayer(); + void hidePlayer(); + signals: void playerSongChanged(const FullMsgId &msgId); private: + // Use startPlayer()/stopPlayer() or showPlayer()/hidePlayer() instead. + void show(); + void hide(); + enum OverState { OverNone = 0, OverPrev, @@ -87,12 +99,17 @@ private: QPoint _lastMousePos; void updateSelected(); - bool _prevAvailable, _nextAvailable, _fullAvailable; - OverState _over, _down; - int32 _downCoord; + bool _playerOpened = false; + + bool _prevAvailable = false; + bool _nextAvailable = false; + bool _fullAvailable = false; + OverState _over = OverNone; + OverState _down = OverNone; + int32 _downCoord = 0; int64 _downDuration; - int32 _downFrequency; - float64 _downProgress; + int32 _downFrequency = AudioVoiceMsgFrequency; + float64 _downProgress = 0.; float64 _stateHovers[OverStateCount]; typedef QMap StateAnimations; @@ -100,20 +117,23 @@ private: Animation _a_state; SongMsgId _song; - bool _msgmigrated; - int32 _index; - History *_migrated, *_history; + bool _msgmigrated = false; + int32 _index = -1; + History *_migrated = nullptr; + History *_history = nullptr; QRect _playRect, _prevRect, _nextRect, _playbackRect; QRect _closeRect, _volumeRect, _fullRect, _repeatRect, _infoRect; - int32 _timeWidth; - bool _repeat; + int32 _timeWidth = 0; + bool _repeat = false; QString _time; Text _name; - bool _showPause; - int64 _position, _duration; - int32 _loaded; + bool _showPause = false; + int64 _position = 0; + 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; PlainShadow _sideShadow; diff --git a/Telegram/SourceFiles/shortcuts.cpp b/Telegram/SourceFiles/shortcuts.cpp index 2e5599ac5..c87e79f86 100644 --- a/Telegram/SourceFiles/shortcuts.cpp +++ b/Telegram/SourceFiles/shortcuts.cpp @@ -27,413 +27,450 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "playerwidget.h" namespace ShortcutCommands { - typedef void(*Handler)(); - void lock_telegram() { - if (auto w = App::wnd()) { - if (App::passcoded()) { - w->passcodeWidget()->onSubmit(); - } else if (cHasPasscode()) { - w->setupPasscode(true); - } +typedef void(*Handler)(); + +void lock_telegram() { + if (auto w = App::wnd()) { + if (App::passcoded()) { + w->passcodeWidget()->onSubmit(); + } else if (cHasPasscode()) { + w->setupPasscode(true); } } - - 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 - } +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) { return a < b; } namespace Shortcuts { - // inspired by https://github.com/sindresorhus/strip-json-comments - QByteArray _stripJsonComments(const QByteArray &json) { - enum InsideComment { - InsideCommentNone, - InsideCommentSingleLine, - InsideCommentMultiLine, - }; - InsideComment insideComment = InsideCommentNone; - bool insideString = false; +// inspired by https://github.com/sindresorhus/strip-json-comments +QByteArray _stripJsonComments(const QByteArray &json) { + enum InsideComment { + InsideCommentNone, + InsideCommentSingleLine, + InsideCommentMultiLine, + }; + InsideComment insideComment = InsideCommentNone; + bool insideString = false; - QByteArray result; + QByteArray result; - const char *b = json.cbegin(), *e = json.cend(), *offset = b; - for (const char *ch = offset; ch != e; ++ch) { - char currentChar = *ch; - char nextChar = (ch + 1 == e) ? 0 : *(ch + 1); + const char *b = json.cbegin(), *e = json.cend(), *offset = b; + for (const char *ch = offset; ch != e; ++ch) { + char currentChar = *ch; + char nextChar = (ch + 1 == e) ? 0 : *(ch + 1); - if (insideComment == InsideCommentNone && currentChar == '"') { - bool escaped = ((ch > b) && *(ch - 1) == '\\') && ((ch - 1 < b) || *(ch - 2) != '\\'); - if (!escaped) { - 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 && currentChar == '"') { + bool escaped = ((ch > b) && *(ch - 1) == '\\') && ((ch - 1 < b) || *(ch - 2) != '\\'); + if (!escaped) { + insideString = !insideString; } } - if (insideComment == InsideCommentNone && e > offset && !result.isEmpty()) { - result.append(offset, e - offset); + 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; } - return result.isEmpty() ? json : result; } - struct DataStruct; - DataStruct *DataPtr = nullptr; + if (insideComment == InsideCommentNone && e > offset && !result.isEmpty()) { + result.append(offset, e - offset); + } + return result.isEmpty() ? json : result; +} - void _createCommand(const QString &command, ShortcutCommands::Handler handler); - QKeySequence _setShortcut(const QString &keys, const QString &command); - struct DataStruct { - DataStruct() { - t_assert(DataPtr == nullptr); - DataPtr = this; +struct DataStruct; +DataStruct *DataPtr = nullptr; -#define DeclareAlias(keys, command) _setShortcut(qsl(keys), qsl(#command)) -#define DeclareCommand(keys, command) _createCommand(qsl(#command), ShortcutCommands::command); DeclareAlias(keys, command) +namespace { - DeclareCommand("ctrl+w", close_telegram); - DeclareAlias("ctrl+f4", close_telegram); - DeclareCommand("ctrl+l", lock_telegram); - DeclareCommand("ctrl+m", minimize_telegram); - DeclareCommand("ctrl+q", quit_telegram); +void createCommand(const QString &command, ShortcutCommands::Handler handler); +QKeySequence setShortcut(const QString &keys, const QString &command); +void destroyShortcut(QShortcut *shortcut); - //DeclareCommand("ctrl+r", start_stop_recording); - //DeclareCommand("ctrl+shift+r", cancel_recording); - //DeclareCommand("media record", start_stop_recording); +} // namespace - 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); +struct DataStruct { + DataStruct() { + t_assert(DataPtr == nullptr); + DataPtr = this; - DeclareCommand("ctrl+f", search); - DeclareAlias("search", search); - DeclareAlias("find", search); +#define DeclareAlias(keys, command) setShortcut(qsl(keys), qsl(#command)) +#define DeclareCommand(keys, command) createCommand(qsl(#command), ShortcutCommands::command); DeclareAlias(keys, command) - 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); - } + DeclareCommand("ctrl+w", close_telegram); + DeclareAlias("ctrl+f4", close_telegram); + DeclareCommand("ctrl+l", lock_telegram); + DeclareCommand("ctrl+m", minimize_telegram); + DeclareCommand("ctrl+q", quit_telegram); - // 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 DeclareAlias - } - QStringList errors; + } + QStringList errors; - QMap commands; - QMap commandnames; + QMap commands; + QMap commandnames; - QMap sequences; - QMap handlers; + QMap sequences; + QMap handlers; - QSet autoRepeatCommands = { - qsl("media_previous"), - qsl("media_next"), - qsl("next_chat"), - qsl("previous_chat"), - }; + QSet mediaShortcuts; + + QSet autoRepeatCommands = { + qsl("media_previous"), + qsl("media_next"), + qsl("next_chat"), + qsl("previous_chat"), }; - void _createCommand(const QString &command, ShortcutCommands::Handler handler) { - t_assert(DataPtr != nullptr); - t_assert(!command.isEmpty()); + QSet mediaCommands = { + qsl("media_play"), + qsl("media_pause"), + qsl("media_playpause"), + qsl("media_stop"), + qsl("media_previous"), + qsl("media_next") + }; +}; - DataPtr->commands.insert(command, handler); - DataPtr->commandnames.insert(handler, command); - } +namespace { - QKeySequence _setShortcut(const QString &keys, const QString &command) { - t_assert(DataPtr != nullptr); - t_assert(!command.isEmpty()); - if (keys.isEmpty()) return QKeySequence(); +void createCommand(const QString &command, ShortcutCommands::Handler handler) { + t_assert(DataPtr != nullptr); + t_assert(!command.isEmpty()); - QKeySequence seq(keys, QKeySequence::PortableText); - if (seq.isEmpty()) { - DataPtr->errors.push_back(qsl("Could not derive key sequence '%1'!").arg(keys)); + DataPtr->commands.insert(command, handler); + DataPtr->commandnames.insert(handler, command); +} + +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 { - auto it = DataPtr->commands.constFind(command); - if (it == DataPtr->commands.cend()) { - LOG(("Warning: could not find shortcut command handler '%1'").arg(command)); + auto shortcut = std_::make_unique(seq, App::wnd(), nullptr, nullptr, Qt::ApplicationShortcut); + if (!DataPtr->autoRepeatCommands.contains(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 { - QShortcut *shortcut(new QShortcut(seq, App::wnd(), nullptr, nullptr, Qt::ApplicationShortcut)); - if (!DataPtr->autoRepeatCommands.contains(command)) { - shortcut->setAutoRepeat(false); - } - int shortcutId = shortcut->id(); - if (!shortcutId) { - DataPtr->errors.push_back(qsl("Could not create shortcut '%1'!").arg(keys)); + auto seqIt = DataPtr->sequences.find(seq); + if (seqIt == DataPtr->sequences.cend()) { + seqIt = DataPtr->sequences.insert(seq, shortcut.release()); } else { - QMap::iterator seqIt = DataPtr->sequences.find(seq); - if (seqIt == DataPtr->sequences.cend()) { - seqIt = DataPtr->sequences.insert(seq, shortcut); - } else { - DataPtr->handlers.remove(seqIt.value()->id()); - delete seqIt.value(); - seqIt.value() = shortcut; - } - DataPtr->handlers.insert(shortcutId, it.value()); + auto oldShortcut = seqIt.value(); + seqIt.value() = shortcut.release(); + destroyShortcut(oldShortcut); + } + DataPtr->handlers.insert(shortcutId, it.value()); + if (isMediaShortcut) { + DataPtr->mediaShortcuts.insert(seqIt.value()); } } } - return seq; } + return seq; +} - QKeySequence _removeShortcut(const QString &keys) { - t_assert(DataPtr != nullptr); - if (keys.isEmpty()) return QKeySequence(); +QKeySequence removeShortcut(const QString &keys) { + t_assert(DataPtr != nullptr); + 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 { - QMap::iterator seqIt = DataPtr->sequences.find(seq); - if (seqIt != DataPtr->sequences.cend()) { - DataPtr->handlers.remove(seqIt.value()->id()); - delete seqIt.value(); - DataPtr->sequences.erase(seqIt); - } + QKeySequence seq(keys, QKeySequence::PortableText); + if (seq.isEmpty()) { + DataPtr->errors.push_back(qsl("Could not derive key sequence '%1'!").arg(keys)); + } else { + auto seqIt = DataPtr->sequences.find(seq); + if (seqIt != DataPtr->sequences.cend()) { + auto shortcut = seqIt.value(); + DataPtr->sequences.erase(seqIt); + destroyShortcut(shortcut); } - return seq; } + return seq; +} - void start() { - t_assert(Global::started()); +void destroyShortcut(QShortcut *shortcut) { + 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 - 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(); +} // namespace - 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; - } +void start() { + t_assert(Global::started()); + + new DataStruct(); + + // write default shortcuts to a file if they are not there already + 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\ // 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"; - defaultFile.write(defaultHeader); + defaultFile.write(defaultHeader); - QJsonArray shortcuts; + QJsonArray shortcuts; - QJsonObject version; - version.insert(qsl("version"), QString::number(AppVersion)); - shortcuts.push_back(version); + QJsonObject version; + version.insert(qsl("version"), QString::number(AppVersion)); + shortcuts.push_back(version); - for (QMap::const_iterator i = DataPtr->sequences.cbegin(), e = DataPtr->sequences.cend(); i != e; ++i) { - QMap::const_iterator h = DataPtr->handlers.constFind(i.value()->id()); - if (h != DataPtr->handlers.cend()) { - QMap::const_iterator n = DataPtr->commandnames.constFind(h.value()); - if (n != DataPtr->commandnames.cend()) { - QJsonObject entry; - entry.insert(qsl("keys"), i.key().toString().toLower()); - entry.insert(qsl("command"), n.value()); - shortcuts.append(entry); - } + for (auto i = DataPtr->sequences.cbegin(), e = DataPtr->sequences.cend(); i != e; ++i) { + auto h = DataPtr->handlers.constFind(i.value()->id()); + if (h != DataPtr->handlers.cend()) { + auto n = DataPtr->commandnames.constFind(h.value()); + if (n != DataPtr->commandnames.cend()) { + QJsonObject entry; + entry.insert(qsl("keys"), i.key().toString().toLower()); + entry.insert(qsl("command"), n.value()); + 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 - QFile customFile(cWorkingDir() + qsl("tdata/shortcuts-custom.json")); - if (customFile.exists()) { - if (customFile.open(QIODevice::ReadOnly)) { - QJsonParseError error = { 0, QJsonParseError::NoError }; - QJsonDocument doc = QJsonDocument::fromJson(_stripJsonComments(customFile.readAll()), &error); - customFile.close(); + QJsonDocument doc; + doc.setArray(shortcuts); + defaultFile.write(doc.toJson(QJsonDocument::Indented)); + defaultFile.close(); + } - if (error.error != QJsonParseError::NoError) { - 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")); + // read custom shortcuts from file if it exists or write an empty custom shortcuts file + QFile customFile(cWorkingDir() + qsl("tdata/shortcuts-custom.json")); + if (customFile.exists()) { + if (customFile.open(QIODevice::ReadOnly)) { + QJsonParseError error = { 0, QJsonParseError::NoError }; + QJsonDocument doc = QJsonDocument::fromJson(_stripJsonComments(customFile.readAll()), &error); + customFile.close(); + + if (error.error != QJsonParseError::NoError) { + 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 { - 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 { - seq = _setShortcut((*keys).toString(), (*command).toString()); - } - if (!--limit) { - DataPtr->errors.push_back(qsl("Too many entries! Limit is %1").arg(ShortcutsCountLimit)); - break; - } + 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()) { - DataPtr->errors.push_front(qsl("While reading file '%1'...").arg(customFile.fileName())); - } - } else if (customFile.open(QIODevice::WriteOnly)) { - const char *customContent = "\ + } else { + DataPtr->errors.push_back(qsl("Could not read the file!")); + } + if (!DataPtr->errors.isEmpty()) { + 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\ // 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\ @@ -447,41 +484,55 @@ namespace Shortcuts { // \"keys\": \"ctrl+q\"\n\ // }\n\ ]\n"; - customFile.write(customContent); - customFile.close(); - } + customFile.write(customContent); + customFile.close(); } - - const QStringList &errors() { - t_assert(DataPtr != nullptr); - return DataPtr->errors; - } - - bool launch(int shortcutId) { - t_assert(DataPtr != nullptr); - - QMap::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::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 diff --git a/Telegram/SourceFiles/shortcuts.h b/Telegram/SourceFiles/shortcuts.h index 8d2483dd1..bfb665e90 100644 --- a/Telegram/SourceFiles/shortcuts.h +++ b/Telegram/SourceFiles/shortcuts.h @@ -28,6 +28,12 @@ namespace Shortcuts { bool launch(int shortcutId); 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(); } From bb70a76b9c376c3981aecd4f1f302d84aa62ee95 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 14 Apr 2016 22:24:42 +0300 Subject: [PATCH 11/14] Several crashes fixed. --- Telegram/SourceFiles/app.cpp | 12 +-- Telegram/SourceFiles/application.cpp | 15 ++-- Telegram/SourceFiles/application.h | 9 +- .../SourceFiles/core/click_handler_types.cpp | 8 +- .../SourceFiles/dialogs/dialogs_layout.cpp | 4 +- Telegram/SourceFiles/dialogswidget.cpp | 7 +- Telegram/SourceFiles/facades.cpp | 18 +++- Telegram/SourceFiles/facades.h | 4 +- Telegram/SourceFiles/history.cpp | 70 +++++++++------ Telegram/SourceFiles/history.h | 6 +- Telegram/SourceFiles/historywidget.cpp | 88 ++++++++++--------- Telegram/SourceFiles/historywidget.h | 2 +- Telegram/SourceFiles/intro/introwidget.cpp | 49 ++++------- Telegram/SourceFiles/intro/introwidget.h | 23 +++-- Telegram/SourceFiles/mainwidget.cpp | 13 +-- Telegram/SourceFiles/mainwidget.h | 2 +- Telegram/SourceFiles/mainwindow.cpp | 12 +-- Telegram/SourceFiles/mainwindow.h | 3 +- Telegram/SourceFiles/profilewidget.cpp | 4 +- Telegram/SourceFiles/pspecific_mac.cpp | 4 +- Telegram/SourceFiles/settingswidget.cpp | 2 +- Telegram/SourceFiles/ui/text/text.h | 6 +- 22 files changed, 195 insertions(+), 166 deletions(-) diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index c227c243b..ec8db9052 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -1768,22 +1768,22 @@ namespace { void historyItemDetached(HistoryItem *item) { if (::hoveredItem == item) { - hoveredItem(0); + hoveredItem(nullptr); } if (::pressedItem == item) { - pressedItem(0); + pressedItem(nullptr); } if (::hoveredLinkItem == item) { - hoveredLinkItem(0); + hoveredLinkItem(nullptr); } if (::pressedLinkItem == item) { - pressedLinkItem(0); + pressedLinkItem(nullptr); } if (::contextItem == item) { - contextItem(0); + contextItem(nullptr); } if (::mousedItem == item) { - mousedItem(0); + mousedItem(nullptr); } if (App::wnd()) { App::wnd()->notifyItemRemoved(item); diff --git a/Telegram/SourceFiles/application.cpp b/Telegram/SourceFiles/application.cpp index a5d4a7334..906c8c7e7 100644 --- a/Telegram/SourceFiles/application.cpp +++ b/Telegram/SourceFiles/application.cpp @@ -90,14 +90,7 @@ namespace { AppClass *AppObject = 0; -Application::Application(int &argc, char **argv) : QApplication(argc, argv) -, _secondInstance(false) -#ifndef TDESKTOP_DISABLE_AUTOUPDATE -, _updateReply(0) -, _updateThread(0) -, _updateChecker(0) -#endif -{ +Application::Application(int &argc, char **argv) : QApplication(argc, argv) { QByteArray d(QFile::encodeName(QDir(cWorkingDir()).absolutePath())); char h[33] = { 0 }; hashMd5Hex(d.constData(), d.size(), h); @@ -905,6 +898,12 @@ void AppClass::call_handleHistoryUpdate() { Notify::handlePendingHistoryUpdate(); } +void AppClass::call_handleUnreadCounterUpdate() { + if (auto w = App::wnd()) { + w->updateUnreadCounter(); + } +} + void AppClass::killDownloadSessions() { uint64 ms = getms(), left = MTPAckSendWaiting + MTPKillFileSessionTimeout; for (QMap::iterator i = killDownloadSessionTimes.begin(); i != killDownloadSessionTimes.end(); ) { diff --git a/Telegram/SourceFiles/application.h b/Telegram/SourceFiles/application.h index 774ebc85b..f894102fe 100644 --- a/Telegram/SourceFiles/application.h +++ b/Telegram/SourceFiles/application.h @@ -56,7 +56,7 @@ private: QLocalServer _localServer; QLocalSocket _localSocket; LocalClients _localClients; - bool _secondInstance; + bool _secondInstance = false; void singleInstanceChecked(); @@ -98,10 +98,10 @@ public slots: private: SingleTimer _updateCheckTimer; - QNetworkReply *_updateReply; + QNetworkReply *_updateReply = nullptr; QNetworkAccessManager _updateManager; - QThread *_updateThread; - UpdateChecker *_updateChecker; + QThread *_updateThread = nullptr; + UpdateChecker *_updateChecker = nullptr; #endif }; @@ -202,6 +202,7 @@ public slots: void onAppStateChanged(Qt::ApplicationState state); void call_handleHistoryUpdate(); + void call_handleUnreadCounterUpdate(); private: diff --git a/Telegram/SourceFiles/core/click_handler_types.cpp b/Telegram/SourceFiles/core/click_handler_types.cpp index 3c317c3dd..5bbf2df64 100644 --- a/Telegram/SourceFiles/core/click_handler_types.cpp +++ b/Telegram/SourceFiles/core/click_handler_types.cpp @@ -124,8 +124,14 @@ void HashtagClickHandler::onClick(Qt::MouseButton button) const { 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, _cmd); + App::sendBotCommand(peer, bot, _cmd); } else { App::insertBotCommand(_cmd); } diff --git a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp index 64671379c..081463267 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp @@ -132,10 +132,10 @@ QImage colorizeCircleHalf(int size, int half, int xoffset, style::color color) { 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; - QImage result(size, size, QImage::Format_ARGB32_Premultiplied); + QImage result(half, size, QImage::Format_ARGB32_Premultiplied); uchar *bits = result.bits(), *maskbits = unreadBadgeStyle->circle.bits(); 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) { int s = y * bpl + (x * 4); int o = maskbits[y * maskbpl + x + xoffset] + 1; diff --git a/Telegram/SourceFiles/dialogswidget.cpp b/Telegram/SourceFiles/dialogswidget.cpp index 1f0aa382f..f6447d0a4 100644 --- a/Telegram/SourceFiles/dialogswidget.cpp +++ b/Telegram/SourceFiles/dialogswidget.cpp @@ -1028,7 +1028,7 @@ void DialogsInner::dialogsReceived(const QVector &added) { } } - if (App::wnd()) App::wnd()->updateCounter(); + Notify::unreadCounterUpdated(); if (!_sel && !shownDialogs()->isEmpty()) { _sel = *shownDialogs()->cbegin(); _importantSwitchSel = false; @@ -1936,7 +1936,7 @@ void DialogsWidget::unreadCountsReceived(const QVector &dialogs) { if (History *h = App::historyLoaded(peerFromMTP(d.vpeer))) { App::main()->applyNotifySetting(MTP_notifyPeer(d.vpeer), d.vnotify_settings, h); 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; } } @@ -1954,14 +1954,13 @@ void DialogsWidget::unreadCountsReceived(const QVector &dialogs) { App::main()->applyNotifySetting(MTP_notifyPeer(d.vpeer), d.vnotify_settings, h); int32 unreadCount = h->isMegagroup() ? d.vunread_count.v : d.vunread_important_count.v; if (unreadCount >= h->unreadCount()) { - h->setUnreadCount(unreadCount, false); + h->setUnreadCount(unreadCount); h->inboxReadBefore = d.vread_inbox_max_id.v + 1; } } } break; } } - if (App::wnd()) App::wnd()->updateCounter(); } void DialogsWidget::dialogsReceived(const MTPmessages_Dialogs &dialogs, mtpRequestId req) { diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index 60aa53e2e..4932f1887 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -33,12 +33,16 @@ Q_DECLARE_METATYPE(Qt::MouseButton); namespace App { -void sendBotCommand(PeerData *peer, const QString &cmd, MsgId replyTo) { - if (MainWidget *m = main()) m->sendBotCommand(peer, cmd, replyTo); +void sendBotCommand(PeerData *peer, UserData *bot, const QString &cmd, MsgId replyTo) { + if (auto m = main()) { + m->sendBotCommand(peer, bot, cmd, replyTo); + } } 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; } @@ -59,7 +63,7 @@ void activateBotCommand(const HistoryItem *msg, int row, int col) { // Copy string before passing it to the sending method // because the original button can be destroyed inside. 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; case HistoryMessageReplyMarkup::Button::Callback: { @@ -326,6 +330,10 @@ void handlePendingHistoryUpdate() { Global::RefPendingRepaintItems().clear(); } +void unreadCounterUpdated() { + Global::RefHandleUnreadCounterUpdate().call(); +} + } // namespace Notify #define DefineReadOnlyVar(Namespace, Type, Name) const Type &Name() { \ @@ -479,6 +487,7 @@ namespace internal { struct Data { uint64 LaunchId = 0; SingleDelayedCall HandleHistoryUpdate = { App::app(), "call_handleHistoryUpdate" }; + SingleDelayedCall HandleUnreadCounterUpdate = { App::app(), "call_handleUnreadCounterUpdate" }; Adaptive::Layout AdaptiveLayout = Adaptive::NormalLayout; bool AdaptiveForWide = true; @@ -541,6 +550,7 @@ void finish() { DefineReadOnlyVar(Global, uint64, LaunchId); DefineRefVar(Global, SingleDelayedCall, HandleHistoryUpdate); +DefineRefVar(Global, SingleDelayedCall, HandleUnreadCounterUpdate); DefineVar(Global, Adaptive::Layout, AdaptiveLayout); DefineVar(Global, bool, AdaptiveForWide); diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index a8bf6fbb1..412c0d65a 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -24,7 +24,7 @@ class LayeredWidget; 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); void activateBotCommand(const HistoryItem *msg, int row, int col); void searchByHashtag(const QString &tag, PeerData *inPeer); @@ -116,6 +116,7 @@ void historyMuteUpdated(History *history); // handle pending resize() / paint() on history items void handlePendingHistoryUpdate(); +void unreadCounterUpdated(); } // namespace Notify @@ -184,6 +185,7 @@ void finish(); DeclareReadOnlyVar(uint64, LaunchId); DeclareRefVar(SingleDelayedCall, HandleHistoryUpdate); +DeclareRefVar(SingleDelayedCall, HandleUnreadCounterUpdate); DeclareVar(Adaptive::Layout, AdaptiveLayout); DeclareVar(bool, AdaptiveForWide); diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index ec27218e1..7970cfbe2 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -325,9 +325,7 @@ void ChannelHistory::insertCollapseItem(MsgId wasMinId) { HistoryItem *item = block->items.at(itemIndex); if (insertAfter || item->id > wasMinId || (item->id == wasMinId && !item->isImportant())) { _collapseMessage = HistoryCollapse::create((History*)this, wasMinId, item->date); - if (!addNewInTheMiddle(_collapseMessage, blockIndex, itemIndex)) { - _collapseMessage = 0; - } + addNewInTheMiddle(_collapseMessage, blockIndex, itemIndex); return; } else if (item->id == wasMinId && item->isImportant()) { insertAfter = true; @@ -663,16 +661,19 @@ void ChannelHistory::switchMode() { checkJoinedMessage(); } -void ChannelHistory::cleared() { - _collapseMessage = 0; - _joinedMessage = 0; +void ChannelHistory::cleared(bool leaveItems) { + _collapseMessage = nullptr; + _joinedMessage = nullptr; + if (!leaveItems) { + _otherList.clear(); + } } HistoryGroup *ChannelHistory::findGroup(MsgId msgId) const { // find message group using binary search if (!_onlyImportant) return findGroupInOther(msgId); HistoryBlock *block = findGroupBlock(msgId); - if (!block) return 0; + if (!block) return nullptr; int32 itemIndex = 0; if (block->items.size() > 1) for (int32 minItem = 0, maxItem = block->items.size();;) { @@ -698,10 +699,14 @@ HistoryGroup *ChannelHistory::findGroup(MsgId msgId) const { // find message gro } } - HistoryItem *item = block->items.at(itemIndex); - if (item->type() != HistoryItemGroup) return 0; - HistoryGroup *result = static_cast(item); - return (result->minId() < msgId && result->maxId() > msgId) ? result : 0; + auto item = block->items.at(itemIndex); + if (item->type() == HistoryItemGroup) { + auto result = static_cast(item); + if (result->minId() < msgId && result->maxId() > msgId) { + return result; + } + } + return nullptr; } HistoryBlock *ChannelHistory::findGroupBlock(MsgId msgId) const { // find block with message group using binary search @@ -838,7 +843,7 @@ History *Histories::findOrInsert(const PeerId &peerId, int32 unreadCount, int32 Map::const_iterator i = map.constFind(peerId); if (i == map.cend()) { i = map.insert(peerId, peerIsChannel(peerId) ? static_cast(new ChannelHistory(peerId)) : (new History(peerId))); - i.value()->setUnreadCount(unreadCount, false); + i.value()->setUnreadCount(unreadCount); i.value()->inboxReadBefore = maxInboxRead + 1; } return i.value(); @@ -846,18 +851,17 @@ History *Histories::findOrInsert(const PeerId &peerId, int32 unreadCount, int32 void Histories::clear() { App::historyClearMsgs(); - for (Map::const_iterator i = map.cbegin(), e = map.cend(); i != e; ++i) { - delete i.value(); + + Map temp; + std::swap(temp, map); + for_const (auto history, temp) { + delete history; } - Global::RefPendingRepaintItems().clear(); _unreadFull = _unreadMuted = 0; - if (App::wnd()) { - App::wnd()->updateCounter(); - } + Notify::unreadCounterUpdated(); App::historyClearItems(); typing.clear(); - map.clear(); } void Histories::regSendAction(History *history, UserData *user, const MTPSendMessageAction &action) { @@ -1742,7 +1746,7 @@ HistoryItem *History::lastImportantMessage() const { return nullptr; } -void History::setUnreadCount(int newUnreadCount, bool psUpdate) { +void History::setUnreadCount(int newUnreadCount) { if (_unreadCount != newUnreadCount) { if (newUnreadCount == 1) { if (loadedAtBottom()) showFrom = lastImportantMessage(); @@ -1753,8 +1757,8 @@ void History::setUnreadCount(int newUnreadCount, bool psUpdate) { } if (inChatList(Dialogs::Mode::All)) { App::histories().unreadIncrement(newUnreadCount - _unreadCount, mute()); - if (psUpdate && (!mute() || cIncludeMuted()) && App::wnd()) { - App::wnd()->updateCounter(); + if (!mute() || cIncludeMuted()) { + Notify::unreadCounterUpdated(); } } _unreadCount = newUnreadCount; @@ -1780,7 +1784,7 @@ void History::setUnreadCount(int newUnreadCount, bool psUpdate) { if (inChatList(Dialogs::Mode::All)) { if (_unreadCount) { App::histories().unreadMuteChanged(_unreadCount, newMute); - if (App::wnd()) App::wnd()->updateCounter(); + Notify::unreadCounterUpdated(); } Notify::historyMuteUpdated(this); } @@ -2179,6 +2183,15 @@ void History::clear(bool leaveItems) { } if (!leaveItems) { setLastMessage(nullptr); + notifies.clear(); + auto &pending = Global::RefPendingRepaintItems(); + for (auto i = pending.begin(); i != pending.end();) { + if ((*i)->history() == this) { + i = pending.erase(i); + } else { + ++i; + } + } } for (int32 i = 0; i < OverviewCount; ++i) { if (!overview[i].isEmpty() || !overviewIds[i].isEmpty()) { @@ -2199,6 +2212,10 @@ void History::clear(bool leaveItems) { lastKeyboardInited = false; } else { setUnreadCount(0); + if (peer->isMegagroup()) { + peer->asChannel()->mgInfo->pinnedMsgId = 0; + } + clearLastKeyboard(); } setPendingResize(); @@ -2209,7 +2226,7 @@ void History::clear(bool leaveItems) { peer->asChat()->lastAuthors.clear(); peer->asChat()->markupSenders.clear(); } else if (isChannel()) { - asChannelHistory()->cleared(); + asChannelHistory()->cleared(leaveItems); if (isMegagroup()) { peer->asChannel()->mgInfo->markupSenders.clear(); } @@ -2251,7 +2268,7 @@ Dialogs::Row *History::addToChatList(Dialogs::Mode list, Dialogs::IndexedList *i chatListLinks(list) = indexed->addToEnd(this); if (list == Dialogs::Mode::All && unreadCount()) { App::histories().unreadIncrement(unreadCount(), mute()); - if (App::wnd()) App::wnd()->updateCounter(); + Notify::unreadCounterUpdated(); } } return mainChatListLink(list); @@ -2264,7 +2281,7 @@ void History::removeFromChatList(Dialogs::Mode list, Dialogs::IndexedList *index chatListLinks(list).clear(); if (list == Dialogs::Mode::All && unreadCount()) { App::histories().unreadIncrement(-unreadCount(), mute()); - if (App::wnd()) App::wnd()->updateCounter(); + Notify::unreadCounterUpdated(); } } } @@ -2994,6 +3011,7 @@ void HistoryItem::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pres } void HistoryItem::destroy() { + // All this must be done for all items manually in History::clear(false)! bool wasAtBottom = history()->loadedAtBottom(); _history->removeNotification(this); detach(); diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index de909ffd0..81314ee64 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -255,7 +255,7 @@ public: int unreadCount() const { return _unreadCount; } - void setUnreadCount(int newUnreadCount, bool psUpdate = true); + void setUnreadCount(int newUnreadCount); bool mute() const { return _mute; } @@ -642,7 +642,7 @@ private: HistoryItem *findPrevItem(HistoryItem *item) const; void switchMode(); - void cleared(); + void cleared(bool leaveItems); bool _onlyImportant; @@ -2637,7 +2637,7 @@ public: HistoryItem::clickHandlerActiveChanged(p, active); } void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override { - if (_media) _media->clickHandlerActiveChanged(p, pressed); + if (_media) _media->clickHandlerPressedChanged(p, pressed); HistoryItem::clickHandlerPressedChanged(p, pressed); } diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index c5556bb25..59c6ae8ec 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -2260,8 +2260,7 @@ void BotKeyboard::enterEvent(QEvent *e) { } void BotKeyboard::leaveEvent(QEvent *e) { - _lastMousePos = QPoint(-1, -1); - updateSelected(); + clearSelection(); } void BotKeyboard::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { @@ -2275,44 +2274,43 @@ void BotKeyboard::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pres } bool BotKeyboard::updateMarkup(HistoryItem *to, bool force) { - if (to && to->definesReplyKeyboard()) { - if (_wasForMsgId == FullMsgId(to->channelId(), to->id) && !force) { - return false; + if (!to || !to->definesReplyKeyboard()) { + if (_wasForMsgId.msg) { + _maximizeSize = _singleUse = _forceReply = false; + _wasForMsgId = FullMsgId(); + _impl = nullptr; + return true; } - - _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()) { - if (!markup->rows.isEmpty()) { - _impl.reset(new ReplyKeyboard(to, std_::make_unique