mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-06 23:24:01 +02:00
merged with master
This commit is contained in:
commit
f3e560541b
152 changed files with 22341 additions and 10852 deletions
|
@ -11,6 +11,7 @@ This document describes how you can contribute to Telegram Desktop. Please read
|
|||
* [Pull upstream changes into your fork regularly](#pull-upstream-changes-into-your-fork-regularly)
|
||||
* [How to get your pull request accepted](#how-to-get-your-pull-request-accepted)
|
||||
* [Keep your pull requests limited to a single issue](#keep-your-pull-requests-limited-to-a-single-issue)
|
||||
* [Squash your commits to a single commit](#squash-your-commits-to-a-single-commit)
|
||||
* [Don't mix code changes with whitespace cleanup](#dont-mix-code-changes-with-whitespace-cleanup)
|
||||
* [Keep your code simple!](#keep-your-code-simple)
|
||||
* [Test your changes!](#test-your-changes)
|
||||
|
@ -107,6 +108,21 @@ Pull requests should be as small/atomic as possible. Large, wide-sweeping change
|
|||
* If you are making spelling corrections in the docs, don't modify other files.
|
||||
* If you are adding new functions don't '*cleanup*' unrelated functions. That cleanup belongs in another pull request.
|
||||
|
||||
#### Squash your commits to a single commit
|
||||
|
||||
To keep the history of the project clean, you should make one commit per pull request.
|
||||
If you already have multiple commits, you can add the commits together (squash them) with the following commands in Git Bash:
|
||||
|
||||
1. Open `Git Bash` (or `Git Shell`)
|
||||
2. Enter following command to squash the recent {N} commits: `git reset --soft HEAD~{N} && git commit` (replace `{N}` with the number of commits you want to squash)
|
||||
3. Press <kbd>i</kbd> to get into Insert-mode
|
||||
4. Enter the commit message of the new commit (and add the [signature](#sign-your-work) at the and)
|
||||
5. After adding the message, press <kbd>ESC</kbd> to get out of the Insert-mode
|
||||
6. Write `:wq` and press <kbd>Enter</kbd> to save the new message or write `:q!` to discard your changes
|
||||
7. Enter `git push --force` to push the new commit to the remote repository
|
||||
|
||||
For example, if you want to squash the last 5 commits, use `git reset --soft HEAD~5 && git commit`
|
||||
|
||||
### Don't mix code changes with whitespace cleanup
|
||||
|
||||
If you change two lines of code and correct 200 lines of whitespace issues in a file the diff on that pull request is functionally unreadable and will be **rejected**. Whitespace cleanups need to be in their own pull request.
|
||||
|
|
4
MSVC.md
4
MSVC.md
|
@ -141,7 +141,7 @@ Open **VS2015 x86 Native Tools Command Prompt.bat** (should be in **Start Menu >
|
|||
|
||||
PKG_CONFIG_PATH="/mingw64/lib/pkgconfig:$PKG_CONFIG_PATH"
|
||||
|
||||
./configure --toolchain=msvc --disable-programs --disable-everything --enable-libopus --enable-decoder=aac --enable-decoder=aac_latm --enable-decoder=aasc --enable-decoder=mp1 --enable-decoder=mp1float --enable-decoder=mp2 --enable-decoder=mp2float --enable-decoder=mp3 --enable-decoder=mp3adu --enable-decoder=mp3adufloat --enable-decoder=mp3float --enable-decoder=mp3on4 --enable-decoder=mp3on4float --enable-decoder=wavpack --enable-decoder=opus --enable-decoder=vorbis --enable-decoder=wmalossless --enable-decoder=wmapro --enable-decoder=wmav1 --enable-decoder=wmav2 --enable-decoder=wmavoice --enable-decoder=flac --enable-encoder=libopus --enable-parser=aac --enable-parser=aac_latm --enable-parser=mpegaudio --enable-parser=opus --enable-parser=vorbis --enable-parser=flac --enable-demuxer=aac --enable-demuxer=wav --enable-demuxer=mp3 --enable-demuxer=ogg --enable-demuxer=mov --enable-demuxer=flac --enable-muxer=ogg --enable-muxer=opus --extra-ldflags="-libpath:/d/TBuild/Libraries/opus/win32/VS2010/Win32/Release celt.lib silk_common.lib silk_float.lib"
|
||||
./configure --toolchain=msvc --disable-programs --disable-doc --disable-everything --disable-w32threads --enable-libopus --enable-decoder=aac --enable-decoder=aac_latm --enable-decoder=aasc --enable-decoder=flac --enable-decoder=gif --enable-decoder=h264 --enable-decoder=mp1 --enable-decoder=mp1float --enable-decoder=mp2 --enable-decoder=mp2float --enable-decoder=mp3 --enable-decoder=mp3adu --enable-decoder=mp3adufloat --enable-decoder=mp3float --enable-decoder=mp3on4 --enable-decoder=mp3on4float --enable-decoder=mpeg4 --enable-decoder=msmpeg4v2 --enable-decoder=msmpeg4v3 --enable-decoder=wavpack --enable-decoder=opus --enable-decoder=vorbis --enable-decoder=wmalossless --enable-decoder=wmapro --enable-decoder=wmav1 --enable-decoder=wmav2 --enable-decoder=wmavoice --enable-encoder=libopus --enable-hwaccel=h264_d3d11va --enable-hwaccel=h264_dxva2 --enable-parser=aac --enable-parser=aac_latm --enable-parser=flac --enable-parser=h264 --enable-parser=mpeg4video --enable-parser=mpegaudio --enable-parser=opus --enable-parser=vorbis --enable-demuxer=aac --enable-demuxer=flac --enable-demuxer=gif --enable-demuxer=h264 --enable-demuxer=mov --enable-demuxer=mp3 --enable-demuxer=ogg --enable-demuxer=wav --enable-muxer=ogg --enable-muxer=opus --extra-ldflags="-libpath:/d/TBuild/Libraries/opus/win32/VS2010/Win32/Release celt.lib silk_common.lib silk_float.lib"
|
||||
|
||||
make
|
||||
make install
|
||||
|
@ -169,7 +169,7 @@ and run
|
|||
#####Apply the patch
|
||||
|
||||
cd qtbase && git apply ../../../tdesktop/Telegram/_qtbase_5_5_1_patch.diff && cd ..
|
||||
|
||||
|
||||
|
||||
#####Install Windows SDKs
|
||||
|
||||
|
|
15
QTCREATOR.md
15
QTCREATOR.md
|
@ -44,13 +44,24 @@ Download [opus-1.1 sources](http://downloads.xiph.org/releases/opus/opus-1.1.tar
|
|||
|
||||
####FFmpeg
|
||||
|
||||
Download sources [ffmpeg-2.6.3.tar.bz2](http://ffmpeg.org/releases/ffmpeg-2.6.3.tar.bz2) from https://www.ffmpeg.org/download.html, extract to **/home/user/TBuild/Libraries** to have **/home/user/TBuild/Libraries/ffmpeg-2.6.3**, go to **/home/user/TBuild/Libraries/ffmpeg-2.6.3** and run
|
||||
In Terminal go to **/home/user/TBuild/Libraries** and run
|
||||
|
||||
git clone git://anongit.freedesktop.org/git/libva
|
||||
cd libva
|
||||
./autogen.sh --enable-static
|
||||
make
|
||||
sudo make install
|
||||
cd ..
|
||||
|
||||
git clone https://github.com/FFmpeg/FFmpeg.git ffmpeg
|
||||
cd ffmpeg
|
||||
git checkout release/2.8
|
||||
|
||||
sudo apt-get update
|
||||
sudo apt-get -y --force-yes install autoconf automake build-essential libass-dev libfreetype6-dev libgpac-dev libsdl1.2-dev libtheora-dev libtool libva-dev libvdpau-dev libvorbis-dev libxcb1-dev libxcb-shm0-dev libxcb-xfixes0-dev pkg-config texi2html zlib1g-dev
|
||||
sudo apt-get install yasm
|
||||
|
||||
./configure --prefix=/usr/local --disable-programs --disable-everything --enable-libopus --enable-decoder=aac --enable-decoder=aac_latm --enable-decoder=aasc --enable-decoder=mp1 --enable-decoder=mp1float --enable-decoder=mp2 --enable-decoder=mp2float --enable-decoder=mp3 --enable-decoder=mp3adu --enable-decoder=mp3adufloat --enable-decoder=mp3float --enable-decoder=mp3on4 --enable-decoder=mp3on4float --enable-decoder=wavpack --enable-decoder=opus --enable-decoder=vorbis --enable-decoder=wmalossless --enable-decoder=wmapro --enable-decoder=wmav1 --enable-decoder=wmav2 --enable-decoder=wmavoice --enable-decoder=flac --enable-encoder=libopus --enable-parser=aac --enable-parser=aac_latm --enable-parser=mpegaudio --enable-parser=opus --enable-parser=vorbis --enable-parser=flac --enable-demuxer=aac --enable-demuxer=wav --enable-demuxer=mp3 --enable-demuxer=ogg --enable-demuxer=mov --enable-demuxer=flac --enable-muxer=ogg --enable-muxer=opus
|
||||
./configure --prefix=/usr/local --disable-programs --disable-doc --disable-pthreads --disable-mmx --disable-everything --enable-libopus --enable-decoder=aac --enable-decoder=aac_latm --enable-decoder=aasc --enable-decoder=flac --enable-decoder=gif --enable-decoder=h264 --enable-decoder=h264_vdpau --enable-decoder=mp1 --enable-decoder=mp1float --enable-decoder=mp2 --enable-decoder=mp2float --enable-decoder=mp3 --enable-decoder=mp3adu --enable-decoder=mp3adufloat --enable-decoder=mp3float --enable-decoder=mp3on4 --enable-decoder=mp3on4float --enable-decoder=mpeg4 --enable-decoder=mpeg4_vdpau --enable-decoder=msmpeg4v2 --enable-decoder=msmpeg4v3 --enable-decoder=opus --enable-decoder=vorbis --enable-decoder=wavpack --enable-decoder=wmalossless --enable-decoder=wmapro --enable-decoder=wmav1 --enable-decoder=wmav2 --enable-decoder=wmavoice --enable-encoder=libopus --enable-hwaccel=h264_vaapi --enable-hwaccel=h264_vdpau --enable-hwaccel=mpeg4_vaapi --enable-hwaccel=mpeg4_vdpau --enable-parser=aac --enable-parser=aac_latm --enable-parser=flac --enable-parser=h264 --enable-parser=mpeg4video --enable-parser=mpegaudio --enable-parser=opus --enable-parser=vorbis --enable-demuxer=aac --enable-demuxer=flac --enable-demuxer=gif --enable-demuxer=h264 --enable-demuxer=mov --enable-demuxer=mp3 --enable-demuxer=ogg --enable-demuxer=wav --enable-muxer=ogg --enable-muxer=opus
|
||||
|
||||
make
|
||||
sudo make install
|
||||
|
|
|
@ -31,6 +31,10 @@ set "DeployPath=%ReleasePath%\deploy\%AppVersionStrMajor%\%AppVersionStrFull%"
|
|||
set "SignPath=..\..\TelegramPrivate\Sign.bat"
|
||||
|
||||
if %BetaVersion% neq 0 (
|
||||
if exist %DeployPath%\ (
|
||||
echo Deploy folder for version %AppVersionStr% already exists!
|
||||
exit /b 1
|
||||
)
|
||||
if exist %ReleasePath%\%BetaKeyFile% (
|
||||
echo Beta version key file for version %AppVersion% already exists!
|
||||
exit /b 1
|
||||
|
@ -40,19 +44,21 @@ if %BetaVersion% neq 0 (
|
|||
echo Deploy folder for version %AppVersionStr%.dev already exists!
|
||||
exit /b 1
|
||||
)
|
||||
if exist %ReleasePath%\deploy\%AppVersionStrMajor%\%AppVersionStr%\ (
|
||||
echo Deploy folder for version %AppVersionStr% already exists!
|
||||
exit /b 1
|
||||
)
|
||||
if exist %ReleasePath%\tupdate%AppVersion% (
|
||||
echo Update file for version %AppVersion% already exists!
|
||||
exit /b 1
|
||||
)
|
||||
)
|
||||
|
||||
if exist %ReleasePath%\deploy\%AppVersionStrMajor%\%AppVersionStr%\ (
|
||||
echo Deploy folder for version %AppVersionStr% already exists!
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
cd SourceFiles\
|
||||
rem copy telegram.qrc /B+,,/Y
|
||||
if "%1" == "fast" (
|
||||
echo Skipping touching of telegram.qrc..
|
||||
) else (
|
||||
copy telegram.qrc /B+,,/Y
|
||||
)
|
||||
cd ..\
|
||||
if %errorlevel% neq 0 goto error
|
||||
|
||||
|
@ -149,7 +155,7 @@ xcopy %DeployPath%\%PortableFile% %FinalDeployPath%\
|
|||
if %BetaVersion% equ 0 (
|
||||
xcopy %DeployPath%\%SetupFile% %FinalDeployPath%\
|
||||
) else (
|
||||
xcopy %DeployPath%\%BetaKeyFile% %FinalDeployPath%\
|
||||
xcopy %DeployPath%\%BetaKeyFile% %FinalDeployPath%\ /Y
|
||||
)
|
||||
xcopy %DeployPath%\Telegram.pdb %FinalDeployPath%\
|
||||
xcopy %DeployPath%\Updater.exe %FinalDeployPath%\
|
||||
|
|
|
@ -27,4 +27,6 @@ Replace '\-lopenal' '\/usr\/local\/lib\/libopenal\.a'
|
|||
Replace '\-lavformat' '\/usr\/local\/lib\/libavformat\.a'
|
||||
Replace '\-lavcodec' '\/usr\/local\/lib\/libavcodec\.a'
|
||||
Replace '\-lswresample' '\/usr\/local\/lib\/libswresample\.a'
|
||||
Replace '\-lswscale' '\/usr\/local\/lib\/libswscale\.a'
|
||||
Replace '\-lavutil' '\/usr\/local\/lib\/libavutil\.a'
|
||||
Replace '\-lva' '\/usr\/local\/lib\/libva\.a'
|
||||
|
|
|
@ -27,4 +27,6 @@ Replace '\-lopenal' '\/usr\/local\/lib\/libopenal\.a'
|
|||
Replace '\-lavformat' '\/usr\/local\/lib\/libavformat\.a'
|
||||
Replace '\-lavcodec' '\/usr\/local\/lib\/libavcodec\.a'
|
||||
Replace '\-lswresample' '\/usr\/local\/lib\/libswresample\.a'
|
||||
Replace '\-lswscale' '\/usr\/local\/lib\/libswscale\.a'
|
||||
Replace '\-lavutil' '\/usr\/local\/lib\/libavutil\.a'
|
||||
Replace '\-lva' '\/usr\/local\/lib\/libva\.a'
|
||||
|
|
|
@ -48,6 +48,19 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_month11" = "November";
|
||||
"lng_month12" = "December";
|
||||
|
||||
"lng_month1_small" = "Jan";
|
||||
"lng_month2_small" = "Feb";
|
||||
"lng_month3_small" = "Mar";
|
||||
"lng_month4_small" = "Apr";
|
||||
"lng_month5_small" = "May";
|
||||
"lng_month6_small" = "Jun";
|
||||
"lng_month7_small" = "Jul";
|
||||
"lng_month8_small" = "Aug";
|
||||
"lng_month9_small" = "Sep";
|
||||
"lng_month10_small" = "Oct";
|
||||
"lng_month11_small" = "Nov";
|
||||
"lng_month12_small" = "Dec";
|
||||
|
||||
"lng_weekday1" = "Mon";
|
||||
"lng_weekday2" = "Tue";
|
||||
"lng_weekday3" = "Wed";
|
||||
|
@ -66,6 +79,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
|
||||
"lng_month_day" = "{month} {day}";
|
||||
"lng_month_day_year" = "{month} {day}, {year}";
|
||||
"lng_month_year" = "{month}, {year}";
|
||||
|
||||
"lng_box_ok" = "OK";
|
||||
|
||||
|
@ -108,6 +122,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
|
||||
"lng_server_error" = "Internal server error.";
|
||||
"lng_flood_error" = "Too many tries. Please try again later.";
|
||||
"lng_gif_error" = "An error has occured while reading GIF animation :(";
|
||||
"lng_deleted" = "Unknown";
|
||||
"lng_deleted_message" = "Deleted message";
|
||||
|
||||
|
@ -470,8 +485,8 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_create_channel_crop" = "Select a square area for channel photo";
|
||||
|
||||
"lng_failed_add_participant" = "Could not add user. Please try again later.";
|
||||
"lng_failed_add_not_mutual" = "Sorry, if a person leaves a group, only a\nmutual contact can bring them back\n(they need to have your phone\nnumber, and you need theirs).";
|
||||
"lng_failed_add_not_mutual_channel" = "Sorry, if a person leaves a channel, only a\nmutual contact can bring them back\n(they need to have your phone\nnumber, and you need theirs).";
|
||||
"lng_failed_add_not_mutual" = "Sorry, if a person leaves a group, only a mutual contact can bring them back (they need to have your phone number, and you need theirs).";
|
||||
"lng_failed_add_not_mutual_channel" = "Sorry, if a person leaves a channel, only a mutual contact can bring them back (they need to have your phone number, and you need theirs).";
|
||||
|
||||
"lng_sure_delete_contact" = "Are you sure, you want to delete {contact} from your contact list?";
|
||||
"lng_sure_delete_history" = "Are you sure, you want to delete all message history with {contact}?\n\nThis action cannot be undone.";
|
||||
|
@ -483,7 +498,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_sure_delete_group" = "Are you sure, you want to delete this group? All members will be removed and all messages will be lost.";
|
||||
|
||||
"lng_message_empty" = "Empty Message";
|
||||
"lng_media_unsupported" = "Media Unsupported";
|
||||
"lng_message_unsupported" = "This message is not supported by your version of Telegram Desktop. Please update to the last version in Settings or install it from {link}";
|
||||
|
||||
"lng_action_add_user" = "{from} added {user}";
|
||||
"lng_action_add_users_many" = "{from} added {users}";
|
||||
|
@ -561,6 +576,14 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_media_video" = "Video file";
|
||||
"lng_media_audio" = "Voice message";
|
||||
|
||||
"lng_media_auto_settings" = "Automatic media download settings";
|
||||
"lng_media_auto_photo" = "Automatic photo download";
|
||||
"lng_media_auto_audio" = "Automatic voice message download";
|
||||
"lng_media_auto_gif" = "Automatic GIF download";
|
||||
"lng_media_auto_private_chats" = "Private chats";
|
||||
"lng_media_auto_groups" = "Groups and channels";
|
||||
"lng_media_auto_play" = "Autoplay";
|
||||
|
||||
"lng_emoji_category0" = "Frequently used";
|
||||
"lng_emoji_category1" = "People";
|
||||
"lng_emoji_category2" = "Nature";
|
||||
|
@ -571,8 +594,14 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_emoji_category7" = "Symbols & Flags";
|
||||
|
||||
"lng_switch_stickers" = "Stickers";
|
||||
"lng_switch_stickers_gifs" = "GIFs & Stickers";
|
||||
"lng_switch_emoji" = "Emoji";
|
||||
|
||||
"lng_saved_gifs" = "Saved GIFs";
|
||||
"lng_inline_bot_results" = "Results from {inline_bot}";
|
||||
"lng_inline_bot_no_results" = "No results";
|
||||
"lng_inline_bot_via" = "via {inline_bot}";
|
||||
|
||||
"lng_box_remove" = "Remove";
|
||||
|
||||
"lng_custom_stickers" = "Custom stickers";
|
||||
|
@ -664,6 +693,8 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_save_file" = "Save file";
|
||||
"lng_save_downloaded" = "{ready} / {total} {mb}";
|
||||
"lng_duration_and_size" = "{duration}, {size}";
|
||||
"lng_duration_played" = "{played} / {duration}";
|
||||
"lng_date_and_duration" = "{date}, {duration}";
|
||||
"lng_choose_images" = "Choose images";
|
||||
|
||||
"lng_context_view_profile" = "View profile";
|
||||
|
@ -699,6 +730,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_context_delete_file" = "Delete File";
|
||||
"lng_context_close_file" = "Close File";
|
||||
"lng_context_copy_text" = "Copy Text";
|
||||
"lng_context_save_gif" = "Save GIF";
|
||||
"lng_context_to_msg" = "Go To Message";
|
||||
"lng_context_reply_msg" = "Reply";
|
||||
"lng_context_forward_msg" = "Forward Message";
|
||||
|
@ -762,7 +794,8 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_selected_delete" = "Delete";
|
||||
"lng_selected_forward" = "Forward";
|
||||
"lng_selected_count" = "{count:_not_used_|# message|# messages}";
|
||||
"lng_selected_cancel_sure_this" = "Do you want to cancel this upload?";
|
||||
"lng_selected_cancel_sure_this" = "Cancel uploading?";
|
||||
"lng_selected_upload_stop" = "Stop";
|
||||
"lng_selected_delete_sure_this" = "Do you want to delete this message?";
|
||||
"lng_selected_delete_sure" = "Do you want to delete {count:_not_used_|# message|# messages}?";
|
||||
"lng_box_delete" = "Delete";
|
||||
|
@ -801,7 +834,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
|
||||
"lng_new_version_wrap" = "Telegram Desktop was updated to version {version}\n\n{changes}\n\nFull version history is available here:\n{link}";
|
||||
"lng_new_version_minor" = "— Bug fixes and other minor improvements";
|
||||
"lng_new_version_text" = "— Sticker management: manually rearrange your sticker packs, pack order is now synced across all your devices\n— Click and hold on a sticker to preview it before sending\n— New context menu for chats in chats list\n— Support for all existing emoji";
|
||||
"lng_new_version_text" = "GIF revolution: 10x faster sending and downloading, autoplay, save your favorite GIFs to a dedicated tab on the sticker panel.\n\nMore about GIFs:\n{gifs_link}\n\nInline bots: A new way to add bot content to any chat. Type a bot's username and your query in the text field to get instant results and send them to your chat partner. Try typing “@gif dog” in your next chat. Sample bots: @gif, @wiki, @bing, @vid, @bold.\n\nMore about inline bots:\n{bots_link}\n\nAlso in this release: New cute design for media, automatic download settings for photos, voice messages and GIFs.";
|
||||
|
||||
"lng_menu_insert_unicode" = "Insert Unicode control character";
|
||||
|
||||
|
|
|
@ -554,8 +554,8 @@ taDefFlat: flatTextarea {
|
|||
font: inpDefFont;
|
||||
cursor: cursor(text);
|
||||
|
||||
phColor: #AAA;
|
||||
phFocusColor: #CCC;
|
||||
phColor: #999;
|
||||
phFocusColor: #AAA;
|
||||
phAlign: align(topleft);
|
||||
phPos: point(2px, 0px);
|
||||
phShift: 50px;
|
||||
|
@ -776,8 +776,8 @@ setClose: iconedButton(btnDefIconed) {
|
|||
height: 43px;
|
||||
}
|
||||
setClosePos: point(32px, 32px);
|
||||
setPhotoImg: sprite(0px, 220px, 120px, 120px);
|
||||
setOverPhotoImg: sprite(122px, 220px, 120px, 120px);
|
||||
setPhotoImg: sprite(0px, 218px, 120px, 120px);
|
||||
setOverPhotoImg: sprite(122px, 218px, 120px, 120px);
|
||||
setPhotoDuration: 150;
|
||||
|
||||
setPadding: 26px;
|
||||
|
@ -1015,25 +1015,25 @@ msgPadding: margins(13px, 7px, 13px, 8px);
|
|||
msgMargin: margins(13px, 4px, 53px, 4px);
|
||||
msgLnkPadding: 2px; // for media open / save links
|
||||
msgBorder: #f0f0f0;
|
||||
msgOutBg: #effdde;
|
||||
msgInBg: #fff;
|
||||
msgOutSelectBg: #b7dbdb;
|
||||
msgInSelectBg: #c2dcf2; // #358cd4 with 30% opacity
|
||||
msgInBgSelected: #c2dcf2; // #358cd4 with 30% opacity
|
||||
msgOutBg: #effdde;
|
||||
msgOutBgSelected: #b7dbdb;
|
||||
msgSelectOverlay: #358cd44c;
|
||||
msgStickerOverlay: #358cd47f;
|
||||
msgOutServiceColor: #3a8e26;
|
||||
msgInServiceColor: #0e7acd;
|
||||
msgOutServiceSelColor: #367570;
|
||||
msgInServiceSelColor: #0e7acd;
|
||||
msgInServiceFg: #0e7acd;
|
||||
msgInServiceFgSelected: #0e7acd;
|
||||
msgOutServiceFg: #3a8e26;
|
||||
msgOutServiceFgSelected: #367570;
|
||||
msgShadow: 2px;
|
||||
msgInShadow: #748ea229;
|
||||
msgInShadowSelected: #548dbb29;
|
||||
msgOutShadow: #3ac34740;
|
||||
msgInSelectShadow: #548dbb29;
|
||||
msgOutSelectShadow: #37a78e40;
|
||||
msgInDateColor: #a0acb6;
|
||||
msgOutDateColor: #6cc264;
|
||||
msgInSelectDateColor: #6a9cc5;
|
||||
msgOutSelectDateColor: #50a79c;
|
||||
msgOutShadowSelected: #37a78e40;
|
||||
msgInDateFg: #a0acb6;
|
||||
msgInDateFgSelected: #6a9cc5;
|
||||
msgOutDateFg: #6cc264;
|
||||
msgOutDateFgSelected: #50a79c;
|
||||
|
||||
msgReplyPadding: margins(6px, 6px, 11px, 6px);
|
||||
msgReplyBarPos: point(1px, 0px);
|
||||
|
@ -1086,11 +1086,12 @@ msgDateDelta: point(2px, 5px);
|
|||
msgDateImgDelta: 4px;
|
||||
msgDateImgColor: #fff;
|
||||
msgDateImgBg: #00000054;
|
||||
msgDateImgSelectBg: #1c4a7187;
|
||||
msgDateImgBgOver: #00000074;
|
||||
msgDateImgBgSelected: #1c4a7187;
|
||||
msgDateImgPadding: point(8px, 2px);
|
||||
msgDateImgCheckSpace: 4px;
|
||||
|
||||
msgDogImg: sprite(213px, 93px, 126px, 126px);
|
||||
msgDogImg: sprite(216px, 92px, 126px, 126px);
|
||||
historyPadding: 10px;
|
||||
|
||||
collapseButton: flatButton(btnDefFlat) {
|
||||
|
@ -1117,7 +1118,7 @@ defaultTextStyle: textStyle {
|
|||
linkFg: btnYesColor;
|
||||
linkFgDown: btnYesHover;
|
||||
monoFg: #777;
|
||||
selectBg: msgInSelectBg;
|
||||
selectBg: msgInBgSelected;
|
||||
selectOverlay: msgSelectOverlay;
|
||||
lineHeight: 0px;
|
||||
}
|
||||
|
@ -1135,12 +1136,12 @@ serviceTextStyle: textStyle(defaultTextStyle) {
|
|||
}
|
||||
inTextStyle: textStyle(defaultTextStyle) {
|
||||
monoFg: #4e7391;
|
||||
selectBg: msgInSelectBg;
|
||||
selectBg: msgInBgSelected;
|
||||
selectOverlay: msgSelectOverlay;
|
||||
}
|
||||
outTextStyle: textStyle(defaultTextStyle) {
|
||||
monoFg: #469165;
|
||||
selectBg: msgOutSelectBg;
|
||||
selectBg: msgOutBgSelected;
|
||||
selectOverlay: msgSelectOverlay;
|
||||
}
|
||||
medviewSaveAsTextStyle: textStyle(defaultTextStyle) {
|
||||
|
@ -1165,52 +1166,109 @@ introErrLabelTextStyle: textStyle(defaultTextStyle) {
|
|||
lineHeight: 27px;
|
||||
}
|
||||
|
||||
mediaMaxWidth: 250px;
|
||||
mediaFont: font(fsize);
|
||||
mediaPadding: margins(7px, 6px, 7px, 6px);
|
||||
mediaPadding: margins(0px, 0px, 0px, 0px);//1px, 1px, 1px, 1px);//2px, 2px, 2px, 2px);
|
||||
mediaCaptionSkip: 5px;
|
||||
mediaHeaderSkip: 5px;
|
||||
mediaThumbSize: 48px;
|
||||
mediaNameTop: 3px;
|
||||
mediaDetailsShift: 3px;
|
||||
mediaDocOutImg: sprite(6px, 146px, 48px, 48px);
|
||||
mediaDocInImg: sprite(56px, 146px, 48px, 48px);
|
||||
mediaAudioOutImg: sprite(106px, 146px, 48px, 48px);
|
||||
mediaAudioInImg: sprite(156px, 146px, 48px, 48px);
|
||||
mediaMusicOutImg: sprite(322px, 345px, 48px, 48px);
|
||||
mediaMusicInImg: sprite(322px, 395px, 48px, 48px);
|
||||
mediaPlayOutImg: sprite(122px, 341px, 48px, 48px);
|
||||
mediaPlayInImg: sprite(172px, 341px, 48px, 48px);
|
||||
mediaPauseOutImg: sprite(222px, 341px, 48px, 48px);
|
||||
mediaPauseInImg: sprite(272px, 341px, 48px, 48px);
|
||||
mediaInColor: msgInDateColor;
|
||||
mediaOutColor: msgOutDateColor;
|
||||
mediaInSelectColor: msgInSelectDateColor;
|
||||
mediaOutSelectColor: msgOutSelectDateColor;
|
||||
mediaOutUnreadColor: #6aad60;
|
||||
mediaOutUnreadSelectColor: #5aa382;
|
||||
mediaInUnreadColor: #999;
|
||||
mediaInUnreadSelectColor: #7b95aa;
|
||||
mediaUnreadSize: 4px;
|
||||
mediaInFg: msgInDateFg;
|
||||
mediaInFgSelected: msgInDateFgSelected;
|
||||
mediaOutFg: msgOutDateFg;
|
||||
mediaOutFgSelected: msgOutDateFgSelected;
|
||||
mediaInUnreadFg: #999;
|
||||
mediaInUnreadFgSelected: #7b95aa;
|
||||
mediaOutUnreadFg: #6aad60;
|
||||
mediaOutUnreadFgSelected: #5aa382;
|
||||
mediaUnreadSize: 7px;
|
||||
mediaUnreadSkip: 5px;
|
||||
mediaSaveDelta: 14px; // between bubble and download
|
||||
mediaSaveButton: flatButton(btnDefFlat) {
|
||||
color: #507da2;
|
||||
overColor: #507da2;
|
||||
downColor: #507da2;
|
||||
mediaUnreadTop: 6px;
|
||||
|
||||
bgColor: white;
|
||||
overBgColor: overBg;
|
||||
downBgColor: overBg;
|
||||
|
||||
width: -28px;
|
||||
height: 34px;
|
||||
|
||||
textTop: 7px;
|
||||
overTextTop: 7px;
|
||||
downTextTop: 8px;
|
||||
|
||||
font: font(fsize);
|
||||
overFont: font(fsize);
|
||||
mediaInStyle: textStyle(defaultTextStyle) {
|
||||
linkFg: mediaInFg;
|
||||
linkFgDown: mediaInFg;
|
||||
}
|
||||
mediaInStyleSelected: textStyle(defaultTextStyle) {
|
||||
linkFg: mediaInFgSelected;
|
||||
linkFgDown: mediaInFgSelected;
|
||||
}
|
||||
|
||||
msgFileRedColor: #e47272;
|
||||
msgFileYellowColor: #efc274;
|
||||
msgFileGreenColor: #61b96e;
|
||||
msgFileBlueColor: #72b1df;
|
||||
msgFileRedDark: #cd5b5e;
|
||||
msgFileYellowDark: #e6a561;
|
||||
msgFileGreenDark: #4da859;
|
||||
msgFileBlueDark: #5c9ece;
|
||||
msgFileRedOver: #c35154;
|
||||
msgFileYellowOver: #dc9c5a;
|
||||
msgFileGreenOver: #44a050;
|
||||
msgFileBlueOver: #5294c4;
|
||||
msgFileRedSelected: #9f6a82;
|
||||
msgFileYellowSelected: #b19d84;
|
||||
msgFileGreenSelected: #46a07e;
|
||||
msgFileBlueSelected: #5099d0;
|
||||
|
||||
msgFileMenuSize: size(36px, 36px);
|
||||
msgFileSize: 44px;
|
||||
msgFilePadding: margins(14px, 12px, 11px, 12px);
|
||||
msgFileThumbSize: 72px;
|
||||
msgFileThumbPadding: margins(10px, 10px, 14px, 10px);
|
||||
msgFileThumbNameTop: 12px;
|
||||
msgFileThumbStatusTop: 32px;
|
||||
msgFileThumbLinkTop: 60px;
|
||||
msgFileThumbLinkInFg: #3da5e0;
|
||||
msgFileThumbLinkInFgSelected: #3da5e0;
|
||||
msgFileThumbLinkOutFg: #5eba5b;
|
||||
msgFileThumbLinkOutFgSelected: #31a298;
|
||||
msgFileNameTop: 16px;
|
||||
msgFileStatusTop: 37px;
|
||||
msgFileMinWidth: 294px;
|
||||
msgFileInBg: #59b6eb;
|
||||
msgFileInBgOver: #4eade3;
|
||||
msgFileInBgSelected: #51a3d3;
|
||||
msgFileOutBg: #78c67f;
|
||||
msgFileOutBgOver: #6bc272;
|
||||
msgFileOutBgSelected: #5fb389;
|
||||
|
||||
msgFileOutImage: sprite(0px, 146px, 18px, 18px);
|
||||
msgFileOutImageSelected: sprite(18px, 146px, 18px, 18px);
|
||||
msgFileInImage: sprite(0px, 164px, 18px, 18px);
|
||||
msgFileInImageSelected: sprite(18px, 164px, 18px, 18px);
|
||||
msgFileOutFile: sprite(36px, 146px, 18px, 18px);
|
||||
msgFileOutFileSelected: sprite(54px, 146px, 18px, 18px);
|
||||
msgFileInFile: sprite(36px, 164px, 18px, 18px);
|
||||
msgFileInFileSelected: sprite(54px, 164px, 18px, 18px);
|
||||
msgFileOutDownload: sprite(72px, 142px, 14px, 20px);
|
||||
msgFileOutDownloadSelected: sprite(86px, 142px, 14px, 20px);
|
||||
msgFileInDownload: sprite(72px, 162px, 14px, 20px);
|
||||
msgFileInDownloadSelected: sprite(86px, 162px, 14px, 20px);
|
||||
msgFileOutCancel: sprite(100px, 147px, 16px, 16px);
|
||||
msgFileOutCancelSelected: sprite(116px, 147px, 16px, 16px);
|
||||
msgFileInCancel: sprite(100px, 165px, 16px, 16px);
|
||||
msgFileInCancelSelected: sprite(116px, 165px, 16px, 16px);
|
||||
msgFileOutPause: sprite(132px, 147px, 14px, 16px);
|
||||
msgFileOutPauseSelected: sprite(146px, 147px, 14px, 16px);
|
||||
msgFileInPause: sprite(132px, 165px, 14px, 16px);
|
||||
msgFileInPauseSelected: sprite(146px, 165px, 14px, 16px);
|
||||
msgFileOutPlay: sprite(160px, 146px, 20px, 18px);
|
||||
msgFileOutPlaySelected: sprite(180px, 146px, 20px, 18px);
|
||||
msgFileInPlay: sprite(160px, 164px, 20px, 18px);
|
||||
msgFileInPlaySelected: sprite(180px, 164px, 20px, 18px);
|
||||
|
||||
msgFileRed: sprite(0px, 425px, 20px, 20px);
|
||||
msgFileYellow: sprite(20px, 425px, 20px, 20px);
|
||||
msgFileGreen: sprite(40px, 425px, 20px, 20px);
|
||||
msgFileBlue: sprite(60px, 425px, 20px, 20px);
|
||||
|
||||
msgFileOverDuration: 200;
|
||||
msgFileRadialLine: 3px;
|
||||
|
||||
msgFileExtPadding: 8px;
|
||||
msgFileExtTop: 30px;
|
||||
|
||||
msgVideoSize: size(320px, 240px);
|
||||
|
||||
sendPadding: 9px;
|
||||
btnSend: flatButton(btnDefFlat) {
|
||||
|
@ -1261,6 +1319,13 @@ btnAttachEmoji: iconedButton(btnAttachDocument) {
|
|||
|
||||
width: 33px;
|
||||
}
|
||||
emojiCircle: size(19px, 19px);
|
||||
emojiCirclePeriod: 1500;
|
||||
emojiCircleDuration: 500;
|
||||
emojiCircleTop: 13px;
|
||||
emojiCircleLine: 2px;
|
||||
emojiCircleFg: #b9b9b9;
|
||||
emojiCirclePart: 3.5;
|
||||
btnBotKbShow: iconedButton(btnAttachEmoji) {
|
||||
icon: sprite(375px, 74px, 21px, 21px);
|
||||
iconPos: point(6px, 12px);
|
||||
|
@ -1480,7 +1545,6 @@ notifySlowHideFunc: transition(easeInCirc);
|
|||
notifyWaitShortHide: 0;
|
||||
notifyWaitLongHide: 20000;
|
||||
notifyFastAnim: 150;
|
||||
notifyFastAnimFunc: transition(linear);
|
||||
notifyWidth: 316px;
|
||||
notifyHeight: 80px;
|
||||
notifyDeltaX: 6px;
|
||||
|
@ -1550,7 +1614,7 @@ profileMinBtnPadding: 10px;
|
|||
membersPadding: margins(0px, 10px, 0px, 10px);
|
||||
|
||||
forwardMargins: margins(30px, 10px, 30px, 10px);
|
||||
forwardFont: font(16px);
|
||||
forwardFont: font(16px);
|
||||
forwardBg: rgba(0, 0, 0, 76);
|
||||
btnProfileCancel: flatButton(btnDefFlat, btnDefBig) {
|
||||
color: #666d78;
|
||||
|
@ -1820,6 +1884,8 @@ emojiObjectsActive: sprite(308px, 264px, 21px, 22px);
|
|||
emojiSymbolsOver: sprite(84px, 196px, 21px, 22px);
|
||||
emojiSymbolsActive: sprite(287px, 286px, 21px, 22px);
|
||||
stickersSettings: sprite(140px, 124px, 21px, 22px);
|
||||
savedGifsOver: sprite(329px, 286px, 21px, 22px);
|
||||
savedGifsActive: sprite(350px, 286px, 21px, 22px);
|
||||
|
||||
emojiPanCategories: #f7f7f7;
|
||||
|
||||
|
@ -1975,6 +2041,11 @@ botKbScroll: flatScroll(solidScroll) {
|
|||
width: 10px;
|
||||
}
|
||||
|
||||
minPhotoSize: 100px;
|
||||
maxMediaSize: 420px;
|
||||
maxStickerSize: 256px;
|
||||
maxGifSize: 320px;
|
||||
|
||||
mvBgColor: #222;
|
||||
mvBgOpacity: 0.92;
|
||||
mvThickFont: semiboldFont;
|
||||
|
@ -2063,14 +2134,12 @@ mvDocExtFont: font(semibold 18px);
|
|||
mvDocExtColor: white;
|
||||
mvDocExtPadding: 10px;
|
||||
mvDocLinksTop: 57px;
|
||||
mvDocRed: sprite(0px, 400px, 80px, 80px);
|
||||
mvDocRedColor: #e47272;
|
||||
mvDocYellow: sprite(80px, 400px, 80px, 80px);
|
||||
mvDocYellowColor: #efc274;
|
||||
mvDocGreen: sprite(160px, 400px, 80px, 80px);
|
||||
mvDocGreenColor: #61b96e;
|
||||
mvDocBlue: sprite(240px, 400px, 80px, 80px);
|
||||
mvDocBlueColor: #72b1df;
|
||||
mvDocRed: sprite(0px, 400px, 25px, 25px);
|
||||
mvDocYellow: sprite(25px, 400px, 25px, 25px);
|
||||
mvDocGreen: sprite(50px, 400px, 25px, 25px);
|
||||
mvDocBlue: sprite(75px, 400px, 25px, 25px);
|
||||
mvDocIconSize: 80px;
|
||||
|
||||
mvDocLink: linkButton(btnDefLink) {
|
||||
color: #4595d3;
|
||||
overColor: #4595d3;
|
||||
|
@ -2098,11 +2167,20 @@ medviewSaveMsg: #000000b2;
|
|||
mvTransparentBrush: sprite(9px, 124px, 8px, 8px);
|
||||
|
||||
overviewPhotoSkip: 10px;
|
||||
overviewPhotoMinSize: 100px;
|
||||
overviewPhotoBg: #F1F1F1;
|
||||
overviewPhotoMinSize: minPhotoSize;
|
||||
overviewPhotoCheck: sprite(245px, 308px, 32px, 32px);
|
||||
overviewPhotoChecked: sprite(278px, 308px, 32px, 32px);
|
||||
overviewPhotoSelectOverlay: #0a7bb03f;
|
||||
|
||||
overviewFilePadding: margins(0px, 3px, 16px, 3px);
|
||||
overviewFileSize: 70px;
|
||||
overviewFileNameTop: 7px;
|
||||
overviewFileStatusTop: 27px;
|
||||
overviewFileDateTop: 49px;
|
||||
overviewFileChecked: #2fa9e2;
|
||||
overviewFileCheck: #00000066;
|
||||
|
||||
// Mac specific
|
||||
|
||||
macAccessory: size(450, 90);
|
||||
|
@ -2159,10 +2237,6 @@ mediaviewLoader: size(78px, 33px);
|
|||
mediaviewLoaderPoint: size(9px, 9px);
|
||||
mediaviewLoaderSkip: 9px;
|
||||
|
||||
minPhotoSize: 100px;
|
||||
maxMediaSize: 420px;
|
||||
maxStickerSize: 256px;
|
||||
|
||||
downloadPathSkip: 10px;
|
||||
|
||||
usernamePadding: margins(23px, 22px, 21px, 12px);
|
||||
|
@ -2172,10 +2246,9 @@ usernameTextStyle: textStyle(defaultTextStyle) {
|
|||
}
|
||||
usernameDefaultFg: #777;
|
||||
|
||||
youtubeIcon: sprite(336px, 221px, 60px, 60px);
|
||||
vimeoIcon: sprite(336px, 283px, 60px, 60px);
|
||||
youtubeIcon: sprite(116px, 338px, 72px, 50px);
|
||||
videoIcon: sprite(0px, 340px, 60px, 60px);
|
||||
locationSize: size(320, 240);
|
||||
locationSize: size(320px, 240px);
|
||||
|
||||
boxOptionListPadding: margins(2px, 20px, 2px, 2px);
|
||||
|
||||
|
@ -2293,11 +2366,24 @@ playlistPadding: 10px;
|
|||
linksSearchMargin: margins(20px, 20px, 20px, 0px);
|
||||
linksMaxWidth: 520px;
|
||||
linksLetterFont: font(24px);
|
||||
linksMargin: 5px;
|
||||
linksMargin: margins(0px, 7px, 0px, 5px);
|
||||
linksTextTop: 6px;
|
||||
linksBorder: 1px;
|
||||
linksBorderColor: #eaeaea;
|
||||
linksDateColor: #000;
|
||||
linksDateMargin: 15px;
|
||||
linksBorderFg: #eaeaea;
|
||||
linksDateColor: #808080;
|
||||
linksDateMargin: margins(0px, 15px, 0px, 2px);
|
||||
|
||||
linksPhotoCheck: sprite(184px, 196px, 16px, 16px);
|
||||
linksPhotoChecked: sprite(168px, 196px, 16px, 16px);
|
||||
|
||||
inlineResultsLeft: 15px;
|
||||
inlineResultsSkip: 3px;
|
||||
inlineMediaHeight: 96px;
|
||||
inlineThumbSize: 64px;
|
||||
inlineThumbSkip: 10px;
|
||||
inlineDescriptionFg: #8a8a8a;
|
||||
inlineRowMargin: 6px;
|
||||
inlineRowBorder: linksBorder;
|
||||
inlineRowBorderFg: linksBorderFg;
|
||||
inlineResultsMinWidth: 64px;
|
||||
inlineDurationMargin: 3px;
|
||||
|
|
|
@ -333,9 +333,8 @@ void updateRegistry() {
|
|||
int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR cmdParamarg, int cmdShow) {
|
||||
openLog();
|
||||
|
||||
#ifdef _NEED_WIN_GENERATE_DUMP
|
||||
_oldWndExceptionFilter = SetUnhandledExceptionFilter(_exceptionFilter);
|
||||
#endif
|
||||
// CAPIHook apiHook("kernel32.dll", "SetUnhandledExceptionFilter", (PROC)RedirectedSetUnhandledExceptionFilter);
|
||||
|
||||
writeLog(L"Updaters started..");
|
||||
|
||||
|
@ -465,7 +464,6 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR cmdPara
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef _NEED_WIN_GENERATE_DUMP
|
||||
static const WCHAR *_programName = L"Telegram Desktop"; // folder in APPDATA, if current path is unavailable for writing
|
||||
static const WCHAR *_exeName = L"Updater.exe";
|
||||
|
||||
|
@ -507,10 +505,10 @@ HANDLE _generateDumpFileAtPath(const WCHAR *path) {
|
|||
|
||||
GetLocalTime(&stLocalTime);
|
||||
|
||||
wsprintf(szFileName, L"%s%s-%s-%04d%02d%02d-%02d%02d%02d-%ld-%ld.dmp",
|
||||
szPath, szExeName, updaterVersionStr,
|
||||
stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay,
|
||||
stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond,
|
||||
wsprintf(szFileName, L"%s%s-%s-%04d%02d%02d-%02d%02d%02d-%ld-%ld.dmp",
|
||||
szPath, szExeName, updaterVersionStr,
|
||||
stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay,
|
||||
stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond,
|
||||
GetCurrentProcessId(), GetCurrentThreadId());
|
||||
return CreateFile(szFileName, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);
|
||||
}
|
||||
|
@ -546,7 +544,7 @@ void _generateDump(EXCEPTION_POINTERS* pExceptionPointers) {
|
|||
hDumpFile = _generateDumpFileAtPath(wstrPath);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!hDumpFile || hDumpFile == INVALID_HANDLE_VALUE) {
|
||||
return;
|
||||
}
|
||||
|
@ -564,4 +562,10 @@ LONG CALLBACK _exceptionFilter(EXCEPTION_POINTERS* pExceptionPointers) {
|
|||
return _oldWndExceptionFilter ? (*_oldWndExceptionFilter)(pExceptionPointers) : EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
#endif
|
||||
// see http://www.codeproject.com/Articles/154686/SetUnhandledExceptionFilter-and-the-C-C-Runtime-Li
|
||||
LPTOP_LEVEL_EXCEPTION_FILTER WINAPI RedirectedSetUnhandledExceptionFilter(_In_opt_ LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter) {
|
||||
// When the CRT calls SetUnhandledExceptionFilter with NULL parameter
|
||||
// our handler will not get removed.
|
||||
_oldWndExceptionFilter = lpTopLevelExceptionFilter;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -32,12 +32,9 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
using std::deque;
|
||||
using std::wstring;
|
||||
|
||||
#define _NEED_WIN_GENERATE_DUMP
|
||||
|
||||
#ifdef _NEED_WIN_GENERATE_DUMP
|
||||
extern LPTOP_LEVEL_EXCEPTION_FILTER _oldWndExceptionFilter;
|
||||
LONG CALLBACK _exceptionFilter(EXCEPTION_POINTERS* pExceptionPointers);
|
||||
#endif _NEED_WIN_GENERATE_DUMP
|
||||
LPTOP_LEVEL_EXCEPTION_FILTER WINAPI RedirectedSetUnhandledExceptionFilter(_In_opt_ LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter);
|
||||
|
||||
static int updaterVersion = 1000;
|
||||
static const WCHAR *updaterVersionStr = L"0.1.0";
|
||||
|
|
|
@ -64,36 +64,6 @@ void ApiWrap::itemRemoved(HistoryItem *item) {
|
|||
}
|
||||
}
|
||||
|
||||
void ApiWrap::itemReplaced(HistoryItem *oldItem, HistoryItem *newItem) {
|
||||
if (HistoryReply *reply = oldItem->toHistoryReply()) {
|
||||
ChannelData *channel = reply->history()->peer->asChannel();
|
||||
ReplyToRequests *requests(replyToRequests(channel, true));
|
||||
if (requests) {
|
||||
ReplyToRequests::iterator i = requests->find(reply->replyToId());
|
||||
if (i != requests->cend()) {
|
||||
for (QList<HistoryReply*>::iterator j = i->replies.begin(); j != i->replies.end();) {
|
||||
if ((*j) == reply) {
|
||||
if (HistoryReply *newReply = newItem->toHistoryReply()) {
|
||||
*j = newReply;
|
||||
++j;
|
||||
} else {
|
||||
j = i->replies.erase(j);
|
||||
}
|
||||
} else {
|
||||
++j;
|
||||
}
|
||||
}
|
||||
if (i->replies.isEmpty()) {
|
||||
requests->erase(i);
|
||||
}
|
||||
}
|
||||
if (channel && requests->isEmpty()) {
|
||||
_channelReplyToRequests.remove(channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ApiWrap::requestReplyTo(HistoryReply *reply, ChannelData *channel, MsgId id) {
|
||||
ReplyToRequest &req(channel ? _channelReplyToRequests[channel][id] : _replyToRequests[id]);
|
||||
req.replies.append(reply);
|
||||
|
@ -460,7 +430,7 @@ void ApiWrap::requestBots(ChannelData *peer) {
|
|||
|
||||
void ApiWrap::gotChat(PeerData *peer, const MTPmessages_Chats &result) {
|
||||
_peerRequests.remove(peer);
|
||||
|
||||
|
||||
if (result.type() == mtpc_messages_chats) {
|
||||
const QVector<MTPChat> &v(result.c_messages_chats().vchats.c_vector().v);
|
||||
bool badVersion = false;
|
||||
|
@ -702,9 +672,9 @@ void ApiWrap::scheduleStickerSetRequest(uint64 setId, uint64 access) {
|
|||
|
||||
void ApiWrap::requestStickerSets() {
|
||||
for (QMap<uint64, QPair<uint64, mtpRequestId> >::iterator i = _stickerSetRequests.begin(), j = i, e = _stickerSetRequests.end(); i != e; i = j) {
|
||||
++j;
|
||||
if (i.value().second) continue;
|
||||
|
||||
++j;
|
||||
int32 wait = (j == e) ? 0 : 10;
|
||||
i.value().second = MTP::send(MTPmessages_GetStickerSet(MTP_inputStickerSetID(MTP_long(i.key()), MTP_long(i.value().first))), rpcDone(&ApiWrap::gotStickerSet, i.key()), rpcFail(&ApiWrap::gotStickerSetFail, i.key()), 0, wait);
|
||||
}
|
||||
|
@ -712,10 +682,10 @@ void ApiWrap::requestStickerSets() {
|
|||
|
||||
void ApiWrap::gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result) {
|
||||
_stickerSetRequests.remove(setId);
|
||||
|
||||
|
||||
if (result.type() != mtpc_messages_stickerSet) return;
|
||||
const MTPDmessages_stickerSet &d(result.c_messages_stickerSet());
|
||||
|
||||
|
||||
if (d.vset.type() != mtpc_stickerSet) return;
|
||||
const MTPDstickerSet &s(d.vset.c_stickerSet());
|
||||
|
||||
|
@ -761,12 +731,32 @@ void ApiWrap::gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result)
|
|||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
if (pack.isEmpty()) {
|
||||
int32 removeIndex = cStickerSetsOrder().indexOf(setId);
|
||||
if (removeIndex >= 0) cRefStickerSetsOrder().removeAt(removeIndex);
|
||||
sets.erase(it);
|
||||
} else {
|
||||
it->stickers = pack;
|
||||
it->emoji.clear();
|
||||
const QVector<MTPStickerPack> &v(d.vpacks.c_vector().v);
|
||||
for (int32 i = 0, l = v.size(); i < l; ++i) {
|
||||
if (v.at(i).type() != mtpc_stickerPack) continue;
|
||||
|
||||
const MTPDstickerPack &pack(v.at(i).c_stickerPack());
|
||||
if (EmojiPtr e = emojiGetNoColor(emojiFromText(qs(pack.vemoticon)))) {
|
||||
const QVector<MTPlong> &stickers(pack.vdocuments.c_vector().v);
|
||||
StickerPack p;
|
||||
p.reserve(stickers.size());
|
||||
for (int32 j = 0, c = stickers.size(); j < c; ++j) {
|
||||
DocumentData *doc = App::document(stickers.at(j).v);
|
||||
if (!doc || !doc->sticker()) continue;
|
||||
|
||||
p.push_back(doc);
|
||||
}
|
||||
it->emoji.insert(e, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (writeRecent) {
|
||||
|
@ -916,12 +906,11 @@ void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &msgs
|
|||
}
|
||||
}
|
||||
|
||||
MainWidget *m = App::main();
|
||||
for (QMap<uint64, int32>::const_iterator i = msgsIds.cbegin(), e = msgsIds.cend(); i != e; ++i) {
|
||||
HistoryItem *item = App::histories().addNewMessage(v->at(i.value()), NewMessageExisting);
|
||||
if (item) {
|
||||
item->initDimensions();
|
||||
if (m) m->itemResized(item);
|
||||
Notify::historyItemResized(item);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -934,7 +923,7 @@ void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &msgs
|
|||
if (j != items.cend()) {
|
||||
for (HistoryItemsMap::const_iterator k = j.value().cbegin(), e = j.value().cend(); k != e; ++k) {
|
||||
k.key()->initDimensions();
|
||||
if (m) m->itemResized(k.key());
|
||||
Notify::historyItemResized(k.key());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -946,5 +935,5 @@ void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &msgs
|
|||
}
|
||||
|
||||
ApiWrap::~ApiWrap() {
|
||||
App::deinitMedia(false);
|
||||
App::clearHistories();
|
||||
}
|
||||
|
|
|
@ -29,7 +29,6 @@ public:
|
|||
void init();
|
||||
|
||||
void itemRemoved(HistoryItem *item);
|
||||
void itemReplaced(HistoryItem *oldItem, HistoryItem *newItem);
|
||||
|
||||
void requestReplyTo(HistoryReply *reply, ChannelData *channel, MsgId id);
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -32,12 +32,22 @@ class Color;
|
|||
class FileUploader;
|
||||
|
||||
#include "history.h"
|
||||
#include "layout.h"
|
||||
|
||||
typedef QMap<HistoryItem*, bool> HistoryItemsMap;
|
||||
typedef QMap<HistoryItem*, NullType> HistoryItemsMap;
|
||||
typedef QHash<PhotoData*, HistoryItemsMap> PhotoItems;
|
||||
typedef QHash<VideoData*, HistoryItemsMap> VideoItems;
|
||||
typedef QHash<AudioData*, HistoryItemsMap> AudioItems;
|
||||
typedef QHash<DocumentData*, HistoryItemsMap> DocumentItems;
|
||||
typedef QHash<WebPageData*, HistoryItemsMap> WebPageItems;
|
||||
typedef QHash<int32, HistoryItemsMap> SharedContactItems;
|
||||
typedef QHash<ClipReader*, HistoryItem*> GifItems;
|
||||
|
||||
typedef QHash<PhotoId, PhotoData*> PhotosData;
|
||||
typedef QHash<VideoId, VideoData*> VideosData;
|
||||
typedef QHash<AudioId, AudioData*> AudiosData;
|
||||
typedef QHash<DocumentId, DocumentData*> DocumentsData;
|
||||
|
||||
struct ReplyMarkup {
|
||||
ReplyMarkup(int32 flags = 0) : flags(flags) {
|
||||
}
|
||||
|
@ -46,40 +56,6 @@ struct ReplyMarkup {
|
|||
int32 flags;
|
||||
};
|
||||
|
||||
enum RoundCorners {
|
||||
NoneCorners = 0x00, // for images
|
||||
BlackCorners,
|
||||
ServiceCorners,
|
||||
ServiceSelectedCorners,
|
||||
SelectedOverlayCorners,
|
||||
DateCorners,
|
||||
DateSelectedCorners,
|
||||
ForwardCorners,
|
||||
MediaviewSaveCorners,
|
||||
EmojiHoverCorners,
|
||||
StickerHoverCorners,
|
||||
BotKeyboardCorners,
|
||||
BotKeyboardOverCorners,
|
||||
BotKeyboardDownCorners,
|
||||
PhotoSelectOverlayCorners,
|
||||
|
||||
DocRedCorners,
|
||||
DocYellowCorners,
|
||||
DocGreenCorners,
|
||||
DocBlueCorners,
|
||||
|
||||
InShadowCorners, // for photos without bg
|
||||
InSelectedShadowCorners,
|
||||
|
||||
MessageInCorners, // with shadow
|
||||
MessageInSelectedCorners,
|
||||
MessageOutCorners,
|
||||
MessageOutSelectedCorners,
|
||||
ButtonHoverCorners,
|
||||
|
||||
RoundCornersCount
|
||||
};
|
||||
|
||||
class LayeredWidget;
|
||||
|
||||
namespace App {
|
||||
|
@ -109,6 +85,8 @@ namespace App {
|
|||
void feedChatAdmins(const MTPDupdateChatAdmins &d, bool emitPeerUpdated = true);
|
||||
void feedParticipantAdmin(const MTPDupdateChatParticipantAdmin &d, bool emitPeerUpdated = true);
|
||||
bool checkEntitiesAndViewsUpdate(const MTPDmessage &m); // returns true if item found and it is not detached
|
||||
void addSavedGif(DocumentData *doc);
|
||||
void checkSavedGif(HistoryItem *item);
|
||||
void feedMsgs(const QVector<MTPMessage> &msgs, NewMessageType type);
|
||||
void feedMsgs(const MTPVector<MTPMessage> &msgs, NewMessageType type);
|
||||
void feedInboxRead(const PeerId &peer, MsgId upTo);
|
||||
|
@ -180,7 +158,7 @@ namespace App {
|
|||
inline HistoryItem *histItemById(const FullMsgId &msgId) {
|
||||
return histItemById(msgId.channel, msgId.msg);
|
||||
}
|
||||
HistoryItem *historyRegItem(HistoryItem *item);
|
||||
void historyRegItem(HistoryItem *item);
|
||||
void historyItemDetached(HistoryItem *item);
|
||||
void historyUnregItem(HistoryItem *item);
|
||||
void historyClearMsgs();
|
||||
|
@ -214,8 +192,10 @@ namespace App {
|
|||
const QPixmap &emojiLarge();
|
||||
const QPixmap &emojiSingle(EmojiPtr emoji, int32 fontHeight);
|
||||
|
||||
void clearHistories();
|
||||
|
||||
void initMedia();
|
||||
void deinitMedia(bool completely = true);
|
||||
void deinitMedia();
|
||||
void playSound();
|
||||
|
||||
void checkImageCacheSize();
|
||||
|
@ -229,34 +209,53 @@ namespace App {
|
|||
QImage readImage(QByteArray data, QByteArray *format = 0, bool opaque = true, bool *animated = 0);
|
||||
QImage readImage(const QString &file, QByteArray *format = 0, bool opaque = true, bool *animated = 0, QByteArray *content = 0);
|
||||
|
||||
void regPhotoItem(PhotoData *data, HistoryItem *item);
|
||||
void unregPhotoItem(PhotoData *data, HistoryItem *item);
|
||||
const PhotoItems &photoItems();
|
||||
const PhotosData &photosData();
|
||||
|
||||
void regVideoItem(VideoData *data, HistoryItem *item);
|
||||
void unregVideoItem(VideoData *data, HistoryItem *item);
|
||||
const VideoItems &videoItems();
|
||||
const VideosData &videosData();
|
||||
|
||||
void regAudioItem(AudioData *data, HistoryItem *item);
|
||||
void unregAudioItem(AudioData*data, HistoryItem *item);
|
||||
const AudioItems &audioItems();
|
||||
const AudiosData &audiosData();
|
||||
|
||||
void regDocumentItem(DocumentData *data, HistoryItem *item);
|
||||
void unregDocumentItem(DocumentData *data, HistoryItem *item);
|
||||
const DocumentItems &documentItems();
|
||||
const DocumentsData &documentsData();
|
||||
|
||||
void regWebPageItem(WebPageData *data, HistoryItem *item);
|
||||
void unregWebPageItem(WebPageData *data, HistoryItem *item);
|
||||
const WebPageItems &webPageItems();
|
||||
|
||||
void regSharedContactPhone(int32 userId, const QString &phone);
|
||||
void regSharedContactItem(int32 userId, HistoryItem *item);
|
||||
void unregSharedContactItem(int32 userId, HistoryItem *item);
|
||||
const SharedContactItems &sharedContactItems();
|
||||
QString phoneFromSharedContact(int32 userId);
|
||||
|
||||
void regGifItem(ClipReader *reader, HistoryItem *item);
|
||||
void unregGifItem(ClipReader *reader);
|
||||
void stopGifItems();
|
||||
|
||||
void regMuted(PeerData *peer, int32 changeIn);
|
||||
void unregMuted(PeerData *peer);
|
||||
void updateMuted();
|
||||
|
||||
void regInlineResultLoader(FileLoader *loader, InlineResult *result);
|
||||
void unregInlineResultLoader(FileLoader *loader);
|
||||
InlineResult *inlineResultFromLoader(FileLoader *loader);
|
||||
|
||||
void feedReplyMarkup(ChannelId channelId, MsgId msgId, const MTPReplyMarkup &markup);
|
||||
void clearReplyMarkup(ChannelId channelId, MsgId msgId);
|
||||
const ReplyMarkup &replyMarkup(ChannelId channelId, MsgId msgId);
|
||||
|
||||
void setProxySettings(QNetworkAccessManager &manager);
|
||||
QNetworkProxy getHttpProxySettings();
|
||||
void setProxySettings(QTcpSocket &socket);
|
||||
|
||||
QImage **cornersMask();
|
||||
|
@ -295,25 +294,4 @@ namespace App {
|
|||
|
||||
};
|
||||
|
||||
inline int32 stickersCountHash(bool checkOfficial = false) {
|
||||
uint32 acc = 0;
|
||||
bool foundOfficial = false, foundBad = false;;
|
||||
const StickerSets &sets(cStickerSets());
|
||||
const StickerSetsOrder &order(cStickerSetsOrder());
|
||||
for (StickerSetsOrder::const_iterator i = order.cbegin(), e = order.cend(); i != e; ++i) {
|
||||
StickerSets::const_iterator j = sets.constFind(*i);
|
||||
if (j != sets.cend()) {
|
||||
if (j->id == 0) {
|
||||
foundBad = true;
|
||||
} else if (j->flags & MTPDstickerSet::flag_official) {
|
||||
foundOfficial = true;
|
||||
}
|
||||
if (!(j->flags & MTPDstickerSet::flag_disabled)) {
|
||||
acc = (acc * 20261) + j->hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (!checkOfficial || (!foundBad && foundOfficial)) ? int32(acc & 0x7FFFFFFF) : 0;
|
||||
}
|
||||
|
||||
#include "facades.h"
|
||||
|
|
|
@ -208,7 +208,7 @@ void Application::updateGotCurrent() {
|
|||
if (!updateReply || updateThread) return;
|
||||
|
||||
cSetLastUpdateCheck(unixtime());
|
||||
QRegularExpressionMatch m = QRegularExpression(qsl("^\\s*(\\d+)\\s*:\\s*([\\x21-\\x7f]+)\\s*$")).match(QString::fromUtf8(updateReply->readAll()));
|
||||
QRegularExpressionMatch m = QRegularExpression(qsl("^\\s*(\\d+)\\s*:\\s*([\\x21-\\x7f]+)\\s*$")).match(QString::fromLatin1(updateReply->readAll()));
|
||||
if (m.hasMatch()) {
|
||||
uint64 currentVersion = m.captured(1).toULongLong();
|
||||
QString url = m.captured(2);
|
||||
|
@ -445,7 +445,7 @@ void Application::onSwitchDebugMode() {
|
|||
f.write("1");
|
||||
f.close();
|
||||
}
|
||||
App::wnd()->hideLayer();
|
||||
Ui::hideLayer();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -489,7 +489,7 @@ int32 Application::updatingReady() {
|
|||
#endif
|
||||
|
||||
FileUploader *Application::uploader() {
|
||||
if (!::uploader) ::uploader = new FileUploader();
|
||||
if (!::uploader && !App::quiting()) ::uploader = new FileUploader();
|
||||
return ::uploader;
|
||||
}
|
||||
|
||||
|
@ -548,9 +548,9 @@ void Application::stopUpdate() {
|
|||
void Application::startUpdateCheck(bool forceWait) {
|
||||
updateCheckTimer.stop();
|
||||
if (updateRequestId || updateThread || updateReply || !cAutoUpdate()) return;
|
||||
|
||||
|
||||
int32 constDelay = cBetaVersion() ? 600 : UpdateDelayConstPart, randDelay = cBetaVersion() ? 300 : UpdateDelayRandPart;
|
||||
int32 updateInSecs = cLastUpdateCheck() + constDelay + (rand() % randDelay) - unixtime();
|
||||
int32 updateInSecs = cLastUpdateCheck() + constDelay + int32(MTP::nonce<uint32>() % randDelay) - unixtime();
|
||||
bool sendRequest = (updateInSecs <= 0 || updateInSecs > (constDelay + randDelay));
|
||||
if (!sendRequest && !forceWait) {
|
||||
QDir updates(cWorkingDir() + "tupdates");
|
||||
|
@ -642,7 +642,7 @@ void Application::socketConnected() {
|
|||
}
|
||||
commands += qsl("CMD:show;");
|
||||
DEBUG_LOG(("Application Info: writing commands %1").arg(commands));
|
||||
socket.write(commands.toLocal8Bit());
|
||||
socket.write(commands.toLatin1());
|
||||
}
|
||||
|
||||
void Application::socketWritten(qint64/* bytes*/) {
|
||||
|
@ -684,7 +684,7 @@ void Application::socketError(QLocalSocket::LocalSocketError e) {
|
|||
socket.close();
|
||||
|
||||
psCheckLocalSocket(serverName);
|
||||
|
||||
|
||||
if (!server.listen(serverName)) {
|
||||
DEBUG_LOG(("Application Error: failed to start listening to %1 server, error %2").arg(serverName).arg(int(server.serverError())));
|
||||
return App::quit();
|
||||
|
@ -705,10 +705,10 @@ void Application::checkMapVersion() {
|
|||
if (Local::oldMapVersion() < AppVersion) {
|
||||
if (Local::oldMapVersion()) {
|
||||
QString versionFeatures;
|
||||
if (cDevVersion() && Local::oldMapVersion() < 9014) {
|
||||
versionFeatures = QString::fromUtf8("\xe2\x80\x94 Sticker management: manually rearrange your sticker packs, pack order is now synced across all your devices\n\xe2\x80\x94 Click and hold on a sticker to preview it before sending\n\xe2\x80\x94 New context menu for chats in chats list\n\xe2\x80\x94 Support for all existing emoji");// .replace('@', qsl("@") + QChar(0x200D));
|
||||
} else if (Local::oldMapVersion() < 9015) {
|
||||
versionFeatures = lang(lng_new_version_text).trimmed();
|
||||
if (cDevVersion() && Local::oldMapVersion() < 9019) {
|
||||
versionFeatures = QString::fromUtf8("\xe2\x80\x94 Choose an emoticon and see the suggested stickers\n\xe2\x80\x94 Bug fixes in minor improvements");// .replace('@', qsl("@") + QChar(0x200D));
|
||||
} else if (Local::oldMapVersion() < 9016) {
|
||||
versionFeatures = lng_new_version_text(lt_gifs_link, qsl("https://telegram.org/blog/gif-revolution"), lt_bots_link, qsl("https://telegram.org/blog/inline-bots")).trimmed();
|
||||
} else {
|
||||
versionFeatures = lang(lng_new_version_minor).trimmed();
|
||||
}
|
||||
|
@ -769,7 +769,7 @@ void Application::startApp() {
|
|||
}
|
||||
|
||||
QNetworkProxyFactory::setUseSystemConfiguration(true);
|
||||
|
||||
|
||||
if (state != Local::ReadMapPassNeeded) {
|
||||
checkMapVersion();
|
||||
}
|
||||
|
@ -799,13 +799,13 @@ void Application::readClients() {
|
|||
for (ClientSockets::iterator i = clients.begin(), e = clients.end(); i != e; ++i) {
|
||||
i->second.append(i->first->readAll());
|
||||
if (i->second.size()) {
|
||||
QString cmds(QString::fromLocal8Bit(i->second));
|
||||
QString cmds(QString::fromLatin1(i->second));
|
||||
int32 from = 0, l = cmds.length();
|
||||
for (int32 to = cmds.indexOf(QChar(';'), from); to >= from; to = (from < l) ? cmds.indexOf(QChar(';'), from) : -1) {
|
||||
QStringRef cmd(&cmds, from, to - from);
|
||||
if (cmd.startsWith(qsl("CMD:"))) {
|
||||
execExternal(cmds.mid(from + 4, to - from - 4));
|
||||
QByteArray response(qsl("RES:%1;").arg(QCoreApplication::applicationPid()).toUtf8());
|
||||
QByteArray response(qsl("RES:%1;").arg(QCoreApplication::applicationPid()).toLatin1());
|
||||
i->first->write(response.data(), response.size());
|
||||
} else if (cmd.startsWith(qsl("SEND:"))) {
|
||||
if (cSendPaths().isEmpty()) {
|
||||
|
@ -878,16 +878,20 @@ void Application::closeApplication() {
|
|||
|
||||
Application::~Application() {
|
||||
App::setQuiting();
|
||||
|
||||
window->setParent(0);
|
||||
|
||||
anim::stopManager();
|
||||
|
||||
socket.close();
|
||||
closeApplication();
|
||||
stopWebLoadManager();
|
||||
App::deinitMedia();
|
||||
deinitImageLinkManager();
|
||||
|
||||
mainApp = 0;
|
||||
delete ::uploader;
|
||||
|
||||
#ifndef TDESKTOP_DISABLE_AUTOUPDATE
|
||||
delete updateReply;
|
||||
updateReply = 0;
|
||||
|
@ -897,7 +901,9 @@ Application::~Application() {
|
|||
updateThread = 0;
|
||||
#endif
|
||||
|
||||
delete window;
|
||||
Window *w = window;
|
||||
window = 0;
|
||||
delete w;
|
||||
|
||||
delete cChatBackground();
|
||||
cSetChatBackground(0);
|
||||
|
@ -906,7 +912,7 @@ Application::~Application() {
|
|||
cSetChatDogImage(0);
|
||||
|
||||
style::stopManager();
|
||||
|
||||
|
||||
delete _translator;
|
||||
}
|
||||
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 178 KiB After Width: | Height: | Size: 177 KiB |
Binary file not shown.
Before Width: | Height: | Size: 240 KiB After Width: | Height: | Size: 238 KiB |
|
@ -27,15 +27,6 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
#define AL_ALEXT_PROTOTYPES
|
||||
#include <AL/alext.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavutil/opt.h>
|
||||
#include <libswresample/swresample.h>
|
||||
|
||||
}
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
|
||||
extern "C" {
|
||||
|
@ -106,15 +97,11 @@ bool _checkALError() {
|
|||
Q_DECLARE_METATYPE(AudioMsgId);
|
||||
Q_DECLARE_METATYPE(SongMsgId);
|
||||
void audioInit() {
|
||||
av_register_all();
|
||||
avcodec_register_all();
|
||||
|
||||
if (!capture) {
|
||||
capture = new AudioCapture();
|
||||
cSetHasAudioCapture(capture->check());
|
||||
}
|
||||
|
||||
uint64 ms = getms();
|
||||
if (audioDevice) return;
|
||||
|
||||
audioDevice = alcOpenDevice(0);
|
||||
|
@ -122,7 +109,7 @@ void audioInit() {
|
|||
LOG(("Audio Error: default sound device not present."));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ALCint attributes[] = { ALC_STEREO_SOURCES, 8, 0 };
|
||||
audioContext = alcCreateContext(audioDevice, attributes);
|
||||
alcMakeContextCurrent(audioContext);
|
||||
|
@ -223,7 +210,6 @@ void audioInit() {
|
|||
player = new AudioPlayer();
|
||||
alcDevicePauseSOFT(audioDevice);
|
||||
|
||||
LOG(("Audio init time: %1").arg(getms() - ms));
|
||||
cSetHasAudioPlayer(true);
|
||||
}
|
||||
|
||||
|
@ -464,7 +450,7 @@ void AudioPlayer::play(const AudioMsgId &audio, int64 position) {
|
|||
}
|
||||
current->audio = audio;
|
||||
current->file = audio.audio->location(true);
|
||||
current->data = audio.audio->data;
|
||||
current->data = audio.audio->data();
|
||||
if (current->file.isEmpty() && current->data.isEmpty()) {
|
||||
setStoppedState(current, AudioPlayerStoppedAtError);
|
||||
onError(audio);
|
||||
|
@ -508,14 +494,11 @@ void AudioPlayer::play(const SongMsgId &song, int64 position) {
|
|||
}
|
||||
current->song = song;
|
||||
current->file = song.song->location(true);
|
||||
current->data = song.song->data;
|
||||
current->data = song.song->data();
|
||||
if (current->file.isEmpty() && current->data.isEmpty()) {
|
||||
setStoppedState(current);
|
||||
if (!song.song->loader) {
|
||||
if (!song.song->loading()) {
|
||||
DocumentOpenLink::doOpen(song.song);
|
||||
song.song->openOnSave = 0;
|
||||
song.song->openOnSaveMsgId = FullMsgId();
|
||||
if (song.song->loader) song.song->loader->start(true, true);
|
||||
}
|
||||
} else {
|
||||
current->state = fadedStart ? AudioPlayerStarting : AudioPlayerPlaying;
|
||||
|
@ -528,7 +511,7 @@ void AudioPlayer::play(const SongMsgId &song, int64 position) {
|
|||
|
||||
bool AudioPlayer::checkCurrentALError(MediaOverviewType type) {
|
||||
if (_checkALError()) return true;
|
||||
|
||||
|
||||
switch (type) {
|
||||
case OverviewAudios:
|
||||
setStoppedState(&_audioData[_audioCurrent], AudioPlayerStoppedAtError);
|
||||
|
@ -1103,7 +1086,7 @@ protected:
|
|||
|
||||
QFile f;
|
||||
int32 dataPos;
|
||||
|
||||
|
||||
bool openFile() {
|
||||
if (data.isEmpty()) {
|
||||
if (f.isOpen()) f.close();
|
||||
|
@ -1126,7 +1109,6 @@ protected:
|
|||
|
||||
};
|
||||
|
||||
static const uint32 AVBlockSize = 4096; // 4Kb
|
||||
static const AVSampleFormat _toFormat = AV_SAMPLE_FMT_S16;
|
||||
static const int64_t _toChannelLayout = AV_CH_LAYOUT_STEREO;
|
||||
static const int32 _toChannels = 2;
|
||||
|
@ -1189,14 +1171,14 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
freq = fmtContext->streams[streamId]->codec->sample_rate;
|
||||
freq = codecContext->sample_rate;
|
||||
if (fmtContext->streams[streamId]->duration == AV_NOPTS_VALUE) {
|
||||
len = (fmtContext->duration * freq) / AV_TIME_BASE;
|
||||
} else {
|
||||
len = (fmtContext->streams[streamId]->duration * freq * fmtContext->streams[streamId]->time_base.num) / fmtContext->streams[streamId]->time_base.den;
|
||||
}
|
||||
uint64_t layout = fmtContext->streams[streamId]->codec->channel_layout;
|
||||
inputFormat = fmtContext->streams[streamId]->codec->sample_fmt;
|
||||
uint64_t layout = codecContext->channel_layout;
|
||||
inputFormat = codecContext->sample_fmt;
|
||||
switch (layout) {
|
||||
case AV_CH_LAYOUT_MONO:
|
||||
switch (inputFormat) {
|
||||
|
@ -1302,7 +1284,7 @@ public:
|
|||
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||
LOG(("Audio Error: Unable to avcodec_decode_audio4() file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
||||
|
||||
av_free_packet(&avpkt);
|
||||
av_packet_unref(&avpkt);
|
||||
if (res == AVERROR_INVALIDDATA) return 0; // try to skip bad packet
|
||||
return -1;
|
||||
}
|
||||
|
@ -1319,7 +1301,7 @@ public:
|
|||
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||
LOG(("Audio Error: Unable to av_samples_alloc for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
||||
|
||||
av_free_packet(&avpkt);
|
||||
av_packet_unref(&avpkt);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -1327,7 +1309,7 @@ public:
|
|||
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||
LOG(("Audio Error: Unable to swr_convert for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
|
||||
|
||||
av_free_packet(&avpkt);
|
||||
av_packet_unref(&avpkt);
|
||||
return -1;
|
||||
}
|
||||
int32 resultLen = av_samples_get_buffer_size(0, _toChannels, res, _toFormat, 1);
|
||||
|
@ -1339,7 +1321,7 @@ public:
|
|||
}
|
||||
}
|
||||
}
|
||||
av_free_packet(&avpkt);
|
||||
av_packet_unref(&avpkt);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1897,7 +1879,7 @@ void AudioCaptureInner::onInit() {
|
|||
}
|
||||
|
||||
void AudioCaptureInner::onStart() {
|
||||
|
||||
|
||||
// Start OpenAL Capture
|
||||
const ALCchar *dName = alcGetString(0, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
|
||||
DEBUG_LOG(("Audio Info: Capture device name '%1'").arg(dName));
|
||||
|
@ -1918,7 +1900,7 @@ void AudioCaptureInner::onStart() {
|
|||
// Create encoding context
|
||||
|
||||
d->ioBuffer = (uchar*)av_malloc(AVBlockSize);
|
||||
|
||||
|
||||
d->ioContext = avio_alloc_context(d->ioBuffer, AVBlockSize, 1, static_cast<void*>(d), &AudioCapturePrivate::_read_data, &AudioCapturePrivate::_write_data, &AudioCapturePrivate::_seek_data);
|
||||
int res = 0;
|
||||
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
|
||||
|
@ -2403,7 +2385,7 @@ public:
|
|||
QString title() {
|
||||
return _title;
|
||||
}
|
||||
|
||||
|
||||
QString performer() {
|
||||
return _performer;
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ void UpdateDownloader::initOutput() {
|
|||
fileName = m.captured(1).replace(QRegularExpression(qsl("[^a-zA-Z0-9_\\-]")), QString());
|
||||
}
|
||||
if (fileName.isEmpty()) {
|
||||
fileName = qsl("tupdate-%1").arg(rand());
|
||||
fileName = qsl("tupdate-%1").arg(MTP::nonce<uint32>() % 1000000);
|
||||
}
|
||||
QString dirStr = cWorkingDir() + qsl("tupdates/");
|
||||
fileName = dirStr + fileName;
|
||||
|
@ -614,4 +614,3 @@ QString countBetaVersionSignature(uint64 version) { // duplicated in packer.cpp
|
|||
signature = signature.replace('-', '8').replace('_', 'B');
|
||||
return QString::fromUtf8(signature.mid(19, 32));
|
||||
}
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ void AboutBox::onVersion() {
|
|||
|
||||
App::app()->clipboard()->setText(url);
|
||||
|
||||
App::showLayer(new InformBox("The link to the current private beta version of Telegram Desktop was copied to the clipboard."));
|
||||
Ui::showLayer(new InformBox("The link to the current private beta version of Telegram Desktop was copied to the clipboard."));
|
||||
} else {
|
||||
QDesktopServices::openUrl(qsl("https://desktop.telegram.org/?_hash=changelog"));
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ void BlueTitleShadow::paintEvent(QPaintEvent *e) {
|
|||
|
||||
BlueTitleClose::BlueTitleClose(QWidget *parent) : Button(parent)
|
||||
, a_iconFg(st::boxBlueCloseBg->c)
|
||||
, _a_over(animFunc(this, &BlueTitleClose::animStep_over)) {
|
||||
, _a_over(animation(this, &BlueTitleClose::step_over)) {
|
||||
resize(st::boxTitleHeight, st::boxTitleHeight);
|
||||
setCursor(style::cur_pointer);
|
||||
connect(this, SIGNAL(stateChanged(int, ButtonStateChangeSource)), this, SLOT(onStateChange(int, ButtonStateChangeSource)));
|
||||
|
@ -49,18 +49,15 @@ void BlueTitleClose::onStateChange(int oldState, ButtonStateChangeSource source)
|
|||
}
|
||||
}
|
||||
|
||||
bool BlueTitleClose::animStep_over(float64 ms) {
|
||||
void BlueTitleClose::step_over(float64 ms, bool timer) {
|
||||
float64 dt = ms / st::boxBlueCloseDuration;
|
||||
bool res = true;
|
||||
if (dt >= 1) {
|
||||
res = false;
|
||||
_a_over.stop();
|
||||
a_iconFg.finish();
|
||||
} else {
|
||||
a_iconFg.update(dt, anim::linear);
|
||||
}
|
||||
update((st::boxTitleHeight - st::boxBlueCloseIcon.pxWidth()) / 2, (st::boxTitleHeight - st::boxBlueCloseIcon.pxHeight()) / 2, st::boxBlueCloseIcon.pxWidth(), st::boxBlueCloseIcon.pxHeight());
|
||||
return res;
|
||||
|
||||
if (timer) update((st::boxTitleHeight - st::boxBlueCloseIcon.pxWidth()) / 2, (st::boxTitleHeight - st::boxBlueCloseIcon.pxHeight()) / 2, st::boxBlueCloseIcon.pxWidth(), st::boxBlueCloseIcon.pxHeight());
|
||||
}
|
||||
|
||||
void BlueTitleClose::paintEvent(QPaintEvent *e) {
|
||||
|
@ -156,7 +153,7 @@ void AbstractBox::paintEvent(QPaintEvent *e) {
|
|||
if (paint(p)) return;
|
||||
}
|
||||
|
||||
void AbstractBox::animStep(float64 ms) {
|
||||
void AbstractBox::showStep(float64 ms) {
|
||||
if (ms >= 1) {
|
||||
a_opacity.finish();
|
||||
_cache = QPixmap();
|
||||
|
|
|
@ -41,7 +41,7 @@ public slots:
|
|||
void onStateChange(int oldState, ButtonStateChangeSource source);
|
||||
|
||||
private:
|
||||
bool animStep_over(float64 ms);
|
||||
void step_over(float64 ms, bool timer);
|
||||
anim::cvalue a_iconFg;
|
||||
Animation _a_over;
|
||||
|
||||
|
@ -54,7 +54,7 @@ public:
|
|||
|
||||
AbstractBox(int32 w = st::boxWideWidth);
|
||||
void parentResized();
|
||||
void animStep(float64 ms);
|
||||
void showStep(float64 ms);
|
||||
void keyPressEvent(QKeyEvent *e);
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
void paintEvent(QPaintEvent *e);
|
||||
|
|
|
@ -235,8 +235,8 @@ void AddContactBox::onImportDone(const MTPcontacts_ImportedContacts &res) {
|
|||
}
|
||||
}
|
||||
if (uid) {
|
||||
App::main()->addNewContact(uid);
|
||||
App::wnd()->hideLayer();
|
||||
Notify::userIsContactChanged(App::userLoaded(peerFromUser(uid)), true);
|
||||
Ui::hideLayer();
|
||||
} else {
|
||||
_save.hide();
|
||||
_first.hide();
|
||||
|
@ -336,13 +336,13 @@ void NewGroupBox::resizeEvent(QResizeEvent *e) {
|
|||
}
|
||||
|
||||
void NewGroupBox::onNext() {
|
||||
App::wnd()->replaceLayer(new GroupInfoBox(_group.checked() ? CreatingGroupGroup : CreatingGroupChannel, true));
|
||||
Ui::showLayer(new GroupInfoBox(_group.checked() ? CreatingGroupGroup : CreatingGroupChannel, true), KeepOtherLayers);
|
||||
}
|
||||
|
||||
GroupInfoBox::GroupInfoBox(CreatingGroupType creating, bool fromTypeChoose) : AbstractBox(),
|
||||
_creating(creating),
|
||||
a_photoOver(0, 0),
|
||||
_a_photoOver(animFunc(this, &GroupInfoBox::animStep_photoOver)),
|
||||
_a_photoOver(animation(this, &GroupInfoBox::step_photoOver)),
|
||||
_photoOver(false),
|
||||
_title(this, st::defaultInputField, lang(_creating == CreatingGroupChannel ? lng_dlg_new_channel_name : lng_dlg_new_group_name)),
|
||||
_description(this, st::newGroupDescription, lang(lng_create_group_description)),
|
||||
|
@ -464,17 +464,15 @@ void GroupInfoBox::leaveEvent(QEvent *e) {
|
|||
updateSelected(QCursor::pos());
|
||||
}
|
||||
|
||||
bool GroupInfoBox::animStep_photoOver(float64 ms) {
|
||||
void GroupInfoBox::step_photoOver(float64 ms, bool timer) {
|
||||
float64 dt = ms / st::setPhotoDuration;
|
||||
bool res = true;
|
||||
if (dt >= 1) {
|
||||
res = false;
|
||||
_a_photoOver.stop();
|
||||
a_photoOver.finish();
|
||||
} else {
|
||||
a_photoOver.update(dt, anim::linear);
|
||||
}
|
||||
update(photoRect());
|
||||
return res;
|
||||
if (timer) update(photoRect());
|
||||
}
|
||||
|
||||
void GroupInfoBox::onNameSubmit() {
|
||||
|
@ -498,7 +496,7 @@ void GroupInfoBox::onNext() {
|
|||
return;
|
||||
}
|
||||
if (_creating == CreatingGroupGroup) {
|
||||
App::wnd()->replaceLayer(new ContactsBox(title, _photoBig));
|
||||
Ui::showLayer(new ContactsBox(title, _photoBig), KeepOtherLayers);
|
||||
} else {
|
||||
bool mega = false;
|
||||
int32 flags = mega ? MTPchannels_CreateChannel::flag_megagroup : MTPchannels_CreateChannel::flag_broadcast;
|
||||
|
@ -551,7 +549,7 @@ void GroupInfoBox::exportDone(const MTPExportedChatInvite &result) {
|
|||
if (result.type() == mtpc_chatInviteExported) {
|
||||
_createdChannel->invitationUrl = qs(result.c_chatInviteExported().vlink);
|
||||
}
|
||||
App::wnd()->showLayer(new SetupChannelBox(_createdChannel));
|
||||
Ui::showLayer(new SetupChannelBox(_createdChannel));
|
||||
}
|
||||
|
||||
void GroupInfoBox::onDescriptionResized() {
|
||||
|
@ -595,7 +593,7 @@ void GroupInfoBox::onPhoto() {
|
|||
}
|
||||
PhotoCropBox *box = new PhotoCropBox(img, (_creating == CreatingGroupChannel) ? peerFromChannel(0) : peerFromChat(0));
|
||||
connect(box, SIGNAL(ready(const QImage&)), this, SLOT(onPhotoReady(const QImage&)));
|
||||
App::wnd()->replaceLayer(box);
|
||||
Ui::showLayer(box, KeepOtherLayers);
|
||||
}
|
||||
|
||||
void GroupInfoBox::onPhotoReady(const QImage &img) {
|
||||
|
@ -604,23 +602,25 @@ void GroupInfoBox::onPhotoReady(const QImage &img) {
|
|||
_photoSmall.setDevicePixelRatio(cRetinaFactor());
|
||||
}
|
||||
|
||||
SetupChannelBox::SetupChannelBox(ChannelData *channel, bool existing) : AbstractBox(),
|
||||
_channel(channel),
|
||||
_existing(existing),
|
||||
_public(this, qsl("channel_privacy"), 0, lang(lng_create_public_channel_title), true),
|
||||
_private(this, qsl("channel_privacy"), 1, lang(lng_create_private_channel_title)),
|
||||
_comments(this, lang(lng_create_channel_comments), false),
|
||||
_aboutPublicWidth(width() - st::boxPadding.left() - st::boxButtonPadding.right() - st::newGroupPadding.left() - st::defaultRadiobutton.textPosition.x()),
|
||||
_aboutPublic(st::normalFont, lang(lng_create_public_channel_about), _defaultOptions, _aboutPublicWidth),
|
||||
_aboutPrivate(st::normalFont, lang(lng_create_private_channel_about), _defaultOptions, _aboutPublicWidth),
|
||||
_aboutComments(st::normalFont, lang(lng_create_channel_comments_about), _defaultOptions, _aboutPublicWidth),
|
||||
_link(this, st::defaultInputField, QString(), channel->username, true),
|
||||
_linkOver(false),
|
||||
_save(this, lang(lng_settings_save), st::defaultBoxButton),
|
||||
_skip(this, lang(existing ? lng_cancel : lng_create_group_skip), st::cancelBoxButton),
|
||||
_tooMuchUsernames(false),
|
||||
_saveRequestId(0), _checkRequestId(0),
|
||||
a_goodOpacity(0, 0), _a_goodFade(animFunc(this, &SetupChannelBox::animStep_goodFade)) {
|
||||
SetupChannelBox::SetupChannelBox(ChannelData *channel, bool existing) : AbstractBox()
|
||||
, _channel(channel)
|
||||
, _existing(existing)
|
||||
, _public(this, qsl("channel_privacy"), 0, lang(lng_create_public_channel_title), true)
|
||||
, _private(this, qsl("channel_privacy"), 1, lang(lng_create_private_channel_title))
|
||||
, _comments(this, lang(lng_create_channel_comments), false)
|
||||
, _aboutPublicWidth(width() - st::boxPadding.left() - st::boxButtonPadding.right() - st::newGroupPadding.left() - st::defaultRadiobutton.textPosition.x())
|
||||
, _aboutPublic(st::normalFont, lang(lng_create_public_channel_about), _defaultOptions, _aboutPublicWidth)
|
||||
, _aboutPrivate(st::normalFont, lang(lng_create_private_channel_about), _defaultOptions, _aboutPublicWidth)
|
||||
, _aboutComments(st::normalFont, lang(lng_create_channel_comments_about), _defaultOptions, _aboutPublicWidth)
|
||||
, _link(this, st::defaultInputField, QString(), channel->username, true)
|
||||
, _linkOver(false)
|
||||
, _save(this, lang(lng_settings_save), st::defaultBoxButton)
|
||||
, _skip(this, lang(existing ? lng_cancel : lng_create_group_skip), st::cancelBoxButton)
|
||||
, _tooMuchUsernames(false)
|
||||
, _saveRequestId(0)
|
||||
, _checkRequestId(0)
|
||||
, a_goodOpacity(0, 0)
|
||||
, _a_goodFade(animation(this, &SetupChannelBox::step_goodFade)) {
|
||||
setMouseTracking(true);
|
||||
|
||||
_checkRequestId = MTP::send(MTPchannels_CheckUsername(_channel->inputChannel, MTP_string("preston")), RPCDoneHandlerPtr(), rpcFail(&SetupChannelBox::onFirstCheckFail));
|
||||
|
@ -772,22 +772,20 @@ void SetupChannelBox::updateSelected(const QPoint &cursorGlobalPosition) {
|
|||
}
|
||||
}
|
||||
|
||||
bool SetupChannelBox::animStep_goodFade(float64 ms) {
|
||||
void SetupChannelBox::step_goodFade(float64 ms, bool timer) {
|
||||
float dt = ms / st::newGroupLinkFadeDuration;
|
||||
bool res = true;
|
||||
if (dt >= 1) {
|
||||
res = false;
|
||||
_a_goodFade.stop();
|
||||
a_goodOpacity.finish();
|
||||
} else {
|
||||
a_goodOpacity.update(dt, anim::linear);
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
if (timer) update();
|
||||
}
|
||||
|
||||
void SetupChannelBox::closePressed() {
|
||||
if (!_existing) {
|
||||
App::wnd()->showLayer(new ContactsBox(_channel));
|
||||
Ui::showLayer(new ContactsBox(_channel));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -872,7 +870,7 @@ void SetupChannelBox::onPrivacyChange() {
|
|||
if (_public.checked()) {
|
||||
if (_tooMuchUsernames) {
|
||||
_private.setChecked(true);
|
||||
App::wnd()->replaceLayer(new InformBox(lang(lng_channels_too_much_public)));
|
||||
Ui::showLayer(new InformBox(lang(lng_channels_too_much_public)), KeepOtherLayers);
|
||||
return;
|
||||
}
|
||||
_link.show();
|
||||
|
@ -933,7 +931,7 @@ bool SetupChannelBox::onCheckFail(const RPCError &error) {
|
|||
QString err(error.type());
|
||||
if (err == "CHANNELS_ADMIN_PUBLIC_TOO_MUCH") {
|
||||
if (_existing) {
|
||||
App::wnd()->showLayer(new InformBox(lang(lng_channels_too_much_public_existing)));
|
||||
Ui::showLayer(new InformBox(lang(lng_channels_too_much_public_existing)));
|
||||
} else {
|
||||
_tooMuchUsernames = true;
|
||||
_private.setChecked(true);
|
||||
|
@ -961,7 +959,7 @@ bool SetupChannelBox::onFirstCheckFail(const RPCError &error) {
|
|||
QString err(error.type());
|
||||
if (err == "CHANNELS_ADMIN_PUBLIC_TOO_MUCH") {
|
||||
if (_existing) {
|
||||
App::wnd()->showLayer(new InformBox(lang(lng_channels_too_much_public_existing)));
|
||||
Ui::showLayer(new InformBox(lang(lng_channels_too_much_public_existing)));
|
||||
} else {
|
||||
_tooMuchUsernames = true;
|
||||
_private.setChecked(true);
|
||||
|
@ -1269,7 +1267,7 @@ void EditChannelBox::onSave() {
|
|||
}
|
||||
|
||||
void EditChannelBox::onPublicLink() {
|
||||
App::wnd()->replaceLayer(new SetupChannelBox(_channel, true));
|
||||
Ui::showLayer(new SetupChannelBox(_channel, true), KeepOtherLayers);
|
||||
}
|
||||
|
||||
void EditChannelBox::saveDescription() {
|
||||
|
|
|
@ -113,8 +113,6 @@ public:
|
|||
void mousePressEvent(QMouseEvent *e);
|
||||
void leaveEvent(QEvent *e);
|
||||
|
||||
bool animStep_photoOver(float64 ms);
|
||||
|
||||
void setInnerFocus() {
|
||||
_title.setFocus();
|
||||
}
|
||||
|
@ -136,6 +134,8 @@ protected:
|
|||
|
||||
private:
|
||||
|
||||
void step_photoOver(float64 ms, bool timer);
|
||||
|
||||
QRect photoRect() const;
|
||||
|
||||
void updateMaxHeight();
|
||||
|
@ -202,7 +202,7 @@ protected:
|
|||
private:
|
||||
|
||||
void updateSelected(const QPoint &cursorGlobalPosition);
|
||||
bool animStep_goodFade(float64 ms);
|
||||
void step_goodFade(float64 ms, bool timer);
|
||||
|
||||
void onUpdateDone(const MTPBool &result);
|
||||
bool onUpdateFail(const RPCError &error);
|
||||
|
|
|
@ -94,7 +94,7 @@ void ConfirmBox::mouseReleaseEvent(QMouseEvent *e) {
|
|||
_lastMousePos = e->globalPos();
|
||||
updateHover();
|
||||
if (textlnkOver() && textlnkOver() == textlnkDown()) {
|
||||
App::wnd()->hideLayer();
|
||||
Ui::hideLayer();
|
||||
textlnkOver()->onClick(e->button());
|
||||
}
|
||||
textlnkDown(TextLinkPtr());
|
||||
|
@ -184,14 +184,16 @@ void ConfirmLinkBox::onOpenLink() {
|
|||
} else {
|
||||
TextLink(_url).onClick(Qt::LeftButton);
|
||||
}
|
||||
App::wnd()->hideLayer();
|
||||
Ui::hideLayer();
|
||||
}
|
||||
|
||||
MaxInviteBox::MaxInviteBox(const QString &link) : AbstractBox(st::boxWidth),
|
||||
_close(this, lang(lng_box_ok), st::defaultBoxButton),
|
||||
_text(st::boxTextFont, lng_participant_invite_sorry(lt_count, cMaxGroupCount()), _confirmBoxTextOptions, st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right()),
|
||||
_link(link), _linkOver(false),
|
||||
a_goodOpacity(0, 0), a_good(animFunc(this, &MaxInviteBox::goodAnimStep)) {
|
||||
MaxInviteBox::MaxInviteBox(const QString &link) : AbstractBox(st::boxWidth)
|
||||
, _close(this, lang(lng_box_ok), st::defaultBoxButton)
|
||||
, _text(st::boxTextFont, lng_participant_invite_sorry(lt_count, cMaxGroupCount()), _confirmBoxTextOptions, st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right())
|
||||
, _link(link)
|
||||
, _linkOver(false)
|
||||
, a_goodOpacity(0, 0)
|
||||
, _a_good(animation(this, &MaxInviteBox::step_good)) {
|
||||
setMouseTracking(true);
|
||||
|
||||
_textWidth = st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right();
|
||||
|
@ -213,7 +215,7 @@ void MaxInviteBox::mousePressEvent(QMouseEvent *e) {
|
|||
App::app()->clipboard()->setText(_link);
|
||||
_goodTextLink = lang(lng_create_channel_link_copied);
|
||||
a_goodOpacity = anim::fvalue(1, 0);
|
||||
a_good.start();
|
||||
_a_good.start();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -232,17 +234,15 @@ void MaxInviteBox::updateSelected(const QPoint &cursorGlobalPosition) {
|
|||
}
|
||||
}
|
||||
|
||||
bool MaxInviteBox::goodAnimStep(float64 ms) {
|
||||
void MaxInviteBox::step_good(float64 ms, bool timer) {
|
||||
float dt = ms / st::newGroupLinkFadeDuration;
|
||||
bool res = true;
|
||||
if (dt >= 1) {
|
||||
res = false;
|
||||
_a_good.stop();
|
||||
a_goodOpacity.finish();
|
||||
} else {
|
||||
a_goodOpacity.update(dt, anim::linear);
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
if (timer) update();
|
||||
}
|
||||
|
||||
void MaxInviteBox::hideAll() {
|
||||
|
|
|
@ -108,8 +108,7 @@ public:
|
|||
void mouseMoveEvent(QMouseEvent *e);
|
||||
void mousePressEvent(QMouseEvent *e);
|
||||
void leaveEvent(QEvent *e);
|
||||
void updateLink();
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
void hideAll();
|
||||
|
@ -118,7 +117,7 @@ protected:
|
|||
private:
|
||||
|
||||
void updateSelected(const QPoint &cursorGlobalPosition);
|
||||
bool goodAnimStep(float64 ms);
|
||||
void step_good(float64 ms, bool timer);
|
||||
|
||||
BoxButton _close;
|
||||
Text _text;
|
||||
|
@ -132,5 +131,5 @@ private:
|
|||
|
||||
QString _goodTextLink;
|
||||
anim::fvalue a_goodOpacity;
|
||||
Animation a_good;
|
||||
Animation _a_good;
|
||||
};
|
||||
|
|
|
@ -27,17 +27,17 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
#include "mainwidget.h"
|
||||
#include "window.h"
|
||||
|
||||
ConnectionBox::ConnectionBox() : AbstractBox(st::boxWidth),
|
||||
_hostInput(this, st::connectionHostInputField, lang(lng_connection_host_ph), cConnectionProxy().host),
|
||||
_portInput(this, st::connectionPortInputField, lang(lng_connection_port_ph), QString::number(cConnectionProxy().port)),
|
||||
_userInput(this, st::connectionUserInputField, lang(lng_connection_user_ph), cConnectionProxy().user),
|
||||
_passwordInput(this, st::connectionPasswordInputField, lang(lng_connection_password_ph), cConnectionProxy().password),
|
||||
_autoRadio(this, qsl("conn_type"), dbictAuto, lang(lng_connection_auto_rb), (cConnectionType() == dbictAuto)),
|
||||
_httpProxyRadio(this, qsl("conn_type"), dbictHttpProxy, lang(lng_connection_http_proxy_rb), (cConnectionType() == dbictHttpProxy)),
|
||||
_tcpProxyRadio(this, qsl("conn_type"), dbictTcpProxy, lang(lng_connection_tcp_proxy_rb), (cConnectionType() == dbictTcpProxy)),
|
||||
_tryIPv6(this, lang(lng_connection_try_ipv6), cTryIPv6()),
|
||||
_save(this, lang(lng_connection_save), st::defaultBoxButton),
|
||||
_cancel(this, lang(lng_cancel), st::cancelBoxButton) {
|
||||
ConnectionBox::ConnectionBox() : AbstractBox(st::boxWidth)
|
||||
, _hostInput(this, st::connectionHostInputField, lang(lng_connection_host_ph), cConnectionProxy().host)
|
||||
, _portInput(this, st::connectionPortInputField, lang(lng_connection_port_ph), QString::number(cConnectionProxy().port))
|
||||
, _userInput(this, st::connectionUserInputField, lang(lng_connection_user_ph), cConnectionProxy().user)
|
||||
, _passwordInput(this, st::connectionPasswordInputField, lang(lng_connection_password_ph), cConnectionProxy().password)
|
||||
, _autoRadio(this, qsl("conn_type"), dbictAuto, lang(lng_connection_auto_rb), (cConnectionType() == dbictAuto))
|
||||
, _httpProxyRadio(this, qsl("conn_type"), dbictHttpProxy, lang(lng_connection_http_proxy_rb), (cConnectionType() == dbictHttpProxy))
|
||||
, _tcpProxyRadio(this, qsl("conn_type"), dbictTcpProxy, lang(lng_connection_tcp_proxy_rb), (cConnectionType() == dbictTcpProxy))
|
||||
, _tryIPv6(this, lang(lng_connection_try_ipv6), cTryIPv6())
|
||||
, _save(this, lang(lng_connection_save), st::defaultBoxButton)
|
||||
, _cancel(this, lang(lng_cancel), st::cancelBoxButton) {
|
||||
|
||||
connect(&_save, SIGNAL(clicked()), this, SLOT(onSave()));
|
||||
connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
|
||||
|
@ -215,6 +215,132 @@ void ConnectionBox::onSave() {
|
|||
Local::writeSettings();
|
||||
MTP::restart();
|
||||
reinitImageLinkManager();
|
||||
reinitWebLoadManager();
|
||||
emit closed();
|
||||
}
|
||||
}
|
||||
|
||||
AutoDownloadBox::AutoDownloadBox() : AbstractBox(st::boxWidth)
|
||||
, _photoPrivate(this, lang(lng_media_auto_private_chats), !(cAutoDownloadPhoto() & dbiadNoPrivate))
|
||||
, _photoGroups(this, lang(lng_media_auto_groups), !(cAutoDownloadPhoto() & dbiadNoGroups))
|
||||
, _audioPrivate(this, lang(lng_media_auto_private_chats), !(cAutoDownloadAudio() & dbiadNoPrivate))
|
||||
, _audioGroups(this, lang(lng_media_auto_groups), !(cAutoDownloadAudio() & dbiadNoGroups))
|
||||
, _gifPrivate(this, lang(lng_media_auto_private_chats), !(cAutoDownloadGif() & dbiadNoPrivate))
|
||||
, _gifGroups(this, lang(lng_media_auto_groups), !(cAutoDownloadGif() & dbiadNoGroups))
|
||||
, _gifPlay(this, lang(lng_media_auto_play), cAutoPlayGif())
|
||||
, _sectionHeight(st::boxTitleHeight + 2 * (st::defaultCheckbox.height + st::setLittleSkip))
|
||||
, _save(this, lang(lng_connection_save), st::defaultBoxButton)
|
||||
, _cancel(this, lang(lng_cancel), st::cancelBoxButton) {
|
||||
|
||||
setMaxHeight(3 * _sectionHeight + st::setLittleSkip + _gifPlay.height() + st::setLittleSkip + st::boxButtonPadding.top() + _save.height() + st::boxButtonPadding.bottom());
|
||||
|
||||
connect(&_save, SIGNAL(clicked()), this, SLOT(onSave()));
|
||||
connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
|
||||
|
||||
prepare();
|
||||
}
|
||||
|
||||
void AutoDownloadBox::hideAll() {
|
||||
_photoPrivate.hide();
|
||||
_photoGroups.hide();
|
||||
_audioPrivate.hide();
|
||||
_audioGroups.hide();
|
||||
_gifPrivate.hide();
|
||||
_gifGroups.hide();
|
||||
_gifPlay.hide();
|
||||
|
||||
_save.hide();
|
||||
_cancel.hide();
|
||||
}
|
||||
|
||||
void AutoDownloadBox::showAll() {
|
||||
_photoPrivate.show();
|
||||
_photoGroups.show();
|
||||
_audioPrivate.show();
|
||||
_audioGroups.show();
|
||||
_gifPrivate.show();
|
||||
_gifGroups.show();
|
||||
_gifPlay.show();
|
||||
|
||||
_save.show();
|
||||
_cancel.show();
|
||||
}
|
||||
|
||||
void AutoDownloadBox::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
if (paint(p)) return;
|
||||
|
||||
p.setPen(st::black);
|
||||
p.setFont(st::semiboldFont);
|
||||
p.drawTextLeft(st::boxTitlePosition.x(), st::boxTitlePosition.y(), width(), lang(lng_media_auto_photo));
|
||||
p.drawTextLeft(st::boxTitlePosition.x(), _sectionHeight + st::boxTitlePosition.y(), width(), lang(lng_media_auto_audio));
|
||||
p.drawTextLeft(st::boxTitlePosition.x(), 2 * _sectionHeight + st::boxTitlePosition.y(), width(), lang(lng_media_auto_gif));
|
||||
}
|
||||
|
||||
void AutoDownloadBox::resizeEvent(QResizeEvent *e) {
|
||||
_photoPrivate.moveToLeft(st::boxTitlePosition.x(), st::boxTitleHeight + st::setLittleSkip);
|
||||
_photoGroups.moveToLeft(st::boxTitlePosition.x(), _photoPrivate.y() + _photoPrivate.height() + st::setLittleSkip);
|
||||
|
||||
_audioPrivate.moveToLeft(st::boxTitlePosition.x(), _sectionHeight + st::boxTitleHeight + st::setLittleSkip);
|
||||
_audioGroups.moveToLeft(st::boxTitlePosition.x(), _audioPrivate.y() + _audioPrivate.height() + st::setLittleSkip);
|
||||
|
||||
_gifPrivate.moveToLeft(st::boxTitlePosition.x(), 2 * _sectionHeight + st::boxTitleHeight + st::setLittleSkip);
|
||||
_gifGroups.moveToLeft(st::boxTitlePosition.x(), _gifPrivate.y() + _gifPrivate.height() + st::setLittleSkip);
|
||||
_gifPlay.moveToLeft(st::boxTitlePosition.x(), _gifGroups.y() + _gifGroups.height() + st::setLittleSkip);
|
||||
|
||||
_save.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _save.height());
|
||||
_cancel.moveToRight(st::boxButtonPadding.right() + _save.width() + st::boxButtonPadding.left(), _save.y());
|
||||
}
|
||||
|
||||
void AutoDownloadBox::onSave() {
|
||||
bool changed = false;
|
||||
int32 autoDownloadPhoto = (_photoPrivate.checked() ? 0 : dbiadNoPrivate) | (_photoGroups.checked() ? 0 : dbiadNoGroups);
|
||||
if (cAutoDownloadPhoto() != autoDownloadPhoto) {
|
||||
bool enabledPrivate = ((cAutoDownloadPhoto() & dbiadNoPrivate) && !(autoDownloadPhoto & dbiadNoPrivate));
|
||||
bool enabledGroups = ((cAutoDownloadPhoto() & dbiadNoGroups) && !(autoDownloadPhoto & dbiadNoGroups));
|
||||
cSetAutoDownloadPhoto(autoDownloadPhoto);
|
||||
if (enabledPrivate || enabledGroups) {
|
||||
const PhotosData &data(App::photosData());
|
||||
for (PhotosData::const_iterator i = data.cbegin(), e = data.cend(); i != e; ++i) {
|
||||
i.value()->automaticLoadSettingsChanged();
|
||||
}
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
int32 autoDownloadAudio = (_audioPrivate.checked() ? 0 : dbiadNoPrivate) | (_audioGroups.checked() ? 0 : dbiadNoGroups);
|
||||
if (cAutoDownloadAudio() != autoDownloadAudio) {
|
||||
bool enabledPrivate = ((cAutoDownloadAudio() & dbiadNoPrivate) && !(autoDownloadAudio & dbiadNoPrivate));
|
||||
bool enabledGroups = ((cAutoDownloadAudio() & dbiadNoGroups) && !(autoDownloadAudio & dbiadNoGroups));
|
||||
cSetAutoDownloadAudio(autoDownloadAudio);
|
||||
if (enabledPrivate || enabledGroups) {
|
||||
const AudiosData &data(App::audiosData());
|
||||
for (AudiosData::const_iterator i = data.cbegin(), e = data.cend(); i != e; ++i) {
|
||||
i.value()->automaticLoadSettingsChanged();
|
||||
}
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
int32 autoDownloadGif = (_gifPrivate.checked() ? 0 : dbiadNoPrivate) | (_gifGroups.checked() ? 0 : dbiadNoGroups);
|
||||
if (cAutoDownloadGif() != autoDownloadGif) {
|
||||
bool enabledPrivate = ((cAutoDownloadGif() & dbiadNoPrivate) && !(autoDownloadGif & dbiadNoPrivate));
|
||||
bool enabledGroups = ((cAutoDownloadGif() & dbiadNoGroups) && !(autoDownloadGif & dbiadNoGroups));
|
||||
cSetAutoDownloadGif(autoDownloadGif);
|
||||
if (enabledPrivate || enabledGroups) {
|
||||
const DocumentsData &data(App::documentsData());
|
||||
for (DocumentsData::const_iterator i = data.cbegin(), e = data.cend(); i != e; ++i) {
|
||||
i.value()->automaticLoadSettingsChanged();
|
||||
}
|
||||
Notify::automaticLoadSettingsChangedGif();
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
if (cAutoPlayGif() != _gifPlay.checked()) {
|
||||
cSetAutoPlayGif(_gifPlay.checked());
|
||||
if (!cAutoPlayGif()) {
|
||||
App::stopGifItems();
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
if (changed) Local::writeUserSettings();
|
||||
onClose();
|
||||
}
|
||||
|
|
|
@ -54,3 +54,32 @@ private:
|
|||
|
||||
BoxButton _save, _cancel;
|
||||
};
|
||||
|
||||
class AutoDownloadBox : public AbstractBox {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
AutoDownloadBox();
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
|
||||
public slots:
|
||||
|
||||
void onSave();
|
||||
|
||||
protected:
|
||||
|
||||
void hideAll();
|
||||
void showAll();
|
||||
|
||||
private:
|
||||
|
||||
Checkbox _photoPrivate, _photoGroups;
|
||||
Checkbox _audioPrivate, _audioGroups;
|
||||
Checkbox _gifPrivate, _gifGroups, _gifPlay;
|
||||
|
||||
int32 _sectionHeight;
|
||||
|
||||
BoxButton _save, _cancel;
|
||||
};
|
||||
|
|
|
@ -228,8 +228,8 @@ void ContactsInner::onAddBot() {
|
|||
} else {
|
||||
App::main()->addParticipants(_addToPeer, QVector<UserData*>(1, _bot));
|
||||
}
|
||||
App::wnd()->hideLayer();
|
||||
App::main()->showPeerHistory(_addToPeer->id, ShowAtUnreadMsgId);
|
||||
Ui::hideLayer();
|
||||
Ui::showPeerHistory(_addToPeer, ShowAtUnreadMsgId);
|
||||
}
|
||||
|
||||
void ContactsInner::onAddAdmin() {
|
||||
|
@ -269,9 +269,9 @@ bool ContactsInner::addAdminFail(const RPCError &error, mtpRequestId req) {
|
|||
_addAdminRequestId = 0;
|
||||
if (_addAdminBox) _addAdminBox->onClose();
|
||||
if (error.type() == "USERS_TOO_MUCH") {
|
||||
App::wnd()->replaceLayer(new MaxInviteBox(_channel->invitationUrl));
|
||||
Ui::showLayer(new MaxInviteBox(_channel->invitationUrl), KeepOtherLayers);
|
||||
} else if (error.type() == "ADMINS_TOO_MUCH") {
|
||||
App::wnd()->replaceLayer(new InformBox(lang(lng_channel_admins_too_much)));
|
||||
Ui::showLayer(new InformBox(lang(lng_channel_admins_too_much)), KeepOtherLayers);
|
||||
} else {
|
||||
emit adminAdded();
|
||||
}
|
||||
|
@ -292,7 +292,7 @@ void ContactsInner::peerUpdated(PeerData *peer) {
|
|||
inited = true;
|
||||
}
|
||||
if (!_chat->canEdit()) {
|
||||
App::wnd()->hideLayer();
|
||||
Ui::hideLayer();
|
||||
} else if (!_chat->participants.isEmpty()) {
|
||||
for (ContactsData::iterator i = _contactsData.begin(), e = _contactsData.end(); i != e; ++i) {
|
||||
delete i.value();
|
||||
|
@ -741,16 +741,16 @@ void ContactsInner::chooseParticipant() {
|
|||
_addAdminBox = new ConfirmBox(lng_channel_admin_sure(lt_user, _addAdmin->firstName));
|
||||
connect(_addAdminBox, SIGNAL(confirmed()), this, SLOT(onAddAdmin()));
|
||||
connect(_addAdminBox, SIGNAL(destroyed(QObject*)), this, SLOT(onNoAddAdminBox(QObject*)));
|
||||
App::wnd()->replaceLayer(_addAdminBox);
|
||||
Ui::showLayer(_addAdminBox, KeepOtherLayers);
|
||||
} else if (bot() && (peer->isChat() || peer->isMegagroup())) {
|
||||
_addToPeer = peer;
|
||||
ConfirmBox *box = new ConfirmBox(lng_bot_sure_invite(lt_group, peer->name));
|
||||
connect(box, SIGNAL(confirmed()), this, SLOT(onAddBot()));
|
||||
App::wnd()->replaceLayer(box);
|
||||
Ui::showLayer(box, KeepOtherLayers);
|
||||
} else {
|
||||
App::wnd()->hideSettings(true);
|
||||
App::main()->choosePeer(peer->id, ShowAtUnreadMsgId);
|
||||
App::wnd()->hideLayer();
|
||||
Ui::hideLayer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1558,7 +1558,7 @@ void ContactsBox::resizeEvent(QResizeEvent *e) {
|
|||
|
||||
void ContactsBox::closePressed() {
|
||||
if (_inner.channel() && !_inner.hasAlreadyMembersInChannel()) {
|
||||
App::main()->showPeerHistory(_inner.channel()->id, ShowAtTheEndMsgId);
|
||||
Ui::showPeerHistory(_inner.channel(), ShowAtTheEndMsgId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1590,8 +1590,8 @@ void ContactsBox::onInvite() {
|
|||
|
||||
App::main()->addParticipants(_inner.chat() ? (PeerData*)_inner.chat() : _inner.channel(), users);
|
||||
if (_inner.chat()) {
|
||||
App::wnd()->hideLayer();
|
||||
App::main()->showPeerHistory(_inner.chat()->id, ShowAtTheEndMsgId);
|
||||
Ui::hideLayer();
|
||||
Ui::showPeerHistory(_inner.chat(), ShowAtTheEndMsgId);
|
||||
} else {
|
||||
onClose();
|
||||
}
|
||||
|
@ -1713,7 +1713,7 @@ void ContactsBox::onScroll() {
|
|||
}
|
||||
|
||||
void ContactsBox::creationDone(const MTPUpdates &updates) {
|
||||
App::wnd()->hideLayer();
|
||||
Ui::hideLayer();
|
||||
|
||||
App::main()->sentUpdatesReceived(updates);
|
||||
const QVector<MTPChat> *v = 0;
|
||||
|
@ -1730,7 +1730,7 @@ void ContactsBox::creationDone(const MTPUpdates &updates) {
|
|||
if (!_creationPhoto.isNull()) {
|
||||
App::app()->uploadProfilePhoto(_creationPhoto, peer->id);
|
||||
}
|
||||
App::main()->showPeerHistory(peer->id, ShowAtUnreadMsgId);
|
||||
Ui::showPeerHistory(peer, ShowAtUnreadMsgId);
|
||||
}
|
||||
} else {
|
||||
LOG(("API Error: chat not found in updates (ContactsBox::creationDone)"));
|
||||
|
@ -1749,7 +1749,7 @@ bool ContactsBox::creationFail(const RPCError &error) {
|
|||
_filter.showError();
|
||||
return true;
|
||||
} else if (error.type() == "PEER_FLOOD") {
|
||||
App::wnd()->replaceLayer(new InformBox(lng_cant_invite_not_contact(lt_more_info, textcmdLink(qsl("https://telegram.org/faq?_hash=can-39t-send-messages-to-non-contacts"), lang(lng_cant_more_info)))));
|
||||
Ui::showLayer(new InformBox(lng_cant_invite_not_contact(lt_more_info, textcmdLink(qsl("https://telegram.org/faq?_hash=can-39t-send-messages-to-non-contacts"), lang(lng_cant_more_info)))), KeepOtherLayers);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -1872,7 +1872,7 @@ void MembersInner::mouseReleaseEvent(QMouseEvent *e) {
|
|||
_kickBox = new ConfirmBox((_filter == MembersFilterRecent ? (_channel->isMegagroup() ? lng_profile_sure_kick : lng_profile_sure_kick_channel) : lng_profile_sure_kick_admin)(lt_user, _kickConfirm->firstName));
|
||||
connect(_kickBox, SIGNAL(confirmed()), this, SLOT(onKickConfirm()));
|
||||
connect(_kickBox, SIGNAL(destroyed(QObject*)), this, SLOT(onKickBoxDestroyed(QObject*)));
|
||||
App::wnd()->replaceLayer(_kickBox);
|
||||
Ui::showLayer(_kickBox, KeepOtherLayers);
|
||||
}
|
||||
_kickDown = -1;
|
||||
}
|
||||
|
@ -1993,7 +1993,7 @@ void MembersInner::chooseParticipant() {
|
|||
}
|
||||
if (_sel < 0 || _sel >= _rows.size()) return;
|
||||
if (PeerData *peer = _rows[_sel]) {
|
||||
App::wnd()->hideLayer();
|
||||
Ui::hideLayer();
|
||||
App::main()->showPeerProfile(peer, ShowAtUnreadMsgId);
|
||||
}
|
||||
}
|
||||
|
@ -2199,7 +2199,7 @@ void MembersInner::membersReceived(const MTPchannels_ChannelParticipants &result
|
|||
|
||||
bool MembersInner::membersFailed(const RPCError &error, mtpRequestId req) {
|
||||
if (mtpIsFlood(error)) return false;
|
||||
App::wnd()->hideLayer();
|
||||
Ui::hideLayer();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2298,16 +2298,16 @@ void MembersBox::onScroll() {
|
|||
|
||||
void MembersBox::onAdd() {
|
||||
if (_inner.filter() == MembersFilterRecent && _inner.channel()->count >= (_inner.channel()->isMegagroup() ? cMaxMegaGroupCount() : cMaxGroupCount())) {
|
||||
App::wnd()->replaceLayer(new MaxInviteBox(_inner.channel()->invitationUrl));
|
||||
Ui::showLayer(new MaxInviteBox(_inner.channel()->invitationUrl), KeepOtherLayers);
|
||||
return;
|
||||
}
|
||||
ContactsBox *box = new ContactsBox(_inner.channel(), _inner.filter(), _inner.already());
|
||||
if (_inner.filter() == MembersFilterRecent) {
|
||||
App::wnd()->showLayer(box);
|
||||
Ui::showLayer(box);
|
||||
} else {
|
||||
_addBox = box;
|
||||
connect(_addBox, SIGNAL(adminAdded()), this, SLOT(onAdminAdded()));
|
||||
App::wnd()->replaceLayer(_addBox);
|
||||
Ui::showLayer(_addBox, KeepOtherLayers);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -84,16 +84,16 @@ void LanguageBox::mousePressEvent(QMouseEvent *e) {
|
|||
for (int32 i = 1; i < languageCount; ++i) {
|
||||
LangLoaderPlain loader(qsl(":/langs/lang_") + LanguageCodes[i] + qsl(".strings"), LangLoaderRequest(lngkeys_cnt));
|
||||
if (!loader.errors().isEmpty()) {
|
||||
App::wnd()->showLayer(new InformBox(qsl("Lang \"") + LanguageCodes[i] + qsl("\" error :(\n\nError: ") + loader.errors()));
|
||||
Ui::showLayer(new InformBox(qsl("Lang \"") + LanguageCodes[i] + qsl("\" error :(\n\nError: ") + loader.errors()));
|
||||
return;
|
||||
} else if (!loader.warnings().isEmpty()) {
|
||||
QString warn = loader.warnings();
|
||||
if (warn.size() > 256) warn = warn.mid(0, 254) + qsl("..");
|
||||
App::wnd()->showLayer(new InformBox(qsl("Lang \"") + LanguageCodes[i] + qsl("\" warnings :(\n\nWarnings: ") + warn));
|
||||
Ui::showLayer(new InformBox(qsl("Lang \"") + LanguageCodes[i] + qsl("\" warnings :(\n\nWarnings: ") + warn));
|
||||
return;
|
||||
}
|
||||
}
|
||||
App::wnd()->showLayer(new InformBox(qsl("Everything seems great in all %1 languages!").arg(languageCount - 1)));
|
||||
Ui::showLayer(new InformBox(qsl("Everything seems great in all %1 languages!").arg(languageCount - 1)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,7 +124,7 @@ void LanguageBox::onChange() {
|
|||
ConfirmBox *box = new ConfirmBox(text, save, st::defaultBoxButton, cancel);
|
||||
connect(box, SIGNAL(confirmed()), this, SLOT(onSave()));
|
||||
connect(box, SIGNAL(closed()), this, SLOT(onRestore()));
|
||||
App::wnd()->replaceLayer(box);
|
||||
Ui::showLayer(box, KeepOtherLayers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -280,7 +280,7 @@ void PasscodeBox::setPasswordDone(const MTPBool &result) {
|
|||
_setRequest = 0;
|
||||
emit reloadPassword();
|
||||
ConfirmBox *box = new InformBox(lang(_reenterPasscode.isHidden() ? lng_cloud_password_removed : (_oldPasscode.isHidden() ? lng_cloud_password_was_set : lng_cloud_password_updated)));
|
||||
App::wnd()->showLayer(box);
|
||||
Ui::showLayer(box);
|
||||
}
|
||||
|
||||
bool PasscodeBox::setPasswordFail(const RPCError &error) {
|
||||
|
@ -308,7 +308,7 @@ bool PasscodeBox::setPasswordFail(const RPCError &error) {
|
|||
_recoverEmail.showError();
|
||||
update();
|
||||
} else if (err == "EMAIL_UNCONFIRMED") {
|
||||
App::wnd()->showLayer(new InformBox(lang(lng_cloud_password_almost)));
|
||||
Ui::showLayer(new InformBox(lang(lng_cloud_password_almost)));
|
||||
emit reloadPassword();
|
||||
} else if (mtpIsFlood(error)) {
|
||||
if (_oldPasscode.isHidden()) return false;
|
||||
|
@ -385,7 +385,7 @@ void PasscodeBox::onSave(bool force) {
|
|||
_replacedBy = new ConfirmBox(lang(lng_cloud_password_about_recover), lang(lng_cloud_password_skip_email), st::attentionBoxButton);
|
||||
connect(_replacedBy, SIGNAL(confirmed()), this, SLOT(onForceNoMail()));
|
||||
connect(_replacedBy, SIGNAL(destroyed(QObject*)), this, SLOT(onBoxDestroyed(QObject*)));
|
||||
App::wnd()->replaceLayer(_replacedBy);
|
||||
Ui::showLayer(_replacedBy, KeepOtherLayers);
|
||||
} else {
|
||||
QByteArray newPasswordData = pwd.isEmpty() ? QByteArray() : (_newSalt + pwd.toUtf8() + _newSalt);
|
||||
QByteArray newPasswordHash = pwd.isEmpty() ? QByteArray() : QByteArray(32, Qt::Uninitialized);
|
||||
|
@ -481,7 +481,7 @@ void PasscodeBox::recover() {
|
|||
connect(_replacedBy, SIGNAL(reloadPassword()), this, SIGNAL(reloadPassword()));
|
||||
connect(_replacedBy, SIGNAL(recoveryExpired()), this, SLOT(onRecoverExpired()));
|
||||
connect(_replacedBy, SIGNAL(destroyed(QObject*)), this, SLOT(onBoxDestroyed(QObject*)));
|
||||
App::wnd()->replaceLayer(_replacedBy);
|
||||
Ui::showLayer(_replacedBy, KeepOtherLayers);
|
||||
}
|
||||
|
||||
void PasscodeBox::recoverStarted(const MTPauth_PasswordRecovery &result) {
|
||||
|
@ -583,7 +583,7 @@ void RecoverBox::codeSubmitDone(bool recover, const MTPauth_Authorization &resul
|
|||
_submitRequest = 0;
|
||||
|
||||
emit reloadPassword();
|
||||
App::wnd()->showLayer(new InformBox(lang(lng_cloud_password_removed)));
|
||||
Ui::showLayer(new InformBox(lang(lng_cloud_password_removed)));
|
||||
}
|
||||
|
||||
bool RecoverBox::codeSubmitFail(const RPCError &error) {
|
||||
|
@ -592,7 +592,7 @@ bool RecoverBox::codeSubmitFail(const RPCError &error) {
|
|||
const QString &err = error.type();
|
||||
if (err == "PASSWORD_EMPTY") {
|
||||
emit reloadPassword();
|
||||
App::wnd()->showLayer(new InformBox(lang(lng_cloud_password_removed)));
|
||||
Ui::showLayer(new InformBox(lang(lng_cloud_password_removed)));
|
||||
return true;
|
||||
} else if (err == "PASSWORD_RECOVERY_NA") {
|
||||
onClose();
|
||||
|
|
|
@ -29,31 +29,67 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
|
||||
PhotoSendBox::PhotoSendBox(const FileLoadResultPtr &file) : AbstractBox(st::boxWideWidth)
|
||||
, _file(file)
|
||||
, _thumbx(0)
|
||||
, _thumby(0)
|
||||
, _thumbw(0)
|
||||
, _thumbh(0)
|
||||
, _namew(0)
|
||||
, _textw(0)
|
||||
, _animated(false)
|
||||
, _caption(this, st::confirmCaptionArea, lang(lng_photo_caption))
|
||||
, _compressedFromSettings(_file->type == PrepareAuto)
|
||||
, _compressed(this, lang(lng_send_image_compressed), _compressedFromSettings ? cCompressPastedImage() : true)
|
||||
, _send(this, lang(lng_send_button), st::defaultBoxButton)
|
||||
, _cancel(this, lang(lng_cancel), st::cancelBoxButton)
|
||||
, _thumbx(0)
|
||||
, _thumby(0)
|
||||
, _thumbw(0)
|
||||
, _thumbh(0)
|
||||
, _statusw(0)
|
||||
, _isImage(false)
|
||||
, _replyTo(_file->to.replyTo)
|
||||
, _confirmed(false) {
|
||||
connect(&_send, SIGNAL(clicked()), this, SLOT(onSend()));
|
||||
connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
|
||||
|
||||
_animated = false;
|
||||
QSize dimensions;
|
||||
if (_file->photo.type() != mtpc_photoEmpty) {
|
||||
_file->type = PreparePhoto;
|
||||
} else if (_file->document.type() == mtpc_document) {
|
||||
const MTPDdocument &document(_file->document.c_document());
|
||||
const QVector<MTPDocumentAttribute> &attributes(document.vattributes.c_vector().v);
|
||||
for (int32 i = 0, l = attributes.size(); i < l; ++i) {
|
||||
if (attributes.at(i).type() == mtpc_documentAttributeAnimated) {
|
||||
_animated = true;
|
||||
} else if (attributes.at(i).type() == mtpc_documentAttributeImageSize) {
|
||||
dimensions = QSize(attributes.at(i).c_documentAttributeImageSize().vw.v, attributes.at(i).c_documentAttributeImageSize().vh.v);
|
||||
} else if (attributes.at(i).type() == mtpc_documentAttributeVideo) {
|
||||
dimensions = QSize(attributes.at(i).c_documentAttributeVideo().vw.v, attributes.at(i).c_documentAttributeVideo().vh.v);
|
||||
}
|
||||
}
|
||||
if (dimensions.isEmpty()) _animated = false;
|
||||
}
|
||||
if (_file->type == PreparePhoto) {
|
||||
if (_file->type == PreparePhoto || _animated) {
|
||||
int32 maxW = 0, maxH = 0;
|
||||
for (PreparedPhotoThumbs::const_iterator i = _file->photoThumbs.cbegin(), e = _file->photoThumbs.cend(); i != e; ++i) {
|
||||
if (i->width() >= maxW && i->height() >= maxH) {
|
||||
_thumb = *i;
|
||||
maxW = _thumb.width();
|
||||
maxH = _thumb.height();
|
||||
if (_animated) {
|
||||
int32 limitW = width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right();
|
||||
int32 limitH = st::confirmMaxHeight;
|
||||
maxW = dimensions.width();
|
||||
maxH = dimensions.height();
|
||||
if (maxW * limitH > maxH * limitW) {
|
||||
if (maxW < limitW) {
|
||||
maxH = maxH * limitW / maxW;
|
||||
maxW = limitW;
|
||||
}
|
||||
} else {
|
||||
if (maxH < limitH) {
|
||||
maxW = maxW * limitH / maxH;
|
||||
maxH = limitH;
|
||||
}
|
||||
}
|
||||
_thumb = imagePix(_file->thumb.toImage(), maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), true, true, false, maxW, maxH);
|
||||
} else {
|
||||
for (PreparedPhotoThumbs::const_iterator i = _file->photoThumbs.cbegin(), e = _file->photoThumbs.cend(); i != e; ++i) {
|
||||
if (i->width() >= maxW && i->height() >= maxH) {
|
||||
_thumb = *i;
|
||||
maxW = _thumb.width();
|
||||
maxH = _thumb.height();
|
||||
}
|
||||
}
|
||||
}
|
||||
int32 tw = _thumb.width(), th = _thumb.height();
|
||||
|
@ -78,32 +114,28 @@ PhotoSendBox::PhotoSendBox(const FileLoadResultPtr &file) : AbstractBox(st::boxW
|
|||
_thumb = QPixmap::fromImage(_thumb.toImage().scaled(_thumbw * cIntRetinaFactor(), _thumbh * cIntRetinaFactor(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly);
|
||||
_thumb.setDevicePixelRatio(cRetinaFactor());
|
||||
} else {
|
||||
_compressed.hide();
|
||||
if (!_file->thumb.isNull()) {
|
||||
if (_file->thumb.isNull()) {
|
||||
_thumbw = 0;
|
||||
} else {
|
||||
_thumb = _file->thumb;
|
||||
int32 tw = _thumb.width(), th = _thumb.height();
|
||||
if (_thumb.isNull() || !tw || !th) {
|
||||
_thumbw = _thumbx = _thumby = 0;
|
||||
} else if (tw > th) {
|
||||
_thumbw = (tw * st::mediaThumbSize) / th;
|
||||
_thumbx = (_thumbw - st::mediaThumbSize) / 2;
|
||||
_thumby = 0;
|
||||
if (tw > th) {
|
||||
_thumbw = (tw * st::msgFileThumbSize) / th;
|
||||
} else {
|
||||
_thumbw = st::mediaThumbSize;
|
||||
_thumbx = 0;
|
||||
_thumby = ((th * _thumbw) / tw - st::mediaThumbSize) / 2;
|
||||
_thumbw = st::msgFileThumbSize;
|
||||
}
|
||||
}
|
||||
if (_thumbw) {
|
||||
_thumb = QPixmap::fromImage(_thumb.toImage().scaledToWidth(_thumbw * cIntRetinaFactor(), Qt::SmoothTransformation), Qt::ColorOnly);
|
||||
_thumb.setDevicePixelRatio(cRetinaFactor());
|
||||
_thumb = imagePix(_thumb.toImage(), _thumbw * cIntRetinaFactor(), 0, true, false, true, st::msgFileThumbSize, st::msgFileThumbSize);
|
||||
}
|
||||
|
||||
_name = _file->filename;
|
||||
_namew = st::mediaFont->width(_name);
|
||||
_size = formatSizeText(_file->filesize);
|
||||
_textw = qMax(_namew, st::mediaFont->width(_size));
|
||||
_name.setText(st::semiboldFont, _file->filename, _textNameOptions);
|
||||
_status = formatSizeText(_file->filesize);
|
||||
_statusw = qMax(_name.maxWidth(), st::normalFont->width(_status));
|
||||
_isImage = fileIsImage(_file->filename, _file->filemime);
|
||||
}
|
||||
if (_file->type != PreparePhoto) {
|
||||
_compressed.hide();
|
||||
}
|
||||
|
||||
updateBoxSize();
|
||||
_caption.setMaxLength(MaxPhotoCaption);
|
||||
_caption.setCtrlEnterSubmit(CtrlEnterSubmitBoth);
|
||||
|
@ -111,20 +143,21 @@ PhotoSendBox::PhotoSendBox(const FileLoadResultPtr &file) : AbstractBox(st::boxW
|
|||
connect(&_caption, SIGNAL(resized()), this, SLOT(onCaptionResized()));
|
||||
connect(&_caption, SIGNAL(submitted(bool)), this, SLOT(onSend(bool)));
|
||||
connect(&_caption, SIGNAL(cancelled()), this, SLOT(onClose()));
|
||||
|
||||
prepare();
|
||||
}
|
||||
|
||||
PhotoSendBox::PhotoSendBox(const QString &phone, const QString &fname, const QString &lname, MsgId replyTo) : AbstractBox(st::boxWideWidth)
|
||||
, _thumbx(0)
|
||||
, _thumby(0)
|
||||
, _thumbw(0)
|
||||
, _thumbh(0)
|
||||
, _namew(0)
|
||||
, _textw(0)
|
||||
, _caption(this, st::confirmCaptionArea, lang(lng_photo_caption))
|
||||
, _compressed(this, lang(lng_send_image_compressed), true)
|
||||
, _send(this, lang(lng_send_button), st::defaultBoxButton)
|
||||
, _cancel(this, lang(lng_cancel), st::cancelBoxButton)
|
||||
, _thumbx(0)
|
||||
, _thumby(0)
|
||||
, _thumbw(0)
|
||||
, _thumbh(0)
|
||||
, _statusw(0)
|
||||
, _isImage(false)
|
||||
, _phone(phone)
|
||||
, _fname(fname)
|
||||
, _lname(lname)
|
||||
|
@ -135,10 +168,9 @@ PhotoSendBox::PhotoSendBox(const QString &phone, const QString &fname, const QSt
|
|||
|
||||
_compressed.hide();
|
||||
|
||||
_name = lng_full_name(lt_first_name, _fname, lt_last_name, _lname);
|
||||
_namew = st::mediaFont->width(_name);
|
||||
_size = _phone;
|
||||
_textw = qMax(_namew, st::mediaFont->width(_size));
|
||||
_name.setText(st::semiboldFont, lng_full_name(lt_first_name, _fname, lt_last_name, _lname), _textNameOptions);
|
||||
_status = _phone;
|
||||
_statusw = qMax(_name.maxWidth(), st::normalFont->width(_status));
|
||||
|
||||
updateBoxSize();
|
||||
prepare();
|
||||
|
@ -163,10 +195,12 @@ void PhotoSendBox::onCaptionResized() {
|
|||
}
|
||||
|
||||
void PhotoSendBox::updateBoxSize() {
|
||||
if (_file && _file->type == PreparePhoto) {
|
||||
setMaxHeight(st::boxPhotoPadding.top() + _thumbh + st::boxPhotoPadding.bottom() + st::boxPhotoCompressedPadding.top() + _compressed.height() + (_compressed.checked() ? (st::boxPhotoCompressedPadding.bottom() + _caption.height()) : 0) + st::boxButtonPadding.top() + _send.height() + st::boxButtonPadding.bottom());
|
||||
if (_file && (_file->type == PreparePhoto || _animated)) {
|
||||
setMaxHeight(st::boxPhotoPadding.top() + _thumbh + st::boxPhotoPadding.bottom() + (_animated ? 0 : (st::boxPhotoCompressedPadding.top() + _compressed.height())) + st::boxPhotoCompressedPadding.bottom() + _caption.height() + st::boxButtonPadding.top() + _send.height() + st::boxButtonPadding.bottom());
|
||||
} else if (_thumbw) {
|
||||
setMaxHeight(st::boxPhotoPadding.top() + st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom() + (_file ? (st::boxPhotoCompressedPadding.bottom() + _caption.height()) : 0) + st::boxPhotoPadding.bottom() + st::boxButtonPadding.top() + _send.height() + st::boxButtonPadding.bottom());
|
||||
} else {
|
||||
setMaxHeight(st::boxPhotoPadding.top() + st::mediaPadding.top() + st::mediaThumbSize + st::mediaPadding.bottom() + st::boxPhotoPadding.bottom() + st::boxButtonPadding.top() + _send.height() + st::boxButtonPadding.bottom());
|
||||
setMaxHeight(st::boxPhotoPadding.top() + st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom() + (_file ? (st::boxPhotoCompressedPadding.bottom() + _caption.height()) : 0) + st::boxPhotoPadding.bottom() + st::boxButtonPadding.top() + _send.height() + st::boxButtonPadding.bottom());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -182,7 +216,7 @@ void PhotoSendBox::paintEvent(QPaintEvent *e) {
|
|||
Painter p(this);
|
||||
if (paint(p)) return;
|
||||
|
||||
if (_file && _file->type == PreparePhoto) {
|
||||
if (_file && (_file->type == PreparePhoto || _animated)) {
|
||||
if (_thumbx > st::boxPhotoPadding.left()) {
|
||||
p.fillRect(st::boxPhotoPadding.left(), st::boxPhotoPadding.top(), _thumbx - st::boxPhotoPadding.left(), _thumbh, st::confirmBg->b);
|
||||
}
|
||||
|
@ -190,36 +224,66 @@ void PhotoSendBox::paintEvent(QPaintEvent *e) {
|
|||
p.fillRect(_thumbx + _thumbw, st::boxPhotoPadding.top(), width() - st::boxPhotoPadding.right() - _thumbx - _thumbw, _thumbh, st::confirmBg->b);
|
||||
}
|
||||
p.drawPixmap(_thumbx, st::boxPhotoPadding.top(), _thumb);
|
||||
if (_animated) {
|
||||
QRect inner(_thumbx + (_thumbw - st::msgFileSize) / 2, st::boxPhotoPadding.top() + (_thumbh - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize);
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(st::msgDateImgBg);
|
||||
|
||||
p.setRenderHint(QPainter::HighQualityAntialiasing);
|
||||
p.drawEllipse(inner);
|
||||
p.setRenderHint(QPainter::HighQualityAntialiasing, false);
|
||||
|
||||
p.drawSpriteCenter(inner, st::msgFileInPlay);
|
||||
}
|
||||
} else {
|
||||
int32 w = width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right(), h = st::mediaPadding.top() + st::mediaThumbSize + st::mediaPadding.bottom();
|
||||
int32 tleft = st::mediaPadding.left() + st::mediaThumbSize + st::mediaPadding.right();
|
||||
int32 twidth = w - tleft - st::mediaPadding.right();
|
||||
if (twidth > _textw) {
|
||||
w -= (twidth - _textw);
|
||||
twidth = _textw;
|
||||
int32 w = width() - st::boxPhotoPadding.left() - st::boxPhotoPadding.right();
|
||||
int32 h = _thumbw ? (st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom()) : (st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom());
|
||||
int32 nameleft = 0, nametop = 0, nameright = 0, statustop = 0, linktop = 0;
|
||||
if (_thumbw) {
|
||||
nameleft = st::msgFileThumbPadding.left() + st::msgFileThumbSize + st::msgFileThumbPadding.right();
|
||||
nametop = st::msgFileThumbNameTop;
|
||||
nameright = st::msgFileThumbPadding.left();
|
||||
statustop = st::msgFileThumbStatusTop;
|
||||
linktop = st::msgFileThumbLinkTop;
|
||||
} else {
|
||||
nameleft = st::msgFilePadding.left() + st::msgFileSize + st::msgFilePadding.right();
|
||||
nametop = st::msgFileNameTop;
|
||||
nameright = st::msgFilePadding.left();
|
||||
statustop = st::msgFileStatusTop;
|
||||
}
|
||||
int32 namewidth = w - nameleft - (_thumbw ? st::msgFileThumbPadding.left() : st::msgFilePadding.left());
|
||||
if (namewidth > _statusw) {
|
||||
w -= (namewidth - _statusw);
|
||||
namewidth = _statusw;
|
||||
}
|
||||
int32 x = (width() - w) / 2, y = st::boxPhotoPadding.top();
|
||||
|
||||
App::roundRect(p, x, y, w, h, st::msgOutBg, MessageOutCorners, &st::msgOutShadow);
|
||||
|
||||
if (_thumbw) {
|
||||
int32 rf(cIntRetinaFactor());
|
||||
p.drawPixmap(QPoint(x + st::mediaPadding.left(), y + st::mediaPadding.top()), _thumb, QRect(_thumbx * rf, _thumby * rf, st::mediaThumbSize * rf, st::mediaThumbSize * rf));
|
||||
QRect rthumb(rtlrect(x + st::msgFileThumbPadding.left(), y + st::msgFileThumbPadding.top(), st::msgFileThumbSize, st::msgFileThumbSize, width()));
|
||||
p.drawPixmap(rthumb.topLeft(), _thumb);
|
||||
} else if (_file) {
|
||||
p.drawPixmap(QPoint(x + st::mediaPadding.left(), y + st::mediaPadding.top()), App::sprite(), st::mediaDocOutImg);
|
||||
} else {
|
||||
p.drawPixmap(x + st::mediaPadding.left(), y + st::mediaPadding.top(), userDefPhoto(1)->pix(st::mediaThumbSize));
|
||||
}
|
||||
QRect inner(rtlrect(x + st::msgFilePadding.left(), y + st::msgFilePadding.top(), st::msgFileSize, st::msgFileSize, width()));
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(st::msgFileOutBg);
|
||||
|
||||
p.setFont(st::mediaFont->f);
|
||||
p.setPen(st::black->c);
|
||||
if (twidth < _namew) {
|
||||
p.drawText(x + tleft, y + st::mediaPadding.top() + st::mediaNameTop + st::mediaFont->ascent, st::mediaFont->elided(_name, twidth));
|
||||
} else {
|
||||
p.drawText(x + tleft, y + st::mediaPadding.top() + st::mediaNameTop + st::mediaFont->ascent, _name);
|
||||
}
|
||||
p.setRenderHint(QPainter::HighQualityAntialiasing);
|
||||
p.drawEllipse(inner);
|
||||
p.setRenderHint(QPainter::HighQualityAntialiasing, false);
|
||||
|
||||
p.setPen(st::mediaOutColor->p);
|
||||
p.drawText(x + tleft, y + st::mediaPadding.top() + st::mediaThumbSize - st::mediaDetailsShift - st::mediaFont->descent, _size);
|
||||
p.drawSpriteCenter(inner, _isImage ? st::msgFileOutImage : st::msgFileOutFile);
|
||||
} else {
|
||||
p.drawPixmapLeft(x + st::msgFilePadding.left(), y + st::msgFilePadding.top(), width(), userDefPhoto(1)->pixRounded(st::msgFileSize));
|
||||
}
|
||||
p.setFont(st::semiboldFont);
|
||||
p.setPen(st::black);
|
||||
_name.drawLeftElided(p, x + nameleft, y + nametop, namewidth, width());
|
||||
|
||||
style::color status(st::mediaOutFg);
|
||||
p.setFont(st::normalFont);
|
||||
p.setPen(status);
|
||||
p.drawTextLeft(x + nameleft, y + statustop, width(), _status);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -251,13 +315,11 @@ void PhotoSendBox::hideAll() {
|
|||
void PhotoSendBox::showAll() {
|
||||
_send.show();
|
||||
_cancel.show();
|
||||
if (_file && _file->type == PreparePhoto) {
|
||||
_compressed.show();
|
||||
if (_compressed.checked()) {
|
||||
_caption.show();
|
||||
} else {
|
||||
_caption.hide();
|
||||
if (_file) {
|
||||
if (_file->type == PreparePhoto) {
|
||||
_compressed.show();
|
||||
}
|
||||
_caption.show();
|
||||
} else {
|
||||
_caption.hide();
|
||||
_compressed.hide();
|
||||
|
@ -287,7 +349,7 @@ void PhotoSendBox::onSend(bool ctrlShiftEnter) {
|
|||
}
|
||||
}
|
||||
if (!_caption.isHidden()) {
|
||||
_file->photoCaption = prepareText(_caption.getLastText(), true);
|
||||
_file->caption = prepareText(_caption.getLastText(), true);
|
||||
}
|
||||
App::main()->onSendFileConfirm(_file, ctrlShiftEnter);
|
||||
} else {
|
||||
|
|
|
@ -65,16 +65,23 @@ private:
|
|||
void updateBoxSize();
|
||||
|
||||
FileLoadResultPtr _file;
|
||||
int32 _thumbx, _thumby, _thumbw, _thumbh;
|
||||
QString _name, _size;
|
||||
int32 _namew, _textw;
|
||||
bool _animated;
|
||||
|
||||
QPixmap _thumb;
|
||||
|
||||
InputArea _caption;
|
||||
bool _compressedFromSettings;
|
||||
Checkbox _compressed;
|
||||
BoxButton _send, _cancel;
|
||||
QPixmap _thumb;
|
||||
|
||||
int32 _thumbx, _thumby, _thumbw, _thumbh;
|
||||
Text _name;
|
||||
QString _status;
|
||||
int32 _statusw;
|
||||
bool _isImage;
|
||||
|
||||
QString _phone, _fname, _lname;
|
||||
|
||||
MsgId _replyTo;
|
||||
|
||||
bool _confirmed;
|
||||
|
|
|
@ -115,7 +115,7 @@ void SessionsInner::onTerminate() {
|
|||
_terminateBox = new ConfirmBox(lang(lng_settings_reset_one_sure), lang(lng_settings_reset_button), st::attentionBoxButton);
|
||||
connect(_terminateBox, SIGNAL(confirmed()), this, SLOT(onTerminateSure()));
|
||||
connect(_terminateBox, SIGNAL(destroyed(QObject*)), this, SLOT(onNoTerminateBox(QObject*)));
|
||||
App::wnd()->replaceLayer(_terminateBox);
|
||||
Ui::showLayer(_terminateBox, KeepOtherLayers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -138,7 +138,7 @@ void SessionsInner::onTerminateAll() {
|
|||
_terminateBox = new ConfirmBox(lang(lng_settings_reset_sure), lang(lng_settings_reset_button), st::attentionBoxButton);
|
||||
connect(_terminateBox, SIGNAL(confirmed()), this, SLOT(onTerminateAllSure()));
|
||||
connect(_terminateBox, SIGNAL(destroyed(QObject*)), this, SLOT(onNoTerminateBox(QObject*)));
|
||||
App::wnd()->replaceLayer(_terminateBox);
|
||||
Ui::showLayer(_terminateBox, KeepOtherLayers);
|
||||
}
|
||||
|
||||
void SessionsInner::onTerminateAllSure() {
|
||||
|
|
|
@ -43,6 +43,7 @@ _input(set), _installRequest(0) {
|
|||
|
||||
void StickerSetInner::gotSet(const MTPmessages_StickerSet &set) {
|
||||
_pack.clear();
|
||||
_emoji.clear();
|
||||
if (set.type() == mtpc_messages_stickerSet) {
|
||||
const MTPDmessages_stickerSet &d(set.c_messages_stickerSet());
|
||||
const QVector<MTPDocument> &v(d.vdocuments.c_vector().v);
|
||||
|
@ -50,9 +51,26 @@ void StickerSetInner::gotSet(const MTPmessages_StickerSet &set) {
|
|||
for (int32 i = 0, l = v.size(); i < l; ++i) {
|
||||
DocumentData *doc = App::feedDocument(v.at(i));
|
||||
if (!doc || !doc->sticker()) continue;
|
||||
|
||||
|
||||
_pack.push_back(doc);
|
||||
}
|
||||
const QVector<MTPStickerPack> &packs(d.vpacks.c_vector().v);
|
||||
for (int32 i = 0, l = packs.size(); i < l; ++i) {
|
||||
if (packs.at(i).type() != mtpc_stickerPack) continue;
|
||||
const MTPDstickerPack &pack(packs.at(i).c_stickerPack());
|
||||
if (EmojiPtr e = emojiGetNoColor(emojiFromText(qs(pack.vemoticon)))) {
|
||||
const QVector<MTPlong> &stickers(pack.vdocuments.c_vector().v);
|
||||
StickerPack p;
|
||||
p.reserve(stickers.size());
|
||||
for (int32 j = 0, c = stickers.size(); j < c; ++j) {
|
||||
DocumentData *doc = App::document(stickers.at(j).v);
|
||||
if (!doc || !doc->sticker()) continue;
|
||||
|
||||
p.push_back(doc);
|
||||
}
|
||||
_emoji.insert(e, p);
|
||||
}
|
||||
}
|
||||
if (d.vset.type() == mtpc_stickerSet) {
|
||||
const MTPDstickerSet &s(d.vset.c_stickerSet());
|
||||
_setTitle = stickerSetTitle(s);
|
||||
|
@ -67,7 +85,7 @@ void StickerSetInner::gotSet(const MTPmessages_StickerSet &set) {
|
|||
}
|
||||
|
||||
if (_pack.isEmpty()) {
|
||||
App::wnd()->showLayer(new InformBox(lang(lng_stickers_not_found)));
|
||||
Ui::showLayer(new InformBox(lang(lng_stickers_not_found)));
|
||||
} else {
|
||||
int32 rows = _pack.size() / StickerPanPerRow + ((_pack.size() % StickerPanPerRow) ? 1 : 0);
|
||||
resize(st::stickersPadding.left() + StickerPanPerRow * st::stickersSize.width(), st::stickersPadding.top() + rows * st::stickersSize.height() + st::stickersPadding.bottom());
|
||||
|
@ -82,7 +100,7 @@ bool StickerSetInner::failedSet(const RPCError &error) {
|
|||
|
||||
_loaded = true;
|
||||
|
||||
App::wnd()->showLayer(new InformBox(lang(lng_stickers_not_found)));
|
||||
Ui::showLayer(new InformBox(lang(lng_stickers_not_found)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -91,7 +109,12 @@ void StickerSetInner::installDone(const MTPBool &result) {
|
|||
StickerSets &sets(cRefStickerSets());
|
||||
|
||||
_setFlags &= ~MTPDstickerSet::flag_disabled;
|
||||
sets.insert(_setId, StickerSet(_setId, _setAccess, _setTitle, _setShortName, _setCount, _setHash, _setFlags)).value().stickers = _pack;
|
||||
StickerSets::iterator it = sets.find(_setId);
|
||||
if (it == sets.cend()) {
|
||||
it = sets.insert(_setId, StickerSet(_setId, _setAccess, _setTitle, _setShortName, _setCount, _setHash, _setFlags));
|
||||
}
|
||||
it.value().stickers = _pack;
|
||||
it.value().emoji = _emoji;
|
||||
|
||||
StickerSetsOrder &order(cRefStickerSetsOrder());
|
||||
int32 insertAtIndex = 0, currentIndex = order.indexOf(_setId);
|
||||
|
@ -112,16 +135,15 @@ void StickerSetInner::installDone(const MTPBool &result) {
|
|||
sets.erase(custom);
|
||||
}
|
||||
}
|
||||
cSetStickersHash(stickersCountHash());
|
||||
Local::writeStickers();
|
||||
emit installed(_setId);
|
||||
App::wnd()->hideLayer();
|
||||
Ui::hideLayer();
|
||||
}
|
||||
|
||||
bool StickerSetInner::installFailed(const RPCError &error) {
|
||||
if (mtpIsFlood(error)) return false;
|
||||
|
||||
App::wnd()->showLayer(new InformBox(lang(lng_stickers_not_found)));
|
||||
Ui::showLayer(new InformBox(lang(lng_stickers_not_found)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -147,15 +169,14 @@ void StickerSetInner::paintEvent(QPaintEvent *e) {
|
|||
if (goodThumb) {
|
||||
doc->thumb->load();
|
||||
} else {
|
||||
bool already = !doc->already().isEmpty(), hasdata = !doc->data.isEmpty();
|
||||
if (!doc->loader && doc->status != FileFailed && !already && !hasdata) {
|
||||
doc->save(QString());
|
||||
if (doc->status == FileReady) {
|
||||
doc->automaticLoad(0);
|
||||
}
|
||||
if (doc->sticker()->img->isNull() && (already || hasdata)) {
|
||||
if (already) {
|
||||
if (doc->sticker()->img->isNull() && doc->loaded() && doc->loaded(true)) {
|
||||
if (doc->data().isEmpty()) {
|
||||
doc->sticker()->img = ImagePtr(doc->already());
|
||||
} else {
|
||||
doc->sticker()->img = ImagePtr(doc->data);
|
||||
doc->sticker()->img = ImagePtr(doc->data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -252,7 +273,7 @@ void StickerSetBox::onAddStickers() {
|
|||
void StickerSetBox::onShareStickers() {
|
||||
QString url = qsl("https://telegram.me/addstickers/") + _inner.shortName();
|
||||
QApplication::clipboard()->setText(url);
|
||||
App::wnd()->showLayer(new InformBox(lang(lng_stickers_copied)));
|
||||
Ui::showLayer(new InformBox(lang(lng_stickers_copied)));
|
||||
}
|
||||
|
||||
void StickerSetBox::onUpdateButtons() {
|
||||
|
@ -333,7 +354,7 @@ StickersInner::StickersInner() : TWidget()
|
|||
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
||||
, _aboveShadowFadeStart(0)
|
||||
, _aboveShadowFadeOpacity(0, 0)
|
||||
, _a_shifting(animFunc(this, &StickersInner::animStep_shifting))
|
||||
, _a_shifting(animation(this, &StickersInner::step_shifting))
|
||||
, _itemsTop(st::membersPadding.top())
|
||||
, _saving(false)
|
||||
, _removeSel(-1)
|
||||
|
@ -355,7 +376,7 @@ void StickersInner::paintEvent(QPaintEvent *e) {
|
|||
QRect r(e->rect());
|
||||
Painter p(this);
|
||||
|
||||
updateAnimatedValues();
|
||||
_a_shifting.step();
|
||||
|
||||
p.fillRect(r, st::white);
|
||||
p.setClipRect(r);
|
||||
|
@ -489,7 +510,7 @@ void StickersInner::onUpdateSelected() {
|
|||
}
|
||||
_rows.at(_dragging)->yadd = anim::ivalue(local.y() - _dragStart.y(), local.y() - _dragStart.y());
|
||||
_animStartTimes[_dragging] = 0;
|
||||
updateAnimatedRegions();
|
||||
_a_shifting.step(getms(), true);
|
||||
|
||||
emit checkDraggingScroll(local.y());
|
||||
} else {
|
||||
|
@ -509,7 +530,7 @@ void StickersInner::onUpdateSelected() {
|
|||
|
||||
float64 StickersInner::aboveShadowOpacity() const {
|
||||
if (_above < 0) return 0;
|
||||
|
||||
|
||||
int32 dx = 0;
|
||||
int32 dy = qAbs(_above * _rowHeight + _rows.at(_above)->yadd.current() - _started * _rowHeight);
|
||||
return qMin((dx + dy) * 2. / _rowHeight, 1.);
|
||||
|
@ -538,33 +559,14 @@ void StickersInner::mouseReleaseEvent(QMouseEvent *e) {
|
|||
}
|
||||
}
|
||||
|
||||
void StickersInner::updateAnimatedRegions() {
|
||||
int32 updateMin = -1, updateMax = 0;
|
||||
for (int32 i = 0, l = _animStartTimes.size(); i < l; ++i) {
|
||||
if (_animStartTimes.at(i)) {
|
||||
if (updateMin < 0) updateMin = i;
|
||||
updateMax = i;
|
||||
}
|
||||
}
|
||||
if (_aboveShadowFadeStart) {
|
||||
if (updateMin < 0 || updateMin > _above) updateMin = _above;
|
||||
if (updateMax < _above) updateMin = _above;
|
||||
}
|
||||
if (_dragging >= 0) {
|
||||
if (updateMin < 0 || updateMin > _dragging) updateMin = _dragging;
|
||||
if (updateMax < _dragging) updateMax = _dragging;
|
||||
}
|
||||
if (updateMin >= 0) {
|
||||
update(0, _itemsTop + _rowHeight * (updateMin - 1), width(), _rowHeight * (updateMax - updateMin + 3));
|
||||
}
|
||||
}
|
||||
|
||||
bool StickersInner::updateAnimatedValues() {
|
||||
void StickersInner::step_shifting(uint64 ms, bool timer) {
|
||||
bool animating = false;
|
||||
uint64 ms = getms();
|
||||
int32 updateMin = -1, updateMax = 0;
|
||||
for (int32 i = 0, l = _animStartTimes.size(); i < l; ++i) {
|
||||
uint64 start = _animStartTimes.at(i);
|
||||
if (start) {
|
||||
if (updateMin < 0) updateMin = i;
|
||||
updateMax = i;
|
||||
if (start + st::stickersRowDuration > ms && ms >= start) {
|
||||
_rows.at(i)->yadd.update((ms - start) / st::stickersRowDuration, anim::sineInOut);
|
||||
animating = true;
|
||||
|
@ -575,6 +577,8 @@ bool StickersInner::updateAnimatedValues() {
|
|||
}
|
||||
}
|
||||
if (_aboveShadowFadeStart) {
|
||||
if (updateMin < 0 || updateMin > _above) updateMin = _above;
|
||||
if (updateMax < _above) updateMin = _above;
|
||||
if (_aboveShadowFadeStart + st::stickersRowDuration > ms && ms > _aboveShadowFadeStart) {
|
||||
_aboveShadowFadeOpacity.update((ms - _aboveShadowFadeStart) / st::stickersRowDuration, anim::sineInOut);
|
||||
animating = true;
|
||||
|
@ -583,17 +587,19 @@ bool StickersInner::updateAnimatedValues() {
|
|||
_aboveShadowFadeStart = 0;
|
||||
}
|
||||
}
|
||||
return animating;
|
||||
}
|
||||
|
||||
bool StickersInner::animStep_shifting(float64) {
|
||||
updateAnimatedRegions();
|
||||
|
||||
bool animating = updateAnimatedValues();
|
||||
if (timer) {
|
||||
if (_dragging >= 0) {
|
||||
if (updateMin < 0 || updateMin > _dragging) updateMin = _dragging;
|
||||
if (updateMax < _dragging) updateMax = _dragging;
|
||||
}
|
||||
if (updateMin >= 0) {
|
||||
update(0, _itemsTop + _rowHeight * (updateMin - 1), width(), _rowHeight * (updateMax - updateMin + 3));
|
||||
}
|
||||
}
|
||||
if (!animating) {
|
||||
_above = _dragging;
|
||||
_a_shifting.stop();
|
||||
}
|
||||
return animating;
|
||||
}
|
||||
|
||||
void StickersInner::clear() {
|
||||
|
@ -630,7 +636,7 @@ void StickersInner::rebuild() {
|
|||
clear();
|
||||
const StickerSetsOrder &order(cStickerSetsOrder());
|
||||
_animStartTimes.reserve(order.size());
|
||||
|
||||
|
||||
const StickerSets &sets(cStickerSets());
|
||||
for (int32 i = 0, l = order.size(); i < l; ++i) {
|
||||
StickerSets::const_iterator it = sets.constFind(order.at(i));
|
||||
|
@ -714,13 +720,14 @@ StickersBox::StickersBox() : ItemListBox(st::boxScroll)
|
|||
, _topShadow(this, st::contactsAboutShadow)
|
||||
, _bottomShadow(this)
|
||||
, _scrollDelta(0)
|
||||
, _aboutWidth(st::boxWideWidth - st::contactsPadding.left() - st::contactsPhotoSize - st::contactsPadding.left() - st::contactsPadding.right())
|
||||
, _aboutWidth(st::boxWideWidth - st::contactsPadding.left() - st::contactsPadding.left())
|
||||
, _about(st::boxTextFont, lang(lng_stickers_reorder), _defaultOptions, _aboutWidth)
|
||||
, _aboutHeight(st::stickersReorderPadding.top() + _about.countHeight(_aboutWidth) + st::stickersReorderPadding.bottom()) {
|
||||
ItemListBox::init(&_inner, st::boxButtonPadding.top() + _save.height() + st::boxButtonPadding.bottom(), st::boxTitleHeight + _aboutHeight);
|
||||
setMaxHeight(snap(countHeight(), int32(st::sessionsHeight), int32(st::boxMaxListHeight)));
|
||||
|
||||
connect(App::main(), SIGNAL(stickersUpdated()), this, SLOT(onStickersUpdated()));
|
||||
App::main()->updateStickers();
|
||||
|
||||
connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
|
||||
connect(&_save, SIGNAL(clicked()), this, SLOT(onSave()));
|
||||
|
@ -793,7 +800,7 @@ void StickersBox::paintEvent(QPaintEvent *e) {
|
|||
|
||||
p.fillRect(0, 0, width(), _aboutHeight, st::contactsAboutBg);
|
||||
p.setPen(st::stickersReorderFg);
|
||||
_about.drawLeft(p, st::contactsPadding.left() + st::contactsPhotoSize + st::contactsPadding.left(), st::stickersReorderPadding.top(), _aboutWidth, width());
|
||||
_about.draw(p, st::contactsPadding.left(), st::stickersReorderPadding.top(), _aboutWidth, style::al_center);
|
||||
}
|
||||
|
||||
void StickersBox::closePressed() {
|
||||
|
@ -908,7 +915,6 @@ void StickersBox::onSave() {
|
|||
}
|
||||
}
|
||||
|
||||
cSetStickersHash(stickersCountHash());
|
||||
Local::writeStickers();
|
||||
if (writeRecent) Local::writeUserSettings();
|
||||
emit App::main()->stickersUpdated();
|
||||
|
|
|
@ -32,7 +32,7 @@ public:
|
|||
void init();
|
||||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
|
||||
|
||||
bool loaded() const;
|
||||
int32 notInstalled() const;
|
||||
bool official() const;
|
||||
|
@ -60,6 +60,7 @@ private:
|
|||
bool installFailed(const RPCError &error);
|
||||
|
||||
StickerPack _pack;
|
||||
StickersByEmojiMap _emoji;
|
||||
bool _loaded;
|
||||
uint64 _setId, _setAccess;
|
||||
QString _title, _setTitle, _setShortName;
|
||||
|
@ -118,7 +119,7 @@ public:
|
|||
void mousePressEvent(QMouseEvent *e);
|
||||
void mouseMoveEvent(QMouseEvent *e);
|
||||
void mouseReleaseEvent(QMouseEvent *e);
|
||||
|
||||
|
||||
void rebuild();
|
||||
bool savingStart() {
|
||||
if (_saving) return false;
|
||||
|
@ -144,13 +145,11 @@ public slots:
|
|||
|
||||
private:
|
||||
|
||||
bool animStep_shifting(float64 ms);
|
||||
void step_shifting(uint64 ms, bool timer);
|
||||
void paintRow(Painter &p, int32 index);
|
||||
void clear();
|
||||
void setRemoveSel(int32 removeSel);
|
||||
float64 aboveShadowOpacity() const;
|
||||
void updateAnimatedRegions();
|
||||
bool updateAnimatedValues();
|
||||
|
||||
int32 _rowHeight;
|
||||
struct StickerSetRow {
|
||||
|
@ -203,7 +202,7 @@ public:
|
|||
StickersBox();
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
void paintEvent(QPaintEvent *e);
|
||||
|
||||
|
||||
void closePressed();
|
||||
|
||||
public slots:
|
||||
|
|
|
@ -20,10 +20,10 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
static const int32 AppVersion = 9015;
|
||||
static const wchar_t *AppVersionStr = L"0.9.15";
|
||||
static const bool DevVersion = false;
|
||||
//#define BETA_VERSION (9014003ULL) // just comment this line to build public version
|
||||
static const int32 AppVersion = 9019;
|
||||
static const wchar_t *AppVersionStr = L"0.9.19";
|
||||
static const bool DevVersion = true;
|
||||
//#define BETA_VERSION (9015008ULL) // just comment this line to build public version
|
||||
|
||||
static const wchar_t *AppNameOld = L"Telegram Win (Unofficial)";
|
||||
static const wchar_t *AppName = L"Telegram Desktop";
|
||||
|
@ -83,6 +83,13 @@ enum {
|
|||
LocalEncryptKeySize = 256, // 2048 bit
|
||||
|
||||
AnimationTimerDelta = 7,
|
||||
ClipThreadsCount = 8,
|
||||
AverageGifSize = 320 * 240,
|
||||
WaitBeforeGifPause = 200, // wait 200ms for gif draw before pausing it
|
||||
InlineBotRequestDelay = 400, // wait 400ms before context bot realtime request
|
||||
RecentInlineBotsLimit = 10,
|
||||
|
||||
AVBlockSize = 4096, // 4Kb for ffmpeg blocksize
|
||||
|
||||
SaveRecentEmojisTimeout = 3000, // 3 secs
|
||||
SaveWindowPositionTimeout = 1000, // 1 sec
|
||||
|
@ -108,12 +115,14 @@ enum {
|
|||
AudioVoiceMsgUpdateView = 100, // 100ms
|
||||
AudioVoiceMsgChannels = 2, // stereo
|
||||
AudioVoiceMsgBufferSize = 1024 * 1024, // 1 Mb buffers
|
||||
AudioVoiceMsgInMemory = 1024 * 1024, // 1 Mb audio is hold in memory and auto loaded
|
||||
AudioVoiceMsgInMemory = 2 * 1024 * 1024, // 2 Mb audio is hold in memory and auto loaded
|
||||
AudioPauseDeviceTimeout = 3000, // pause in 3 secs after playing is over
|
||||
|
||||
StickerInMemory = 1024 * 1024, // 1024 Kb stickers hold in memory, auto loaded and displayed inline
|
||||
StickerInMemory = 2 * 1024 * 1024, // 2 Mb stickers hold in memory, auto loaded and displayed inline
|
||||
StickerMaxSize = 2048, // 2048x2048 is a max image size for sticker
|
||||
|
||||
AnimationInMemory = 10 * 1024 * 1024, // 10 Mb gif and mp4 animations held in memory while playing
|
||||
|
||||
MediaViewImageSizeLimit = 100 * 1024 * 1024, // show up to 100mb jpg/png/gif docs in app
|
||||
MaxZoomLevel = 7, // x8
|
||||
ZoomToScreenLevel = 1024, // just constant
|
||||
|
@ -123,6 +132,7 @@ enum {
|
|||
EmojiPanRowsPerPage = 6,
|
||||
StickerPanPerRow = 5,
|
||||
StickerPanRowsPerPage = 4,
|
||||
SavedGifsMaxPerRow = 4,
|
||||
StickersUpdateTimeout = 3600000, // update not more than once in an hour
|
||||
|
||||
SearchPeopleLimit = 5,
|
||||
|
@ -335,6 +345,7 @@ enum {
|
|||
MaxUploadDocumentSize = 1500 * 1024 * 1024, // 1500mb documents max
|
||||
UseBigFilesFrom = 10 * 1024 * 1024, // mtp big files methods used for files greater than 10mb
|
||||
MaxFileQueries = 16, // max 16 file parts downloaded at the same time
|
||||
MaxWebFileQueries = 8, // max 8 http[s] files downloaded at the same time
|
||||
|
||||
UploadPartSize = 32 * 1024, // 32kb for photo
|
||||
DocumentMaxPartsCount = 3000, // no more than 3000 parts
|
||||
|
|
|
@ -163,7 +163,7 @@ void DialogsInner::paintRegion(Painter &p, const QRegion ®ion, bool paintingO
|
|||
PeerData *act = App::main()->activePeer();
|
||||
MsgId actId = App::main()->activeMsgId();
|
||||
for (; from < to; ++from) {
|
||||
bool active = ((_filterResults[from]->history->peer == act) || (_filterResults[from]->history->peer->migrateTo() && _filterResults[from]->history->peer->migrateTo() == act)) && !actId;
|
||||
bool active = ((_filterResults[from]->history->peer == act) || (_filterResults[from]->history->peer->migrateTo() && _filterResults[from]->history->peer->migrateTo() == act)) && !actId;
|
||||
bool selected = (from == _filteredSel) || (_filterResults[from]->history->peer == _menuPeer);
|
||||
_filterResults[from]->paint(p, w, active, selected, paintingOther);
|
||||
p.translate(0, st::dlgHeight);
|
||||
|
@ -488,16 +488,6 @@ void DialogsInner::removeDialog(History *history) {
|
|||
refresh();
|
||||
}
|
||||
|
||||
void DialogsInner::removeContact(UserData *user) {
|
||||
if (sel && sel->history->peer == user) {
|
||||
sel = 0;
|
||||
}
|
||||
contactsNoDialogs.del(user);
|
||||
contacts.del(user);
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
void DialogsInner::dlgUpdated(DialogRow *row) {
|
||||
if (_state == DefaultState) {
|
||||
update(0, row->pos * st::dlgHeight, fullWidth(), st::dlgHeight);
|
||||
|
@ -675,12 +665,12 @@ void DialogsInner::onContextClearHistory() {
|
|||
_menuActionPeer = _menuPeer;
|
||||
ConfirmBox *box = new ConfirmBox(_menuPeer->isUser() ? lng_sure_delete_history(lt_contact, _menuPeer->name) : lng_sure_delete_group_history(lt_group, _menuPeer->name), lang(lng_box_delete), st::attentionBoxButton);
|
||||
connect(box, SIGNAL(confirmed()), this, SLOT(onContextClearHistorySure()));
|
||||
App::showLayer(box);
|
||||
Ui::showLayer(box);
|
||||
}
|
||||
|
||||
void DialogsInner::onContextClearHistorySure() {
|
||||
if (!_menuActionPeer || _menuActionPeer->isChannel()) return;
|
||||
App::wnd()->hideLayer();
|
||||
Ui::hideLayer();
|
||||
App::main()->clearHistory(_menuActionPeer);
|
||||
}
|
||||
|
||||
|
@ -690,14 +680,14 @@ void DialogsInner::onContextDeleteAndLeave() {
|
|||
_menuActionPeer = _menuPeer;
|
||||
ConfirmBox *box = new ConfirmBox(_menuPeer->isUser() ? lng_sure_delete_history(lt_contact, _menuPeer->name) : (_menuPeer->isChat() ? lng_sure_delete_and_exit(lt_group, _menuPeer->name) : lang(_menuPeer->isMegagroup() ? lng_sure_leave_group : lng_sure_leave_channel)), lang(_menuPeer->isUser() ? lng_box_delete : lng_box_leave), _menuPeer->isChannel() ? st::defaultBoxButton : st::attentionBoxButton);
|
||||
connect(box, SIGNAL(confirmed()), this, SLOT(onContextDeleteAndLeaveSure()));
|
||||
App::wnd()->showLayer(box);
|
||||
Ui::showLayer(box);
|
||||
}
|
||||
|
||||
void DialogsInner::onContextDeleteAndLeaveSure() {
|
||||
if (!_menuActionPeer) return;
|
||||
|
||||
App::wnd()->hideLayer();
|
||||
App::main()->showDialogs();
|
||||
Ui::hideLayer();
|
||||
Ui::showChatsList();
|
||||
if (_menuActionPeer->isUser()) {
|
||||
App::main()->deleteConversation(_menuActionPeer);
|
||||
} else if (_menuActionPeer->isChat()) {
|
||||
|
@ -882,7 +872,7 @@ void DialogsInner::onHashtagFilterUpdate(QStringRef newFilter) {
|
|||
}
|
||||
_hashtagFilter = newFilter.toString();
|
||||
if (cRecentSearchHashtags().isEmpty() && cRecentWriteHashtags().isEmpty()) {
|
||||
Local::readRecentHashtags();
|
||||
Local::readRecentHashtagsAndBots();
|
||||
}
|
||||
const RecentHashtagPack &recent(cRecentSearchHashtags());
|
||||
_hashtagResults.clear();
|
||||
|
@ -917,14 +907,6 @@ void DialogsInner::clearSearchResults(bool clearPeople) {
|
|||
_lastSearchId = _lastSearchMigratedId = 0;
|
||||
}
|
||||
|
||||
void DialogsInner::itemReplaced(HistoryItem *oldItem, HistoryItem *newItem) {
|
||||
for (int i = 0; i < _searchResults.size(); ++i) {
|
||||
if (_searchResults[i]->_item == oldItem) {
|
||||
_searchResults[i]->_item = newItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DialogsInner::updateNotifySettings(PeerData *peer) {
|
||||
if (_menu && _menuPeer == peer && _menu->actions().size() > 1) {
|
||||
_menu->actions().at(1)->setText(lang(menuPeerMuted() ? lng_enable_notifications_from_tray : lng_disable_notifications_from_tray));
|
||||
|
@ -1096,9 +1078,11 @@ void DialogsInner::peopleReceived(const QString &query, const QVector<MTPPeer> &
|
|||
void DialogsInner::contactsReceived(const QVector<MTPContact> &contacts) {
|
||||
for (QVector<MTPContact>::const_iterator i = contacts.cbegin(), e = contacts.cend(); i != e; ++i) {
|
||||
int32 uid = i->c_contact().vuser_id.v;
|
||||
addNewContact(uid);
|
||||
if (uid == MTP::authedId() && App::self()) {
|
||||
App::self()->contact = 1;
|
||||
if (App::self()->contact < 1) {
|
||||
App::self()->contact = 1;
|
||||
Notify::userIsContactChanged(App::self());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!sel && contactsNoDialogs.list.count && false) {
|
||||
|
@ -1108,23 +1092,25 @@ void DialogsInner::contactsReceived(const QVector<MTPContact> &contacts) {
|
|||
refresh();
|
||||
}
|
||||
|
||||
int32 DialogsInner::addNewContact(int32 uid, bool select) { // -2 - err, -1 - don't scroll, >= 0 - scroll
|
||||
PeerId peer = peerFromUser(uid);
|
||||
if (!App::peerLoaded(peer)) return -2;
|
||||
|
||||
History *history = App::history(peer);
|
||||
contacts.addByName(history);
|
||||
DialogsList::RowByPeer::const_iterator i = dialogs.list.rowByPeer.constFind(peer);
|
||||
if (i == dialogs.list.rowByPeer.cend()) {
|
||||
DialogRow *added = contactsNoDialogs.addByName(history);
|
||||
if (!added) return -2;
|
||||
return -1;
|
||||
void DialogsInner::notify_userIsContactChanged(UserData *user, bool fromThisApp) {
|
||||
if (user->contact > 0) {
|
||||
History *history = App::history(user->id);
|
||||
contacts.addByName(history);
|
||||
DialogsList::RowByPeer::const_iterator i = dialogs.list.rowByPeer.constFind(user->id);
|
||||
if (i == dialogs.list.rowByPeer.cend()) {
|
||||
contactsNoDialogs.addByName(history);
|
||||
} else if (fromThisApp) {
|
||||
sel = i.value();
|
||||
contactSel = false;
|
||||
}
|
||||
} else {
|
||||
if (sel && sel->history->peer == user) {
|
||||
sel = 0;
|
||||
}
|
||||
contactsNoDialogs.del(user);
|
||||
contacts.del(user);
|
||||
}
|
||||
if (select) {
|
||||
sel = i.value();
|
||||
contactSel = false;
|
||||
}
|
||||
return i.value()->pos * st::dlgHeight;
|
||||
refresh();
|
||||
}
|
||||
|
||||
void DialogsInner::refresh(bool toTop) {
|
||||
|
@ -1399,7 +1385,7 @@ void DialogsInner::loadPeerPhotos(int32 yFrom) {
|
|||
if (from < _filterResults.size()) {
|
||||
int32 to = (yTo / int32(st::dlgHeight)) + 1, w = width();
|
||||
if (to > _filterResults.size()) to = _filterResults.size();
|
||||
|
||||
|
||||
for (; from < to; ++from) {
|
||||
_filterResults[from]->history->peer->photo->load();
|
||||
}
|
||||
|
@ -1448,7 +1434,7 @@ bool DialogsInner::choosePeer() {
|
|||
}
|
||||
}
|
||||
cSetRecentSearchHashtags(recent);
|
||||
Local::writeRecentHashtags();
|
||||
Local::writeRecentHashtagsAndBots();
|
||||
emit refreshHashtags();
|
||||
|
||||
selByMouse = true;
|
||||
|
@ -1501,7 +1487,7 @@ void DialogsInner::saveRecentHashtags(const QString &text) {
|
|||
}
|
||||
}
|
||||
if (!found && cRecentWriteHashtags().isEmpty() && cRecentSearchHashtags().isEmpty()) {
|
||||
Local::readRecentHashtags();
|
||||
Local::readRecentHashtagsAndBots();
|
||||
recent = cRecentSearchHashtags();
|
||||
}
|
||||
found = true;
|
||||
|
@ -1509,7 +1495,7 @@ void DialogsInner::saveRecentHashtags(const QString &text) {
|
|||
}
|
||||
if (found) {
|
||||
cSetRecentSearchHashtags(recent);
|
||||
Local::writeRecentHashtags();
|
||||
Local::writeRecentHashtagsAndBots();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1737,7 +1723,7 @@ DialogsWidget::DialogsWidget(MainWidget *parent) : TWidget(parent)
|
|||
, _cancelSearch(this, st::btnCancelSearch)
|
||||
, _scroll(this, st::dlgScroll)
|
||||
, _inner(&_scroll, parent)
|
||||
, _a_show(animFunc(this, &DialogsWidget::animStep_show))
|
||||
, _a_show(animation(this, &DialogsWidget::step_show))
|
||||
, _searchInPeer(0)
|
||||
, _searchInMigrated(0)
|
||||
, _searchFull(false)
|
||||
|
@ -1839,13 +1825,11 @@ void DialogsWidget::animShow(const QPixmap &bgAnimCache) {
|
|||
show();
|
||||
}
|
||||
|
||||
bool DialogsWidget::animStep_show(float64 ms) {
|
||||
void DialogsWidget::step_show(float64 ms, bool timer) {
|
||||
float64 dt = ms / st::slideDuration;
|
||||
bool res = true;
|
||||
if (dt >= 1) {
|
||||
_a_show.stop();
|
||||
|
||||
res = false;
|
||||
a_coordUnder.finish();
|
||||
a_coordOver.finish();
|
||||
a_shadow.finish();
|
||||
|
@ -1865,8 +1849,7 @@ bool DialogsWidget::animStep_show(float64 ms) {
|
|||
a_coordOver.update(dt, st::slideFunction);
|
||||
a_shadow.update(dt, st::slideFunction);
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
if (timer) update();
|
||||
}
|
||||
|
||||
void DialogsWidget::onCancel() {
|
||||
|
@ -1879,14 +1862,19 @@ void DialogsWidget::itemRemoved(HistoryItem *item) {
|
|||
_inner.itemRemoved(item);
|
||||
}
|
||||
|
||||
void DialogsWidget::itemReplaced(HistoryItem *oldItem, HistoryItem *newItem) {
|
||||
_inner.itemReplaced(oldItem, newItem);
|
||||
}
|
||||
|
||||
void DialogsWidget::updateNotifySettings(PeerData *peer) {
|
||||
_inner.updateNotifySettings(peer);
|
||||
}
|
||||
|
||||
void DialogsWidget::notify_userIsContactChanged(UserData *user, bool fromThisApp) {
|
||||
if (fromThisApp) {
|
||||
_filter.setText(QString());
|
||||
_filter.updatePlaceholder();
|
||||
onFilterUpdate();
|
||||
}
|
||||
_inner.notify_userIsContactChanged(user, fromThisApp);
|
||||
}
|
||||
|
||||
void DialogsWidget::unreadCountsReceived(const QVector<MTPDialog> &dialogs) {
|
||||
for (QVector<MTPDialog>::const_iterator i = dialogs.cbegin(), e = dialogs.cend(); i != e; ++i) {
|
||||
switch (i->type()) {
|
||||
|
@ -2273,17 +2261,6 @@ bool DialogsWidget::peopleFailed(const RPCError &error, mtpRequestId req) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool DialogsWidget::addNewContact(int32 uid, bool show) {
|
||||
_filter.setText(QString());
|
||||
_filter.updatePlaceholder();
|
||||
onFilterUpdate();
|
||||
int32 to = _inner.addNewContact(uid, true);
|
||||
if (to < -1 || !show) return false;
|
||||
_inner.refresh();
|
||||
if (to >= 0) _scroll.scrollToY(to);
|
||||
return true;
|
||||
}
|
||||
|
||||
void DialogsWidget::dragEnterEvent(QDragEnterEvent *e) {
|
||||
if (App::main()->selectingPeer()) return;
|
||||
|
||||
|
@ -2540,13 +2517,6 @@ void DialogsWidget::removeDialog(History *history) {
|
|||
onFilterUpdate();
|
||||
}
|
||||
|
||||
void DialogsWidget::removeContact(UserData *user) {
|
||||
_filter.setText(QString());
|
||||
_filter.updatePlaceholder();
|
||||
onFilterUpdate();
|
||||
_inner.removeContact(user);
|
||||
}
|
||||
|
||||
DialogsIndexed &DialogsWidget::contactsList() {
|
||||
return _inner.contactsList();
|
||||
}
|
||||
|
@ -2556,11 +2526,11 @@ DialogsIndexed &DialogsWidget::dialogsList() {
|
|||
}
|
||||
|
||||
void DialogsWidget::onAddContact() {
|
||||
App::wnd()->replaceLayer(new AddContactBox());
|
||||
Ui::showLayer(new AddContactBox(), KeepOtherLayers);
|
||||
}
|
||||
|
||||
void DialogsWidget::onNewGroup() {
|
||||
App::wnd()->showLayer(new NewGroupBox());
|
||||
Ui::showLayer(new NewGroupBox());
|
||||
}
|
||||
|
||||
bool DialogsWidget::onCancelSearch() {
|
||||
|
@ -2571,7 +2541,7 @@ bool DialogsWidget::onCancelSearch() {
|
|||
}
|
||||
if (_searchInPeer && !clearing) {
|
||||
if (!cWideMode()) {
|
||||
App::main()->showPeerHistory(_searchInPeer->id, ShowAtUnreadMsgId);
|
||||
Ui::showPeerHistory(_searchInPeer, ShowAtUnreadMsgId);
|
||||
}
|
||||
_searchInPeer = _searchInMigrated = 0;
|
||||
_inner.searchInPeer(0);
|
||||
|
@ -2591,7 +2561,7 @@ void DialogsWidget::onCancelSearchInPeer() {
|
|||
}
|
||||
if (_searchInPeer) {
|
||||
if (!cWideMode() && !App::main()->selectingPeer()) {
|
||||
App::main()->showPeerHistory(_searchInPeer->id, ShowAtUnreadMsgId);
|
||||
Ui::showPeerHistory(_searchInPeer, ShowAtUnreadMsgId);
|
||||
}
|
||||
_searchInPeer = _searchInMigrated = 0;
|
||||
_inner.searchInPeer(0);
|
||||
|
|
|
@ -48,7 +48,6 @@ public:
|
|||
void activate();
|
||||
|
||||
void contactsReceived(const QVector<MTPContact> &contacts);
|
||||
int32 addNewContact(int32 uid, bool sel = false); // -2 - err, -1 - don't scroll, >= 0 - scroll
|
||||
|
||||
int32 filteredOffset() const;
|
||||
int32 peopleOffset() const;
|
||||
|
@ -72,7 +71,6 @@ public:
|
|||
void dlgUpdated(DialogRow *row);
|
||||
void dlgUpdated(History *row, MsgId msgId);
|
||||
void removeDialog(History *history);
|
||||
void removeContact(UserData *user);
|
||||
|
||||
void loadPeerPhotos(int32 yFrom);
|
||||
void clearFilter();
|
||||
|
@ -117,12 +115,13 @@ public:
|
|||
void onFilterUpdate(QString newFilter, bool force = false);
|
||||
void onHashtagFilterUpdate(QStringRef newFilter);
|
||||
void itemRemoved(HistoryItem *item);
|
||||
void itemReplaced(HistoryItem *oldItem, HistoryItem *newItem);
|
||||
|
||||
PeerData *updateFromParentDrag(QPoint globalPos);
|
||||
|
||||
void updateNotifySettings(PeerData *peer);
|
||||
|
||||
void notify_userIsContactChanged(UserData *user, bool fromThisApp);
|
||||
|
||||
~DialogsInner();
|
||||
|
||||
public slots:
|
||||
|
@ -220,7 +219,6 @@ public:
|
|||
void contactsReceived(const MTPcontacts_Contacts &contacts);
|
||||
void searchReceived(DialogsSearchRequestType type, const MTPmessages_Messages &result, mtpRequestId req);
|
||||
void peopleReceived(const MTPcontacts_Found &result, mtpRequestId req);
|
||||
bool addNewContact(int32 uid, bool show = true);
|
||||
|
||||
void dragEnterEvent(QDragEnterEvent *e);
|
||||
void dragMoveEvent(QDragMoveEvent *e);
|
||||
|
@ -242,7 +240,7 @@ public:
|
|||
void dialogsToUp();
|
||||
|
||||
void animShow(const QPixmap &bgAnimCache);
|
||||
bool animStep_show(float64 ms);
|
||||
void step_show(float64 ms, bool timer);
|
||||
|
||||
void destroyData();
|
||||
|
||||
|
@ -251,7 +249,6 @@ public:
|
|||
void scrollToPeer(const PeerId &peer, MsgId msgId);
|
||||
|
||||
void removeDialog(History *history);
|
||||
void removeContact(UserData *user);
|
||||
|
||||
DialogsIndexed &contactsList();
|
||||
DialogsIndexed &dialogsList();
|
||||
|
@ -260,10 +257,11 @@ public:
|
|||
void onSearchMore();
|
||||
|
||||
void itemRemoved(HistoryItem *item);
|
||||
void itemReplaced(HistoryItem *oldItem, HistoryItem *newItem);
|
||||
|
||||
void updateNotifySettings(PeerData *peer);
|
||||
|
||||
void notify_userIsContactChanged(UserData *user, bool fromThisApp);
|
||||
|
||||
signals:
|
||||
|
||||
void cancelled();
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -23,7 +23,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
#include "gui/twidget.h"
|
||||
#include "gui/boxshadow.h"
|
||||
|
||||
class Dropdown : public TWidget, public Animated {
|
||||
class Dropdown : public TWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
@ -46,12 +46,12 @@ public:
|
|||
void fastHide();
|
||||
void ignoreShow(bool ignore = true);
|
||||
|
||||
bool animStep(float64 ms);
|
||||
void step_appearance(float64 ms, bool timer);
|
||||
|
||||
bool eventFilter(QObject *obj, QEvent *e);
|
||||
|
||||
bool overlaps(const QRect &globalRect) {
|
||||
if (isHidden() || animating()) return false;
|
||||
if (isHidden() || _a_appearance.animating()) return false;
|
||||
|
||||
return QRect(_st.padding.left(),
|
||||
_st.padding.top(),
|
||||
|
@ -91,6 +91,7 @@ private:
|
|||
bool _hiding;
|
||||
|
||||
anim::fvalue a_opacity;
|
||||
Animation _a_appearance;
|
||||
|
||||
QTimer _hideTimer;
|
||||
|
||||
|
@ -98,7 +99,7 @@ private:
|
|||
|
||||
};
|
||||
|
||||
class DragArea : public TWidget, public Animated {
|
||||
class DragArea : public TWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
@ -119,10 +120,10 @@ public:
|
|||
|
||||
void fastHide();
|
||||
|
||||
bool animStep(float64 ms);
|
||||
void step_appearance(float64 ms, bool timer);
|
||||
|
||||
bool overlaps(const QRect &globalRect) {
|
||||
if (isHidden() || animating()) return false;
|
||||
if (isHidden() || _a_appearance.animating()) return false;
|
||||
|
||||
return QRect(st::dragPadding.left(),
|
||||
st::dragPadding.top(),
|
||||
|
@ -148,6 +149,7 @@ private:
|
|||
|
||||
anim::fvalue a_opacity;
|
||||
anim::cvalue a_color;
|
||||
Animation _a_appearance;
|
||||
|
||||
BoxShadow _shadow;
|
||||
|
||||
|
@ -158,7 +160,7 @@ private:
|
|||
class EmojiPanel;
|
||||
static const int EmojiColorsCount = 5;
|
||||
|
||||
class EmojiColorPicker : public TWidget, public Animated {
|
||||
class EmojiColorPicker : public TWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
@ -174,7 +176,8 @@ public:
|
|||
void mouseReleaseEvent(QMouseEvent *e);
|
||||
void mouseMoveEvent(QMouseEvent *e);
|
||||
|
||||
bool animStep(float64 ms);
|
||||
void step_appearance(float64 ms, bool timer);
|
||||
void step_selected(uint64 ms, bool timer);
|
||||
void showStart();
|
||||
|
||||
void clearSelection(bool fast = false);
|
||||
|
@ -200,6 +203,7 @@ private:
|
|||
|
||||
typedef QMap<int32, uint64> EmojiAnimations; // index - showing, -index - hiding
|
||||
EmojiAnimations _emojiAnimations;
|
||||
Animation _a_selected;
|
||||
|
||||
float64 _hovers[EmojiColorsCount + 1];
|
||||
|
||||
|
@ -210,6 +214,7 @@ private:
|
|||
QPixmap _cache;
|
||||
|
||||
anim::fvalue a_opacity;
|
||||
Animation _a_appearance;
|
||||
|
||||
QTimer _hideTimer;
|
||||
|
||||
|
@ -217,7 +222,7 @@ private:
|
|||
|
||||
};
|
||||
|
||||
class EmojiPanInner : public TWidget, public Animated {
|
||||
class EmojiPanInner : public TWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
@ -234,7 +239,7 @@ public:
|
|||
void leaveToChildEvent(QEvent *e);
|
||||
void enterFromChildEvent(QEvent *e);
|
||||
|
||||
bool animStep(float64 ms);
|
||||
void step_selected(uint64 ms, bool timer);
|
||||
void hideFinish();
|
||||
|
||||
void showEmojiPack(DBIEmojiTab packIndex);
|
||||
|
@ -249,11 +254,10 @@ public:
|
|||
|
||||
void fillPanels(QVector<EmojiPanel*> &panels);
|
||||
void refreshPanels(QVector<EmojiPanel*> &panels);
|
||||
|
||||
|
||||
public slots:
|
||||
|
||||
void updateSelected();
|
||||
void onSaveConfig();
|
||||
|
||||
void onShowPicker();
|
||||
void onPickerHidden();
|
||||
|
@ -271,6 +275,7 @@ signals:
|
|||
void disableScroll(bool dis);
|
||||
|
||||
void needRefreshPanels();
|
||||
void saveConfigDelayed(int32 delay);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -283,6 +288,7 @@ private:
|
|||
|
||||
typedef QMap<int32, uint64> Animations; // index - showing, -index - hiding
|
||||
Animations _animations;
|
||||
Animation _a_selected;
|
||||
|
||||
int32 _top, _counts[emojiTabCount];
|
||||
|
||||
|
@ -294,14 +300,12 @@ private:
|
|||
int32 _selected, _pressedSel, _pickerSel;
|
||||
QPoint _lastMousePos;
|
||||
|
||||
QTimer _saveConfigTimer;
|
||||
|
||||
EmojiColorPicker _picker;
|
||||
QTimer _showPickerTimer;
|
||||
};
|
||||
|
||||
struct StickerIcon {
|
||||
StickerIcon() : setId(RecentStickerSetId), sticker(0), pixw(0), pixh(0) {
|
||||
StickerIcon(uint64 setId) : setId(setId), sticker(0), pixw(0), pixh(0) {
|
||||
}
|
||||
StickerIcon(uint64 setId, DocumentData *sticker, int32 pixw, int32 pixh) : setId(setId), sticker(sticker), pixw(pixw), pixh(pixh) {
|
||||
}
|
||||
|
@ -310,7 +314,7 @@ struct StickerIcon {
|
|||
int32 pixw, pixh;
|
||||
};
|
||||
|
||||
class StickerPanInner : public TWidget, public Animated {
|
||||
class StickerPanInner : public TWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
@ -327,16 +331,26 @@ public:
|
|||
void leaveToChildEvent(QEvent *e);
|
||||
void enterFromChildEvent(QEvent *e);
|
||||
|
||||
bool animStep(float64 ms);
|
||||
void step_selected(uint64 ms, bool timer);
|
||||
|
||||
void hideFinish(bool completely);
|
||||
void showFinish();
|
||||
void showStickerSet(uint64 setId);
|
||||
void updateShowingSavedGifs();
|
||||
|
||||
bool showSectionIcons() const;
|
||||
void clearSelection(bool fast = false);
|
||||
|
||||
void refreshStickers();
|
||||
void refreshRecent(bool resize = true);
|
||||
void refreshRecentStickers(bool resize = true);
|
||||
void refreshSavedGifs();
|
||||
int32 refreshInlineRows(UserData *bot, const InlineResults &results, bool resultsDeleted);
|
||||
void refreshRecent();
|
||||
void inlineBotChanged();
|
||||
void hideInlineRowsPanel();
|
||||
void clearInlineRowsPanel();
|
||||
|
||||
void fillIcons(QVector<StickerIcon> &icons);
|
||||
void fillIcons(QList<StickerIcon> &icons);
|
||||
void fillPanels(QVector<EmojiPanel*> &panels);
|
||||
void refreshPanels(QVector<EmojiPanel*> &panels);
|
||||
|
||||
|
@ -345,37 +359,63 @@ public:
|
|||
|
||||
uint64 currentSet(int yOffset) const;
|
||||
|
||||
void ui_repaintInlineItem(const LayoutInlineItem *layout);
|
||||
bool ui_isInlineItemVisible(const LayoutInlineItem *layout);
|
||||
bool ui_isInlineItemBeingChosen();
|
||||
|
||||
bool inlineResultsShown() const {
|
||||
return _showingInlineItems && !_showingSavedGifs;
|
||||
}
|
||||
int32 countHeight(bool plain = false);
|
||||
|
||||
~StickerPanInner() {
|
||||
clearInlineRows(true);
|
||||
deleteUnusedGifLayouts();
|
||||
deleteUnusedInlineLayouts();
|
||||
}
|
||||
|
||||
public slots:
|
||||
|
||||
void updateSelected();
|
||||
void onSettings();
|
||||
void onPreview();
|
||||
void onUpdateInlineItems();
|
||||
|
||||
signals:
|
||||
|
||||
void selected(DocumentData *sticker);
|
||||
void selected(PhotoData *photo);
|
||||
void selected(InlineResult *result, UserData *bot);
|
||||
|
||||
void removing(quint64 setId);
|
||||
|
||||
void refreshIcons();
|
||||
void emptyInlineRows();
|
||||
|
||||
void switchToEmoji();
|
||||
|
||||
void scrollToY(int y);
|
||||
void scrollUpdated();
|
||||
void disableScroll(bool dis);
|
||||
void needRefreshPanels();
|
||||
|
||||
void saveConfigDelayed(int32 delay);
|
||||
|
||||
private:
|
||||
|
||||
void paintInlineItems(Painter &p, const QRect &r);
|
||||
void paintStickers(Painter &p, const QRect &r);
|
||||
|
||||
int32 _maxHeight;
|
||||
|
||||
void appendSet(uint64 setId);
|
||||
|
||||
int32 countHeight();
|
||||
void selectEmoji(EmojiPtr emoji);
|
||||
QRect stickerRect(int tab, int sel);
|
||||
|
||||
typedef QMap<int32, uint64> Animations; // index - showing, -index - hiding
|
||||
Animations _animations;
|
||||
Animation _a_selected;
|
||||
|
||||
int32 _top;
|
||||
|
||||
|
@ -391,8 +431,45 @@ private:
|
|||
QList<DisplayedSet> _sets;
|
||||
QList<bool> _custom;
|
||||
|
||||
bool _showingSavedGifs, _showingInlineItems;
|
||||
bool _setGifCommand;
|
||||
UserData *_inlineBot;
|
||||
QString _inlineBotTitle;
|
||||
uint64 _lastScrolled;
|
||||
QTimer _updateInlineItems;
|
||||
bool _inlineWithThumb;
|
||||
|
||||
typedef QVector<LayoutInlineItem*> InlineItems;
|
||||
struct InlineRow {
|
||||
InlineRow() : height(0) {
|
||||
}
|
||||
int32 height;
|
||||
InlineItems items;
|
||||
};
|
||||
typedef QVector<InlineRow> InlineRows;
|
||||
InlineRows _inlineRows;
|
||||
void clearInlineRows(bool resultsDeleted);
|
||||
|
||||
typedef QMap<DocumentData*, LayoutInlineGif*> GifLayouts;
|
||||
GifLayouts _gifLayouts;
|
||||
LayoutInlineGif *layoutPrepareSavedGif(DocumentData *doc, int32 position);
|
||||
|
||||
typedef QMap<InlineResult*, LayoutInlineItem*> InlineLayouts;
|
||||
InlineLayouts _inlineLayouts;
|
||||
LayoutInlineItem *layoutPrepareInlineResult(InlineResult *result, int32 position);
|
||||
|
||||
bool inlineRowsAddItem(DocumentData *savedGif, InlineResult *result, InlineRow &row, int32 &sumWidth);
|
||||
bool inlineRowFinalize(InlineRow &row, int32 &sumWidth, bool force = false);
|
||||
|
||||
InlineRow &layoutInlineRow(InlineRow &row, int32 sumWidth = 0);
|
||||
void deleteUnusedGifLayouts();
|
||||
|
||||
void deleteUnusedInlineLayouts();
|
||||
|
||||
int32 validateExistingInlineRows(const InlineResults &results);
|
||||
int32 _selected, _pressedSel;
|
||||
QPoint _lastMousePos;
|
||||
TextLinkPtr _linkOver, _linkDown;
|
||||
|
||||
LinkButton _settings;
|
||||
|
||||
|
@ -445,6 +522,7 @@ public:
|
|||
|
||||
EmojiSwitchButton(QWidget *parent, bool toStickers); // otherwise toEmoji
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void updateText(const QString &inlineBotUsername = QString());
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -454,7 +532,7 @@ protected:
|
|||
|
||||
};
|
||||
|
||||
class EmojiPan : public TWidget, public Animated {
|
||||
class EmojiPan : public TWidget, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
@ -464,6 +542,8 @@ public:
|
|||
void setMaxHeight(int32 h);
|
||||
void paintEvent(QPaintEvent *e);
|
||||
|
||||
void moveBottom(int32 bottom, bool force = false);
|
||||
|
||||
void enterEvent(QEvent *e);
|
||||
void leaveEvent(QEvent *e);
|
||||
void otherEnter();
|
||||
|
@ -480,13 +560,16 @@ public:
|
|||
return _hiding || _hideTimer.isActive();
|
||||
}
|
||||
|
||||
bool animStep(float64 ms);
|
||||
|
||||
bool iconAnim(float64 ms);
|
||||
void step_appearance(float64 ms, bool timer);
|
||||
void step_slide(float64 ms, bool timer);
|
||||
void step_icons(uint64 ms, bool timer);
|
||||
|
||||
bool eventFilter(QObject *obj, QEvent *e);
|
||||
void stickersInstalled(uint64 setId);
|
||||
|
||||
void queryInlineBot(UserData *bot, QString query);
|
||||
void clearInlineBot();
|
||||
|
||||
bool overlaps(const QRect &globalRect) {
|
||||
if (isHidden() || !_cache.isNull()) return false;
|
||||
|
||||
|
@ -497,9 +580,19 @@ public:
|
|||
).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
|
||||
}
|
||||
|
||||
void ui_repaintInlineItem(const LayoutInlineItem *layout);
|
||||
bool ui_isInlineItemVisible(const LayoutInlineItem *layout);
|
||||
bool ui_isInlineItemBeingChosen();
|
||||
|
||||
bool inlineResultsShown() const {
|
||||
return s_inner.inlineResultsShown();
|
||||
}
|
||||
void notify_automaticLoadSettingsChangedGif();
|
||||
|
||||
public slots:
|
||||
|
||||
void refreshStickers();
|
||||
void refreshSavedGifs();
|
||||
|
||||
void hideStart();
|
||||
void hideFinish();
|
||||
|
@ -518,18 +611,32 @@ public slots:
|
|||
void onRefreshIcons();
|
||||
void onRefreshPanels();
|
||||
|
||||
void onSaveConfig();
|
||||
void onSaveConfigDelayed(int32 delay);
|
||||
|
||||
void onInlineRequest();
|
||||
void onEmptyInlineRows();
|
||||
|
||||
signals:
|
||||
|
||||
void emojiSelected(EmojiPtr emoji);
|
||||
void stickerSelected(DocumentData *sticker);
|
||||
void photoSelected(PhotoData *photo);
|
||||
void inlineResultSelected(InlineResult *result, UserData *bot);
|
||||
|
||||
void updateStickers();
|
||||
|
||||
private:
|
||||
|
||||
int32 _maxHeight;
|
||||
void validateSelectedIcon(bool animated = false);
|
||||
|
||||
int32 _maxHeight, _contentMaxHeight, _contentHeight, _contentHeightEmoji, _contentHeightStickers;
|
||||
bool _horizontal;
|
||||
void updateContentHeight();
|
||||
|
||||
void leaveToChildEvent(QEvent *e);
|
||||
void hideAnimated();
|
||||
void prepareShowHideCache();
|
||||
|
||||
void updateSelected();
|
||||
void updateIcons();
|
||||
|
@ -542,35 +649,36 @@ private:
|
|||
|
||||
bool _noTabUpdate;
|
||||
|
||||
int32 _width, _height;
|
||||
int32 _width, _height, _bottom;
|
||||
bool _hiding;
|
||||
QPixmap _cache;
|
||||
|
||||
anim::fvalue a_opacity;
|
||||
Animation _a_appearance;
|
||||
|
||||
QTimer _hideTimer;
|
||||
|
||||
BoxShadow _shadow;
|
||||
|
||||
FlatRadiobutton _recent, _people, _nature, _food, _activity, _travel, _objects, _symbols;
|
||||
QVector<StickerIcon> _icons;
|
||||
QList<StickerIcon> _icons;
|
||||
QVector<float64> _iconHovers;
|
||||
int32 _iconOver, _iconSel, _iconDown;
|
||||
bool _iconsDragging;
|
||||
typedef QMap<int32, uint64> Animations; // index - showing, -index - hiding
|
||||
Animations _iconAnimations;
|
||||
Animation _iconAnim;
|
||||
Animation _a_icons;
|
||||
QPoint _iconsMousePos, _iconsMouseDown;
|
||||
int32 _iconsLeft, _iconsTop;
|
||||
int32 _iconsStartX, _iconsMax;
|
||||
anim::ivalue _iconsX, _iconSelX;
|
||||
uint64 _iconsStartAnim;
|
||||
|
||||
bool _stickersShown;
|
||||
bool _stickersShown, _shownFromInlineQuery;
|
||||
QPixmap _fromCache, _toCache;
|
||||
anim::ivalue a_fromCoord, a_toCoord;
|
||||
anim::fvalue a_fromAlpha, a_toAlpha;
|
||||
uint64 _moveStart;
|
||||
Animation _a_slide;
|
||||
|
||||
ScrollArea e_scroll;
|
||||
EmojiPanInner e_inner;
|
||||
|
@ -583,6 +691,37 @@ private:
|
|||
|
||||
uint64 _removingSetId;
|
||||
|
||||
QTimer _saveConfigTimer;
|
||||
|
||||
// inline bots
|
||||
struct InlineCacheEntry {
|
||||
~InlineCacheEntry() {
|
||||
clearResults();
|
||||
}
|
||||
QString nextOffset;
|
||||
InlineResults results;
|
||||
void clearResults() {
|
||||
for (int32 i = 0, l = results.size(); i < l; ++i) {
|
||||
delete results.at(i);
|
||||
}
|
||||
results.clear();
|
||||
}
|
||||
};
|
||||
typedef QMap<QString, InlineCacheEntry*> InlineCache;
|
||||
InlineCache _inlineCache;
|
||||
QTimer _inlineRequestTimer;
|
||||
|
||||
void inlineBotChanged();
|
||||
int32 showInlineRows(bool newResults);
|
||||
bool hideOnNoInlineResults();
|
||||
void recountContentMaxHeight();
|
||||
bool refreshInlineRows(int32 *added = 0);
|
||||
UserData *_inlineBot;
|
||||
QString _inlineQuery, _inlineNextQuery, _inlineNextOffset;
|
||||
mtpRequestId _inlineRequestId;
|
||||
void inlineResultsDone(const MTPmessages_BotResults &result);
|
||||
bool inlineResultsFail(const RPCError &error);
|
||||
|
||||
};
|
||||
|
||||
typedef QList<UserData*> MentionRows;
|
||||
|
@ -590,14 +729,15 @@ typedef QList<QString> HashtagRows;
|
|||
typedef QList<QPair<UserData*, const BotCommand*> > BotCommandRows;
|
||||
|
||||
class MentionsDropdown;
|
||||
class MentionsInner : public QWidget {
|
||||
class MentionsInner : public TWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
MentionsInner(MentionsDropdown *parent, MentionRows *rows, HashtagRows *hrows, BotCommandRows *crows);
|
||||
MentionsInner(MentionsDropdown *parent, MentionRows *mrows, HashtagRows *hrows, BotCommandRows *brows, StickerPack *srows);
|
||||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
|
||||
void enterEvent(QEvent *e);
|
||||
void leaveEvent(QEvent *e);
|
||||
|
@ -606,14 +746,17 @@ public:
|
|||
void mouseMoveEvent(QMouseEvent *e);
|
||||
|
||||
void clearSel();
|
||||
bool moveSel(int direction);
|
||||
bool moveSel(int key);
|
||||
bool select();
|
||||
|
||||
void setRecentInlineBotsInRows(int32 bots);
|
||||
|
||||
QString getSelected() const;
|
||||
|
||||
signals:
|
||||
|
||||
void chosen(QString mentionOrHashtag);
|
||||
void selected(DocumentData *sticker);
|
||||
void mustScrollTo(int scrollToTop, int scrollToBottom);
|
||||
|
||||
public slots:
|
||||
|
@ -623,12 +766,15 @@ public slots:
|
|||
|
||||
private:
|
||||
|
||||
void updateSelectedRow();
|
||||
void setSel(int sel, bool scroll = false);
|
||||
|
||||
MentionsDropdown *_parent;
|
||||
MentionRows *_rows;
|
||||
MentionRows *_mrows;
|
||||
HashtagRows *_hrows;
|
||||
BotCommandRows *_crows;
|
||||
BotCommandRows *_brows;
|
||||
StickerPack *_srows;
|
||||
int32 _stickersPerRow, _recentInlineBotsInRows;
|
||||
int32 _sel;
|
||||
bool _mouseSel;
|
||||
QPoint _mousePos;
|
||||
|
@ -636,7 +782,7 @@ private:
|
|||
bool _overDelete;
|
||||
};
|
||||
|
||||
class MentionsDropdown : public TWidget, public Animated {
|
||||
class MentionsDropdown : public TWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
@ -647,12 +793,13 @@ public:
|
|||
|
||||
void fastHide();
|
||||
|
||||
bool clearFilteredCommands();
|
||||
void showFiltered(PeerData *peer, QString start);
|
||||
void updateFiltered(bool toDown = false);
|
||||
bool clearFilteredBotCommands();
|
||||
void showFiltered(PeerData *peer, QString query, bool start);
|
||||
void showStickers(EmojiPtr emoji);
|
||||
void updateFiltered(bool resetScroll = false);
|
||||
void setBoundings(QRect boundings);
|
||||
|
||||
bool animStep(float64 ms);
|
||||
void step_appearance(float64 ms, bool timer);
|
||||
|
||||
const QString &filter() const;
|
||||
ChatData *chat() const;
|
||||
|
@ -665,6 +812,10 @@ public:
|
|||
bool eventFilter(QObject *obj, QEvent *e);
|
||||
QString getSelected() const;
|
||||
|
||||
bool stickersShown() const {
|
||||
return !_srows.isEmpty();
|
||||
}
|
||||
|
||||
bool overlaps(const QRect &globalRect) {
|
||||
if (isHidden() || !testAttribute(Qt::WA_OpaquePaintEvent)) return false;
|
||||
|
||||
|
@ -676,6 +827,7 @@ public:
|
|||
signals:
|
||||
|
||||
void chosen(QString mentionOrHashtag);
|
||||
void stickerSelected(DocumentData *sticker);
|
||||
|
||||
public slots:
|
||||
|
||||
|
@ -686,12 +838,15 @@ public slots:
|
|||
|
||||
private:
|
||||
|
||||
void recount(bool toDown = false);
|
||||
void recount(bool resetScroll = false);
|
||||
|
||||
QPixmap _cache;
|
||||
MentionRows _rows;
|
||||
MentionRows _mrows;
|
||||
HashtagRows _hrows;
|
||||
BotCommandRows _crows;
|
||||
BotCommandRows _brows;
|
||||
StickerPack _srows;
|
||||
|
||||
void rowsUpdated(const MentionRows &mrows, const HashtagRows &hrows, const BotCommandRows &brows, const StickerPack &srows, bool resetScroll);
|
||||
|
||||
ScrollArea _scroll;
|
||||
MentionsInner _inner;
|
||||
|
@ -699,13 +854,16 @@ private:
|
|||
ChatData *_chat;
|
||||
UserData *_user;
|
||||
ChannelData *_channel;
|
||||
EmojiPtr _emoji;
|
||||
QString _filter;
|
||||
QRect _boundings;
|
||||
bool _addInlineBots;
|
||||
|
||||
int32 _width, _height;
|
||||
bool _hiding;
|
||||
|
||||
anim::fvalue a_opacity;
|
||||
Animation _a_appearance;
|
||||
|
||||
QTimer _hideTimer;
|
||||
|
||||
|
|
|
@ -23,14 +23,17 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
#include "window.h"
|
||||
#include "mainwidget.h"
|
||||
|
||||
#include "layerwidget.h"
|
||||
|
||||
namespace App {
|
||||
|
||||
void sendBotCommand(const QString &cmd, MsgId replyTo) {
|
||||
if (MainWidget *m = main()) m->sendBotCommand(cmd, replyTo);
|
||||
}
|
||||
|
||||
void insertBotCommand(const QString &cmd) {
|
||||
if (MainWidget *m = main()) m->insertBotCommand(cmd);
|
||||
bool insertBotCommand(const QString &cmd, bool specialGif) {
|
||||
if (MainWidget *m = main()) return m->insertBotCommand(cmd, specialGif);
|
||||
return false;
|
||||
}
|
||||
|
||||
void searchByHashtag(const QString &tag, PeerData *inPeer) {
|
||||
|
@ -66,18 +69,6 @@ namespace App {
|
|||
if (Window *win = wnd()) win->showSettings();
|
||||
}
|
||||
|
||||
void showLayer(LayeredWidget *widget, bool forceFast) {
|
||||
if (Window *w = wnd()) w->showLayer(widget, forceFast);
|
||||
}
|
||||
|
||||
void replaceLayer(LayeredWidget *widget) {
|
||||
if (Window *w = wnd()) w->replaceLayer(widget);
|
||||
}
|
||||
|
||||
void showLayerLast(LayeredWidget *widget) {
|
||||
if (Window *w = wnd()) w->showLayerLast(widget);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Ui {
|
||||
|
@ -90,20 +81,133 @@ namespace Ui {
|
|||
if (MainWidget *m = App::main()) m->ui_hideStickerPreview();
|
||||
}
|
||||
|
||||
void showLayer(LayeredWidget *box, ShowLayerOptions options) {
|
||||
if (Window *w = App::wnd()) {
|
||||
w->ui_showLayer(box, options);
|
||||
} else {
|
||||
delete box;
|
||||
}
|
||||
}
|
||||
|
||||
void hideLayer(bool fast) {
|
||||
if (Window *w = App::wnd()) w->ui_showLayer(0, ShowLayerOptions(CloseOtherLayers) | (fast ? ForceFastShowLayer : AnimatedShowLayer));
|
||||
}
|
||||
|
||||
bool isLayerShown() {
|
||||
if (Window *w = App::wnd()) return w->ui_isLayerShown();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isMediaViewShown() {
|
||||
if (Window *w = App::wnd()) return w->ui_isMediaViewShown();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isInlineItemBeingChosen() {
|
||||
if (MainWidget *m = App::main()) return m->ui_isInlineItemBeingChosen();
|
||||
return false;
|
||||
}
|
||||
|
||||
void repaintHistoryItem(const HistoryItem *item) {
|
||||
if (!item) return;
|
||||
if (MainWidget *m = App::main()) m->ui_repaintHistoryItem(item);
|
||||
}
|
||||
|
||||
void repaintInlineItem(const LayoutInlineItem *layout) {
|
||||
if (!layout) return;
|
||||
if (MainWidget *m = App::main()) m->ui_repaintInlineItem(layout);
|
||||
}
|
||||
|
||||
bool isInlineItemVisible(const LayoutInlineItem *layout) {
|
||||
if (MainWidget *m = App::main()) return m->ui_isInlineItemVisible(layout);
|
||||
return false;
|
||||
}
|
||||
|
||||
void showPeerHistory(const PeerId &peer, MsgId msgId, bool back) {
|
||||
if (MainWidget *m = App::main()) m->ui_showPeerHistory(peer, msgId, back);
|
||||
}
|
||||
|
||||
void showPeerHistoryAsync(const PeerId &peer, MsgId msgId) {
|
||||
if (MainWidget *m = App::main()) {
|
||||
QMetaObject::invokeMethod(m, "ui_showPeerHistoryAsync", Qt::QueuedConnection, Q_ARG(quint64, peer), Q_ARG(qint32, msgId));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Notify {
|
||||
|
||||
void userIsBotChanged(UserData *user) {
|
||||
if (MainWidget *m = App::main()) m->notifyUserIsBotChanged(user);
|
||||
if (MainWidget *m = App::main()) m->notify_userIsBotChanged(user);
|
||||
}
|
||||
|
||||
void userIsContactChanged(UserData *user, bool fromThisApp) {
|
||||
if (MainWidget *m = App::main()) m->notify_userIsContactChanged(user, fromThisApp);
|
||||
}
|
||||
|
||||
void botCommandsChanged(UserData *user) {
|
||||
if (MainWidget *m = App::main()) m->notifyBotCommandsChanged(user);
|
||||
if (MainWidget *m = App::main()) m->notify_botCommandsChanged(user);
|
||||
}
|
||||
|
||||
void inlineBotRequesting(bool requesting) {
|
||||
if (MainWidget *m = App::main()) m->notify_inlineBotRequesting(requesting);
|
||||
}
|
||||
|
||||
void migrateUpdated(PeerData *peer) {
|
||||
if (MainWidget *m = App::main()) m->notifyMigrateUpdated(peer);
|
||||
if (MainWidget *m = App::main()) m->notify_migrateUpdated(peer);
|
||||
}
|
||||
|
||||
void clipStopperHidden(ClipStopperType type) {
|
||||
if (MainWidget *m = App::main()) m->notify_clipStopperHidden(type);
|
||||
}
|
||||
|
||||
void historyItemResized(const HistoryItem *item, bool scrollToIt) {
|
||||
if (MainWidget *m = App::main()) m->notify_historyItemResized(item, scrollToIt);
|
||||
}
|
||||
|
||||
void historyItemLayoutChanged(const HistoryItem *item) {
|
||||
if (MainWidget *m = App::main()) m->notify_historyItemLayoutChanged(item);
|
||||
}
|
||||
|
||||
void automaticLoadSettingsChangedGif() {
|
||||
if (MainWidget *m = App::main()) m->notify_automaticLoadSettingsChangedGif();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Global {
|
||||
|
||||
struct Data {
|
||||
uint64 LaunchId = 0;
|
||||
};
|
||||
|
||||
Data *_data = 0;
|
||||
|
||||
Initializer::Initializer() {
|
||||
initThirdParty();
|
||||
_data = new Data();
|
||||
|
||||
memset_rand(&_data->LaunchId, sizeof(_data->LaunchId));
|
||||
}
|
||||
|
||||
Initializer::~Initializer() {
|
||||
deinitThirdParty();
|
||||
}
|
||||
|
||||
#define DefineGlobalReadOnly(Type, Name) const Type &Name() { \
|
||||
t_assert_full(_data != 0, "_data is null in Global::" #Name, __FILE__, __LINE__); \
|
||||
return _data->Name; \
|
||||
}
|
||||
#define DefineGlobal(Type, Name) DefineGlobalReadOnly(Type, Name) \
|
||||
void Set##Name(const Type &Name) { \
|
||||
t_assert_full(_data != 0, "_data is null in Global::Set" #Name, __FILE__, __LINE__); \
|
||||
_data->Name = Name; \
|
||||
} \
|
||||
Type &Ref##Name() { \
|
||||
t_assert_full(_data != 0, "_data is null in Global::Ref" #Name, __FILE__, __LINE__); \
|
||||
return _data->Name; \
|
||||
}
|
||||
|
||||
DefineGlobalReadOnly(uint64, LaunchId);
|
||||
|
||||
};
|
||||
|
|
|
@ -25,7 +25,7 @@ class LayeredWidget;
|
|||
namespace App {
|
||||
|
||||
void sendBotCommand(const QString &cmd, MsgId replyTo = 0);
|
||||
void insertBotCommand(const QString &cmd);
|
||||
bool insertBotCommand(const QString &cmd, bool specialGif = false);
|
||||
void searchByHashtag(const QString &tag, PeerData *inPeer);
|
||||
void openPeerByName(const QString &username, bool toProfile = false, const QString &startToken = QString());
|
||||
void joinGroupByHash(const QString &hash);
|
||||
|
@ -34,23 +34,81 @@ namespace App {
|
|||
bool forward(const PeerId &peer, ForwardWhatMessages what);
|
||||
void removeDialog(History *history);
|
||||
void showSettings();
|
||||
void showLayer(LayeredWidget *w, bool forceFast = false);
|
||||
void replaceLayer(LayeredWidget *w);
|
||||
void showLayerLast(LayeredWidget *w);
|
||||
|
||||
};
|
||||
|
||||
namespace Ui { // it doesn't allow me to use UI :(
|
||||
namespace Ui { // openssl doesn't allow me to use UI :(
|
||||
|
||||
void showStickerPreview(DocumentData *sticker);
|
||||
void hideStickerPreview();
|
||||
|
||||
void showLayer(LayeredWidget *box, ShowLayerOptions options = CloseOtherLayers);
|
||||
void hideLayer(bool fast = false);
|
||||
bool isLayerShown();
|
||||
bool isMediaViewShown();
|
||||
bool isInlineItemBeingChosen();
|
||||
|
||||
void repaintHistoryItem(const HistoryItem *item);
|
||||
void repaintInlineItem(const LayoutInlineItem *layout);
|
||||
bool isInlineItemVisible(const LayoutInlineItem *reader);
|
||||
|
||||
void showPeerHistory(const PeerId &peer, MsgId msgId, bool back = false);
|
||||
inline void showPeerHistory(const PeerData *peer, MsgId msgId, bool back = false) {
|
||||
showPeerHistory(peer->id, msgId, back);
|
||||
}
|
||||
inline void showPeerHistory(const History *history, MsgId msgId, bool back = false) {
|
||||
showPeerHistory(history->peer->id, msgId, back);
|
||||
}
|
||||
inline void showPeerHistoryAtItem(const HistoryItem *item) {
|
||||
showPeerHistory(item->history()->peer->id, item->id);
|
||||
}
|
||||
void showPeerHistoryAsync(const PeerId &peer, MsgId msgId);
|
||||
inline void showChatsList() {
|
||||
showPeerHistory(PeerId(0), 0);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
enum ClipStopperType {
|
||||
ClipStopperMediaview,
|
||||
ClipStopperSavedGifsPanel,
|
||||
};
|
||||
|
||||
namespace Notify {
|
||||
|
||||
void userIsBotChanged(UserData *user);
|
||||
void userIsContactChanged(UserData *user, bool fromThisApp = false);
|
||||
void botCommandsChanged(UserData *user);
|
||||
|
||||
void inlineBotRequesting(bool requesting);
|
||||
|
||||
void migrateUpdated(PeerData *peer);
|
||||
|
||||
void clipStopperHidden(ClipStopperType type);
|
||||
|
||||
void historyItemResized(const HistoryItem *item, bool scrollToIt = false);
|
||||
inline void historyItemsResized() {
|
||||
historyItemResized(0);
|
||||
}
|
||||
void historyItemLayoutChanged(const HistoryItem *item);
|
||||
|
||||
void automaticLoadSettingsChangedGif();
|
||||
|
||||
};
|
||||
|
||||
namespace Global {
|
||||
|
||||
class Initializer {
|
||||
public:
|
||||
Initializer();
|
||||
~Initializer();
|
||||
};
|
||||
|
||||
#define DeclareGlobalReadOnly(Type, Name) const Type &Name();
|
||||
#define DeclareGlobal(Type, Name) DeclareGlobalReadOnly(Type, Name) \
|
||||
void Set##Name(const Type &Name); \
|
||||
Type &Ref##Name();
|
||||
|
||||
DeclareGlobalReadOnly(uint64, LaunchId);
|
||||
|
||||
};
|
||||
|
|
|
@ -46,7 +46,7 @@ void FileUploader::uploadMedia(const FullMsgId &msgId, const ReadyLocalMedia &me
|
|||
} else if (media.type == PrepareAudio) {
|
||||
AudioData *audio = App::feedAudio(media.audio);
|
||||
audio->status = FileUploading;
|
||||
audio->data = media.data;
|
||||
audio->setData(media.data);
|
||||
}
|
||||
queue.insert(msgId, File(media));
|
||||
sendNext();
|
||||
|
@ -54,7 +54,8 @@ void FileUploader::uploadMedia(const FullMsgId &msgId, const ReadyLocalMedia &me
|
|||
|
||||
void FileUploader::upload(const FullMsgId &msgId, const FileLoadResultPtr &file) {
|
||||
if (file->type == PreparePhoto) {
|
||||
App::feedPhoto(file->photo, file->photoThumbs);
|
||||
PhotoData *photo = App::feedPhoto(file->photo, file->photoThumbs);
|
||||
photo->uploadingData = new PhotoData::UploadingData(file->partssize);
|
||||
} else if (file->type == PrepareDocument) {
|
||||
DocumentData *document;
|
||||
if (file->thumb.isNull()) {
|
||||
|
@ -69,7 +70,7 @@ void FileUploader::upload(const FullMsgId &msgId, const FileLoadResultPtr &file)
|
|||
} else if (file->type == PrepareAudio) {
|
||||
AudioData *audio = App::feedAudio(file->audio);
|
||||
audio->status = FileUploading;
|
||||
audio->data = file->content;
|
||||
audio->setData(file->content);
|
||||
}
|
||||
queue.insert(msgId, File(file));
|
||||
sendNext();
|
||||
|
@ -83,13 +84,13 @@ void FileUploader::currentFailed() {
|
|||
} else if (j->type() == PrepareDocument) {
|
||||
DocumentData *doc = App::document(j->id());
|
||||
if (doc->status == FileUploading) {
|
||||
doc->status = FileFailed;
|
||||
doc->status = FileUploadFailed;
|
||||
}
|
||||
emit documentFailed(j.key());
|
||||
} else if (j->type() == PrepareAudio) {
|
||||
AudioData *audio = App::audio(j->id());
|
||||
if (audio->status == FileUploading) {
|
||||
audio->status = FileFailed;
|
||||
audio->status = FileUploadFailed;
|
||||
}
|
||||
emit audioFailed(j.key());
|
||||
}
|
||||
|
@ -115,7 +116,7 @@ void FileUploader::killSessions() {
|
|||
}
|
||||
|
||||
void FileUploader::sendNext() {
|
||||
if (sentSize >= MaxUploadFileParallelSize) return;
|
||||
if (sentSize >= MaxUploadFileParallelSize || _paused.msg) return;
|
||||
|
||||
bool killing = killSessionsTimer.isActive();
|
||||
if (queue.isEmpty()) {
|
||||
|
@ -232,6 +233,15 @@ void FileUploader::cancel(const FullMsgId &msgId) {
|
|||
}
|
||||
}
|
||||
|
||||
void FileUploader::pause(const FullMsgId &msgId) {
|
||||
_paused = msgId;
|
||||
}
|
||||
|
||||
void FileUploader::unpause() {
|
||||
_paused = FullMsgId();
|
||||
sendNext();
|
||||
}
|
||||
|
||||
void FileUploader::confirm(const FullMsgId &msgId) {
|
||||
}
|
||||
|
||||
|
@ -274,21 +284,28 @@ void FileUploader::partLoaded(const MTPBool &result, mtpRequestId requestId) {
|
|||
int32 dc = dcIt.value();
|
||||
dcMap.erase(dcIt);
|
||||
|
||||
int32 sentPartSize = 0;
|
||||
Queue::const_iterator k = queue.constFind(uploading);
|
||||
if (i != requestsSent.cend()) {
|
||||
sentSize -= i.value().size();
|
||||
sentSizes[dc] -= i.value().size();
|
||||
sentPartSize = i.value().size();
|
||||
requestsSent.erase(i);
|
||||
} else {
|
||||
sentSize -= k->docPartSize;
|
||||
sentSizes[dc] -= k->docPartSize;
|
||||
sentPartSize = k->docPartSize;
|
||||
docRequestsSent.erase(j);
|
||||
}
|
||||
sentSize -= sentPartSize;
|
||||
sentSizes[dc] -= sentPartSize;
|
||||
if (k->type() == PreparePhoto) {
|
||||
k->fileSentSize += sentPartSize;
|
||||
PhotoData *photo = App::photo(k->id());
|
||||
if (photo->uploading() && k->file) {
|
||||
photo->uploadingData->size = k->file->partssize;
|
||||
photo->uploadingData->offset = k->fileSentSize;
|
||||
}
|
||||
emit photoProgress(k.key());
|
||||
} else if (k->type() == PrepareDocument) {
|
||||
DocumentData *doc = App::document(k->id());
|
||||
if (doc->status == FileUploading) {
|
||||
if (doc->uploading()) {
|
||||
doc->uploadOffset = (k->docSentParts - docRequestsSent.size()) * k->docPartSize;
|
||||
if (doc->uploadOffset > doc->size) {
|
||||
doc->uploadOffset = doc->size;
|
||||
|
@ -297,7 +314,7 @@ void FileUploader::partLoaded(const MTPBool &result, mtpRequestId requestId) {
|
|||
emit documentProgress(k.key());
|
||||
} else if (k->type() == PrepareAudio) {
|
||||
AudioData *audio = App::audio(k->id());
|
||||
if (audio->status == FileUploading) {
|
||||
if (audio->uploading()) {
|
||||
audio->uploadOffset = (k->docSentParts - docRequestsSent.size()) * k->docPartSize;
|
||||
if (audio->uploadOffset > audio->size) {
|
||||
audio->uploadOffset = audio->size;
|
||||
|
|
|
@ -35,12 +35,14 @@ public:
|
|||
int32 fullSize(const FullMsgId &msgId) const;
|
||||
|
||||
void cancel(const FullMsgId &msgId);
|
||||
void pause(const FullMsgId &msgId);
|
||||
void confirm(const FullMsgId &msgId);
|
||||
|
||||
void clear();
|
||||
|
||||
public slots:
|
||||
|
||||
void unpause();
|
||||
void sendNext();
|
||||
void killSessions();
|
||||
|
||||
|
@ -101,6 +103,7 @@ private:
|
|||
FileLoadResultPtr file;
|
||||
ReadyLocalMedia media;
|
||||
int32 partsCount;
|
||||
mutable int32 fileSentSize;
|
||||
|
||||
uint64 id() const {
|
||||
return file ? file->id : media.id;
|
||||
|
@ -136,7 +139,7 @@ private:
|
|||
uint32 sentSize;
|
||||
uint32 sentSizes[MTPUploadSessionsCount];
|
||||
|
||||
FullMsgId uploading;
|
||||
FullMsgId uploading, _paused;
|
||||
Queue queue;
|
||||
Queue uploaded;
|
||||
QTimer nextTimer, killSessionsTimer;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -24,12 +24,10 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
#include <QtCore/QTimer>
|
||||
#include <QtGui/QColor>
|
||||
|
||||
class Animated;
|
||||
|
||||
namespace anim {
|
||||
|
||||
typedef float64 (*transition)(const float64 &delta, const float64 &dt);
|
||||
|
||||
|
||||
float64 linear(const float64 &delta, const float64 &dt);
|
||||
float64 sineInOut(const float64 &delta, const float64 &dt);
|
||||
float64 halfSine(const float64 &delta, const float64 &dt);
|
||||
|
@ -74,6 +72,8 @@ namespace anim {
|
|||
_delta = 0;
|
||||
}
|
||||
|
||||
typedef float64 Type;
|
||||
|
||||
private:
|
||||
|
||||
float64 _cur, _from, _delta;
|
||||
|
@ -112,6 +112,8 @@ namespace anim {
|
|||
_delta = 0;
|
||||
}
|
||||
|
||||
typedef int32 Type;
|
||||
|
||||
private:
|
||||
|
||||
int32 _cur;
|
||||
|
@ -181,253 +183,486 @@ namespace anim {
|
|||
_delta_r = _delta_g = _delta_b = _delta_a = 0;
|
||||
}
|
||||
|
||||
typedef QColor Type;
|
||||
|
||||
private:
|
||||
|
||||
QColor _cur;
|
||||
float64 _from_r, _from_g, _from_b, _from_a, _delta_r, _delta_g, _delta_b, _delta_a;
|
||||
};
|
||||
|
||||
void start(Animated *obj);
|
||||
void step(Animated *obj);
|
||||
void stop(Animated *obj);
|
||||
|
||||
void startManager();
|
||||
void stopManager();
|
||||
|
||||
};
|
||||
|
||||
class Animated {
|
||||
class Animation;
|
||||
|
||||
class AnimationImplementation {
|
||||
public:
|
||||
virtual void start() {}
|
||||
virtual void step(Animation *a, uint64 ms, bool timer) = 0;
|
||||
virtual ~AnimationImplementation() {}
|
||||
};
|
||||
class AnimationCreator {
|
||||
public:
|
||||
AnimationCreator(AnimationImplementation *ptr) : _ptr(ptr) {}
|
||||
AnimationCreator(const AnimationCreator &other) : _ptr(other.create()) {}
|
||||
AnimationImplementation *create() const { return exchange(_ptr); }
|
||||
~AnimationCreator() { deleteAndMark(_ptr); }
|
||||
private:
|
||||
AnimationCreator &operator=(const AnimationCreator &other);
|
||||
mutable AnimationImplementation *_ptr;
|
||||
};
|
||||
class AnimationCallbacks {
|
||||
public:
|
||||
AnimationCallbacks(const AnimationCreator &creator) : _implementation(creator.create()) {}
|
||||
void start() { _implementation->start(); }
|
||||
void step(Animation *a, uint64 ms, bool timer) { _implementation->step(a, ms, timer); }
|
||||
~AnimationCallbacks() { deleteAndMark(_implementation); }
|
||||
private:
|
||||
AnimationCallbacks(const AnimationCallbacks &other);
|
||||
AnimationCallbacks &operator=(const AnimationCallbacks &other);
|
||||
AnimationImplementation *_implementation;
|
||||
};
|
||||
|
||||
Animated() : animStarted(0), animInProcess(false) {
|
||||
class Animation {
|
||||
public:
|
||||
Animation(AnimationCreator cb) : _cb(cb), _animating(false) {
|
||||
}
|
||||
|
||||
virtual bool animStep(float64 ms) = 0;
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
void animReset() {
|
||||
animStarted = float64(getms());
|
||||
void step(uint64 ms, bool timer = false) {
|
||||
_cb.step(this, ms, timer);
|
||||
}
|
||||
|
||||
virtual ~Animated() {
|
||||
if (animating()) {
|
||||
anim::stop(this);
|
||||
}
|
||||
void step() {
|
||||
step(getms(), false);
|
||||
}
|
||||
|
||||
bool animating() const {
|
||||
return animInProcess;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
float64 animStarted;
|
||||
bool animInProcess;
|
||||
friend class AnimationManager;
|
||||
|
||||
};
|
||||
|
||||
class AnimationFunc {
|
||||
public:
|
||||
virtual bool animStep(float64 ms) = 0;
|
||||
virtual ~AnimationFunc() {
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
class AnimationFuncOwned : public AnimationFunc {
|
||||
public:
|
||||
typedef bool (Type::*Method)(float64);
|
||||
|
||||
AnimationFuncOwned(Type *obj, Method method) : _obj(obj), _method(method) {
|
||||
}
|
||||
|
||||
bool animStep(float64 ms) {
|
||||
return (_obj->*_method)(ms);
|
||||
}
|
||||
|
||||
private:
|
||||
Type *_obj;
|
||||
Method _method;
|
||||
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
AnimationFunc *animFunc(Type *obj, typename AnimationFuncOwned<Type>::Method method) {
|
||||
return new AnimationFuncOwned<Type>(obj, method);
|
||||
}
|
||||
|
||||
class Animation : public Animated {
|
||||
public:
|
||||
|
||||
Animation(AnimationFunc *func) : _func(func) {
|
||||
}
|
||||
|
||||
void start() {
|
||||
anim::start(this);
|
||||
}
|
||||
void stop() {
|
||||
anim::stop(this);
|
||||
}
|
||||
|
||||
//Animation
|
||||
bool animStep(float64 ms) {
|
||||
return _func->animStep(ms);
|
||||
return _animating;
|
||||
}
|
||||
|
||||
~Animation() {
|
||||
delete _func;
|
||||
if (_animating) stop();
|
||||
}
|
||||
|
||||
private:
|
||||
AnimationFunc *_func;
|
||||
AnimationCallbacks _cb;
|
||||
bool _animating;
|
||||
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
class AnimationCallbacksRelative : public AnimationImplementation {
|
||||
public:
|
||||
typedef void (Type::*Method)(float64, bool);
|
||||
|
||||
AnimationCallbacksRelative(Type *obj, Method method) : _started(0), _obj(obj), _method(method) {
|
||||
}
|
||||
|
||||
void start() {
|
||||
_started = float64(getms());
|
||||
}
|
||||
|
||||
void step(Animation *a, uint64 ms, bool timer) {
|
||||
(_obj->*_method)(ms - _started, timer);
|
||||
}
|
||||
|
||||
private:
|
||||
float64 _started;
|
||||
Type *_obj;
|
||||
Method _method;
|
||||
|
||||
};
|
||||
template <typename Type>
|
||||
AnimationCreator animation(Type *obj, typename AnimationCallbacksRelative<Type>::Method method) {
|
||||
return AnimationCreator(new AnimationCallbacksRelative<Type>(obj, method));
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
class AnimationCallbacksAbsolute : public AnimationImplementation {
|
||||
public:
|
||||
typedef void (Type::*Method)(uint64, bool);
|
||||
|
||||
AnimationCallbacksAbsolute(Type *obj, Method method) : _obj(obj), _method(method) {
|
||||
}
|
||||
|
||||
void step(Animation *a, uint64 ms, bool timer) {
|
||||
(_obj->*_method)(ms, timer);
|
||||
}
|
||||
|
||||
private:
|
||||
Type *_obj;
|
||||
Method _method;
|
||||
|
||||
};
|
||||
template <typename Type>
|
||||
AnimationCreator animation(Type *obj, typename AnimationCallbacksAbsolute<Type>::Method method) {
|
||||
return AnimationCreator(new AnimationCallbacksAbsolute<Type>(obj, method));
|
||||
}
|
||||
|
||||
template <typename Type, typename Param>
|
||||
class AnimationCallbacksRelativeWithParam : public AnimationImplementation {
|
||||
public:
|
||||
typedef void (Type::*Method)(Param, float64, bool);
|
||||
|
||||
AnimationCallbacksRelativeWithParam(Param param, Type *obj, Method method) : _started(0), _param(param), _obj(obj), _method(method) {
|
||||
}
|
||||
|
||||
void start() {
|
||||
_started = float64(getms());
|
||||
}
|
||||
|
||||
void step(Animation *a, uint64 ms, bool timer) {
|
||||
(_obj->*_method)(_param, ms - _started, timer);
|
||||
}
|
||||
|
||||
private:
|
||||
float64 _started;
|
||||
Param _param;
|
||||
Type *_obj;
|
||||
Method _method;
|
||||
|
||||
};
|
||||
template <typename Type, typename Param>
|
||||
AnimationCreator animation(Param param, Type *obj, typename AnimationCallbacksRelativeWithParam<Type, Param>::Method method) {
|
||||
return AnimationCreator(new AnimationCallbacksRelativeWithParam<Type, Param>(param, obj, method));
|
||||
}
|
||||
|
||||
template <typename Type, typename Param>
|
||||
class AnimationCallbacksAbsoluteWithParam : public AnimationImplementation {
|
||||
public:
|
||||
typedef void (Type::*Method)(Param, uint64, bool);
|
||||
|
||||
AnimationCallbacksAbsoluteWithParam(Param param, Type *obj, Method method) : _param(param), _obj(obj), _method(method) {
|
||||
}
|
||||
|
||||
void step(Animation *a, uint64 ms, bool timer) {
|
||||
(_obj->*_method)(_param, ms, timer);
|
||||
}
|
||||
|
||||
private:
|
||||
Param _param;
|
||||
Type *_obj;
|
||||
Method _method;
|
||||
|
||||
};
|
||||
template <typename Type, typename Param>
|
||||
AnimationCreator animation(Param param, Type *obj, typename AnimationCallbacksAbsoluteWithParam<Type, Param>::Method method) {
|
||||
return AnimationCreator(new AnimationCallbacksAbsoluteWithParam<Type, Param>(param, obj, method));
|
||||
}
|
||||
|
||||
template <typename AnimType>
|
||||
class SimpleAnimation {
|
||||
public:
|
||||
|
||||
typedef Function<void> Callback;
|
||||
|
||||
SimpleAnimation() : _data(0) {
|
||||
}
|
||||
|
||||
bool animating(uint64 ms) {
|
||||
if (_data && _data->_a.animating()) {
|
||||
_data->_a.step(ms);
|
||||
return _data && _data->_a.animating();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isNull() {
|
||||
return !_data;
|
||||
}
|
||||
|
||||
typename AnimType::Type current() {
|
||||
return _data ? _data->a.current() : typename AnimType::Type();
|
||||
}
|
||||
|
||||
typename AnimType::Type current(uint64 ms, const typename AnimType::Type &def) {
|
||||
return animating(ms) ? current() : def;
|
||||
}
|
||||
|
||||
void setup(const typename AnimType::Type &from, Callback::Creator update) {
|
||||
if (!_data) {
|
||||
_data = new Data(from, update, animation(this, &SimpleAnimation<AnimType>::step));
|
||||
} else {
|
||||
_data->a = AnimType(from, from);
|
||||
}
|
||||
}
|
||||
|
||||
void start(const typename AnimType::Type &to, float64 duration, anim::transition transition = anim::linear) {
|
||||
if (_data) {
|
||||
_data->a.start(to);
|
||||
_data->_a.start();
|
||||
_data->duration = duration;
|
||||
_data->transition = transition;
|
||||
}
|
||||
}
|
||||
|
||||
~SimpleAnimation() {
|
||||
deleteAndMark(_data);
|
||||
}
|
||||
|
||||
private:
|
||||
typedef struct _Data {
|
||||
_Data(const typename AnimType::Type &from, Callback::Creator update, AnimationCreator acb)
|
||||
: a(from, from)
|
||||
, _a(acb)
|
||||
, update(update)
|
||||
, duration(0)
|
||||
, transition(anim::linear) {
|
||||
}
|
||||
AnimType a;
|
||||
Animation _a;
|
||||
Callback update;
|
||||
float64 duration;
|
||||
anim::transition transition;
|
||||
} Data;
|
||||
Data *_data;
|
||||
|
||||
void step(float64 ms, bool timer) {
|
||||
float64 dt = (ms >= _data->duration) ? 1 : (ms / _data->duration);
|
||||
if (dt >= 1) {
|
||||
_data->a.finish();
|
||||
_data->_a.stop();
|
||||
} else {
|
||||
_data->a.update(dt, _data->transition);
|
||||
}
|
||||
if (timer) {
|
||||
_data->update.call();
|
||||
}
|
||||
if (!_data->_a.animating()) {
|
||||
delete _data;
|
||||
_data = 0;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
typedef SimpleAnimation<anim::fvalue> FloatAnimation;
|
||||
typedef SimpleAnimation<anim::ivalue> IntAnimation;
|
||||
typedef SimpleAnimation<anim::cvalue> ColorAnimation;
|
||||
|
||||
#define EnsureAnimation(animation, from, callback) if ((animation).isNull()) { (animation).setup((from), (callback)); }
|
||||
|
||||
class ClipReader;
|
||||
|
||||
class AnimationManager : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AnimationManager();
|
||||
|
||||
AnimationManager() : timer(this), iterating(false) {
|
||||
timer.setSingleShot(false);
|
||||
connect(&timer, SIGNAL(timeout()), this, SLOT(timeout()));
|
||||
}
|
||||
|
||||
void start(Animated *obj) {
|
||||
obj->animReset();
|
||||
if (iterating) {
|
||||
toStart.insert(obj);
|
||||
if (!toStop.isEmpty()) {
|
||||
toStop.remove(obj);
|
||||
}
|
||||
} else {
|
||||
if (!objs.size()) {
|
||||
timer.start(AnimationTimerDelta);
|
||||
}
|
||||
objs.insert(obj);
|
||||
}
|
||||
obj->animInProcess = true;
|
||||
}
|
||||
|
||||
void step(Animated *obj) {
|
||||
if (iterating) return;
|
||||
|
||||
float64 ms = float64(getms());
|
||||
AnimObjs::iterator i = objs.find(obj);
|
||||
if (i != objs.cend()) {
|
||||
Animated *obj = *i;
|
||||
if (!obj->animStep(ms - obj->animStarted)) {
|
||||
objs.erase(i);
|
||||
if (!objs.size()) {
|
||||
timer.stop();
|
||||
}
|
||||
obj->animInProcess = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void stop(Animated *obj) {
|
||||
if (iterating) {
|
||||
toStop.insert(obj);
|
||||
if (!toStart.isEmpty()) {
|
||||
toStart.insert(obj);
|
||||
}
|
||||
} else {
|
||||
AnimObjs::iterator i = objs.find(obj);
|
||||
if (i != objs.cend()) {
|
||||
objs.erase(i);
|
||||
if (!objs.size()) {
|
||||
timer.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
obj->animInProcess = false;
|
||||
}
|
||||
void start(Animation *obj);
|
||||
void stop(Animation *obj);
|
||||
|
||||
public slots:
|
||||
void timeout() {
|
||||
iterating = true;
|
||||
float64 ms = float64(getms());
|
||||
for (AnimObjs::iterator i = objs.begin(), e = objs.end(); i != e; ) {
|
||||
Animated *obj = *i;
|
||||
if (!obj->animStep(ms - obj->animStarted)) {
|
||||
i = objs.erase(i);
|
||||
obj->animInProcess = false;
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
iterating = false;
|
||||
if (!toStart.isEmpty()) {
|
||||
for (AnimObjs::iterator i = toStart.begin(), e = toStart.end(); i != e; ++i) {
|
||||
objs.insert(*i);
|
||||
}
|
||||
toStart.clear();
|
||||
}
|
||||
if (!toStop.isEmpty()) {
|
||||
for (AnimObjs::iterator i = toStop.begin(), e = toStop.end(); i != e; ++i) {
|
||||
objs.remove(*i);
|
||||
}
|
||||
toStop.clear();
|
||||
}
|
||||
if (!objs.size()) {
|
||||
timer.stop();
|
||||
}
|
||||
}
|
||||
void timeout();
|
||||
|
||||
void clipCallback(ClipReader *reader, qint32 threadIndex, qint32 notification);
|
||||
|
||||
private:
|
||||
|
||||
typedef QSet<Animated*> AnimObjs;
|
||||
AnimObjs objs;
|
||||
AnimObjs toStart;
|
||||
AnimObjs toStop;
|
||||
QTimer timer;
|
||||
bool iterating;
|
||||
typedef QMap<Animation*, NullType> AnimatingObjects;
|
||||
AnimatingObjects _objects, _starting, _stopping;
|
||||
QTimer _timer;
|
||||
bool _iterating;
|
||||
|
||||
};
|
||||
|
||||
class HistoryItem;
|
||||
class FileLocation;
|
||||
class AnimatedGif : public QObject, public Animated {
|
||||
|
||||
enum ClipState {
|
||||
ClipReading,
|
||||
ClipError,
|
||||
};
|
||||
|
||||
struct ClipFrameRequest {
|
||||
ClipFrameRequest() : factor(0), framew(0), frameh(0), outerw(0), outerh(0), rounded(false) {
|
||||
}
|
||||
bool valid() const {
|
||||
return factor > 0;
|
||||
}
|
||||
int32 factor;
|
||||
int32 framew, frameh;
|
||||
int32 outerw, outerh;
|
||||
bool rounded;
|
||||
};
|
||||
|
||||
enum ClipReaderNotification {
|
||||
ClipReaderReinit,
|
||||
ClipReaderRepaint,
|
||||
};
|
||||
|
||||
enum ClipReaderSteps {
|
||||
WaitingForDimensionsStep = -3, // before ClipReaderPrivate read the first image and got the original frame size
|
||||
WaitingForRequestStep = -2, // before ClipReader got the original frame size and prepared the frame request
|
||||
WaitingForFirstFrameStep = -1, // before ClipReaderPrivate got the frame request and started waiting for the 1-2 delay
|
||||
};
|
||||
|
||||
class ClipReaderPrivate;
|
||||
class ClipReader {
|
||||
public:
|
||||
|
||||
typedef Function1<void, ClipReaderNotification> Callback;
|
||||
|
||||
ClipReader(const FileLocation &location, const QByteArray &data, Callback::Creator cb);
|
||||
static void callback(ClipReader *reader, int32 threadIndex, ClipReaderNotification notification); // reader can be deleted
|
||||
|
||||
void setAutoplay() {
|
||||
_autoplay = true;
|
||||
}
|
||||
bool autoplay() const {
|
||||
return _autoplay;
|
||||
}
|
||||
|
||||
void start(int32 framew, int32 frameh, int32 outerw, int32 outerh, bool rounded);
|
||||
QPixmap current(int32 framew, int32 frameh, int32 outerw, int32 outerh, uint64 ms);
|
||||
QPixmap frameOriginal() const {
|
||||
Frame *frame = frameToShow();
|
||||
if (!frame) return QPixmap();
|
||||
QPixmap result(frame ? QPixmap::fromImage(frame->original) : QPixmap());
|
||||
result.detach();
|
||||
return result;
|
||||
}
|
||||
bool currentDisplayed() const {
|
||||
Frame *frame = frameToShow();
|
||||
return frame ? (frame->displayed.loadAcquire() != 0) : true;
|
||||
}
|
||||
bool paused() const {
|
||||
return _paused.loadAcquire();
|
||||
}
|
||||
int32 threadIndex() const {
|
||||
return _threadIndex;
|
||||
}
|
||||
|
||||
int32 width() const;
|
||||
int32 height() const;
|
||||
|
||||
ClipState state() const;
|
||||
bool started() const {
|
||||
int32 step = _step.loadAcquire();
|
||||
return (step == WaitingForFirstFrameStep) || (step >= 0);
|
||||
}
|
||||
bool ready() const;
|
||||
|
||||
void stop();
|
||||
void error();
|
||||
|
||||
~ClipReader();
|
||||
|
||||
private:
|
||||
|
||||
Callback _cb;
|
||||
|
||||
ClipState _state;
|
||||
|
||||
mutable int32 _width, _height;
|
||||
|
||||
mutable QAtomicInt _step; // -2, -1 - init, 0-5 - work, show ((state + 1) / 2) % 3 state, write ((state + 3) / 2) % 3
|
||||
struct Frame {
|
||||
Frame() : displayed(false) {
|
||||
}
|
||||
void clear() {
|
||||
pix = QPixmap();
|
||||
original = QImage();
|
||||
}
|
||||
QPixmap pix;
|
||||
QImage original;
|
||||
ClipFrameRequest request;
|
||||
QAtomicInt displayed;
|
||||
};
|
||||
mutable Frame _frames[3];
|
||||
Frame *frameToShow(int32 *index = 0) const; // 0 means not ready
|
||||
Frame *frameToWrite(int32 *index = 0) const; // 0 means not ready
|
||||
Frame *frameToWriteNext(bool check, int32 *index = 0) const;
|
||||
void moveToNextShow() const;
|
||||
void moveToNextWrite() const;
|
||||
|
||||
QAtomicInt _paused;
|
||||
int32 _threadIndex;
|
||||
|
||||
bool _autoplay;
|
||||
|
||||
friend class ClipReadManager;
|
||||
|
||||
ClipReaderPrivate *_private;
|
||||
|
||||
};
|
||||
|
||||
static ClipReader * const BadClipReader = SharedMemoryLocation<ClipReader, 0>();
|
||||
|
||||
enum ClipProcessResult {
|
||||
ClipProcessError,
|
||||
ClipProcessStarted,
|
||||
ClipProcessPaused,
|
||||
ClipProcessRepaint,
|
||||
ClipProcessCopyFrame,
|
||||
ClipProcessWait,
|
||||
};
|
||||
|
||||
class ClipReadManager : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
AnimatedGif() : msg(0), file(0), access(false), reader(0), w(0), h(0), frame(0), framesCount(0), duration(0) {
|
||||
ClipReadManager(QThread *thread);
|
||||
int32 loadLevel() const {
|
||||
return _loadLevel.load();
|
||||
}
|
||||
|
||||
bool animStep(float64 ms);
|
||||
|
||||
void start(HistoryItem *row, const FileLocation &file);
|
||||
void stop(bool onItemRemoved = false);
|
||||
|
||||
bool isNull() const {
|
||||
return !reader;
|
||||
}
|
||||
|
||||
~AnimatedGif() {
|
||||
stop(true);
|
||||
}
|
||||
|
||||
const QPixmap ¤t(int32 width = 0, int32 height = 0, bool rounded = false);
|
||||
void append(ClipReader *reader, const FileLocation &location, const QByteArray &data);
|
||||
void start(ClipReader *reader);
|
||||
void update(ClipReader *reader);
|
||||
void stop(ClipReader *reader);
|
||||
bool carries(ClipReader *reader) const;
|
||||
~ClipReadManager();
|
||||
|
||||
signals:
|
||||
|
||||
void updated();
|
||||
void processDelayed();
|
||||
|
||||
public:
|
||||
void callback(ClipReader *reader, qint32 threadIndex, qint32 notification);
|
||||
|
||||
HistoryItem *msg;
|
||||
QImage img;
|
||||
FileLocation *file;
|
||||
bool access;
|
||||
QImageReader *reader;
|
||||
int32 w, h, frame;
|
||||
public slots:
|
||||
|
||||
void process();
|
||||
void finish();
|
||||
|
||||
private:
|
||||
|
||||
QVector<QPixmap> frames;
|
||||
QVector<QImage> images;
|
||||
QVector<int64> delays;
|
||||
int32 framesCount, duration;
|
||||
void clear();
|
||||
|
||||
QAtomicInt _loadLevel;
|
||||
struct MutableAtomicInt {
|
||||
MutableAtomicInt(int value) : v(value) {
|
||||
}
|
||||
mutable QAtomicInt v;
|
||||
};
|
||||
typedef QMap<ClipReader*, MutableAtomicInt> ReaderPointers;
|
||||
ReaderPointers _readerPointers;
|
||||
mutable QReadWriteLock _readerPointersMutex;
|
||||
|
||||
ReaderPointers::const_iterator constUnsafeFindReaderPointer(ClipReaderPrivate *reader) const;
|
||||
ReaderPointers::iterator unsafeFindReaderPointer(ClipReaderPrivate *reader);
|
||||
|
||||
bool handleProcessResult(ClipReaderPrivate *reader, ClipProcessResult result, uint64 ms);
|
||||
|
||||
enum ResultHandleState {
|
||||
ResultHandleRemove,
|
||||
ResultHandleStop,
|
||||
ResultHandleContinue,
|
||||
};
|
||||
ResultHandleState handleResult(ClipReaderPrivate *reader, ClipProcessResult result, uint64 ms);
|
||||
|
||||
typedef QMap<ClipReaderPrivate*, uint64> Readers;
|
||||
Readers _readers;
|
||||
|
||||
QTimer _timer;
|
||||
QThread *_processingInThread;
|
||||
bool _needReProcess;
|
||||
|
||||
};
|
||||
|
||||
MTPDocumentAttribute clipReadAnimatedAttributes(const QString &fname, const QByteArray &data, QImage &cover);
|
||||
|
|
|
@ -137,7 +137,7 @@ void CountryInput::mousePressEvent(QMouseEvent *e) {
|
|||
if (_active) {
|
||||
CountrySelectBox *box = new CountrySelectBox();
|
||||
connect(box, SIGNAL(countryChosen(const QString&)), this, SLOT(onChooseCountry(const QString&)));
|
||||
App::wnd()->showLayer(box);
|
||||
Ui::showLayer(box);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,7 +152,7 @@ void CountryInput::leaveEvent(QEvent *e) {
|
|||
}
|
||||
|
||||
void CountryInput::onChooseCode(const QString &code) {
|
||||
App::wnd()->hideLayer();
|
||||
Ui::hideLayer();
|
||||
if (code.length()) {
|
||||
CountriesByCode::const_iterator i = _countriesByCode.constFind(code);
|
||||
if (i != _countriesByCode.cend()) {
|
||||
|
@ -169,7 +169,7 @@ void CountryInput::onChooseCode(const QString &code) {
|
|||
}
|
||||
|
||||
bool CountryInput::onChooseCountry(const QString &iso) {
|
||||
App::wnd()->hideLayer();
|
||||
Ui::hideLayer();
|
||||
|
||||
CountriesByISO2::const_iterator i = _countriesByISO2.constFind(iso);
|
||||
const CountryInfo *info = (i == _countriesByISO2.cend()) ? 0 : (*i);
|
||||
|
|
|
@ -83,7 +83,7 @@ inline EmojiPtr emojiFromUrl(const QString &url) {
|
|||
return emojiFromKey(url.midRef(10).toULongLong(0, 16)); // skip emoji://e.
|
||||
}
|
||||
|
||||
inline EmojiPtr emojiFromText(const QChar *ch, const QChar *e, int &len) {
|
||||
inline EmojiPtr emojiFromText(const QChar *ch, const QChar *e, int *plen = 0) {
|
||||
EmojiPtr emoji = 0;
|
||||
if (ch + 1 < e && ((ch->isHighSurrogate() && (ch + 1)->isLowSurrogate()) || (((ch->unicode() >= 0x30 && ch->unicode() < 0x3A) || ch->unicode() == 0x23 || ch->unicode() == 0x2A) && (ch + 1)->unicode() == 0x20E3))) {
|
||||
uint32 code = (ch->unicode() << 16) | (ch + 1)->unicode();
|
||||
|
@ -108,15 +108,15 @@ inline EmojiPtr emojiFromText(const QChar *ch, const QChar *e, int &len) {
|
|||
} else if (ch + 2 < e && ((ch->unicode() >= 0x30 && ch->unicode() < 0x3A) || ch->unicode() == 0x23 || ch->unicode() == 0x2A) && (ch + 1)->unicode() == 0xFE0F && (ch + 2)->unicode() == 0x20E3) {
|
||||
uint32 code = (ch->unicode() << 16) | (ch + 2)->unicode();
|
||||
emoji = emojiGet(code);
|
||||
len = emoji->len + 1;
|
||||
if (plen) *plen = emoji->len + 1;
|
||||
return emoji;
|
||||
} else if (ch < e) {
|
||||
emoji = emojiGet(ch->unicode());
|
||||
Q_ASSERT(emoji != TwoSymbolEmoji);
|
||||
t_assert(emoji != TwoSymbolEmoji);
|
||||
}
|
||||
|
||||
if (emoji) {
|
||||
len = emoji->len + ((ch + emoji->len < e && (ch + emoji->len)->unicode() == 0xFE0F) ? 1 : 0);
|
||||
int32 len = emoji->len + ((ch + emoji->len < e && (ch + emoji->len)->unicode() == 0xFE0F) ? 1 : 0);
|
||||
if (emoji->color && (ch + len + 1 < e && (ch + len)->isHighSurrogate() && (ch + len + 1)->isLowSurrogate())) { // color
|
||||
uint32 color = ((uint32((ch + len)->unicode()) << 16) | uint32((ch + len + 1)->unicode()));
|
||||
EmojiPtr col = emojiGet(emoji, color);
|
||||
|
@ -128,8 +128,21 @@ inline EmojiPtr emojiFromText(const QChar *ch, const QChar *e, int &len) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (plen) *plen = len;
|
||||
}
|
||||
|
||||
return emoji;
|
||||
}
|
||||
|
||||
inline EmojiPtr emojiFromText(const QString &text, int32 *plen = 0) {
|
||||
return text.isEmpty() ? EmojiPtr(0) : emojiFromText(text.constBegin(), text.constEnd(), plen);
|
||||
}
|
||||
|
||||
inline EmojiPtr emojiGetNoColor(EmojiPtr emoji) {
|
||||
if (emoji && emoji->color && (emoji->color & 0xFFFF0000U) != 0xFFFF0000U) {
|
||||
EmojiPtr result = emojiGet(emoji->code);
|
||||
return (result == TwoSymbolEmoji) ? emojiGet(emoji->code, emoji->code2) : result;
|
||||
}
|
||||
|
||||
return emoji;
|
||||
}
|
||||
|
||||
|
@ -180,7 +193,7 @@ inline QString replaceEmojis(const QString &text, EntitiesInText &entities) {
|
|||
if (canFindEmoji) {
|
||||
emojiFind(ch, e, newEmojiEnd, emojiCode);
|
||||
}
|
||||
|
||||
|
||||
while (currentEntity < entitiesCount && ch >= emojiStart + entities[currentEntity].offset + entities[currentEntity].length) {
|
||||
++currentEntity;
|
||||
}
|
||||
|
|
|
@ -21,10 +21,14 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
#include "stdafx.h"
|
||||
#include "gui/flatbutton.h"
|
||||
|
||||
FlatButton::FlatButton(QWidget *parent, const QString &text, const style::flatButton &st) : Button(parent),
|
||||
_text(text),
|
||||
_st(st), _autoFontPadding(0),
|
||||
a_bg(st.bgColor->c), a_text(st.color->c), _opacity(1) {
|
||||
FlatButton::FlatButton(QWidget *parent, const QString &text, const style::flatButton &st) : Button(parent)
|
||||
, _text(text)
|
||||
, _st(st)
|
||||
, _autoFontPadding(0)
|
||||
, a_bg(st.bgColor->c)
|
||||
, a_text(st.color->c)
|
||||
, _a_appearance(animation(this, &FlatButton::step_appearance))
|
||||
, _opacity(1) {
|
||||
if (_st.width < 0) {
|
||||
_st.width = textWidth() - _st.width;
|
||||
} else if (!_st.width) {
|
||||
|
@ -88,19 +92,17 @@ void FlatButton::resizeEvent(QResizeEvent *e) {
|
|||
return Button::resizeEvent(e);
|
||||
}
|
||||
|
||||
bool FlatButton::animStep(float64 ms) {
|
||||
void FlatButton::step_appearance(float64 ms, bool timer) {
|
||||
float64 dt = ms / _st.duration;
|
||||
bool res = true;
|
||||
if (dt >= 1) {
|
||||
_a_appearance.stop();
|
||||
a_bg.finish();
|
||||
a_text.finish();
|
||||
res = false;
|
||||
} else {
|
||||
a_bg.update(dt, anim::linear);
|
||||
a_text.update(dt, anim::linear);
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
if (timer) update();
|
||||
}
|
||||
|
||||
void FlatButton::onStateChange(int oldState, ButtonStateChangeSource source) {
|
||||
|
@ -110,12 +112,12 @@ void FlatButton::onStateChange(int oldState, ButtonStateChangeSource source) {
|
|||
a_bg.start(bgColorTo->c);
|
||||
a_text.start(colorTo->c);
|
||||
if (source == ButtonByUser || source == ButtonByPress) {
|
||||
anim::stop(this);
|
||||
_a_appearance.stop();
|
||||
a_bg.finish();
|
||||
a_text.finish();
|
||||
update();
|
||||
} else {
|
||||
anim::start(this);
|
||||
_a_appearance.start();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -164,8 +166,14 @@ void LinkButton::onStateChange(int oldState, ButtonStateChangeSource source) {
|
|||
LinkButton::~LinkButton() {
|
||||
}
|
||||
|
||||
IconedButton::IconedButton(QWidget *parent, const style::iconedButton &st, const QString &text) : Button(parent),
|
||||
_text(text), _st(st), _width(_st.width), a_opacity(_st.opacity), a_bg(_st.bgColor->c), _opacity(1) {
|
||||
IconedButton::IconedButton(QWidget *parent, const style::iconedButton &st, const QString &text) : Button(parent)
|
||||
, _text(text)
|
||||
, _st(st)
|
||||
, _width(_st.width)
|
||||
, a_opacity(_st.opacity)
|
||||
, a_bg(_st.bgColor->c)
|
||||
, _a_appearance(animation(this, &IconedButton::step_appearance))
|
||||
, _opacity(1) {
|
||||
|
||||
if (_width < 0) {
|
||||
_width = _st.font->width(text) - _width;
|
||||
|
@ -199,25 +207,23 @@ QString IconedButton::getText() const {
|
|||
return _text;
|
||||
}
|
||||
|
||||
bool IconedButton::animStep(float64 ms) {
|
||||
bool res = true;
|
||||
void IconedButton::step_appearance(float64 ms, bool timer) {
|
||||
if (_st.duration <= 1) {
|
||||
_a_appearance.stop();
|
||||
a_opacity.finish();
|
||||
a_bg.finish();
|
||||
res = false;
|
||||
} else {
|
||||
float64 dt = ms / _st.duration;
|
||||
if (dt >= 1) {
|
||||
_a_appearance.stop();
|
||||
a_opacity.finish();
|
||||
a_bg.finish();
|
||||
res = false;
|
||||
} else {
|
||||
a_opacity.update(dt, anim::linear);
|
||||
a_bg.update(dt, anim::linear);
|
||||
}
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
if (timer) update();
|
||||
}
|
||||
|
||||
void IconedButton::onStateChange(int oldState, ButtonStateChangeSource source) {
|
||||
|
@ -225,12 +231,12 @@ void IconedButton::onStateChange(int oldState, ButtonStateChangeSource source) {
|
|||
a_bg.start(((_state & (StateOver | StateDown)) ? _st.overBgColor : _st.bgColor)->c);
|
||||
|
||||
if (source == ButtonByUser || source == ButtonByPress) {
|
||||
anim::stop(this);
|
||||
_a_appearance.stop();
|
||||
a_opacity.finish();
|
||||
a_bg.finish();
|
||||
update();
|
||||
} else {
|
||||
anim::start(this);
|
||||
_a_appearance.start();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -283,10 +289,65 @@ void MaskedButton::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
}
|
||||
|
||||
BoxButton::BoxButton(QWidget *parent, const QString &text, const style::BoxButton &st) : Button(parent),
|
||||
_text(text.toUpper()), _fullText(text.toUpper()), _textWidth(st.font->width(_text)),
|
||||
_st(st),
|
||||
a_textBgOverOpacity(0), a_textFg(st.textFg->c), _a_over(animFunc(this, &BoxButton::animStep_over)) {
|
||||
EmojiButton::EmojiButton(QWidget *parent, const style::iconedButton &st) : IconedButton(parent, st)
|
||||
, _loading(false)
|
||||
, _a_loading(animation(this, &EmojiButton::step_loading)) {
|
||||
}
|
||||
|
||||
void EmojiButton::paintEvent(QPaintEvent *e) {
|
||||
QPainter p(this);
|
||||
|
||||
uint64 ms = getms();
|
||||
float64 loading = a_loading.current(ms, _loading ? 1 : 0);
|
||||
p.setOpacity(_opacity * (1 - loading));
|
||||
|
||||
p.fillRect(e->rect(), a_bg.current());
|
||||
|
||||
p.setOpacity(a_opacity.current() * _opacity * (1 - loading));
|
||||
|
||||
const QRect &i((_state & StateDown) ? _st.downIcon : _st.icon);
|
||||
if (i.width()) {
|
||||
const QPoint &t((_state & StateDown) ? _st.downIconPos : _st.iconPos);
|
||||
p.drawPixmap(t, App::sprite(), i);
|
||||
}
|
||||
|
||||
p.setOpacity(a_opacity.current() * _opacity);
|
||||
p.setPen(QPen(st::emojiCircleFg, st::emojiCircleLine));
|
||||
p.setBrush(Qt::NoBrush);
|
||||
|
||||
p.setRenderHint(QPainter::HighQualityAntialiasing);
|
||||
QRect inner(QPoint((width() - st::emojiCircle.width()) / 2, st::emojiCircleTop), st::emojiCircle);
|
||||
if (loading > 0) {
|
||||
int32 full = 5760;
|
||||
int32 start = qRound(full * float64(ms % uint64(st::emojiCirclePeriod)) / st::emojiCirclePeriod), part = qRound(loading * full / st::emojiCirclePart);
|
||||
p.drawArc(inner, start, full - part);
|
||||
} else {
|
||||
p.drawEllipse(inner);
|
||||
}
|
||||
p.setRenderHint(QPainter::HighQualityAntialiasing, false);
|
||||
}
|
||||
|
||||
void EmojiButton::setLoading(bool loading) {
|
||||
if (_loading != loading) {
|
||||
EnsureAnimation(a_loading, _loading ? 1. : 0., func(this, &EmojiButton::update));
|
||||
a_loading.start(loading ? 1. : 0., st::emojiCircleDuration);
|
||||
_loading = loading;
|
||||
if (_loading) {
|
||||
_a_loading.start();
|
||||
} else {
|
||||
_a_loading.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BoxButton::BoxButton(QWidget *parent, const QString &text, const style::BoxButton &st) : Button(parent)
|
||||
, _text(text.toUpper())
|
||||
, _fullText(text.toUpper())
|
||||
, _textWidth(st.font->width(_text))
|
||||
, _st(st)
|
||||
, a_textBgOverOpacity(0)
|
||||
, a_textFg(st.textFg->c)
|
||||
, _a_over(animation(this, &BoxButton::step_over)) {
|
||||
if (_st.width <= 0) {
|
||||
resize(_textWidth - _st.width, _st.height);
|
||||
} else {
|
||||
|
@ -322,19 +383,17 @@ void BoxButton::paintEvent(QPaintEvent *e) {
|
|||
p.drawText((width() - _textWidth) / 2, _st.textTop + _st.font->ascent, _text);
|
||||
}
|
||||
|
||||
bool BoxButton::animStep_over(float64 ms) {
|
||||
void BoxButton::step_over(float64 ms, bool timer) {
|
||||
float64 dt = ms / _st.duration;
|
||||
bool res = true;
|
||||
if (dt >= 1) {
|
||||
_a_over.stop();
|
||||
a_textFg.finish();
|
||||
a_textBgOverOpacity.finish();
|
||||
res = false;
|
||||
} else {
|
||||
a_textFg.update(dt, anim::linear);
|
||||
a_textBgOverOpacity.update(dt, anim::linear);
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
if (timer) update();
|
||||
}
|
||||
|
||||
void BoxButton::onStateChange(int oldState, ButtonStateChangeSource source) {
|
||||
|
|
|
@ -25,7 +25,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
#include "gui/animation.h"
|
||||
#include "style.h"
|
||||
|
||||
class FlatButton : public Button, public Animated {
|
||||
class FlatButton : public Button {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
@ -34,7 +34,7 @@ public:
|
|||
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
|
||||
bool animStep(float64 ms);
|
||||
void step_appearance(float64 ms, bool timer);
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void setOpacity(float64 o);
|
||||
float64 opacity() const;
|
||||
|
@ -63,7 +63,10 @@ private:
|
|||
style::font _autoFont;
|
||||
|
||||
anim::cvalue a_bg, a_text;
|
||||
Animation _a_appearance;
|
||||
|
||||
float64 _opacity;
|
||||
|
||||
};
|
||||
|
||||
class LinkButton : public Button {
|
||||
|
@ -89,21 +92,21 @@ private:
|
|||
style::linkButton _st;
|
||||
};
|
||||
|
||||
class IconedButton : public Button, public Animated {
|
||||
class IconedButton : public Button {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
IconedButton(QWidget *parent, const style::iconedButton &st, const QString &text = QString());
|
||||
|
||||
bool animStep(float64 ms);
|
||||
void step_appearance(float64 ms, bool timer);
|
||||
void paintEvent(QPaintEvent *e);
|
||||
|
||||
void setOpacity(float64 o);
|
||||
|
||||
void setText(const QString &text);
|
||||
QString getText() const;
|
||||
|
||||
|
||||
public slots:
|
||||
|
||||
void onStateChange(int oldState, ButtonStateChangeSource source);
|
||||
|
@ -117,6 +120,7 @@ protected:
|
|||
|
||||
anim::fvalue a_opacity;
|
||||
anim::cvalue a_bg;
|
||||
Animation _a_appearance;
|
||||
|
||||
float64 _opacity;
|
||||
};
|
||||
|
@ -132,6 +136,28 @@ public:
|
|||
|
||||
};
|
||||
|
||||
class EmojiButton : public IconedButton {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
EmojiButton(QWidget *parent, const style::iconedButton &st);
|
||||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void setLoading(bool loading);
|
||||
|
||||
private:
|
||||
bool _loading;
|
||||
FloatAnimation a_loading;
|
||||
Animation _a_loading;
|
||||
|
||||
void step_loading(uint64 ms, bool timer) {
|
||||
if (timer) {
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class BoxButton : public Button {
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -141,7 +167,7 @@ public:
|
|||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
|
||||
bool animStep_over(float64 ms);
|
||||
void step_over(float64 ms, bool timer);
|
||||
|
||||
public slots:
|
||||
|
||||
|
|
|
@ -24,8 +24,13 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
|
||||
#include "flatcheckbox.h"
|
||||
|
||||
FlatCheckbox::FlatCheckbox(QWidget *parent, const QString &text, bool checked, const style::flatCheckbox &st) : Button(parent),
|
||||
_st(st), a_over(0, 0), _text(text), _opacity(1), _checked(checked) {
|
||||
FlatCheckbox::FlatCheckbox(QWidget *parent, const QString &text, bool checked, const style::flatCheckbox &st) : Button(parent)
|
||||
, _st(st)
|
||||
, a_over(0, 0)
|
||||
, _a_appearance(animation(this, &FlatCheckbox::step_appearance))
|
||||
, _text(text)
|
||||
, _opacity(1)
|
||||
, _checked(checked) {
|
||||
connect(this, SIGNAL(clicked()), this, SLOT(onClicked()));
|
||||
connect(this, SIGNAL(stateChanged(int, ButtonStateChangeSource)), this, SLOT(onStateChange(int, ButtonStateChangeSource)));
|
||||
setCursor(_st.cursor);
|
||||
|
@ -60,17 +65,17 @@ void FlatCheckbox::onClicked() {
|
|||
void FlatCheckbox::onStateChange(int oldState, ButtonStateChangeSource source) {
|
||||
if ((_state & StateOver) && !(oldState & StateOver)) {
|
||||
a_over.start(1);
|
||||
anim::start(this);
|
||||
_a_appearance.start();
|
||||
} else if (!(_state & StateOver) && (oldState & StateOver)) {
|
||||
a_over.start(0);
|
||||
anim::start(this);
|
||||
_a_appearance.start();
|
||||
}
|
||||
if ((_state & StateDisabled) && !(oldState & StateDisabled)) {
|
||||
setCursor(_st.disabledCursor);
|
||||
anim::start(this);
|
||||
_a_appearance.start();
|
||||
} else if (!(_state & StateDisabled) && (oldState & StateDisabled)) {
|
||||
setCursor(_st.cursor);
|
||||
anim::start(this);
|
||||
_a_appearance.start();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,17 +119,15 @@ void FlatCheckbox::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
}
|
||||
|
||||
bool FlatCheckbox::animStep(float64 ms) {
|
||||
void FlatCheckbox::step_appearance(float64 ms, bool timer) {
|
||||
float64 dt = ms / _st.duration;
|
||||
bool res = true;
|
||||
if (dt >= 1) {
|
||||
_a_appearance.stop();
|
||||
a_over.finish();
|
||||
res = false;
|
||||
} else {
|
||||
a_over.update(dt, _st.bgFunc);
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
if (timer) update();
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
|
@ -135,7 +138,8 @@ public:
|
|||
TemplateRadiobuttonsGroup(const QString &name) : _name(name), _val(0) {
|
||||
}
|
||||
|
||||
void remove(Type * const &radio);
|
||||
void remove(Type * const &radio) {
|
||||
}
|
||||
int32 val() const {
|
||||
return _val;
|
||||
}
|
||||
|
@ -232,12 +236,16 @@ FlatRadiobutton::~FlatRadiobutton() {
|
|||
reinterpret_cast<FlatRadiobuttonGroup*>(_group)->remove(this);
|
||||
}
|
||||
|
||||
Checkbox::Checkbox(QWidget *parent, const QString &text, bool checked, const style::Checkbox &st) : Button(parent),
|
||||
_st(st),
|
||||
a_over(0), a_checked(checked ? 1 : 0),
|
||||
_a_over(animFunc(this, &Checkbox::animStep_over)), _a_checked(animFunc(this, &Checkbox::animStep_checked)),
|
||||
_text(text), _fullText(text), _textWidth(st.font->width(text)),
|
||||
_checked(checked) {
|
||||
Checkbox::Checkbox(QWidget *parent, const QString &text, bool checked, const style::Checkbox &st) : Button(parent)
|
||||
, _st(st)
|
||||
, a_over(0)
|
||||
, a_checked(checked ? 1 : 0)
|
||||
, _a_over(animation(this, &Checkbox::step_over))
|
||||
, _a_checked(animation(this, &Checkbox::step_checked))
|
||||
, _text(text)
|
||||
, _fullText(text)
|
||||
, _textWidth(st.font->width(text))
|
||||
, _checked(checked) {
|
||||
if (_st.width <= 0) {
|
||||
resize(_textWidth - _st.width, _st.height);
|
||||
} else {
|
||||
|
@ -275,30 +283,26 @@ void Checkbox::setChecked(bool checked) {
|
|||
}
|
||||
}
|
||||
|
||||
bool Checkbox::animStep_over(float64 ms) {
|
||||
void Checkbox::step_over(float64 ms, bool timer) {
|
||||
float64 dt = ms / _st.duration;
|
||||
bool res = true;
|
||||
if (dt >= 1) {
|
||||
_a_over.stop();
|
||||
a_over.finish();
|
||||
res = false;
|
||||
} else {
|
||||
a_over.update(dt, anim::linear);
|
||||
}
|
||||
update(_checkRect);
|
||||
return res;
|
||||
if (timer) update(_checkRect);
|
||||
}
|
||||
|
||||
bool Checkbox::animStep_checked(float64 ms) {
|
||||
void Checkbox::step_checked(float64 ms, bool timer) {
|
||||
float64 dt = ms / _st.duration;
|
||||
bool res = true;
|
||||
if (dt >= 1) {
|
||||
a_checked.finish();
|
||||
res = false;
|
||||
_a_checked.stop();
|
||||
} else {
|
||||
a_checked.update(dt, anim::linear);
|
||||
}
|
||||
update(_checkRect);
|
||||
return res;
|
||||
if (timer) update(_checkRect);
|
||||
}
|
||||
|
||||
void Checkbox::paintEvent(QPaintEvent *e) {
|
||||
|
@ -372,12 +376,18 @@ void Checkbox::onStateChange(int oldState, ButtonStateChangeSource source) {
|
|||
}
|
||||
}
|
||||
|
||||
Radiobutton::Radiobutton(QWidget *parent, const QString &group, int32 value, const QString &text, bool checked, const style::Radiobutton &st) : Button(parent),
|
||||
_st(st),
|
||||
a_over(0), a_checked(checked ? 1 : 0),
|
||||
_a_over(animFunc(this, &Radiobutton::animStep_over)), _a_checked(animFunc(this, &Radiobutton::animStep_checked)),
|
||||
_text(text), _fullText(text), _textWidth(st.font->width(text)),
|
||||
_checked(checked), _group(radiobuttons.reg(group)), _value(value) {
|
||||
Radiobutton::Radiobutton(QWidget *parent, const QString &group, int32 value, const QString &text, bool checked, const style::Radiobutton &st) : Button(parent)
|
||||
, _st(st)
|
||||
, a_over(0)
|
||||
, a_checked(checked ? 1 : 0)
|
||||
, _a_over(animation(this, &Radiobutton::step_over))
|
||||
, _a_checked(animation(this, &Radiobutton::step_checked))
|
||||
, _text(text)
|
||||
, _fullText(text)
|
||||
, _textWidth(st.font->width(text))
|
||||
, _checked(checked)
|
||||
, _group(radiobuttons.reg(group))
|
||||
, _value(value) {
|
||||
if (_st.width <= 0) {
|
||||
resize(_textWidth - _st.width, _st.height);
|
||||
} else {
|
||||
|
@ -419,30 +429,26 @@ void Radiobutton::setChecked(bool checked) {
|
|||
}
|
||||
}
|
||||
|
||||
bool Radiobutton::animStep_over(float64 ms) {
|
||||
void Radiobutton::step_over(float64 ms, bool timer) {
|
||||
float64 dt = ms / _st.duration;
|
||||
bool res = true;
|
||||
if (dt >= 1) {
|
||||
_a_over.stop();
|
||||
a_over.finish();
|
||||
res = false;
|
||||
} else {
|
||||
a_over.update(dt, anim::linear);
|
||||
}
|
||||
update(_checkRect);
|
||||
return res;
|
||||
if (timer) update(_checkRect);
|
||||
}
|
||||
|
||||
bool Radiobutton::animStep_checked(float64 ms) {
|
||||
void Radiobutton::step_checked(float64 ms, bool timer) {
|
||||
float64 dt = ms / _st.duration;
|
||||
bool res = true;
|
||||
if (dt >= 1) {
|
||||
a_checked.finish();
|
||||
res = false;
|
||||
_a_checked.stop();
|
||||
} else {
|
||||
a_checked.update(dt, anim::linear);
|
||||
}
|
||||
update(_checkRect);
|
||||
return res;
|
||||
if (timer) update(_checkRect);
|
||||
}
|
||||
|
||||
void Radiobutton::paintEvent(QPaintEvent *e) {
|
||||
|
|
|
@ -22,7 +22,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
|
||||
#include "gui/button.h"
|
||||
|
||||
class FlatCheckbox : public Button, public Animated {
|
||||
class FlatCheckbox : public Button {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
@ -32,7 +32,7 @@ public:
|
|||
bool checked() const;
|
||||
void setChecked(bool checked);
|
||||
|
||||
bool animStep(float64 ms);
|
||||
void step_appearance(float64 ms, bool timer);
|
||||
void paintEvent(QPaintEvent *e);
|
||||
|
||||
void setOpacity(float64 o);
|
||||
|
@ -50,6 +50,8 @@ private:
|
|||
|
||||
style::flatCheckbox _st;
|
||||
anim::fvalue a_over;
|
||||
Animation _a_appearance;
|
||||
|
||||
QString _text;
|
||||
style::font _font;
|
||||
|
||||
|
@ -91,8 +93,8 @@ public:
|
|||
bool checked() const;
|
||||
void setChecked(bool checked);
|
||||
|
||||
bool animStep_over(float64 ms);
|
||||
bool animStep_checked(float64 ms);
|
||||
void step_over(float64 ms, bool timer);
|
||||
void step_checked(float64 ms, bool timer);
|
||||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
|
||||
|
@ -133,8 +135,8 @@ public:
|
|||
return _value;
|
||||
}
|
||||
|
||||
bool animStep_over(float64 ms);
|
||||
bool animStep_checked(float64 ms);
|
||||
void step_over(float64 ms, bool timer);
|
||||
void step_checked(float64 ms, bool timer);
|
||||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
|
||||
|
|
|
@ -51,12 +51,22 @@ namespace {
|
|||
InputStyle<MaskedInputField> _inputFieldStyle;
|
||||
}
|
||||
|
||||
FlatInput::FlatInput(QWidget *parent, const style::flatInput &st, const QString &pholder, const QString &v) : QLineEdit(v, parent),
|
||||
_oldtext(v), _fullph(pholder), _fastph(false), _customUpDown(false), _phVisible(!v.length()),
|
||||
a_phLeft(_phVisible ? 0 : st.phShift), a_phAlpha(_phVisible ? 1 : 0), a_phColor(st.phColor->c),
|
||||
a_borderColor(st.borderColor->c), a_bgColor(st.bgColor->c), _notingBene(0), _st(st) {
|
||||
FlatInput::FlatInput(QWidget *parent, const style::flatInput &st, const QString &pholder, const QString &v) : QLineEdit(v, parent)
|
||||
, _oldtext(v)
|
||||
, _fullph(pholder)
|
||||
, _fastph(false)
|
||||
, _customUpDown(false)
|
||||
, _phVisible(!v.length())
|
||||
, a_phLeft(_phVisible ? 0 : st.phShift)
|
||||
, a_phAlpha(_phVisible ? 1 : 0)
|
||||
, a_phColor(st.phColor->c)
|
||||
, a_borderColor(st.borderColor->c)
|
||||
, a_bgColor(st.bgColor->c)
|
||||
, _a_appearance(animation(this, &FlatInput::step_appearance))
|
||||
, _notingBene(0)
|
||||
, _st(st) {
|
||||
resize(_st.width, _st.height);
|
||||
|
||||
|
||||
setFont(_st.font->f);
|
||||
setAlignment(_st.align);
|
||||
|
||||
|
@ -158,7 +168,7 @@ void FlatInput::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
|
||||
bool phDraw = _phVisible;
|
||||
if (animating()) {
|
||||
if (_a_appearance.animating()) {
|
||||
p.setOpacity(a_phAlpha.current());
|
||||
phDraw = true;
|
||||
}
|
||||
|
@ -180,7 +190,7 @@ void FlatInput::focusInEvent(QFocusEvent *e) {
|
|||
a_borderColor.start(_st.borderActive->c);
|
||||
}
|
||||
a_bgColor.start(_st.bgActive->c);
|
||||
anim::start(this);
|
||||
_a_appearance.start();
|
||||
QLineEdit::focusInEvent(e);
|
||||
emit focused();
|
||||
}
|
||||
|
@ -191,7 +201,7 @@ void FlatInput::focusOutEvent(QFocusEvent *e) {
|
|||
a_borderColor.start(_st.borderColor->c);
|
||||
}
|
||||
a_bgColor.start(_st.bgColor->c);
|
||||
anim::start(this);
|
||||
_a_appearance.start();
|
||||
QLineEdit::focusOutEvent(e);
|
||||
emit blurred();
|
||||
}
|
||||
|
@ -224,11 +234,10 @@ QSize FlatInput::minimumSizeHint() const {
|
|||
return geometry().size();
|
||||
}
|
||||
|
||||
bool FlatInput::animStep(float64 ms) {
|
||||
void FlatInput::step_appearance(float64 ms, bool timer) {
|
||||
float dt = ms / _st.phDuration;
|
||||
bool res = true;
|
||||
if (dt >= 1) {
|
||||
res = false;
|
||||
_a_appearance.stop();
|
||||
a_phLeft.finish();
|
||||
a_phAlpha.finish();
|
||||
a_phColor.finish();
|
||||
|
@ -236,8 +245,8 @@ bool FlatInput::animStep(float64 ms) {
|
|||
if (_notingBene > 0) {
|
||||
_notingBene = -1;
|
||||
a_borderColor.start((hasFocus() ? _st.borderActive : _st.borderColor)->c);
|
||||
anim::start(this);
|
||||
return true;
|
||||
_a_appearance.start();
|
||||
return;
|
||||
} else if (_notingBene) {
|
||||
_notingBene = 0;
|
||||
}
|
||||
|
@ -249,8 +258,7 @@ bool FlatInput::animStep(float64 ms) {
|
|||
a_bgColor.update(dt, _st.phColorFunc);
|
||||
a_borderColor.update(dt, _st.phColorFunc);
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
if (timer) update();
|
||||
}
|
||||
|
||||
void FlatInput::setPlaceholder(const QString &ph) {
|
||||
|
@ -279,7 +287,7 @@ void FlatInput::updatePlaceholder() {
|
|||
} else {
|
||||
a_phLeft.start(vis ? 0 : _st.phShift);
|
||||
a_phAlpha.start(vis ? 1 : 0);
|
||||
anim::start(this);
|
||||
_a_appearance.start();
|
||||
}
|
||||
_phVisible = vis;
|
||||
}
|
||||
|
@ -345,11 +353,11 @@ void FlatInput::notaBene() {
|
|||
_notingBene = 1;
|
||||
setFocus();
|
||||
a_borderColor.start(_st.borderError->c);
|
||||
anim::start(this);
|
||||
_a_appearance.start();
|
||||
}
|
||||
|
||||
CountryCodeInput::CountryCodeInput(QWidget *parent, const style::flatInput &st) : FlatInput(parent, st), _nosignal(false) {
|
||||
|
||||
CountryCodeInput::CountryCodeInput(QWidget *parent, const style::flatInput &st) : FlatInput(parent, st)
|
||||
, _nosignal(false) {
|
||||
}
|
||||
|
||||
void CountryCodeInput::startErasing(QKeyEvent *e) {
|
||||
|
@ -541,38 +549,39 @@ void PhonePartInput::onChooseCode(const QString &code) {
|
|||
updatePlaceholder();
|
||||
}
|
||||
|
||||
InputArea::InputArea(QWidget *parent, const style::InputArea &st, const QString &ph, const QString &val) : TWidget(parent),
|
||||
_maxLength(-1),
|
||||
_inner(this),
|
||||
_oldtext(val),
|
||||
InputArea::InputArea(QWidget *parent, const style::InputArea &st, const QString &ph, const QString &val) : TWidget(parent)
|
||||
, _maxLength(-1)
|
||||
, _inner(this)
|
||||
, _oldtext(val)
|
||||
|
||||
_ctrlEnterSubmit(CtrlEnterSubmitCtrlEnter),
|
||||
_undoAvailable(false),
|
||||
_redoAvailable(false),
|
||||
_inHeightCheck(false),
|
||||
, _ctrlEnterSubmit(CtrlEnterSubmitCtrlEnter)
|
||||
, _undoAvailable(false)
|
||||
, _redoAvailable(false)
|
||||
, _inHeightCheck(false)
|
||||
|
||||
_customUpDown(false),
|
||||
, _customUpDown(false)
|
||||
|
||||
_placeholderFull(ph),
|
||||
_placeholderVisible(val.isEmpty()),
|
||||
a_placeholderLeft(_placeholderVisible ? 0 : st.placeholderShift),
|
||||
a_placeholderOpacity(_placeholderVisible ? 1 : 0),
|
||||
a_placeholderFg(st.placeholderFg->c),
|
||||
_a_placeholderFg(animFunc(this, &InputArea::animStep_placeholderFg)),
|
||||
_a_placeholderShift(animFunc(this, &InputArea::animStep_placeholderShift)),
|
||||
, _placeholderFull(ph)
|
||||
, _placeholderVisible(val.isEmpty())
|
||||
, a_placeholderLeft(_placeholderVisible ? 0 : st.placeholderShift)
|
||||
, a_placeholderOpacity(_placeholderVisible ? 1 : 0)
|
||||
, a_placeholderFg(st.placeholderFg->c)
|
||||
, _a_placeholderFg(animation(this, &InputArea::step_placeholderFg))
|
||||
, _a_placeholderShift(animation(this, &InputArea::step_placeholderShift))
|
||||
|
||||
a_borderOpacityActive(0),
|
||||
a_borderFg(st.borderFg->c),
|
||||
_a_border(animFunc(this, &InputArea::animStep_border)),
|
||||
, a_borderOpacityActive(0)
|
||||
, a_borderFg(st.borderFg->c)
|
||||
, _a_border(animation(this, &InputArea::step_border))
|
||||
|
||||
_focused(false), _error(false),
|
||||
, _focused(false)
|
||||
, _error(false)
|
||||
|
||||
_st(st),
|
||||
, _st(st)
|
||||
|
||||
_touchPress(false),
|
||||
_touchRightButton(false),
|
||||
_touchMove(false),
|
||||
_correcting(false) {
|
||||
, _touchPress(false)
|
||||
, _touchRightButton(false)
|
||||
, _touchMove(false)
|
||||
, _correcting(false) {
|
||||
_inner.setAcceptRichText(false);
|
||||
resize(_st.width, _st.heightMin);
|
||||
|
||||
|
@ -950,7 +959,7 @@ void InputArea::processDocumentContentsChange(int position, int charsAdded) {
|
|||
const QChar *ch = t.constData(), *e = ch + t.size();
|
||||
for (; ch != e; ++ch, ++fp) {
|
||||
int32 emojiLen = 0;
|
||||
emoji = emojiFromText(ch, e, emojiLen);
|
||||
emoji = emojiFromText(ch, e, &emojiLen);
|
||||
if (emoji) {
|
||||
if (replacePosition >= 0) {
|
||||
emoji = 0; // replace tilde char format first
|
||||
|
@ -1106,47 +1115,42 @@ void InputArea::onRedoAvailable(bool avail) {
|
|||
if (App::wnd()) App::wnd()->updateGlobalMenu();
|
||||
}
|
||||
|
||||
bool InputArea::animStep_placeholderFg(float64 ms) {
|
||||
float dt = ms / _st.duration;
|
||||
bool res = true;
|
||||
void InputArea::step_placeholderFg(float64 ms, bool timer) {
|
||||
float64 dt = ms / _st.duration;
|
||||
if (dt >= 1) {
|
||||
res = false;
|
||||
_a_placeholderFg.stop();
|
||||
a_placeholderFg.finish();
|
||||
} else {
|
||||
a_placeholderFg.update(dt, anim::linear);
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
if (timer) update();
|
||||
}
|
||||
|
||||
bool InputArea::animStep_placeholderShift(float64 ms) {
|
||||
float dt = ms / _st.duration;
|
||||
bool res = true;
|
||||
void InputArea::step_placeholderShift(float64 ms, bool timer) {
|
||||
float64 dt = ms / _st.duration;
|
||||
if (dt >= 1) {
|
||||
res = false;
|
||||
_a_placeholderShift.stop();
|
||||
a_placeholderLeft.finish();
|
||||
a_placeholderOpacity.finish();
|
||||
} else {
|
||||
a_placeholderLeft.update(dt, anim::linear);
|
||||
a_placeholderOpacity.update(dt, anim::linear);
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
if (timer) update();
|
||||
}
|
||||
|
||||
bool InputArea::animStep_border(float64 ms) {
|
||||
float dt = ms / _st.duration;
|
||||
void InputArea::step_border(float64 ms, bool timer) {
|
||||
float64 dt = ms / _st.duration;
|
||||
bool res = true;
|
||||
if (dt >= 1) {
|
||||
res = false;
|
||||
_a_border.stop();
|
||||
a_borderFg.finish();
|
||||
a_borderOpacityActive.finish();
|
||||
} else {
|
||||
a_borderFg.update(dt, anim::linear);
|
||||
a_borderOpacityActive.update(dt, anim::linear);
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
if (timer) update();
|
||||
}
|
||||
|
||||
void InputArea::updatePlaceholder() {
|
||||
|
@ -1261,41 +1265,41 @@ void InputArea::showError() {
|
|||
}
|
||||
}
|
||||
|
||||
InputField::InputField(QWidget *parent, const style::InputField &st, const QString &ph, const QString &val) : TWidget(parent),
|
||||
_maxLength(-1),
|
||||
_inner(this),
|
||||
_oldtext(val),
|
||||
InputField::InputField(QWidget *parent, const style::InputField &st, const QString &ph, const QString &val) : TWidget(parent)
|
||||
, _maxLength(-1)
|
||||
, _inner(this)
|
||||
, _oldtext(val)
|
||||
|
||||
_undoAvailable(false),
|
||||
_redoAvailable(false),
|
||||
, _undoAvailable(false)
|
||||
, _redoAvailable(false)
|
||||
|
||||
_customUpDown(true),
|
||||
, _customUpDown(true)
|
||||
|
||||
_placeholderFull(ph),
|
||||
_placeholderVisible(val.isEmpty()),
|
||||
a_placeholderLeft(_placeholderVisible ? 0 : st.placeholderShift),
|
||||
a_placeholderOpacity(_placeholderVisible ? 1 : 0),
|
||||
a_placeholderFg(st.placeholderFg->c),
|
||||
_a_placeholderFg(animFunc(this, &InputField::animStep_placeholderFg)),
|
||||
_a_placeholderShift(animFunc(this, &InputField::animStep_placeholderShift)),
|
||||
, _placeholderFull(ph)
|
||||
, _placeholderVisible(val.isEmpty())
|
||||
, a_placeholderLeft(_placeholderVisible ? 0 : st.placeholderShift)
|
||||
, a_placeholderOpacity(_placeholderVisible ? 1 : 0)
|
||||
, a_placeholderFg(st.placeholderFg->c)
|
||||
, _a_placeholderFg(animation(this, &InputField::step_placeholderFg))
|
||||
, _a_placeholderShift(animation(this, &InputField::step_placeholderShift))
|
||||
|
||||
a_borderOpacityActive(0),
|
||||
a_borderFg(st.borderFg->c),
|
||||
_a_border(animFunc(this, &InputField::animStep_border)),
|
||||
, a_borderOpacityActive(0)
|
||||
, a_borderFg(st.borderFg->c)
|
||||
, _a_border(animation(this, &InputField::step_border))
|
||||
|
||||
_focused(false), _error(false),
|
||||
, _focused(false)
|
||||
, _error(false)
|
||||
|
||||
_st(st),
|
||||
, _st(st)
|
||||
|
||||
_touchPress(false),
|
||||
_touchRightButton(false),
|
||||
_touchMove(false),
|
||||
_correcting(false) {
|
||||
, _touchPress(false)
|
||||
, _touchRightButton(false)
|
||||
, _touchMove(false)
|
||||
, _correcting(false) {
|
||||
_inner.setAcceptRichText(false);
|
||||
resize(_st.width, _st.height);
|
||||
|
||||
_inner.setWordWrapMode(QTextOption::NoWrap);
|
||||
_inner.setLineWrapMode(QTextEdit::NoWrap);
|
||||
|
||||
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||
|
||||
|
@ -1327,7 +1331,7 @@ _correcting(false) {
|
|||
connect(&_inner, SIGNAL(undoAvailable(bool)), this, SLOT(onUndoAvailable(bool)));
|
||||
connect(&_inner, SIGNAL(redoAvailable(bool)), this, SLOT(onRedoAvailable(bool)));
|
||||
if (App::wnd()) connect(&_inner, SIGNAL(selectionChanged()), App::wnd(), SLOT(updateGlobalMenu()));
|
||||
|
||||
|
||||
setCursor(style::cur_text);
|
||||
if (!val.isEmpty()) {
|
||||
_inner.setPlainText(val);
|
||||
|
@ -1408,7 +1412,7 @@ void InputField::paintEvent(QPaintEvent *e) {
|
|||
if (_st.iconSprite.pxWidth()) {
|
||||
p.drawSpriteLeft(_st.iconPosition, width(), _st.iconSprite);
|
||||
}
|
||||
|
||||
|
||||
bool drawPlaceholder = _placeholderVisible;
|
||||
if (_a_placeholderShift.animating()) {
|
||||
p.setOpacity(a_placeholderOpacity.current());
|
||||
|
@ -1421,11 +1425,11 @@ void InputField::paintEvent(QPaintEvent *e) {
|
|||
QRect r(rect().marginsRemoved(_st.textMargins + _st.placeholderMargins));
|
||||
r.moveLeft(r.left() + a_placeholderLeft.current());
|
||||
if (rtl()) r.moveLeft(width() - r.left() - r.width());
|
||||
|
||||
|
||||
p.setFont(_st.font);
|
||||
p.setPen(a_placeholderFg.current());
|
||||
p.drawText(r, _placeholder, _st.placeholderAlign);
|
||||
|
||||
|
||||
p.restore();
|
||||
}
|
||||
TWidget::paintEvent(e);
|
||||
|
@ -1659,7 +1663,7 @@ void InputField::processDocumentContentsChange(int position, int charsAdded) {
|
|||
}
|
||||
|
||||
int32 emojiLen = 0;
|
||||
emoji = emojiFromText(ch, e, emojiLen);
|
||||
emoji = emojiFromText(ch, e, &emojiLen);
|
||||
if (emoji) {
|
||||
if (replacePosition >= 0) {
|
||||
emoji = 0; // replace tilde char format first
|
||||
|
@ -1834,47 +1838,41 @@ void InputField::selectAll() {
|
|||
_inner.setTextCursor(c);
|
||||
}
|
||||
|
||||
bool InputField::animStep_placeholderFg(float64 ms) {
|
||||
float dt = ms / _st.duration;
|
||||
bool res = true;
|
||||
void InputField::step_placeholderFg(float64 ms, bool timer) {
|
||||
float64 dt = ms / _st.duration;
|
||||
if (dt >= 1) {
|
||||
res = false;
|
||||
_a_placeholderFg.stop();
|
||||
a_placeholderFg.finish();
|
||||
} else {
|
||||
a_placeholderFg.update(dt, anim::linear);
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
if (timer) update();
|
||||
}
|
||||
|
||||
bool InputField::animStep_placeholderShift(float64 ms) {
|
||||
float dt = ms / _st.duration;
|
||||
bool res = true;
|
||||
void InputField::step_placeholderShift(float64 ms, bool timer) {
|
||||
float64 dt = ms / _st.duration;
|
||||
if (dt >= 1) {
|
||||
res = false;
|
||||
_a_placeholderShift.stop();
|
||||
a_placeholderLeft.finish();
|
||||
a_placeholderOpacity.finish();
|
||||
} else {
|
||||
a_placeholderLeft.update(dt, anim::linear);
|
||||
a_placeholderOpacity.update(dt, anim::linear);
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
if (timer) update();
|
||||
}
|
||||
|
||||
bool InputField::animStep_border(float64 ms) {
|
||||
float dt = ms / _st.duration;
|
||||
bool res = true;
|
||||
void InputField::step_border(float64 ms, bool timer) {
|
||||
float64 dt = ms / _st.duration;
|
||||
if (dt >= 1) {
|
||||
res = false;
|
||||
_a_border.stop();
|
||||
a_borderFg.finish();
|
||||
a_borderOpacityActive.finish();
|
||||
} else {
|
||||
a_borderFg.update(dt, anim::linear);
|
||||
a_borderOpacityActive.update(dt, anim::linear);
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
if (timer) update();
|
||||
}
|
||||
|
||||
void InputField::updatePlaceholder() {
|
||||
|
@ -1981,34 +1979,35 @@ void InputField::showError() {
|
|||
}
|
||||
}
|
||||
|
||||
MaskedInputField::MaskedInputField(QWidget *parent, const style::InputField &st, const QString &placeholder, const QString &val) : QLineEdit(val, parent),
|
||||
_st(st),
|
||||
_maxLength(-1),
|
||||
_oldtext(val),
|
||||
MaskedInputField::MaskedInputField(QWidget *parent, const style::InputField &st, const QString &placeholder, const QString &val) : QLineEdit(val, parent)
|
||||
, _st(st)
|
||||
, _maxLength(-1)
|
||||
, _oldtext(val)
|
||||
|
||||
_undoAvailable(false),
|
||||
_redoAvailable(false),
|
||||
, _undoAvailable(false)
|
||||
, _redoAvailable(false)
|
||||
|
||||
_customUpDown(false),
|
||||
, _customUpDown(false)
|
||||
|
||||
_placeholderFull(placeholder),
|
||||
_placeholderVisible(val.isEmpty()),
|
||||
_placeholderFast(false),
|
||||
a_placeholderLeft(_placeholderVisible ? 0 : st.placeholderShift),
|
||||
a_placeholderOpacity(_placeholderVisible ? 1 : 0),
|
||||
a_placeholderFg(st.placeholderFg->c),
|
||||
_a_placeholderFg(animFunc(this, &MaskedInputField::animStep_placeholderFg)),
|
||||
_a_placeholderShift(animFunc(this, &MaskedInputField::animStep_placeholderShift)),
|
||||
, _placeholderFull(placeholder)
|
||||
, _placeholderVisible(val.isEmpty())
|
||||
, _placeholderFast(false)
|
||||
, a_placeholderLeft(_placeholderVisible ? 0 : st.placeholderShift)
|
||||
, a_placeholderOpacity(_placeholderVisible ? 1 : 0)
|
||||
, a_placeholderFg(st.placeholderFg->c)
|
||||
, _a_placeholderFg(animation(this, &MaskedInputField::step_placeholderFg))
|
||||
, _a_placeholderShift(animation(this, &MaskedInputField::step_placeholderShift))
|
||||
|
||||
a_borderOpacityActive(0),
|
||||
a_borderFg(st.borderFg->c),
|
||||
_a_border(animFunc(this, &MaskedInputField::animStep_border)),
|
||||
, a_borderOpacityActive(0)
|
||||
, a_borderFg(st.borderFg->c)
|
||||
, _a_border(animation(this, &MaskedInputField::step_border))
|
||||
|
||||
_focused(false), _error(false),
|
||||
, _focused(false)
|
||||
, _error(false)
|
||||
|
||||
_touchPress(false),
|
||||
_touchRightButton(false),
|
||||
_touchMove(false) {
|
||||
, _touchPress(false)
|
||||
, _touchRightButton(false)
|
||||
, _touchMove(false) {
|
||||
resize(_st.width, _st.height);
|
||||
|
||||
setFont(_st.font->f);
|
||||
|
@ -2029,7 +2028,7 @@ _touchMove(false) {
|
|||
setStyle(&_inputFieldStyle);
|
||||
QLineEdit::setTextMargins(0, 0, 0, 0);
|
||||
setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
|
||||
setAttribute(Qt::WA_AcceptTouchEvents);
|
||||
_touchTimer.setSingleShot(true);
|
||||
connect(&_touchTimer, SIGNAL(timeout()), this, SLOT(onTouchTimer()));
|
||||
|
@ -2188,47 +2187,41 @@ QSize MaskedInputField::minimumSizeHint() const {
|
|||
return geometry().size();
|
||||
}
|
||||
|
||||
bool MaskedInputField::animStep_placeholderFg(float64 ms) {
|
||||
float dt = ms / _st.duration;
|
||||
bool res = true;
|
||||
void MaskedInputField::step_placeholderFg(float64 ms, bool timer) {
|
||||
float64 dt = ms / _st.duration;
|
||||
if (dt >= 1) {
|
||||
res = false;
|
||||
_a_placeholderFg.stop();
|
||||
a_placeholderFg.finish();
|
||||
} else {
|
||||
a_placeholderFg.update(dt, anim::linear);
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
if (timer) update();
|
||||
}
|
||||
|
||||
bool MaskedInputField::animStep_placeholderShift(float64 ms) {
|
||||
float dt = ms / _st.duration;
|
||||
bool res = true;
|
||||
void MaskedInputField::step_placeholderShift(float64 ms, bool timer) {
|
||||
float64 dt = ms / _st.duration;
|
||||
if (dt >= 1) {
|
||||
res = false;
|
||||
_a_placeholderShift.stop();
|
||||
a_placeholderLeft.finish();
|
||||
a_placeholderOpacity.finish();
|
||||
} else {
|
||||
a_placeholderLeft.update(dt, anim::linear);
|
||||
a_placeholderOpacity.update(dt, anim::linear);
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
if (timer) update();
|
||||
}
|
||||
|
||||
bool MaskedInputField::animStep_border(float64 ms) {
|
||||
float dt = ms / _st.duration;
|
||||
bool res = true;
|
||||
void MaskedInputField::step_border(float64 ms, bool timer) {
|
||||
float64 dt = ms / _st.duration;
|
||||
if (dt >= 1) {
|
||||
res = false;
|
||||
_a_border.stop();
|
||||
a_borderFg.finish();
|
||||
a_borderOpacityActive.finish();
|
||||
} else {
|
||||
a_borderFg.update(dt, anim::linear);
|
||||
a_borderOpacityActive.update(dt, anim::linear);
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
if (timer) update();
|
||||
}
|
||||
|
||||
bool MaskedInputField::setPlaceholder(const QString &placeholder) {
|
||||
|
|
|
@ -23,7 +23,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
#include "style.h"
|
||||
#include "animation.h"
|
||||
|
||||
class FlatInput : public QLineEdit, public Animated {
|
||||
class FlatInput : public QLineEdit {
|
||||
Q_OBJECT
|
||||
T_WIDGET
|
||||
|
||||
|
@ -50,7 +50,7 @@ public:
|
|||
|
||||
QRect getTextRect() const;
|
||||
|
||||
bool animStep(float64 ms);
|
||||
void step_appearance(float64 ms, bool timer);
|
||||
|
||||
QSize sizeHint() const;
|
||||
QSize minimumSizeHint() const;
|
||||
|
@ -98,6 +98,7 @@ private:
|
|||
anim::ivalue a_phLeft;
|
||||
anim::fvalue a_phAlpha;
|
||||
anim::cvalue a_phColor, a_borderColor, a_bgColor;
|
||||
Animation _a_appearance;
|
||||
|
||||
int _notingBene;
|
||||
style::flatInput _st;
|
||||
|
@ -196,9 +197,9 @@ public:
|
|||
}
|
||||
void updatePlaceholder();
|
||||
|
||||
bool animStep_placeholderFg(float64 ms);
|
||||
bool animStep_placeholderShift(float64 ms);
|
||||
bool animStep_border(float64 ms);
|
||||
void step_placeholderFg(float64 ms, bool timer);
|
||||
void step_placeholderShift(float64 ms, bool timer);
|
||||
void step_border(float64 ms, bool timer);
|
||||
|
||||
QSize sizeHint() const;
|
||||
QSize minimumSizeHint() const;
|
||||
|
@ -354,9 +355,9 @@ public:
|
|||
}
|
||||
void updatePlaceholder();
|
||||
|
||||
bool animStep_placeholderFg(float64 ms);
|
||||
bool animStep_placeholderShift(float64 ms);
|
||||
bool animStep_border(float64 ms);
|
||||
void step_placeholderFg(float64 ms, bool timer);
|
||||
void step_placeholderShift(float64 ms, bool timer);
|
||||
void step_border(float64 ms, bool timer);
|
||||
|
||||
QSize sizeHint() const;
|
||||
QSize minimumSizeHint() const;
|
||||
|
@ -523,9 +524,9 @@ public:
|
|||
|
||||
QRect getTextRect() const;
|
||||
|
||||
bool animStep_placeholderFg(float64 ms);
|
||||
bool animStep_placeholderShift(float64 ms);
|
||||
bool animStep_border(float64 ms);
|
||||
void step_placeholderFg(float64 ms, bool timer);
|
||||
void step_placeholderShift(float64 ms, bool timer);
|
||||
void step_border(float64 ms, bool timer);
|
||||
|
||||
QSize sizeHint() const;
|
||||
QSize minimumSizeHint() const;
|
||||
|
|
|
@ -24,18 +24,34 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
#include "flattextarea.h"
|
||||
#include "window.h"
|
||||
|
||||
FlatTextarea::FlatTextarea(QWidget *parent, const style::flatTextarea &st, const QString &pholder, const QString &v) : QTextEdit(parent),
|
||||
_minHeight(-1), _maxHeight(-1), _maxLength(-1), _ctrlEnterSubmit(true),
|
||||
_oldtext(v), _phVisible(!v.length()),
|
||||
a_phLeft(_phVisible ? 0 : st.phShift), a_phAlpha(_phVisible ? 1 : 0), a_phColor(st.phColor->c),
|
||||
_st(st), _undoAvailable(false), _redoAvailable(false), _inDrop(false), _inHeightCheck(false), _fakeMargin(0),
|
||||
_touchPress(false), _touchRightButton(false), _touchMove(false), _correcting(false) {
|
||||
FlatTextarea::FlatTextarea(QWidget *parent, const style::flatTextarea &st, const QString &pholder, const QString &v) : QTextEdit(parent)
|
||||
, _minHeight(-1)
|
||||
, _maxHeight(-1)
|
||||
, _maxLength(-1)
|
||||
, _ctrlEnterSubmit(true)
|
||||
, _oldtext(v)
|
||||
, _phAfter(0)
|
||||
, _phVisible(!v.length())
|
||||
, a_phLeft(_phVisible ? 0 : st.phShift)
|
||||
, a_phAlpha(_phVisible ? 1 : 0)
|
||||
, a_phColor(st.phColor->c)
|
||||
, _a_appearance(animation(this, &FlatTextarea::step_appearance))
|
||||
, _st(st)
|
||||
, _undoAvailable(false)
|
||||
, _redoAvailable(false)
|
||||
, _inDrop(false)
|
||||
, _inHeightCheck(false)
|
||||
, _fakeMargin(0)
|
||||
, _touchPress(false)
|
||||
, _touchRightButton(false)
|
||||
, _touchMove(false)
|
||||
, _correcting(false) {
|
||||
setAcceptRichText(false);
|
||||
resize(_st.width, _st.font->height);
|
||||
|
||||
|
||||
setFont(_st.font->f);
|
||||
setAlignment(_st.align);
|
||||
|
||||
|
||||
setPlaceholder(pholder);
|
||||
|
||||
QPalette p(palette());
|
||||
|
@ -72,12 +88,25 @@ _touchPress(false), _touchRightButton(false), _touchMove(false), _correcting(fal
|
|||
}
|
||||
}
|
||||
|
||||
void FlatTextarea::setTextFast(const QString &text) {
|
||||
setPlainText(text);
|
||||
if (animating()) {
|
||||
void FlatTextarea::setTextFast(const QString &text, bool clearUndoHistory) {
|
||||
if (clearUndoHistory) {
|
||||
setPlainText(text);
|
||||
} else {
|
||||
QTextCursor c(document()->docHandle(), 0);
|
||||
c.joinPreviousEditBlock();
|
||||
c.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
|
||||
c.insertText(text);
|
||||
c.movePosition(QTextCursor::End);
|
||||
c.endEditBlock();
|
||||
}
|
||||
finishPlaceholder();
|
||||
}
|
||||
|
||||
void FlatTextarea::finishPlaceholder() {
|
||||
if (_a_appearance.animating()) {
|
||||
a_phLeft.finish();
|
||||
a_phAlpha.finish();
|
||||
anim::stop(this);
|
||||
_a_appearance.stop();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
@ -184,17 +213,21 @@ void FlatTextarea::paintEvent(QPaintEvent *e) {
|
|||
QRect r(rect().intersected(e->rect()));
|
||||
p.fillRect(r, _st.bgColor->b);
|
||||
bool phDraw = _phVisible;
|
||||
if (animating()) {
|
||||
if (_a_appearance.animating()) {
|
||||
p.setOpacity(a_phAlpha.current());
|
||||
phDraw = true;
|
||||
}
|
||||
if (phDraw) {
|
||||
p.save();
|
||||
p.setClipRect(r);
|
||||
QRect phRect(_st.textMrg.left() - _fakeMargin + _st.phPos.x() + a_phLeft.current(), _st.textMrg.top() - _fakeMargin + _st.phPos.y(), width() - _st.textMrg.left() - _st.textMrg.right(), height() - _st.textMrg.top() - _st.textMrg.bottom());
|
||||
p.setFont(_st.font->f);
|
||||
p.setFont(_st.font);
|
||||
p.setPen(a_phColor.current());
|
||||
p.drawText(phRect, _ph, QTextOption(_st.phAlign));
|
||||
if (_st.phAlign == style::al_topleft && _phAfter > 0) {
|
||||
p.drawText(_st.textMrg.left() - _fakeMargin + a_phLeft.current() + _st.font->width(getLastText().mid(0, _phAfter)), _st.textMrg.top() - _fakeMargin - st::lineWidth + _st.font->ascent, _ph);
|
||||
} else {
|
||||
QRect phRect(_st.textMrg.left() - _fakeMargin + _st.phPos.x() + a_phLeft.current(), _st.textMrg.top() - _fakeMargin + _st.phPos.y(), width() - _st.textMrg.left() - _st.textMrg.right(), height() - _st.textMrg.top() - _st.textMrg.bottom());
|
||||
p.drawText(phRect, _ph, QTextOption(_st.phAlign));
|
||||
}
|
||||
p.restore();
|
||||
p.setOpacity(1);
|
||||
}
|
||||
|
@ -203,13 +236,13 @@ void FlatTextarea::paintEvent(QPaintEvent *e) {
|
|||
|
||||
void FlatTextarea::focusInEvent(QFocusEvent *e) {
|
||||
a_phColor.start(_st.phFocusColor->c);
|
||||
anim::start(this);
|
||||
_a_appearance.start();
|
||||
QTextEdit::focusInEvent(e);
|
||||
}
|
||||
|
||||
void FlatTextarea::focusOutEvent(QFocusEvent *e) {
|
||||
a_phColor.start(_st.phColor->c);
|
||||
anim::start(this);
|
||||
_a_appearance.start();
|
||||
QTextEdit::focusOutEvent(e);
|
||||
}
|
||||
|
||||
|
@ -226,7 +259,7 @@ EmojiPtr FlatTextarea::getSingleEmoji() const {
|
|||
QTextFragment fragment;
|
||||
|
||||
getSingleEmojiFragment(text, fragment);
|
||||
|
||||
|
||||
if (!text.isEmpty()) {
|
||||
QTextCharFormat format = fragment.charFormat();
|
||||
QString imageName = static_cast<QTextImageFormat*>(&format)->name();
|
||||
|
@ -237,10 +270,62 @@ EmojiPtr FlatTextarea::getSingleEmoji() const {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void FlatTextarea::getMentionHashtagBotCommandStart(QString &start) const {
|
||||
int32 pos = textCursor().position();
|
||||
if (textCursor().anchor() != pos) return;
|
||||
QString FlatTextarea::getInlineBotQuery(UserData *&inlineBot, QString &inlineBotUsername) const {
|
||||
const QString &text(getLastText());
|
||||
|
||||
int32 inlineUsernameStart = 1, inlineUsernameLength = 0, size = text.size();
|
||||
if (size > 2 && text.at(0) == '@' && text.at(1).isLetter()) {
|
||||
inlineUsernameLength = 1;
|
||||
for (int32 i = inlineUsernameStart + 1, l = text.size(); i < l; ++i) {
|
||||
if (text.at(i).isLetterOrNumber() || text.at(i).unicode() == '_') {
|
||||
++inlineUsernameLength;
|
||||
continue;
|
||||
}
|
||||
if (!text.at(i).isSpace()) {
|
||||
inlineUsernameLength = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (inlineUsernameLength && inlineUsernameStart + inlineUsernameLength < text.size() && text.at(inlineUsernameStart + inlineUsernameLength).isSpace()) {
|
||||
QStringRef username = text.midRef(inlineUsernameStart, inlineUsernameLength);
|
||||
if (username != inlineBotUsername) {
|
||||
inlineBotUsername = username.toString();
|
||||
PeerData *peer = App::peerByName(inlineBotUsername);
|
||||
if (peer) {
|
||||
if (peer->isUser()) {
|
||||
inlineBot = peer->asUser();
|
||||
} else {
|
||||
inlineBot = 0;
|
||||
}
|
||||
} else {
|
||||
inlineBot = InlineBotLookingUpData;
|
||||
}
|
||||
}
|
||||
if (inlineBot == InlineBotLookingUpData) return QString();
|
||||
|
||||
if (inlineBot && (!inlineBot->botInfo || inlineBot->botInfo->inlinePlaceholder.isEmpty())) {
|
||||
inlineBot = 0;
|
||||
} else {
|
||||
return text.mid(inlineUsernameStart + inlineUsernameLength + 1);
|
||||
}
|
||||
} else {
|
||||
inlineUsernameLength = 0;
|
||||
}
|
||||
}
|
||||
if (inlineUsernameLength < 3) {
|
||||
inlineBot = 0;
|
||||
inlineBotUsername = QString();
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString FlatTextarea::getMentionHashtagBotCommandPart(bool &start) const {
|
||||
start = false;
|
||||
|
||||
int32 pos = textCursor().position();
|
||||
if (textCursor().anchor() != pos) return QString();
|
||||
|
||||
// check mention / hashtag / bot command
|
||||
QTextDocument *doc(document());
|
||||
QTextBlock block = doc->findBlock(pos);
|
||||
for (QTextBlock::Iterator iter = block.begin(); !iter.atEnd(); ++iter) {
|
||||
|
@ -258,29 +343,33 @@ void FlatTextarea::getMentionHashtagBotCommandStart(QString &start) const {
|
|||
for (int i = pos - p; i > 0; --i) {
|
||||
if (t.at(i - 1) == '@') {
|
||||
if ((pos - p - i < 1 || t.at(i).isLetter()) && (i < 2 || !(t.at(i - 2).isLetterOrNumber() || t.at(i - 2) == '_'))) {
|
||||
start = t.mid(i - 1, pos - p - i + 1);
|
||||
start = (i == 1) && (p == 0);
|
||||
return t.mid(i - 1, pos - p - i + 1);
|
||||
} else if ((pos - p - i < 1 || t.at(i).isLetter()) && i > 2 && (t.at(i - 2).isLetterOrNumber() || t.at(i - 2) == '_') && !mentionInCommand) {
|
||||
mentionInCommand = true;
|
||||
--i;
|
||||
continue;
|
||||
}
|
||||
return;
|
||||
return QString();
|
||||
} else if (t.at(i - 1) == '#') {
|
||||
if (i < 2 || !(t.at(i - 2).isLetterOrNumber() || t.at(i - 2) == '_')) {
|
||||
start = t.mid(i - 1, pos - p - i + 1);
|
||||
start = (i == 1) && (p == 0);
|
||||
return t.mid(i - 1, pos - p - i + 1);
|
||||
}
|
||||
return;
|
||||
return QString();
|
||||
} else if (t.at(i - 1) == '/') {
|
||||
if (i < 2) {
|
||||
start = t.mid(i - 1, pos - p - i + 1);
|
||||
start = (i == 1) && (p == 0);
|
||||
return t.mid(i - 1, pos - p - i + 1);
|
||||
}
|
||||
return;
|
||||
return QString();
|
||||
}
|
||||
if (pos - p - i > 127 || (!mentionInCommand && (pos - p - i > 63))) break;
|
||||
if (!t.at(i - 1).isLetterOrNumber() && t.at(i - 1) != '_') break;
|
||||
}
|
||||
return;
|
||||
break;
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
void FlatTextarea::onMentionHashtagOrBotCommandInsert(QString str) {
|
||||
|
@ -649,7 +738,7 @@ void FlatTextarea::processDocumentContentsChange(int position, int charsAdded) {
|
|||
const QChar *ch = t.constData(), *e = ch + t.size();
|
||||
for (; ch != e; ++ch, ++fp) {
|
||||
int32 emojiLen = 0;
|
||||
emoji = emojiFromText(ch, e, emojiLen);
|
||||
emoji = emojiFromText(ch, e, &emojiLen);
|
||||
if (emoji) {
|
||||
if (replacePosition >= 0) {
|
||||
emoji = 0; // replace tilde char format first
|
||||
|
@ -701,7 +790,7 @@ void FlatTextarea::processDocumentContentsChange(int position, int charsAdded) {
|
|||
|
||||
emoji = 0;
|
||||
replacePosition = -1;
|
||||
} else {
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -807,11 +896,10 @@ void FlatTextarea::onRedoAvailable(bool avail) {
|
|||
if (App::wnd()) App::wnd()->updateGlobalMenu();
|
||||
}
|
||||
|
||||
bool FlatTextarea::animStep(float64 ms) {
|
||||
void FlatTextarea::step_appearance(float64 ms, bool timer) {
|
||||
float dt = ms / _st.phDuration;
|
||||
bool res = true;
|
||||
if (dt >= 1) {
|
||||
res = false;
|
||||
_a_appearance.stop();
|
||||
a_phLeft.finish();
|
||||
a_phAlpha.finish();
|
||||
a_phColor.finish();
|
||||
|
@ -823,23 +911,26 @@ bool FlatTextarea::animStep(float64 ms) {
|
|||
a_phAlpha.update(dt, _st.phAlphaFunc);
|
||||
a_phColor.update(dt, _st.phColorFunc);
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
if (timer) update();
|
||||
}
|
||||
|
||||
void FlatTextarea::setPlaceholder(const QString &ph) {
|
||||
void FlatTextarea::setPlaceholder(const QString &ph, int32 afterSymbols) {
|
||||
_ph = ph;
|
||||
_phelided = _st.font->elided(_ph, width() - _st.textMrg.left() - _st.textMrg.right() - _st.phPos.x() - 1);
|
||||
if (_phAfter != afterSymbols) {
|
||||
_phAfter = afterSymbols;
|
||||
updatePlaceholder();
|
||||
}
|
||||
_phelided = _st.font->elided(_ph, width() - _st.textMrg.left() - _st.textMrg.right() - _st.phPos.x() - 1 - (_phAfter ? _st.font->width(getLastText().mid(0, _phAfter)) : 0));
|
||||
if (_phVisible) update();
|
||||
}
|
||||
|
||||
void FlatTextarea::updatePlaceholder() {
|
||||
bool vis = getLastText().isEmpty();
|
||||
bool vis = (getLastText().size() <= _phAfter);
|
||||
if (vis == _phVisible) return;
|
||||
|
||||
a_phLeft.start(vis ? 0 : _st.phShift);
|
||||
a_phAlpha.start(vis ? 1 : 0);
|
||||
anim::start(this);
|
||||
_a_appearance.start();
|
||||
|
||||
_phVisible = vis;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,8 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
#include "style.h"
|
||||
#include "animation.h"
|
||||
|
||||
class FlatTextarea : public QTextEdit, public Animated {
|
||||
class UserData;
|
||||
class FlatTextarea : public QTextEdit {
|
||||
Q_OBJECT
|
||||
T_WIDGET
|
||||
|
||||
|
@ -50,19 +51,21 @@ public:
|
|||
const QString &getLastText() const {
|
||||
return _oldtext;
|
||||
}
|
||||
void setPlaceholder(const QString &ph);
|
||||
void setPlaceholder(const QString &ph, int32 afterSymbols = 0);
|
||||
void updatePlaceholder();
|
||||
void finishPlaceholder();
|
||||
|
||||
QRect getTextRect() const;
|
||||
int32 fakeMargin() const;
|
||||
|
||||
bool animStep(float64 ms);
|
||||
void step_appearance(float64 ms, bool timer);
|
||||
|
||||
QSize sizeHint() const;
|
||||
QSize minimumSizeHint() const;
|
||||
|
||||
EmojiPtr getSingleEmoji() const;
|
||||
void getMentionHashtagBotCommandStart(QString &start) const;
|
||||
QString getMentionHashtagBotCommandPart(bool &start) const;
|
||||
QString getInlineBotQuery(UserData *&contextBot, QString &contextBotUsername) const;
|
||||
void removeSingleEmoji();
|
||||
bool hasText() const;
|
||||
|
||||
|
@ -77,7 +80,7 @@ public:
|
|||
QMimeData *createMimeDataFromSelection() const;
|
||||
void setCtrlEnterSubmit(bool ctrlEnterSubmit);
|
||||
|
||||
void setTextFast(const QString &text);
|
||||
void setTextFast(const QString &text, bool clearUndoHistory = true);
|
||||
|
||||
public slots:
|
||||
|
||||
|
@ -123,10 +126,13 @@ private:
|
|||
bool _ctrlEnterSubmit;
|
||||
|
||||
QString _ph, _phelided, _oldtext;
|
||||
int32 _phAfter;
|
||||
bool _phVisible;
|
||||
anim::ivalue a_phLeft;
|
||||
anim::fvalue a_phAlpha;
|
||||
anim::cvalue a_phColor;
|
||||
Animation _a_appearance;
|
||||
|
||||
style::flatTextarea _st;
|
||||
|
||||
bool _undoAvailable, _redoAvailable, _inDrop, _inHeightCheck;
|
||||
|
|
|
@ -27,9 +27,12 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
#include "pspecific.h"
|
||||
|
||||
namespace {
|
||||
typedef QMap<QString, LocalImage*> LocalImages;
|
||||
typedef QMap<QString, Image*> LocalImages;
|
||||
LocalImages localImages;
|
||||
|
||||
typedef QMap<QString, Image*> WebImages;
|
||||
WebImages webImages;
|
||||
|
||||
Image *blank() {
|
||||
static Image *img = getImage(qsl(":/gui/art/blank.gif"), "GIF");
|
||||
return img;
|
||||
|
@ -38,7 +41,7 @@ namespace {
|
|||
typedef QMap<StorageKey, StorageImage*> StorageImages;
|
||||
StorageImages storageImages;
|
||||
|
||||
int64 globalAquiredSize = 0;
|
||||
int64 globalAcquiredSize = 0;
|
||||
|
||||
static const uint64 BlurredCacheSkip = 0x1000000000000000LLU;
|
||||
static const uint64 ColoredCacheSkip = 0x2000000000000000LLU;
|
||||
|
@ -46,6 +49,8 @@ namespace {
|
|||
static const uint64 RoundedCacheSkip = 0x4000000000000000LLU;
|
||||
}
|
||||
|
||||
StorageImageLocation StorageImageLocation::Null;
|
||||
|
||||
bool Image::isNull() const {
|
||||
return (this == blank());
|
||||
}
|
||||
|
@ -57,8 +62,39 @@ ImagePtr::ImagePtr(int32 width, int32 height, const MTPFileLocation &location, I
|
|||
Parent((location.type() == mtpc_fileLocation) ? (Image*)(getImage(StorageImageLocation(width, height, location.c_fileLocation()))) : def.v()) {
|
||||
}
|
||||
|
||||
Image::Image(const QString &file, QByteArray fmt) : _forgot(false) {
|
||||
_data = QPixmap::fromImage(App::readImage(file, &fmt, false, 0, &_saved), Qt::ColorOnly);
|
||||
_format = fmt;
|
||||
if (!_data.isNull()) {
|
||||
globalAcquiredSize += int64(_data.width()) * _data.height() * 4;
|
||||
}
|
||||
}
|
||||
|
||||
Image::Image(const QByteArray &filecontent, QByteArray fmt) : _forgot(false) {
|
||||
_data = QPixmap::fromImage(App::readImage(filecontent, &fmt, false), Qt::ColorOnly);
|
||||
_format = fmt;
|
||||
_saved = filecontent;
|
||||
if (!_data.isNull()) {
|
||||
globalAcquiredSize += int64(_data.width()) * _data.height() * 4;
|
||||
}
|
||||
}
|
||||
|
||||
Image::Image(const QPixmap &pixmap, QByteArray format) : _format(format), _forgot(false), _data(pixmap) {
|
||||
if (!_data.isNull()) {
|
||||
globalAcquiredSize += int64(_data.width()) * _data.height() * 4;
|
||||
}
|
||||
}
|
||||
|
||||
Image::Image(const QByteArray &filecontent, QByteArray fmt, const QPixmap &pixmap) : _saved(filecontent), _format(fmt), _forgot(false), _data(pixmap) {
|
||||
_data = pixmap;
|
||||
_format = fmt;
|
||||
_saved = filecontent;
|
||||
if (!_data.isNull()) {
|
||||
globalAcquiredSize += int64(_data.width()) * _data.height() * 4;
|
||||
}
|
||||
}
|
||||
|
||||
const QPixmap &Image::pix(int32 w, int32 h) const {
|
||||
restore();
|
||||
checkload();
|
||||
|
||||
if (w <= 0 || !width() || !height()) {
|
||||
|
@ -74,14 +110,13 @@ const QPixmap &Image::pix(int32 w, int32 h) const {
|
|||
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
|
||||
i = _sizesCache.insert(k, p);
|
||||
if (!p.isNull()) {
|
||||
globalAquiredSize += int64(p.width()) * p.height() * 4;
|
||||
globalAcquiredSize += int64(p.width()) * p.height() * 4;
|
||||
}
|
||||
}
|
||||
return i.value();
|
||||
}
|
||||
|
||||
const QPixmap &Image::pixRounded(int32 w, int32 h) const {
|
||||
restore();
|
||||
checkload();
|
||||
|
||||
if (w <= 0 || !width() || !height()) {
|
||||
|
@ -97,14 +132,13 @@ const QPixmap &Image::pixRounded(int32 w, int32 h) const {
|
|||
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
|
||||
i = _sizesCache.insert(k, p);
|
||||
if (!p.isNull()) {
|
||||
globalAquiredSize += int64(p.width()) * p.height() * 4;
|
||||
globalAcquiredSize += int64(p.width()) * p.height() * 4;
|
||||
}
|
||||
}
|
||||
return i.value();
|
||||
}
|
||||
|
||||
const QPixmap &Image::pixBlurred(int32 w, int32 h) const {
|
||||
restore();
|
||||
checkload();
|
||||
|
||||
if (w <= 0 || !width() || !height()) {
|
||||
|
@ -120,14 +154,13 @@ const QPixmap &Image::pixBlurred(int32 w, int32 h) const {
|
|||
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
|
||||
i = _sizesCache.insert(k, p);
|
||||
if (!p.isNull()) {
|
||||
globalAquiredSize += int64(p.width()) * p.height() * 4;
|
||||
globalAcquiredSize += int64(p.width()) * p.height() * 4;
|
||||
}
|
||||
}
|
||||
return i.value();
|
||||
}
|
||||
|
||||
const QPixmap &Image::pixColored(const style::color &add, int32 w, int32 h) const {
|
||||
restore();
|
||||
checkload();
|
||||
|
||||
if (w <= 0 || !width() || !height()) {
|
||||
|
@ -143,14 +176,13 @@ const QPixmap &Image::pixColored(const style::color &add, int32 w, int32 h) cons
|
|||
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
|
||||
i = _sizesCache.insert(k, p);
|
||||
if (!p.isNull()) {
|
||||
globalAquiredSize += int64(p.width()) * p.height() * 4;
|
||||
globalAcquiredSize += int64(p.width()) * p.height() * 4;
|
||||
}
|
||||
}
|
||||
return i.value();
|
||||
}
|
||||
|
||||
const QPixmap &Image::pixBlurredColored(const style::color &add, int32 w, int32 h) const {
|
||||
restore();
|
||||
checkload();
|
||||
|
||||
if (w <= 0 || !width() || !height()) {
|
||||
|
@ -166,14 +198,13 @@ const QPixmap &Image::pixBlurredColored(const style::color &add, int32 w, int32
|
|||
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
|
||||
i = _sizesCache.insert(k, p);
|
||||
if (!p.isNull()) {
|
||||
globalAquiredSize += int64(p.width()) * p.height() * 4;
|
||||
globalAcquiredSize += int64(p.width()) * p.height() * 4;
|
||||
}
|
||||
}
|
||||
return i.value();
|
||||
}
|
||||
|
||||
const QPixmap &Image::pixSingle(int32 w, int32 h, int32 outerw, int32 outerh) const {
|
||||
restore();
|
||||
checkload();
|
||||
|
||||
if (w <= 0 || !width() || !height()) {
|
||||
|
@ -184,22 +215,21 @@ const QPixmap &Image::pixSingle(int32 w, int32 h, int32 outerw, int32 outerh) co
|
|||
}
|
||||
uint64 k = 0LL;
|
||||
Sizes::const_iterator i = _sizesCache.constFind(k);
|
||||
if (i == _sizesCache.cend() || i->width() != w || (h && i->height() != h)) {
|
||||
if (i == _sizesCache.cend() || i->width() != (outerw * cIntRetinaFactor()) || i->height() != (outerh * cIntRetinaFactor())) {
|
||||
if (i != _sizesCache.cend()) {
|
||||
globalAquiredSize -= int64(i->width()) * i->height() * 4;
|
||||
globalAcquiredSize -= int64(i->width()) * i->height() * 4;
|
||||
}
|
||||
QPixmap p(pixNoCache(w, h, true, false, true, outerw, outerh));
|
||||
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
|
||||
i = _sizesCache.insert(k, p);
|
||||
if (!p.isNull()) {
|
||||
globalAquiredSize += int64(p.width()) * p.height() * 4;
|
||||
globalAcquiredSize += int64(p.width()) * p.height() * 4;
|
||||
}
|
||||
}
|
||||
return i.value();
|
||||
}
|
||||
|
||||
const QPixmap &Image::pixBlurredSingle(int32 w, int32 h, int32 outerw, int32 outerh) const {
|
||||
restore();
|
||||
checkload();
|
||||
|
||||
if (w <= 0 || !width() || !height()) {
|
||||
|
@ -210,15 +240,15 @@ const QPixmap &Image::pixBlurredSingle(int32 w, int32 h, int32 outerw, int32 out
|
|||
}
|
||||
uint64 k = BlurredCacheSkip | 0LL;
|
||||
Sizes::const_iterator i = _sizesCache.constFind(k);
|
||||
if (i == _sizesCache.cend() || i->width() != w || (h && i->height() != h)) {
|
||||
if (i == _sizesCache.cend() || i->width() != (outerw * cIntRetinaFactor()) || i->height() != (outerh * cIntRetinaFactor())) {
|
||||
if (i != _sizesCache.cend()) {
|
||||
globalAquiredSize -= int64(i->width()) * i->height() * 4;
|
||||
globalAcquiredSize -= int64(i->width()) * i->height() * 4;
|
||||
}
|
||||
QPixmap p(pixNoCache(w, h, true, true, true, outerw, outerh));
|
||||
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
|
||||
i = _sizesCache.insert(k, p);
|
||||
if (!p.isNull()) {
|
||||
globalAquiredSize += int64(p.width()) * p.height() * 4;
|
||||
globalAcquiredSize += int64(p.width()) * p.height() * 4;
|
||||
}
|
||||
}
|
||||
return i.value();
|
||||
|
@ -335,7 +365,7 @@ yi += stride;
|
|||
|
||||
#undef update
|
||||
}
|
||||
|
||||
|
||||
delete[] rgb;
|
||||
}
|
||||
}
|
||||
|
@ -396,16 +426,9 @@ QImage imageColored(const style::color &add, QImage img) {
|
|||
return img;
|
||||
}
|
||||
|
||||
QPixmap Image::pixNoCache(int32 w, int32 h, bool smooth, bool blurred, bool rounded, int32 outerw, int32 outerh) const {
|
||||
restore();
|
||||
loaded();
|
||||
|
||||
const QPixmap &p(pixData());
|
||||
if (p.isNull()) return blank()->pix();
|
||||
|
||||
QImage img = p.toImage();
|
||||
QPixmap imagePix(QImage img, int32 w, int32 h, bool smooth, bool blurred, bool rounded, int32 outerw, int32 outerh) {
|
||||
if (blurred) img = imageBlur(img);
|
||||
if (w <= 0 || !width() || !height() || (w == width() && (h <= 0 || h == height()))) {
|
||||
if (w <= 0 || (w == img.width() && (h <= 0 || h == img.height()))) {
|
||||
} else if (h <= 0) {
|
||||
img = img.scaledToWidth(w, smooth ? Qt::SmoothTransformation : Qt::FastTransformation);
|
||||
} else {
|
||||
|
@ -421,7 +444,7 @@ QPixmap Image::pixNoCache(int32 w, int32 h, bool smooth, bool blurred, bool roun
|
|||
{
|
||||
QPainter p(&result);
|
||||
if (w < outerw || h < outerh) {
|
||||
p.fillRect(0, 0, result.width(), result.height(), st::black->b);
|
||||
p.fillRect(0, 0, result.width(), result.height(), st::black);
|
||||
}
|
||||
p.drawImage((result.width() - img.width()) / (2 * cIntRetinaFactor()), (result.height() - img.height()) / (2 * cIntRetinaFactor()), img);
|
||||
}
|
||||
|
@ -429,32 +452,65 @@ QPixmap Image::pixNoCache(int32 w, int32 h, bool smooth, bool blurred, bool roun
|
|||
}
|
||||
}
|
||||
if (rounded) imageRound(img);
|
||||
img.setDevicePixelRatio(cRetinaFactor());
|
||||
return QPixmap::fromImage(img, Qt::ColorOnly);
|
||||
}
|
||||
|
||||
QPixmap Image::pixColoredNoCache(const style::color &add, int32 w, int32 h, bool smooth) const {
|
||||
QPixmap Image::pixNoCache(int32 w, int32 h, bool smooth, bool blurred, bool rounded, int32 outerw, int32 outerh) const {
|
||||
if (!loading()) const_cast<Image*>(this)->load();
|
||||
restore();
|
||||
loaded();
|
||||
if (_data.isNull()) {
|
||||
if (h <= 0 && height() > 0) {
|
||||
h = qRound(width() * w / float64(height()));
|
||||
}
|
||||
return blank()->pixNoCache(w, h, smooth, blurred, rounded, outerw, outerh);
|
||||
}
|
||||
|
||||
const QPixmap &p(pixData());
|
||||
if (p.isNull()) {
|
||||
return blank()->pix();
|
||||
if (isNull() && outerw > 0 && outerh > 0) {
|
||||
outerw *= cIntRetinaFactor();
|
||||
outerh *= cIntRetinaFactor();
|
||||
|
||||
QImage result(outerw, outerh, QImage::Format_ARGB32_Premultiplied);
|
||||
result.setDevicePixelRatio(cRetinaFactor());
|
||||
|
||||
{
|
||||
QPainter p(&result);
|
||||
if (w < outerw) {
|
||||
p.fillRect(0, 0, (outerw - w) / 2, result.height(), st::black);
|
||||
p.fillRect(((outerw - w) / 2) + w, 0, result.width() - (((outerw - w) / 2) + w), result.height(), st::black);
|
||||
}
|
||||
if (h < outerh) {
|
||||
p.fillRect(qMax(0, (outerw - w) / 2), 0, qMin(result.width(), w), (outerh - h) / 2, st::black);
|
||||
p.fillRect(qMax(0, (outerw - w) / 2), ((outerh - h) / 2) + h, qMin(result.width(), w), result.height() - (((outerh - h) / 2) + h), st::black);
|
||||
}
|
||||
p.fillRect(qMax(0, (outerw - w) / 2), qMax(0, (outerh - h) / 2), qMin(result.width(), w), qMin(result.height(), h), st::white);
|
||||
}
|
||||
|
||||
if (rounded) imageRound(result);
|
||||
return QPixmap::fromImage(result, Qt::ColorOnly);
|
||||
}
|
||||
if (w <= 0 || !width() || !height() || (w == width() && (h <= 0 || h == height()))) return QPixmap::fromImage(imageColored(add, p.toImage()));
|
||||
return imagePix(_data.toImage(), w, h, smooth, blurred, rounded, outerw, outerh);
|
||||
}
|
||||
|
||||
QPixmap Image::pixColoredNoCache(const style::color &add, int32 w, int32 h, bool smooth) const {
|
||||
const_cast<Image*>(this)->load();
|
||||
restore();
|
||||
if (_data.isNull()) return blank()->pix();
|
||||
|
||||
QImage img = _data.toImage();
|
||||
if (w <= 0 || !width() || !height() || (w == width() && (h <= 0 || h == height()))) return QPixmap::fromImage(imageColored(add, img));
|
||||
if (h <= 0) {
|
||||
return QPixmap::fromImage(imageColored(add, p.toImage().scaledToWidth(w, smooth ? Qt::SmoothTransformation : Qt::FastTransformation)), Qt::ColorOnly);
|
||||
return QPixmap::fromImage(imageColored(add, img.scaledToWidth(w, smooth ? Qt::SmoothTransformation : Qt::FastTransformation)), Qt::ColorOnly);
|
||||
}
|
||||
return QPixmap::fromImage(imageColored(add, p.toImage().scaled(w, h, Qt::IgnoreAspectRatio, smooth ? Qt::SmoothTransformation : Qt::FastTransformation)), Qt::ColorOnly);
|
||||
return QPixmap::fromImage(imageColored(add, img.scaled(w, h, Qt::IgnoreAspectRatio, smooth ? Qt::SmoothTransformation : Qt::FastTransformation)), Qt::ColorOnly);
|
||||
}
|
||||
|
||||
QPixmap Image::pixBlurredColoredNoCache(const style::color &add, int32 w, int32 h) const {
|
||||
const_cast<Image*>(this)->load();
|
||||
restore();
|
||||
loaded();
|
||||
if (_data.isNull()) return blank()->pix();
|
||||
|
||||
const QPixmap &p(pixData());
|
||||
if (p.isNull()) return blank()->pix();
|
||||
|
||||
QImage img = imageBlur(p.toImage());
|
||||
QImage img = imageBlur(_data.toImage());
|
||||
if (h <= 0) {
|
||||
img = img.scaledToWidth(w, Qt::SmoothTransformation);
|
||||
} else {
|
||||
|
@ -465,121 +521,91 @@ QPixmap Image::pixBlurredColoredNoCache(const style::color &add, int32 w, int32
|
|||
}
|
||||
|
||||
void Image::forget() const {
|
||||
if (forgot) return;
|
||||
if (_forgot) return;
|
||||
|
||||
const QPixmap &p(pixData());
|
||||
if (p.isNull()) return;
|
||||
if (_data.isNull()) return;
|
||||
|
||||
invalidateSizeCache();
|
||||
if (saved.isEmpty()) {
|
||||
QBuffer buffer(&saved);
|
||||
if (format.toLower() == "webp") {
|
||||
int a = 0;
|
||||
}
|
||||
if (!p.save(&buffer, format)) {
|
||||
if (p.save(&buffer, "PNG")) {
|
||||
format = "PNG";
|
||||
if (_saved.isEmpty()) {
|
||||
QBuffer buffer(&_saved);
|
||||
if (!_data.save(&buffer, _format)) {
|
||||
if (_data.save(&buffer, "PNG")) {
|
||||
_format = "PNG";
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
globalAquiredSize -= int64(p.width()) * p.height() * 4;
|
||||
doForget();
|
||||
forgot = true;
|
||||
globalAcquiredSize -= int64(_data.width()) * _data.height() * 4;
|
||||
_data = QPixmap();
|
||||
_forgot = true;
|
||||
}
|
||||
|
||||
void Image::restore() const {
|
||||
if (!forgot) return;
|
||||
doRestore();
|
||||
const QPixmap &p(pixData());
|
||||
if (!p.isNull()) {
|
||||
globalAquiredSize += int64(p.width()) * p.height() * 4;
|
||||
if (!_forgot) return;
|
||||
|
||||
QBuffer buffer(&_saved);
|
||||
QImageReader reader(&buffer, _format);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
|
||||
reader.setAutoTransform(true);
|
||||
#endif
|
||||
_data = QPixmap::fromImageReader(&reader, Qt::ColorOnly);
|
||||
|
||||
if (!_data.isNull()) {
|
||||
globalAcquiredSize += int64(_data.width()) * _data.height() * 4;
|
||||
}
|
||||
forgot = false;
|
||||
_forgot = false;
|
||||
}
|
||||
|
||||
void Image::invalidateSizeCache() const {
|
||||
for (Sizes::const_iterator i = _sizesCache.cbegin(), e = _sizesCache.cend(); i != e; ++i) {
|
||||
if (!i->isNull()) {
|
||||
globalAquiredSize -= int64(i->width()) * i->height() * 4;
|
||||
globalAcquiredSize -= int64(i->width()) * i->height() * 4;
|
||||
}
|
||||
}
|
||||
_sizesCache.clear();
|
||||
}
|
||||
|
||||
LocalImage::LocalImage(const QString &file, QByteArray fmt) {
|
||||
data = QPixmap::fromImage(App::readImage(file, &fmt, false, 0, &saved), Qt::ColorOnly);
|
||||
format = fmt;
|
||||
if (!data.isNull()) {
|
||||
globalAquiredSize += int64(data.width()) * data.height() * 4;
|
||||
Image::~Image() {
|
||||
invalidateSizeCache();
|
||||
if (!_data.isNull()) {
|
||||
globalAcquiredSize -= int64(_data.width()) * _data.height() * 4;
|
||||
}
|
||||
}
|
||||
|
||||
LocalImage::LocalImage(const QByteArray &filecontent, QByteArray fmt) {
|
||||
data = QPixmap::fromImage(App::readImage(filecontent, &fmt, false), Qt::ColorOnly);
|
||||
format = fmt;
|
||||
saved = filecontent;
|
||||
if (!data.isNull()) {
|
||||
globalAquiredSize += int64(data.width()) * data.height() * 4;
|
||||
Image *getImage(const QString &file, QByteArray format) {
|
||||
if (file.startsWith(qstr("http://"), Qt::CaseInsensitive) || file.startsWith(qstr("https://"), Qt::CaseInsensitive)) {
|
||||
QString key = file;
|
||||
WebImages::const_iterator i = webImages.constFind(key);
|
||||
if (i == webImages.cend()) {
|
||||
i = webImages.insert(key, new WebImage(file));
|
||||
}
|
||||
return i.value();
|
||||
} else {
|
||||
QFileInfo f(file);
|
||||
QString key = qsl("//:%1//:%2//:").arg(f.size()).arg(f.lastModified().toTime_t()) + file;
|
||||
LocalImages::const_iterator i = localImages.constFind(key);
|
||||
if (i == localImages.cend()) {
|
||||
i = localImages.insert(key, new Image(file, format));
|
||||
}
|
||||
return i.value();
|
||||
}
|
||||
}
|
||||
|
||||
LocalImage::LocalImage(const QPixmap &pixmap, QByteArray format) : Image(format), data(pixmap) {
|
||||
if (!data.isNull()) {
|
||||
globalAquiredSize += int64(data.width()) * data.height() * 4;
|
||||
}
|
||||
Image *getImage(const QByteArray &filecontent, QByteArray format) {
|
||||
return new Image(filecontent, format);
|
||||
}
|
||||
|
||||
LocalImage::LocalImage(const QByteArray &filecontent, QByteArray fmt, const QPixmap &pixmap) {
|
||||
data = pixmap;
|
||||
format = fmt;
|
||||
saved = filecontent;
|
||||
if (!data.isNull()) {
|
||||
globalAquiredSize += int64(data.width()) * data.height() * 4;
|
||||
}
|
||||
Image *getImage(const QPixmap &pixmap, QByteArray format) {
|
||||
return new Image(pixmap, format);
|
||||
}
|
||||
|
||||
const QPixmap &LocalImage::pixData() const {
|
||||
return data;
|
||||
Image *getImage(const QByteArray &filecontent, QByteArray format, const QPixmap &pixmap) {
|
||||
return new Image(filecontent, format, pixmap);
|
||||
}
|
||||
|
||||
int32 LocalImage::width() const {
|
||||
restore();
|
||||
return data.width();
|
||||
}
|
||||
|
||||
int32 LocalImage::height() const {
|
||||
restore();
|
||||
return data.height();
|
||||
}
|
||||
|
||||
LocalImage::~LocalImage() {
|
||||
if (!data.isNull()) {
|
||||
globalAquiredSize -= int64(data.width()) * data.height() * 4;
|
||||
}
|
||||
}
|
||||
|
||||
LocalImage *getImage(const QString &file, QByteArray format) {
|
||||
QFileInfo f(file);
|
||||
QString key = qsl("//:%1//:%2//:").arg(f.size()).arg(f.lastModified().toTime_t()) + file;
|
||||
LocalImages::const_iterator i = localImages.constFind(key);
|
||||
if (i == localImages.cend()) {
|
||||
i = localImages.insert(key, new LocalImage(file, format));
|
||||
}
|
||||
return i.value();
|
||||
}
|
||||
|
||||
LocalImage *getImage(const QByteArray &filecontent, QByteArray format) {
|
||||
return new LocalImage(filecontent, format);
|
||||
}
|
||||
|
||||
LocalImage *getImage(const QPixmap &pixmap, QByteArray format) {
|
||||
return new LocalImage(pixmap, format);
|
||||
}
|
||||
|
||||
LocalImage *getImage(const QByteArray &filecontent, QByteArray format, const QPixmap &pixmap) {
|
||||
return new LocalImage(filecontent, format, pixmap);
|
||||
Image *getImage(int32 width, int32 height) {
|
||||
return new DelayedStorageImage(width, height);
|
||||
}
|
||||
|
||||
void clearStorageImages() {
|
||||
|
@ -587,6 +613,10 @@ void clearStorageImages() {
|
|||
delete i.value();
|
||||
}
|
||||
storageImages.clear();
|
||||
for (WebImages::const_iterator i = webImages.cbegin(), e = webImages.cend(); i != e; ++i) {
|
||||
delete i.value();
|
||||
}
|
||||
webImages.clear();
|
||||
}
|
||||
|
||||
void clearAllImages() {
|
||||
|
@ -598,100 +628,268 @@ void clearAllImages() {
|
|||
}
|
||||
|
||||
int64 imageCacheSize() {
|
||||
return globalAquiredSize;
|
||||
return globalAcquiredSize;
|
||||
}
|
||||
|
||||
StorageImage::StorageImage(const StorageImageLocation &location, int32 size) : w(location.width), h(location.height), loader(new mtpFileLoader(location.dc, location.volume, location.local, location.secret, size)) {
|
||||
void RemoteImage::doCheckload() const {
|
||||
if (!amLoading() || !_loader->done()) return;
|
||||
|
||||
QPixmap data = _loader->imagePixmap();
|
||||
if (data.isNull()) {
|
||||
_loader->deleteLater();
|
||||
_loader->stop();
|
||||
_loader = CancelledFileLoader;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_data.isNull()) {
|
||||
globalAcquiredSize -= int64(_data.width()) * _data.height() * 4;
|
||||
}
|
||||
|
||||
_format = _loader->imageFormat();
|
||||
_data = data;
|
||||
_saved = _loader->bytes();
|
||||
const_cast<RemoteImage*>(this)->setInformation(_saved.size(), _data.width(), _data.height());
|
||||
globalAcquiredSize += int64(_data.width()) * _data.height() * 4;
|
||||
|
||||
invalidateSizeCache();
|
||||
|
||||
_loader->deleteLater();
|
||||
_loader->stop();
|
||||
_loader = 0;
|
||||
|
||||
_forgot = false;
|
||||
}
|
||||
|
||||
StorageImage::StorageImage(const StorageImageLocation &location, QByteArray &bytes) : w(location.width), h(location.height), loader(0) {
|
||||
setData(bytes);
|
||||
if (location.dc) {
|
||||
Local::writeImage(storageKey(location.dc, location.volume, location.local), StorageImageSaved(mtpToStorageType(mtpc_storage_filePartial), bytes));
|
||||
void RemoteImage::loadLocal() {
|
||||
if (loaded() || amLoading()) return;
|
||||
|
||||
_loader = createLoader(LoadFromLocalOnly, true);
|
||||
if (_loader) _loader->start();
|
||||
}
|
||||
|
||||
void RemoteImage::setData(QByteArray &bytes, const QByteArray &bytesFormat) {
|
||||
QBuffer buffer(&bytes);
|
||||
|
||||
if (!_data.isNull()) {
|
||||
globalAcquiredSize -= int64(_data.width()) * _data.height() * 4;
|
||||
}
|
||||
QByteArray fmt(bytesFormat);
|
||||
_data = QPixmap::fromImage(App::readImage(bytes, &fmt, false), Qt::ColorOnly);
|
||||
if (!_data.isNull()) {
|
||||
globalAcquiredSize += int64(_data.width()) * _data.height() * 4;
|
||||
setInformation(bytes.size(), _data.width(), _data.height());
|
||||
}
|
||||
|
||||
invalidateSizeCache();
|
||||
if (amLoading()) {
|
||||
_loader->deleteLater();
|
||||
_loader->stop();
|
||||
_loader = 0;
|
||||
}
|
||||
_saved = bytes;
|
||||
_format = fmt;
|
||||
_forgot = false;
|
||||
}
|
||||
|
||||
void RemoteImage::automaticLoad(const HistoryItem *item) {
|
||||
if (loaded()) return;
|
||||
|
||||
if (_loader != CancelledFileLoader && item) {
|
||||
bool loadFromCloud = false;
|
||||
if (item->history()->peer->isUser()) {
|
||||
loadFromCloud = !(cAutoDownloadPhoto() & dbiadNoPrivate);
|
||||
} else {
|
||||
loadFromCloud = !(cAutoDownloadPhoto() & dbiadNoGroups);
|
||||
}
|
||||
|
||||
if (_loader) {
|
||||
if (loadFromCloud) _loader->permitLoadFromCloud();
|
||||
} else {
|
||||
_loader = createLoader(loadFromCloud ? LoadFromCloudOrLocal : LoadFromLocalOnly, true);
|
||||
if (_loader) _loader->start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const QPixmap &StorageImage::pixData() const {
|
||||
return data;
|
||||
void RemoteImage::automaticLoadSettingsChanged() {
|
||||
if (loaded() || _loader != CancelledFileLoader) return;
|
||||
_loader = 0;
|
||||
}
|
||||
|
||||
void RemoteImage::load(bool loadFirst, bool prior) {
|
||||
if (loaded()) return;
|
||||
|
||||
if (!_loader) {
|
||||
_loader = createLoader(LoadFromCloudOrLocal, false);
|
||||
}
|
||||
if (amLoading()) {
|
||||
_loader->start(loadFirst, prior);
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteImage::loadEvenCancelled(bool loadFirst, bool prior) {
|
||||
if (_loader == CancelledFileLoader) _loader = 0;
|
||||
return load(loadFirst, prior);
|
||||
}
|
||||
|
||||
RemoteImage::~RemoteImage() {
|
||||
if (!_data.isNull()) {
|
||||
globalAcquiredSize -= int64(_data.width()) * _data.height() * 4;
|
||||
}
|
||||
if (amLoading()) {
|
||||
_loader->deleteLater();
|
||||
_loader->stop();
|
||||
_loader = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool RemoteImage::loaded() const {
|
||||
doCheckload();
|
||||
return (!_data.isNull() || !_saved.isNull());
|
||||
}
|
||||
|
||||
bool RemoteImage::displayLoading() const {
|
||||
return amLoading() && (!_loader->loadingLocal() || !_loader->autoLoading());
|
||||
}
|
||||
|
||||
void RemoteImage::cancel() {
|
||||
if (!amLoading()) return;
|
||||
|
||||
FileLoader *l = _loader;
|
||||
_loader = CancelledFileLoader;
|
||||
if (l) {
|
||||
l->cancel();
|
||||
l->deleteLater();
|
||||
l->stop();
|
||||
}
|
||||
}
|
||||
|
||||
float64 RemoteImage::progress() const {
|
||||
return amLoading() ? _loader->currentProgress() : (loaded() ? 1 : 0);
|
||||
}
|
||||
|
||||
int32 RemoteImage::loadOffset() const {
|
||||
return amLoading() ? _loader->currentOffset() : 0;
|
||||
}
|
||||
|
||||
StorageImage::StorageImage(const StorageImageLocation &location, int32 size)
|
||||
: _location(location)
|
||||
, _size(size) {
|
||||
}
|
||||
|
||||
StorageImage::StorageImage(const StorageImageLocation &location, QByteArray &bytes)
|
||||
: _location(location)
|
||||
, _size(bytes.size()) {
|
||||
setData(bytes);
|
||||
if (!_location.isNull()) {
|
||||
Local::writeImage(storageKey(_location), StorageImageSaved(mtpToStorageType(mtpc_storage_filePartial), bytes));
|
||||
}
|
||||
}
|
||||
|
||||
int32 StorageImage::width() const {
|
||||
return w;
|
||||
return _location.width();
|
||||
}
|
||||
|
||||
int32 StorageImage::height() const {
|
||||
return h;
|
||||
return _location.height();
|
||||
}
|
||||
|
||||
bool StorageImage::check() const {
|
||||
if (loader->done()) {
|
||||
if (!data.isNull()) {
|
||||
globalAquiredSize -= int64(data.width()) * data.height() * 4;
|
||||
void StorageImage::setInformation(int32 size, int32 width, int32 height) {
|
||||
_size = size;
|
||||
_location.setSize(width, height);
|
||||
}
|
||||
|
||||
FileLoader *StorageImage::createLoader(LoadFromCloudSetting fromCloud, bool autoLoading) {
|
||||
if (_location.isNull()) return 0;
|
||||
return new mtpFileLoader(&_location, _size, fromCloud, autoLoading);
|
||||
}
|
||||
|
||||
DelayedStorageImage::DelayedStorageImage() : StorageImage(StorageImageLocation())
|
||||
, _loadRequested(false)
|
||||
, _loadCancelled(false)
|
||||
, _loadFromCloud(false) {
|
||||
}
|
||||
|
||||
DelayedStorageImage::DelayedStorageImage(int32 w, int32 h) : StorageImage(StorageImageLocation(w, h, 0, 0, 0, 0))
|
||||
, _loadRequested(false)
|
||||
, _loadCancelled(false)
|
||||
, _loadFromCloud(false) {
|
||||
}
|
||||
|
||||
DelayedStorageImage::DelayedStorageImage(QByteArray &bytes) : StorageImage(StorageImageLocation(), bytes)
|
||||
, _loadRequested(false)
|
||||
, _loadCancelled(false)
|
||||
, _loadFromCloud(false) {
|
||||
}
|
||||
|
||||
void DelayedStorageImage::setStorageLocation(const StorageImageLocation location) {
|
||||
_location = location;
|
||||
if (_loadRequested) {
|
||||
if (!_loadCancelled) {
|
||||
if (_loadFromCloud) {
|
||||
load();
|
||||
} else {
|
||||
loadLocal();
|
||||
}
|
||||
}
|
||||
format = loader->imageFormat();
|
||||
data = loader->imagePixmap();
|
||||
QByteArray bytes = loader->bytes();
|
||||
if (!data.isNull()) {
|
||||
globalAquiredSize += int64(data.width()) * data.height() * 4;
|
||||
_loadRequested = false;
|
||||
}
|
||||
}
|
||||
|
||||
void DelayedStorageImage::automaticLoad(const HistoryItem *item) {
|
||||
if (_location.isNull()) {
|
||||
if (!_loadCancelled && item) {
|
||||
bool loadFromCloud = false;
|
||||
if (item->history()->peer->isUser()) {
|
||||
loadFromCloud = !(cAutoDownloadPhoto() & dbiadNoPrivate);
|
||||
} else {
|
||||
loadFromCloud = !(cAutoDownloadPhoto() & dbiadNoGroups);
|
||||
}
|
||||
|
||||
if (_loadRequested) {
|
||||
if (loadFromCloud) _loadFromCloud = loadFromCloud;
|
||||
} else {
|
||||
_loadFromCloud = loadFromCloud;
|
||||
_loadRequested = true;
|
||||
}
|
||||
}
|
||||
|
||||
w = data.width();
|
||||
h = data.height();
|
||||
invalidateSizeCache();
|
||||
loader->deleteLater();
|
||||
loader->rpcInvalidate();
|
||||
loader = 0;
|
||||
|
||||
saved = bytes;
|
||||
forgot = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void StorageImage::setData(QByteArray &bytes, const QByteArray &format) {
|
||||
QBuffer buffer(&bytes);
|
||||
|
||||
if (!data.isNull()) {
|
||||
globalAquiredSize -= int64(data.width()) * data.height() * 4;
|
||||
}
|
||||
QByteArray fmt(format);
|
||||
data = QPixmap::fromImage(App::readImage(bytes, &fmt, false), Qt::ColorOnly);
|
||||
if (!data.isNull()) {
|
||||
globalAquiredSize += int64(data.width()) * data.height() * 4;
|
||||
}
|
||||
|
||||
w = data.width();
|
||||
h = data.height();
|
||||
invalidateSizeCache();
|
||||
if (loader) {
|
||||
loader->deleteLater();
|
||||
loader->rpcInvalidate();
|
||||
loader = 0;
|
||||
}
|
||||
this->saved = bytes;
|
||||
this->format = fmt;
|
||||
forgot = false;
|
||||
}
|
||||
|
||||
StorageImage::~StorageImage() {
|
||||
if (!data.isNull()) {
|
||||
globalAquiredSize -= int64(data.width()) * data.height() * 4;
|
||||
}
|
||||
if (loader) {
|
||||
loader->deleteLater();
|
||||
loader->rpcInvalidate();
|
||||
loader = 0;
|
||||
} else {
|
||||
StorageImage::automaticLoad(item);
|
||||
}
|
||||
}
|
||||
|
||||
bool StorageImage::loaded() const {
|
||||
if (!loader) return true;
|
||||
return check();
|
||||
void DelayedStorageImage::automaticLoadSettingsChanged() {
|
||||
if (_loadCancelled) _loadCancelled = false;
|
||||
StorageImage::automaticLoadSettingsChanged();
|
||||
}
|
||||
|
||||
void DelayedStorageImage::load(bool loadFirst, bool prior) {
|
||||
if (_location.isNull()) {
|
||||
_loadRequested = _loadFromCloud = true;
|
||||
} else {
|
||||
StorageImage::load(loadFirst, prior);
|
||||
}
|
||||
}
|
||||
|
||||
void DelayedStorageImage::loadEvenCancelled(bool loadFirst, bool prior) {
|
||||
_loadCancelled = false;
|
||||
StorageImage::loadEvenCancelled(loadFirst, prior);
|
||||
}
|
||||
|
||||
bool DelayedStorageImage::displayLoading() const {
|
||||
return _location.isNull() ? true : StorageImage::displayLoading();
|
||||
}
|
||||
|
||||
void DelayedStorageImage::cancel() {
|
||||
if (_loadRequested) {
|
||||
_loadRequested = false;
|
||||
}
|
||||
StorageImage::cancel();
|
||||
}
|
||||
|
||||
StorageImage *getImage(const StorageImageLocation &location, int32 size) {
|
||||
StorageKey key(storageKey(location.dc, location.volume, location.local));
|
||||
StorageKey key(storageKey(location));
|
||||
StorageImages::const_iterator i = storageImages.constFind(key);
|
||||
if (i == storageImages.cend()) {
|
||||
i = storageImages.insert(key, new StorageImage(location, size));
|
||||
|
@ -700,7 +898,7 @@ StorageImage *getImage(const StorageImageLocation &location, int32 size) {
|
|||
}
|
||||
|
||||
StorageImage *getImage(const StorageImageLocation &location, const QByteArray &bytes) {
|
||||
StorageKey key(storageKey(location.dc, location.volume, location.local));
|
||||
StorageKey key(storageKey(location));
|
||||
StorageImages::const_iterator i = storageImages.constFind(key);
|
||||
if (i == storageImages.cend()) {
|
||||
QByteArray bytesArr(bytes);
|
||||
|
@ -708,13 +906,35 @@ StorageImage *getImage(const StorageImageLocation &location, const QByteArray &b
|
|||
} else if (!i.value()->loaded()) {
|
||||
QByteArray bytesArr(bytes);
|
||||
i.value()->setData(bytesArr);
|
||||
if (location.dc) {
|
||||
Local::writeImage(storageKey(location.dc, location.volume, location.local), StorageImageSaved(mtpToStorageType(mtpc_storage_filePartial), bytes));
|
||||
if (!location.isNull()) {
|
||||
Local::writeImage(key, StorageImageSaved(mtpToStorageType(mtpc_storage_filePartial), bytes));
|
||||
}
|
||||
}
|
||||
return i.value();
|
||||
}
|
||||
|
||||
|
||||
WebImage::WebImage(const QString &url) : _url(url), _size(0), _width(0), _height(0) {
|
||||
}
|
||||
|
||||
int32 WebImage::width() const {
|
||||
return _width;
|
||||
}
|
||||
|
||||
int32 WebImage::height() const {
|
||||
return _height;
|
||||
}
|
||||
|
||||
void WebImage::setInformation(int32 size, int32 width, int32 height) {
|
||||
_size = size;
|
||||
_width = width;
|
||||
_height = height;
|
||||
}
|
||||
|
||||
FileLoader *WebImage::createLoader(LoadFromCloudSetting fromCloud, bool autoLoading) {
|
||||
return new webFileLoader(_url, QString(), fromCloud, autoLoading);
|
||||
}
|
||||
|
||||
ReadAccessEnabler::ReadAccessEnabler(const PsFileBookmark *bookmark) : _bookmark(bookmark), _failed(_bookmark ? !_bookmark->enable() : false) {
|
||||
}
|
||||
|
||||
|
|
|
@ -25,87 +25,187 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
QImage imageBlur(QImage img);
|
||||
void imageRound(QImage &img);
|
||||
|
||||
struct StorageImageLocation {
|
||||
StorageImageLocation() : width(0), height(0), dc(0), volume(0), local(0), secret(0) {
|
||||
inline uint32 packInt(int32 a) {
|
||||
return (a < 0) ? uint32(int64(a) + 0x100000000LL) : uint32(a);
|
||||
}
|
||||
inline int32 unpackInt(uint32 a) {
|
||||
return (a > 0x7FFFFFFFU) ? int32(int64(a) - 0x100000000LL) : int32(a);
|
||||
}
|
||||
inline uint64 packUIntUInt(uint32 a, uint32 b) {
|
||||
return (uint64(a) << 32) | uint64(b);
|
||||
}
|
||||
inline uint64 packUIntInt(uint32 a, int32 b) {
|
||||
return packUIntUInt(a, packInt(b));
|
||||
}
|
||||
inline uint64 packIntUInt(int32 a, uint32 b) {
|
||||
return packUIntUInt(packInt(a), b);
|
||||
}
|
||||
inline uint64 packIntInt(int32 a, int32 b) {
|
||||
return packUIntUInt(packInt(a), packInt(b));
|
||||
}
|
||||
inline uint32 unpackUIntFirst(uint64 v) {
|
||||
return uint32(v >> 32);
|
||||
}
|
||||
inline int32 unpackIntFirst(uint64 v) {
|
||||
return unpackInt(unpackUIntFirst(v));
|
||||
}
|
||||
inline uint32 unpackUIntSecond(uint64 v) {
|
||||
return uint32(v & 0xFFFFFFFFULL);
|
||||
}
|
||||
inline int32 unpackIntSecond(uint64 v) {
|
||||
return unpackInt(unpackUIntSecond(v));
|
||||
}
|
||||
|
||||
class StorageImageLocation {
|
||||
public:
|
||||
StorageImageLocation() : _widthheight(0), _dclocal(0), _volume(0), _secret(0) {
|
||||
}
|
||||
StorageImageLocation(int32 width, int32 height, int32 dc, const uint64 &volume, int32 local, const uint64 &secret) : width(width), height(height), dc(dc), volume(volume), local(local), secret(secret) {
|
||||
StorageImageLocation(int32 width, int32 height, int32 dc, const uint64 &volume, int32 local, const uint64 &secret) : _widthheight(packIntInt(width, height)), _dclocal(packIntInt(dc, local)), _volume(volume), _secret(secret) {
|
||||
}
|
||||
StorageImageLocation(int32 width, int32 height, const MTPDfileLocation &location) : width(width), height(height), dc(location.vdc_id.v), volume(location.vvolume_id.v), local(location.vlocal_id.v), secret(location.vsecret.v) {
|
||||
StorageImageLocation(int32 width, int32 height, const MTPDfileLocation &location) : _widthheight(packIntInt(width, height)), _dclocal(packIntInt(location.vdc_id.v, location.vlocal_id.v)), _volume(location.vvolume_id.v), _secret(location.vsecret.v) {
|
||||
}
|
||||
bool isNull() const {
|
||||
return !dc;
|
||||
return !_dclocal;
|
||||
}
|
||||
int32 width, height;
|
||||
int32 dc;
|
||||
uint64 volume;
|
||||
int32 local;
|
||||
uint64 secret;
|
||||
int32 width() const {
|
||||
return unpackIntFirst(_widthheight);
|
||||
}
|
||||
int32 height() const {
|
||||
return unpackIntSecond(_widthheight);
|
||||
}
|
||||
void setSize(int32 width, int32 height) {
|
||||
_widthheight = packIntInt(width, height);
|
||||
}
|
||||
int32 dc() const {
|
||||
return unpackIntFirst(_dclocal);
|
||||
}
|
||||
uint64 volume() const {
|
||||
return _volume;
|
||||
}
|
||||
int32 local() const {
|
||||
return unpackIntSecond(_dclocal);
|
||||
}
|
||||
uint64 secret() const {
|
||||
return _secret;
|
||||
}
|
||||
|
||||
static StorageImageLocation Null;
|
||||
|
||||
private:
|
||||
uint64 _widthheight;
|
||||
uint64 _dclocal;
|
||||
uint64 _volume;
|
||||
uint64 _secret;
|
||||
|
||||
friend inline bool operator==(const StorageImageLocation &a, const StorageImageLocation &b) {
|
||||
return (a._dclocal == b._dclocal) && (a._volume == b._volume) && (a._secret == b._secret);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
inline bool operator==(const StorageImageLocation &a, const StorageImageLocation &b) {
|
||||
return (a.width == b.width) && (a.height == b.height) && (a.dc == b.dc) && (a.volume == b.volume) && (a.local == b.local) && (a.secret == b.secret);
|
||||
}
|
||||
inline bool operator!=(const StorageImageLocation &a, const StorageImageLocation &b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
QPixmap imagePix(QImage img, int32 w, int32 h, bool smooth, bool blurred, bool rounded, int32 outerw, int32 outerh);
|
||||
|
||||
class DelayedStorageImage;
|
||||
|
||||
class HistoryItem;
|
||||
class Image {
|
||||
public:
|
||||
|
||||
Image(QByteArray format = "PNG") : format(format), forgot(false) {
|
||||
Image(const QString &file, QByteArray format = QByteArray());
|
||||
Image(const QByteArray &filecontent, QByteArray format = QByteArray());
|
||||
Image(const QPixmap &pixmap, QByteArray format = QByteArray());
|
||||
Image(const QByteArray &filecontent, QByteArray format, const QPixmap &pixmap);
|
||||
|
||||
virtual void automaticLoad(const HistoryItem *item) { // auto load photo
|
||||
}
|
||||
virtual void automaticLoadSettingsChanged() {
|
||||
}
|
||||
|
||||
virtual bool loaded() const {
|
||||
return true;
|
||||
}
|
||||
virtual bool loading() const {
|
||||
return false;
|
||||
}
|
||||
virtual bool displayLoading() const {
|
||||
return false;
|
||||
}
|
||||
virtual void cancel() {
|
||||
}
|
||||
virtual float64 progress() const {
|
||||
return 1;
|
||||
}
|
||||
virtual int32 loadOffset() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const QPixmap &pix(int32 w = 0, int32 h = 0) const;
|
||||
const QPixmap &pixRounded(int32 w = 0, int32 h = 0) const;
|
||||
const QPixmap &pixBlurred(int32 w = 0, int32 h = 0) const;
|
||||
const QPixmap &pixColored(const style::color &add, int32 w = 0, int32 h = 0) const;
|
||||
const QPixmap &pixBlurredColored(const style::color &add, int32 w = 0, int32 h = 0) const;
|
||||
const QPixmap &pixSingle(int32 w, int32 y, int32 outerw, int32 outerh) const;
|
||||
const QPixmap &pixSingle(int32 w, int32 h, int32 outerw, int32 outerh) const;
|
||||
const QPixmap &pixBlurredSingle(int32 w, int32 h, int32 outerw, int32 outerh) const;
|
||||
QPixmap pixNoCache(int32 w = 0, int32 h = 0, bool smooth = false, bool blurred = false, bool rounded = false, int32 outerw = -1, int32 outerh = -1) const;
|
||||
QPixmap pixColoredNoCache(const style::color &add, int32 w = 0, int32 h = 0, bool smooth = false) const;
|
||||
QPixmap pixBlurredColoredNoCache(const style::color &add, int32 w, int32 h = 0) const;
|
||||
|
||||
virtual int32 width() const = 0;
|
||||
virtual int32 height() const = 0;
|
||||
|
||||
virtual void load(bool /*loadFirst*/ = false, bool /*prior*/ = true) {
|
||||
virtual int32 width() const {
|
||||
restore();
|
||||
return _data.width();
|
||||
}
|
||||
|
||||
virtual void checkload() const {
|
||||
virtual int32 height() const {
|
||||
restore();
|
||||
return _data.height();
|
||||
}
|
||||
|
||||
virtual void load(bool loadFirst = false, bool prior = true) {
|
||||
}
|
||||
|
||||
virtual void loadEvenCancelled(bool loadFirst = false, bool prior = true) {
|
||||
}
|
||||
|
||||
virtual const StorageImageLocation &location() const {
|
||||
return StorageImageLocation::Null;
|
||||
}
|
||||
|
||||
bool isNull() const;
|
||||
|
||||
|
||||
void forget() const;
|
||||
void restore() const;
|
||||
|
||||
QByteArray savedFormat() const {
|
||||
return format;
|
||||
return _format;
|
||||
}
|
||||
QByteArray savedData() const {
|
||||
return saved;
|
||||
return _saved;
|
||||
}
|
||||
|
||||
virtual ~Image() {
|
||||
invalidateSizeCache();
|
||||
virtual DelayedStorageImage *toDelayedStorageImage() {
|
||||
return 0;
|
||||
}
|
||||
virtual const DelayedStorageImage *toDelayedStorageImage() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual ~Image();
|
||||
|
||||
protected:
|
||||
Image(QByteArray format = "PNG") : _format(format), _forgot(false) {
|
||||
}
|
||||
|
||||
virtual const QPixmap &pixData() const = 0;
|
||||
virtual void doForget() const = 0;
|
||||
virtual void doRestore() const = 0;
|
||||
|
||||
void restore() const;
|
||||
virtual void checkload() const {
|
||||
}
|
||||
void invalidateSizeCache() const;
|
||||
|
||||
mutable QByteArray saved, format;
|
||||
mutable bool forgot;
|
||||
mutable QByteArray _saved, _format;
|
||||
mutable bool _forgot;
|
||||
mutable QPixmap _data;
|
||||
|
||||
private:
|
||||
|
||||
|
@ -114,40 +214,11 @@ private:
|
|||
|
||||
};
|
||||
|
||||
class LocalImage : public Image {
|
||||
public:
|
||||
|
||||
LocalImage(const QString &file, QByteArray format = QByteArray());
|
||||
LocalImage(const QByteArray &filecontent, QByteArray format = QByteArray());
|
||||
LocalImage(const QPixmap &pixmap, QByteArray format = QByteArray());
|
||||
LocalImage(const QByteArray &filecontent, QByteArray format, const QPixmap &pixmap);
|
||||
|
||||
int32 width() const;
|
||||
int32 height() const;
|
||||
|
||||
~LocalImage();
|
||||
|
||||
protected:
|
||||
|
||||
const QPixmap &pixData() const;
|
||||
void doForget() const {
|
||||
data = QPixmap();
|
||||
}
|
||||
void doRestore() const {
|
||||
QBuffer buffer(&saved);
|
||||
QImageReader reader(&buffer, format);
|
||||
data = QPixmap::fromImageReader(&reader, Qt::ColorOnly);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
mutable QPixmap data;
|
||||
};
|
||||
|
||||
LocalImage *getImage(const QString &file, QByteArray format);
|
||||
LocalImage *getImage(const QByteArray &filecontent, QByteArray format);
|
||||
LocalImage *getImage(const QPixmap &pixmap, QByteArray format);
|
||||
LocalImage *getImage(const QByteArray &filecontent, QByteArray format, const QPixmap &pixmap);
|
||||
Image *getImage(const QString &file, QByteArray format);
|
||||
Image *getImage(const QByteArray &filecontent, QByteArray format);
|
||||
Image *getImage(const QPixmap &pixmap, QByteArray format);
|
||||
Image *getImage(const QByteArray &filecontent, QByteArray format, const QPixmap &pixmap);
|
||||
Image *getImage(int32 width, int32 height);
|
||||
|
||||
typedef QPair<uint64, uint64> StorageKey;
|
||||
inline uint64 storageMix32To64(int32 a, int32 b) {
|
||||
|
@ -160,64 +231,130 @@ inline StorageKey storageKey(const MTPDfileLocation &location) {
|
|||
return storageKey(location.vdc_id.v, location.vvolume_id.v, location.vlocal_id.v);
|
||||
}
|
||||
inline StorageKey storageKey(const StorageImageLocation &location) {
|
||||
return storageKey(location.dc, location.volume, location.local);
|
||||
return storageKey(location.dc(), location.volume(), location.local());
|
||||
}
|
||||
|
||||
class StorageImage : public Image {
|
||||
class RemoteImage : public Image {
|
||||
public:
|
||||
|
||||
RemoteImage() : _loader(0) {
|
||||
}
|
||||
|
||||
void automaticLoad(const HistoryItem *item); // auto load photo
|
||||
void automaticLoadSettingsChanged();
|
||||
|
||||
bool loaded() const;
|
||||
bool loading() const {
|
||||
return amLoading();
|
||||
}
|
||||
bool displayLoading() const;
|
||||
void cancel();
|
||||
float64 progress() const;
|
||||
int32 loadOffset() const;
|
||||
|
||||
void setData(QByteArray &bytes, const QByteArray &format = QByteArray());
|
||||
|
||||
void load(bool loadFirst = false, bool prior = true);
|
||||
void loadEvenCancelled(bool loadFirst = false, bool prior = true);
|
||||
|
||||
virtual void setInformation(int32 size, int32 width, int32 height) = 0;
|
||||
virtual FileLoader *createLoader(LoadFromCloudSetting fromCloud, bool autoLoading) = 0;
|
||||
|
||||
~RemoteImage();
|
||||
|
||||
protected:
|
||||
void checkload() const {
|
||||
doCheckload();
|
||||
}
|
||||
void loadLocal();
|
||||
|
||||
private:
|
||||
mutable FileLoader *_loader;
|
||||
bool amLoading() const {
|
||||
return _loader && _loader != CancelledFileLoader;
|
||||
}
|
||||
void doCheckload() const;
|
||||
|
||||
};
|
||||
|
||||
class StorageImage : public RemoteImage {
|
||||
public:
|
||||
|
||||
StorageImage(const StorageImageLocation &location, int32 size = 0);
|
||||
StorageImage(const StorageImageLocation &location, QByteArray &bytes);
|
||||
|
||||
|
||||
int32 width() const;
|
||||
int32 height() const;
|
||||
bool loaded() const;
|
||||
bool loading() const {
|
||||
return loader ? loader->loading() : false;
|
||||
}
|
||||
void setData(QByteArray &bytes, const QByteArray &format = QByteArray());
|
||||
|
||||
void load(bool loadFirst = false, bool prior = true) {
|
||||
if (loader) {
|
||||
loader->start(loadFirst, prior);
|
||||
if (loader) check();
|
||||
}
|
||||
}
|
||||
void checkload() const {
|
||||
if (loader) {
|
||||
if (!loader->loading()) {
|
||||
loader->start(true);
|
||||
}
|
||||
if (loader) check();
|
||||
}
|
||||
}
|
||||
virtual void setInformation(int32 size, int32 width, int32 height);
|
||||
virtual FileLoader *createLoader(LoadFromCloudSetting fromCloud, bool autoLoading);
|
||||
|
||||
~StorageImage();
|
||||
virtual const StorageImageLocation &location() const {
|
||||
return _location;
|
||||
}
|
||||
|
||||
protected:
|
||||
StorageImageLocation _location;
|
||||
int32 _size;
|
||||
|
||||
const QPixmap &pixData() const;
|
||||
bool check() const;
|
||||
void doForget() const {
|
||||
data = QPixmap();
|
||||
};
|
||||
|
||||
class DelayedStorageImage : public StorageImage {
|
||||
public:
|
||||
|
||||
DelayedStorageImage();
|
||||
DelayedStorageImage(int32 w, int32 h);
|
||||
DelayedStorageImage(QByteArray &bytes);
|
||||
|
||||
void setStorageLocation(const StorageImageLocation location);
|
||||
|
||||
virtual DelayedStorageImage *toDelayedStorageImage() {
|
||||
return this;
|
||||
}
|
||||
void doRestore() const {
|
||||
QBuffer buffer(&saved);
|
||||
QImageReader reader(&buffer, format);
|
||||
data = QPixmap::fromImageReader(&reader, Qt::ColorOnly);
|
||||
virtual const DelayedStorageImage *toDelayedStorageImage() const {
|
||||
return this;
|
||||
}
|
||||
|
||||
void automaticLoad(const HistoryItem *item); // auto load photo
|
||||
void automaticLoadSettingsChanged();
|
||||
|
||||
bool loading() const {
|
||||
return _location.isNull() ? _loadRequested : StorageImage::loading();
|
||||
}
|
||||
bool displayLoading() const;
|
||||
void cancel();
|
||||
|
||||
void load(bool loadFirst = false, bool prior = true);
|
||||
void loadEvenCancelled(bool loadFirst = false, bool prior = true);
|
||||
|
||||
private:
|
||||
bool _loadRequested, _loadCancelled, _loadFromCloud;
|
||||
|
||||
mutable QPixmap data;
|
||||
mutable int32 w, h;
|
||||
mutable mtpFileLoader *loader;
|
||||
};
|
||||
|
||||
StorageImage *getImage(const StorageImageLocation &location, int32 size = 0);
|
||||
StorageImage *getImage(const StorageImageLocation &location, const QByteArray &bytes);
|
||||
Image *getImage(int32 width, int32 height, const MTPFileLocation &location);
|
||||
|
||||
class WebImage : public RemoteImage {
|
||||
public:
|
||||
|
||||
WebImage(const QString &url);
|
||||
|
||||
int32 width() const;
|
||||
int32 height() const;
|
||||
|
||||
virtual void setInformation(int32 size, int32 width, int32 height);
|
||||
virtual FileLoader *createLoader(LoadFromCloudSetting fromCloud, bool autoLoading);
|
||||
|
||||
private:
|
||||
QString _url;
|
||||
int32 _size, _width, _height;
|
||||
|
||||
};
|
||||
|
||||
WebImage *getImage(const QUrl &url);
|
||||
|
||||
class ImagePtr : public ManagedPtr<Image> {
|
||||
public:
|
||||
ImagePtr();
|
||||
|
@ -234,8 +371,22 @@ public:
|
|||
ImagePtr(const StorageImageLocation &location, const QByteArray &bytes) : Parent(getImage(location, bytes)) {
|
||||
}
|
||||
ImagePtr(int32 width, int32 height, const MTPFileLocation &location, ImagePtr def = ImagePtr());
|
||||
ImagePtr(int32 width, int32 height) : Parent(getImage(width, height)) {
|
||||
}
|
||||
};
|
||||
|
||||
inline QSize resizeKeepAspect(int32 width, int32 height, int32 towidth, int32 toheight) {
|
||||
int32 w = qMax(width, 1), h = qMax(height, 1);
|
||||
if (w * toheight > h * towidth) {
|
||||
h = qRound(h * towidth / float64(w));
|
||||
w = towidth;
|
||||
} else {
|
||||
w = qRound(w * toheight / float64(h));
|
||||
h = toheight;
|
||||
}
|
||||
return QSize(qMax(w, 1), qMax(h, 1));
|
||||
}
|
||||
|
||||
void clearStorageImages();
|
||||
void clearAllImages();
|
||||
int64 imageCacheSize();
|
||||
|
|
|
@ -36,7 +36,7 @@ PopupMenu::PopupMenu(const style::PopupMenu &st) : TWidget(0)
|
|||
, _selected(-1)
|
||||
, _childMenuIndex(-1)
|
||||
, a_opacity(1)
|
||||
, _a_hide(animFunc(this, &PopupMenu::animStep_hide))
|
||||
, _a_hide(animation(this, &PopupMenu::step_hide))
|
||||
, _deleteOnHide(true)
|
||||
, _triggering(false)
|
||||
, _deleteLater(false) {
|
||||
|
@ -54,7 +54,7 @@ PopupMenu::PopupMenu(QMenu *menu, const style::PopupMenu &st) : TWidget(0)
|
|||
, _selected(-1)
|
||||
, _childMenuIndex(-1)
|
||||
, a_opacity(1)
|
||||
, _a_hide(animFunc(this, &PopupMenu::animStep_hide))
|
||||
, _a_hide(animation(this, &PopupMenu::step_hide))
|
||||
, _deleteOnHide(true)
|
||||
, _triggering(false)
|
||||
, _deleteLater(false) {
|
||||
|
@ -440,18 +440,16 @@ void PopupMenu::hideFinish() {
|
|||
hide();
|
||||
}
|
||||
|
||||
bool PopupMenu::animStep_hide(float64 ms) {
|
||||
void PopupMenu::step_hide(float64 ms, bool timer) {
|
||||
float64 dt = ms / _st.duration;
|
||||
bool res = true;
|
||||
if (dt >= 1) {
|
||||
_a_hide.stop();
|
||||
a_opacity.finish();
|
||||
hideFinish();
|
||||
res = false;
|
||||
} else {
|
||||
a_opacity.update(dt, anim::linear);
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
if (timer) update();
|
||||
}
|
||||
|
||||
void PopupMenu::deleteOnHide(bool del) {
|
||||
|
|
|
@ -59,7 +59,7 @@ private:
|
|||
|
||||
void childHiding(PopupMenu *child);
|
||||
|
||||
bool animStep_hide(float64 ms);
|
||||
void step_hide(float64 ms, bool timer);
|
||||
|
||||
void init();
|
||||
void hideFinish();
|
||||
|
|
|
@ -38,12 +38,20 @@ void ScrollShadow::changeVisibility(bool shown) {
|
|||
setVisible(shown);
|
||||
}
|
||||
|
||||
ScrollBar::ScrollBar(ScrollArea *parent, bool vert, const style::flatScroll *st) : QWidget(parent), _st(st), _vertical(vert),
|
||||
_over(false), _overbar(false), _moving(false), _topSh(false), _bottomSh(false),
|
||||
_connected(vert ? parent->verticalScrollBar() : parent->horizontalScrollBar()),
|
||||
_scrollMax(_connected->maximum()), _hideIn(-1),
|
||||
a_bg((_st->hiding ? st::transparent : _st->bgColor)->c),
|
||||
a_bar((_st->hiding ? st::transparent : _st->barColor)->c) {
|
||||
ScrollBar::ScrollBar(ScrollArea *parent, bool vert, const style::flatScroll *st) : QWidget(parent)
|
||||
, _st(st)
|
||||
, _vertical(vert)
|
||||
, _over(false)
|
||||
, _overbar(false)
|
||||
, _moving(false)
|
||||
, _topSh(false)
|
||||
, _bottomSh(false)
|
||||
, _connected(vert ? parent->verticalScrollBar() : parent->horizontalScrollBar())
|
||||
, _scrollMax(_connected->maximum())
|
||||
, _hideIn(-1)
|
||||
, a_bg((_st->hiding ? st::transparent : _st->bgColor)->c)
|
||||
, a_bar((_st->hiding ? st::transparent : _st->barColor)->c)
|
||||
, _a_appearance(animation(this, &ScrollBar::step_appearance)) {
|
||||
recountSize();
|
||||
|
||||
_hideTimer.setSingleShot(true);
|
||||
|
@ -115,7 +123,7 @@ void ScrollBar::onHideTimer() {
|
|||
_hideIn = -1;
|
||||
a_bg.start(QColor(a_bg.current().red(), a_bg.current().green(), a_bg.current().blue(), 0));
|
||||
a_bar.start(QColor(a_bar.current().red(), a_bar.current().green(), a_bar.current().blue(), 0));
|
||||
anim::start(this);
|
||||
_a_appearance.start();
|
||||
}
|
||||
|
||||
ScrollArea *ScrollBar::area() {
|
||||
|
@ -144,26 +152,24 @@ void ScrollBar::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
}
|
||||
|
||||
bool ScrollBar::animStep(float64 ms) {
|
||||
void ScrollBar::step_appearance(float64 ms, bool timer) {
|
||||
float64 dt = ms / _st->duration;
|
||||
bool res = true;
|
||||
if (dt >= 1) {
|
||||
_a_appearance.stop();
|
||||
a_bg.finish();
|
||||
a_bar.finish();
|
||||
res = false;
|
||||
} else {
|
||||
a_bg.update(dt, anim::linear);
|
||||
a_bar.update(dt, anim::linear);
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
if (timer) update();
|
||||
}
|
||||
|
||||
void ScrollBar::hideTimeout(int64 dt) {
|
||||
if (_hideIn < 0) {
|
||||
a_bg.start((_over ? _st->bgOverColor : _st->bgColor)->c);
|
||||
a_bar.start((_overbar ? _st->barOverColor : _st->barColor)->c);
|
||||
anim::start(this);
|
||||
_a_appearance.start();
|
||||
}
|
||||
_hideIn = dt;
|
||||
if (!_moving && _hideIn >= 0) {
|
||||
|
@ -177,7 +183,7 @@ void ScrollBar::enterEvent(QEvent *e) {
|
|||
_over = true;
|
||||
a_bg.start(_st->bgOverColor->c);
|
||||
a_bar.start(_st->barColor->c);
|
||||
anim::start(this);
|
||||
_a_appearance.start();
|
||||
}
|
||||
|
||||
void ScrollBar::leaveEvent(QEvent *e) {
|
||||
|
@ -185,7 +191,7 @@ void ScrollBar::leaveEvent(QEvent *e) {
|
|||
setMouseTracking(false);
|
||||
a_bg.start(_st->bgColor->c);
|
||||
a_bar.start(_st->barColor->c);
|
||||
anim::start(this);
|
||||
_a_appearance.start();
|
||||
if (_hideIn >= 0) {
|
||||
_hideTimer.start(_hideIn);
|
||||
} else if (_st->hiding) {
|
||||
|
@ -202,7 +208,7 @@ void ScrollBar::mouseMoveEvent(QMouseEvent *e) {
|
|||
if (!_moving) {
|
||||
a_bar.start((newOverBar ? _st->barOverColor : _st->barColor)->c);
|
||||
a_bg.start(_st->bgOverColor->c);
|
||||
anim::start(this);
|
||||
_a_appearance.start();
|
||||
}
|
||||
}
|
||||
if (_moving) {
|
||||
|
@ -232,7 +238,7 @@ void ScrollBar::mousePressEvent(QMouseEvent *e) {
|
|||
_overbar = true;
|
||||
a_bar.start(_st->barOverColor->c);
|
||||
a_bg.start(_st->bgOverColor->c);
|
||||
anim::start(this);
|
||||
_a_appearance.start();
|
||||
}
|
||||
}
|
||||
emit area()->scrollStarted();
|
||||
|
@ -257,7 +263,7 @@ void ScrollBar::mouseReleaseEvent(QMouseEvent *e) {
|
|||
_hideTimer.start(_hideIn);
|
||||
}
|
||||
}
|
||||
if (a) anim::start(this);
|
||||
if (a) _a_appearance.start();
|
||||
emit area()->scrollFinished();
|
||||
}
|
||||
if (!_over) {
|
||||
|
|
|
@ -50,7 +50,7 @@ private:
|
|||
|
||||
};
|
||||
|
||||
class ScrollBar : public QWidget, public Animated {
|
||||
class ScrollBar : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
@ -67,7 +67,7 @@ public:
|
|||
void mouseReleaseEvent(QMouseEvent *e);
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
|
||||
bool animStep(float64 ms);
|
||||
void step_appearance(float64 ms, bool timer);
|
||||
|
||||
void hideTimeout(int64 dt);
|
||||
|
||||
|
@ -100,6 +100,8 @@ private:
|
|||
QTimer _hideTimer;
|
||||
|
||||
anim::cvalue a_bg, a_bar;
|
||||
Animation _a_appearance;
|
||||
|
||||
QRect _bar;
|
||||
};
|
||||
|
||||
|
|
|
@ -304,6 +304,14 @@ namespace style {
|
|||
typedef Font font;
|
||||
typedef Color color;
|
||||
|
||||
inline QColor interpolate(const style::color &a, const style::color &b, float64 opacity_b) {
|
||||
QColor result;
|
||||
result.setRedF((a->c.redF() * (1. - opacity_b)) + (b->c.redF() * opacity_b));
|
||||
result.setGreenF((a->c.greenF() * (1. - opacity_b)) + (b->c.greenF() * opacity_b));
|
||||
result.setBlueF((a->c.blueF() * (1. - opacity_b)) + (b->c.blueF() * opacity_b));
|
||||
return result;
|
||||
}
|
||||
|
||||
void startManager();
|
||||
void stopManager();
|
||||
|
||||
|
|
|
@ -1,160 +0,0 @@
|
|||
/*
|
||||
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-2015 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "switcher.h"
|
||||
|
||||
Switcher::Switcher(QWidget *parent, const style::switcher &st) : TWidget(parent)
|
||||
, _selected(0)
|
||||
, _over(-1)
|
||||
, _wasOver(-1)
|
||||
, _pressed(-1)
|
||||
, _st(st)
|
||||
, a_bgOver(_st.bgColor->c)
|
||||
, a_bgWasOver(_st.bgHovered->c) {
|
||||
resize(width(), _st.height);
|
||||
}
|
||||
|
||||
void Switcher::leaveEvent(QEvent *e) {
|
||||
setOver(-1);
|
||||
if (_pressed >= 0) return;
|
||||
|
||||
setMouseTracking(false);
|
||||
return TWidget::leaveEvent(e);
|
||||
}
|
||||
|
||||
void Switcher::enterEvent(QEvent *e) {
|
||||
setMouseTracking(true);
|
||||
return TWidget::enterEvent(e);
|
||||
}
|
||||
|
||||
void Switcher::mousePressEvent(QMouseEvent *e) {
|
||||
if (e->buttons() & Qt::LeftButton) {
|
||||
mouseMoveEvent(e);
|
||||
if (_over != _pressed) {
|
||||
_pressed = _over;
|
||||
e->accept();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Switcher::mouseMoveEvent(QMouseEvent *e) {
|
||||
if (rect().contains(e->pos())) {
|
||||
if (width()) {
|
||||
setOver((e->pos().x() * _buttons.size()) / width());
|
||||
}
|
||||
} else {
|
||||
setOver(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void Switcher::mouseReleaseEvent(QMouseEvent *e) {
|
||||
if (_pressed >= 0) {
|
||||
if (_pressed == _over && _pressed != _selected) {
|
||||
setSelected(_pressed);
|
||||
} else {
|
||||
setSelected(_selected);
|
||||
}
|
||||
} else {
|
||||
leaveEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
void Switcher::addButton(const QString &btn) {
|
||||
_buttons.push_back(btn);
|
||||
update();
|
||||
}
|
||||
|
||||
bool Switcher::animStep(float64 ms) {
|
||||
float64 dt = ms / _st.duration;
|
||||
bool res = true;
|
||||
if (dt >= 1) {
|
||||
res = false;
|
||||
a_bgOver.finish();
|
||||
a_bgWasOver.finish();
|
||||
} else {
|
||||
a_bgOver.update(dt, anim::linear);
|
||||
a_bgWasOver.update(dt, anim::linear);
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
}
|
||||
|
||||
void Switcher::paintEvent(QPaintEvent *e) {
|
||||
QPainter p(this);
|
||||
|
||||
p.fillRect(rect(), _st.bgColor->b);
|
||||
if (!_buttons.isEmpty()) {
|
||||
p.setFont(_st.font->f);
|
||||
float64 btnWidth = float64(width()) / _buttons.size();
|
||||
for (int i = 0; i < _buttons.size(); ++i) {
|
||||
QRect btnRect(qRound(i * btnWidth), 0, qRound((i + 1) * btnWidth) - qRound(i * btnWidth), height());
|
||||
if (i == _selected) {
|
||||
p.fillRect(btnRect, _st.bgActive->b);
|
||||
} else if (i == _over) {
|
||||
p.fillRect(btnRect, a_bgOver.current());
|
||||
} else if (i == _wasOver) {
|
||||
p.fillRect(btnRect, a_bgWasOver.current());
|
||||
}
|
||||
p.setPen((i == _selected ? _st.activeColor : _st.textColor)->p);
|
||||
p.drawText(btnRect, _buttons[i], style::al_center);
|
||||
}
|
||||
}
|
||||
if (_st.border) {
|
||||
p.fillRect(0, 0, width() - _st.border, _st.border, _st.borderColor->b);
|
||||
p.fillRect(width() - _st.border, 0, _st.border, height() - _st.border, _st.borderColor->b);
|
||||
p.fillRect(_st.border, height() - _st.border, width() - _st.border, _st.border, _st.borderColor->b);
|
||||
p.fillRect(0, _st.border, _st.border, height() - _st.border, _st.borderColor->b);
|
||||
}
|
||||
}
|
||||
|
||||
int Switcher::selected() const {
|
||||
return _selected;
|
||||
}
|
||||
|
||||
void Switcher::setSelected(int selected) {
|
||||
if (selected != _selected) {
|
||||
_selected = selected;
|
||||
emit changed();
|
||||
}
|
||||
_pressed = _over = _wasOver = -1;
|
||||
anim::stop(this);
|
||||
setCursor(style::cur_default);
|
||||
update();
|
||||
}
|
||||
|
||||
void Switcher::setOver(int over) {
|
||||
if (over != _over) {
|
||||
QColor c(a_bgOver.current());
|
||||
if (_wasOver == over) {
|
||||
a_bgOver = anim::cvalue(a_bgWasOver.current(), _st.bgHovered->c);
|
||||
} else {
|
||||
a_bgOver = anim::cvalue(_st.bgColor->c, _st.bgHovered->c);
|
||||
}
|
||||
a_bgWasOver = anim::cvalue(c, _st.bgColor->c);
|
||||
|
||||
_wasOver = _over;
|
||||
_over = over;
|
||||
|
||||
anim::start(this);
|
||||
|
||||
setCursor((_over >= 0 && _over != _selected) ? style::cur_pointer : style::cur_default);
|
||||
}
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
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-2015 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QtWidgets/QWidget>
|
||||
#include "gui/twidget.h"
|
||||
|
||||
class Switcher : public TWidget, public Animated {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Switcher(QWidget *parent, const style::switcher &st);
|
||||
|
||||
void mousePressEvent(QMouseEvent *e);
|
||||
void mouseMoveEvent(QMouseEvent *e);
|
||||
void mouseReleaseEvent(QMouseEvent *e);
|
||||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
|
||||
void enterEvent(QEvent *e);
|
||||
void leaveEvent(QEvent *e);
|
||||
|
||||
void addButton(const QString &btn);
|
||||
|
||||
bool animStep(float64 ms);
|
||||
|
||||
int selected() const;
|
||||
void setSelected(int selected);
|
||||
|
||||
signals:
|
||||
|
||||
void changed();
|
||||
|
||||
private:
|
||||
|
||||
void setOver(int over);
|
||||
|
||||
int _selected;
|
||||
int _over, _wasOver, _pressed;
|
||||
|
||||
typedef QVector<QString> Buttons;
|
||||
Buttons _buttons;
|
||||
|
||||
style::switcher _st;
|
||||
anim::cvalue a_bgOver, a_bgWasOver;
|
||||
|
||||
};
|
|
@ -36,10 +36,10 @@ namespace {
|
|||
const QRegularExpression _reMailName(qsl("[a-zA-Z\\-_\\.0-9]{1,256}$"));
|
||||
const QRegularExpression _reMailStart(qsl("^[a-zA-Z\\-_\\.0-9]{1,256}\\@"));
|
||||
const QRegularExpression _reHashtag(qsl("(^|[\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\%\\^\\*\\(\\)\\-\\+=\\x10])#[\\w]{2,64}([\\W]|$)"), QRegularExpression::UseUnicodePropertiesOption);
|
||||
const QRegularExpression _reMention(qsl("(^|[\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\%\\^\\*\\(\\)\\-\\+=\\x10])@[A-Za-z_0-9]{5,32}([\\W]|$)"), QRegularExpression::UseUnicodePropertiesOption);
|
||||
const QRegularExpression _reMention(qsl("(^|[\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\%\\^\\*\\(\\)\\-\\+=\\x10])@[A-Za-z_0-9]{3,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);
|
||||
const QRegularExpression _rePre(qsl("(^|[\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\?\\%\\^\\*\\(\\)\\-\\+=\\x10])(````?)[\\s\\S]+?(````?)([\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\?\\%\\^\\*\\(\\)\\-\\+=\\x10]|$)"), QRegularExpression::UseUnicodePropertiesOption);
|
||||
const QRegularExpression _reCode(qsl("(^|[\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\?\\%\\^\\*\\(\\)\\-\\+=\\x10])(`)[^\\n]+?(`)([\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\?\\%\\^\\*\\(\\)\\-\\+=\\x10]|$)"), QRegularExpression::UseUnicodePropertiesOption);
|
||||
QSet<int32> _validProtocols, _validTopDomains;
|
||||
|
||||
const style::textStyle *_textStyle = 0;
|
||||
|
@ -103,6 +103,10 @@ const TextLinkPtr &textlnkDown() {
|
|||
return _downLnk;
|
||||
}
|
||||
|
||||
bool textlnkDrawOver(const TextLinkPtr &lnk) {
|
||||
return (_overLnk == lnk) && (!_downLnk || _downLnk == lnk);
|
||||
}
|
||||
|
||||
QString textOneLine(const QString &text, bool trim, bool rich) {
|
||||
QString result(text);
|
||||
const QChar *s = text.unicode(), *ch = s, *e = text.unicode() + text.size();
|
||||
|
@ -259,7 +263,7 @@ const QChar *textSkipCommand(const QChar *from, const QChar *end, bool canLink)
|
|||
|
||||
class TextParser {
|
||||
public:
|
||||
|
||||
|
||||
static Qt::LayoutDirection stringDirection(const QString &str, int32 from, int32 to) {
|
||||
const ushort *p = reinterpret_cast<const ushort*>(str.unicode()) + from;
|
||||
const ushort *end = p + (to - from);
|
||||
|
@ -336,7 +340,7 @@ public:
|
|||
void getLinkData(const QString &original, QString &result, int32 &fullDisplayed) {
|
||||
if (!original.isEmpty() && original.at(0) == '/') {
|
||||
result = original;
|
||||
fullDisplayed = -4; // bot command
|
||||
fullDisplayed = -4; // bot command
|
||||
} else if (!original.isEmpty() && original.at(0) == '@') {
|
||||
result = original;
|
||||
fullDisplayed = -3; // mention
|
||||
|
@ -450,7 +454,7 @@ public:
|
|||
while (waitingEntity != entitiesEnd && waitingEntity->length <= 0) ++waitingEntity;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool readCommand() {
|
||||
const QChar *afterCmd = textSkipCommand(ptr, end, links.size() < 0x7FFF);
|
||||
if (afterCmd == ptr) {
|
||||
|
@ -594,7 +598,7 @@ public:
|
|||
|
||||
void parseEmojiFromCurrent() {
|
||||
int len = 0;
|
||||
EmojiPtr e = emojiFromText(ptr - emojiLookback, end, len);
|
||||
EmojiPtr e = emojiFromText(ptr - emojiLookback, end, &len);
|
||||
if (!e) return;
|
||||
|
||||
for (int l = len - emojiLookback - 1; l > 0; --l) {
|
||||
|
@ -916,7 +920,7 @@ void EmailLink::onClick(Qt::MouseButton button) const {
|
|||
}
|
||||
|
||||
void CustomTextLink::onClick(Qt::MouseButton button) const {
|
||||
App::wnd()->showLayer(new ConfirmLinkBox(text()));
|
||||
Ui::showLayer(new ConfirmLinkBox(text()));
|
||||
}
|
||||
|
||||
void MentionLink::onClick(Qt::MouseButton button) const {
|
||||
|
@ -971,7 +975,7 @@ public:
|
|||
|
||||
void initParagraphBidi() {
|
||||
if (!_parLength || !_parAnalysis.isEmpty()) return;
|
||||
|
||||
|
||||
Text::TextBlocks::const_iterator i = _parStartBlock, e = _t->_blocks.cend(), n = i + 1;
|
||||
|
||||
bool ignore = false;
|
||||
|
@ -1027,6 +1031,9 @@ public:
|
|||
_y = top;
|
||||
_yFrom = yFrom + top;
|
||||
_yTo = (yTo < 0) ? -1 : (yTo + top);
|
||||
if (_elideLast) {
|
||||
_yToElide = _yTo;
|
||||
}
|
||||
_selectedFrom = selectedFrom;
|
||||
_selectedTo = selectedTo;
|
||||
_wLeft = _w = w;
|
||||
|
@ -1077,7 +1084,7 @@ public:
|
|||
last_rBearing = _rb;
|
||||
last_rPadding = b->f_rpadding();
|
||||
_wLeft = _w - (b->f_width() - last_rBearing);
|
||||
if (_elideLast && _elideRemoveFromEnd > 0 && (_y + blockHeight >= _yTo)) {
|
||||
if (_elideLast && _elideRemoveFromEnd > 0 && (_y + blockHeight >= _yToElide)) {
|
||||
_wLeft -= _elideRemoveFromEnd;
|
||||
}
|
||||
|
||||
|
@ -1104,6 +1111,15 @@ public:
|
|||
|
||||
if (_btype == TextBlockTText) {
|
||||
TextBlock *t = static_cast<TextBlock*>(b);
|
||||
if (t->_words.isEmpty()) { // no words in this block, spaces only => layout this block in the same line
|
||||
last_rPadding += lpadding;
|
||||
|
||||
_lineHeight = qMax(_lineHeight, blockHeight);
|
||||
|
||||
longWordLine = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
QFixed f_wLeft = _wLeft; // vars for saving state of the last word start
|
||||
int32 f_lineHeight = _lineHeight; // f points to the last word-start element of t->_words
|
||||
for (TextBlock::TextWords::const_iterator j = t->_words.cbegin(), en = t->_words.cend(), f = j; j != en; ++j) {
|
||||
|
@ -1131,7 +1147,7 @@ public:
|
|||
}
|
||||
|
||||
int32 elidedLineHeight = qMax(_lineHeight, blockHeight);
|
||||
bool elidedLine = _elideLast && (_y + elidedLineHeight >= _yTo);
|
||||
bool elidedLine = _elideLast && (_y + elidedLineHeight >= _yToElide);
|
||||
if (elidedLine) {
|
||||
_lineHeight = elidedLineHeight;
|
||||
} else if (f != j) {
|
||||
|
@ -1150,7 +1166,7 @@ public:
|
|||
last_rBearing = j->f_rbearing();
|
||||
last_rPadding = j->rpadding;
|
||||
_wLeft = _w - (j_width - last_rBearing);
|
||||
if (_elideLast && _elideRemoveFromEnd > 0 && (_y + blockHeight >= _yTo)) {
|
||||
if (_elideLast && _elideRemoveFromEnd > 0 && (_y + blockHeight >= _yToElide)) {
|
||||
_wLeft -= _elideRemoveFromEnd;
|
||||
}
|
||||
|
||||
|
@ -1159,33 +1175,11 @@ public:
|
|||
f_wLeft = _wLeft;
|
||||
f_lineHeight = _lineHeight;
|
||||
}
|
||||
if (lpadding > 0) { // no words in this block, spaces only
|
||||
int32 elidedLineHeight = qMax(_lineHeight, blockHeight);
|
||||
bool elidedLine = _elideLast && (_y + elidedLineHeight >= _yTo);
|
||||
if (elidedLine) {
|
||||
_lineHeight = elidedLineHeight;
|
||||
}
|
||||
ushort nextStart = _blockEnd(_t, i, e);
|
||||
if (!drawLine(nextStart, i + 1, e)) return;
|
||||
_y += _lineHeight;
|
||||
_lineHeight = qMax(0, blockHeight);
|
||||
_lineStart = nextStart;
|
||||
_lineStartBlock = blockIndex + 1;
|
||||
|
||||
last_rBearing = _rb;
|
||||
last_rPadding = b->rpadding();
|
||||
_wLeft = _w;
|
||||
if (_elideLast && _elideRemoveFromEnd > 0 && (_y + blockHeight >= _yTo)) {
|
||||
_wLeft -= _elideRemoveFromEnd;
|
||||
}
|
||||
|
||||
longWordLine = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
int32 elidedLineHeight = qMax(_lineHeight, blockHeight);
|
||||
bool elidedLine = _elideLast && (_y + elidedLineHeight >= _yTo);
|
||||
bool elidedLine = _elideLast && (_y + elidedLineHeight >= _yToElide);
|
||||
if (elidedLine) {
|
||||
_lineHeight = elidedLineHeight;
|
||||
}
|
||||
|
@ -1198,7 +1192,7 @@ public:
|
|||
last_rBearing = _rb;
|
||||
last_rPadding = b->f_rpadding();
|
||||
_wLeft = _w - (b->f_width() - last_rBearing);
|
||||
if (_elideLast && _elideRemoveFromEnd > 0 && (_y + blockHeight >= _yTo)) {
|
||||
if (_elideLast && _elideRemoveFromEnd > 0 && (_y + blockHeight >= _yToElide)) {
|
||||
_wLeft -= _elideRemoveFromEnd;
|
||||
}
|
||||
|
||||
|
@ -1297,7 +1291,7 @@ public:
|
|||
}
|
||||
|
||||
ITextBlock *_endBlock = (_endBlockIter == _end) ? 0 : (*_endBlockIter);
|
||||
bool elidedLine = _elideLast && _endBlock && (_y + _lineHeight >= _yTo);
|
||||
bool elidedLine = _elideLast && _endBlock && (_y + _lineHeight >= _yToElide);
|
||||
|
||||
int blockIndex = _lineStartBlock;
|
||||
ITextBlock *currentBlock = _t->_blocks[blockIndex];
|
||||
|
@ -1333,7 +1327,7 @@ public:
|
|||
*_getSymbolAfter = false;
|
||||
*_getSymbolUpon = ((_lnkX >= _x) && (_lineStart > 0)) ? true : false;
|
||||
}
|
||||
return false;
|
||||
return false;
|
||||
} else if (_lnkX >= x + (_w - _wLeft)) {
|
||||
if (_parDirection == Qt::RightToLeft) {
|
||||
*_getSymbol = _lineStart;
|
||||
|
@ -1385,6 +1379,7 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
int skipIndex = -1;
|
||||
QVarLengthArray<int> visualOrder(nItems);
|
||||
QVarLengthArray<uchar> levels(nItems);
|
||||
for (int i = 0; i < nItems; ++i) {
|
||||
|
@ -1396,6 +1391,7 @@ public:
|
|||
TextBlockType _type = currentBlock->type();
|
||||
if (_type == TextBlockTSkip) {
|
||||
levels[i] = si.analysis.bidiLevel = 0;
|
||||
skipIndex = i;
|
||||
} else {
|
||||
levels[i] = si.analysis.bidiLevel;
|
||||
}
|
||||
|
@ -1406,6 +1402,13 @@ public:
|
|||
}
|
||||
}
|
||||
QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
|
||||
if (rtl() && skipIndex == nItems - 1) {
|
||||
for (int32 i = nItems; i > 1;) {
|
||||
--i;
|
||||
visualOrder[i] = visualOrder[i - 1];
|
||||
}
|
||||
visualOrder[0] = skipIndex;
|
||||
}
|
||||
|
||||
blockIndex = _lineStartBlock;
|
||||
currentBlock = _t->_blocks[blockIndex];
|
||||
|
@ -2396,7 +2399,7 @@ private:
|
|||
int32 _elideRemoveFromEnd;
|
||||
style::align _align;
|
||||
QPen _originalPen;
|
||||
int32 _yFrom, _yTo;
|
||||
int32 _yFrom, _yTo, _yToElide;
|
||||
uint16 _selectedFrom, _selectedTo;
|
||||
const QChar *_str;
|
||||
|
||||
|
@ -2412,7 +2415,7 @@ private:
|
|||
style::font _f;
|
||||
QFixed _x, _w, _wLeft;
|
||||
int32 _y, _yDelta, _lineHeight, _fontHeight;
|
||||
|
||||
|
||||
// elided hack support
|
||||
int32 _blocksSize;
|
||||
int32 _elideSavedIndex;
|
||||
|
@ -2746,8 +2749,8 @@ int32 Text::countHeight(int32 w) const {
|
|||
longWordLine = true;
|
||||
continue;
|
||||
}
|
||||
widthLeft -= b->f_lpadding();
|
||||
QFixed newWidthLeft = widthLeft - last_rBearing - (last_rPadding + b->f_width() - _rb);
|
||||
QFixed lpadding = b->f_lpadding();
|
||||
QFixed newWidthLeft = widthLeft - lpadding - last_rBearing - (last_rPadding + b->f_width() - _rb);
|
||||
if (newWidthLeft >= 0) {
|
||||
last_rBearing = _rb;
|
||||
last_rPadding = b->f_rpadding();
|
||||
|
@ -2761,13 +2764,23 @@ int32 Text::countHeight(int32 w) const {
|
|||
|
||||
if (_btype == TextBlockTText) {
|
||||
TextBlock *t = static_cast<TextBlock*>(b);
|
||||
if (t->_words.isEmpty()) { // no words in this block, spaces only => layout this block in the same line
|
||||
last_rPadding += lpadding;
|
||||
|
||||
lineHeight = qMax(lineHeight, blockHeight);
|
||||
|
||||
longWordLine = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
QFixed f_wLeft = widthLeft;
|
||||
int32 f_lineHeight = lineHeight;
|
||||
for (TextBlock::TextWords::const_iterator j = t->_words.cbegin(), e = t->_words.cend(), f = j; j != e; ++j) {
|
||||
bool wordEndsHere = (j->width >= 0);
|
||||
QFixed j_width = wordEndsHere ? j->width : -j->width;
|
||||
|
||||
QFixed newWidthLeft = widthLeft - last_rBearing - (last_rPadding + j_width - j->f_rbearing());
|
||||
QFixed newWidthLeft = widthLeft - lpadding - last_rBearing - (last_rPadding + j_width - j->f_rbearing());
|
||||
lpadding = 0;
|
||||
if (newWidthLeft >= 0) {
|
||||
last_rBearing = j->f_rbearing();
|
||||
last_rPadding = j->rpadding;
|
||||
|
@ -2897,7 +2910,7 @@ QString Text::original(uint16 selectedFrom, uint16 selectedTo, ExpandLinksMode m
|
|||
result.reserve(_text.size());
|
||||
|
||||
int32 lnkFrom = 0, lnkIndex = 0;
|
||||
for (TextBlocks::const_iterator i = _blocks.cbegin(), e = _blocks.cend(); true; ++i) {
|
||||
for (TextBlocks::const_iterator i = _blocks.cbegin(), e = _blocks.cend(); true; ++i) {
|
||||
int32 blockLnkIndex = (i == e) ? 0 : (*i)->lnkIndex();
|
||||
int32 blockFrom = (i == e) ? _text.size() : (*i)->from();
|
||||
if (blockLnkIndex != lnkIndex) {
|
||||
|
@ -3140,7 +3153,8 @@ namespace {
|
|||
class BlockParser {
|
||||
public:
|
||||
|
||||
BlockParser(QTextEngine *e, TextBlock *b, QFixed minResizeWidth, int32 blockFrom) : block(b), eng(e) {
|
||||
BlockParser(QTextEngine *e, TextBlock *b, QFixed minResizeWidth, int32 blockFrom, const QString &str)
|
||||
: block(b), eng(e), str(str) {
|
||||
parseWords(minResizeWidth, blockFrom);
|
||||
}
|
||||
|
||||
|
@ -3218,7 +3232,7 @@ public:
|
|||
|
||||
if (lbh.currentPosition >= eng->layoutData->string.length()
|
||||
|| attributes[lbh.currentPosition].whiteSpace
|
||||
|| attributes[lbh.currentPosition].lineBreak) {
|
||||
|| 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;
|
||||
|
@ -3265,10 +3279,19 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
};
|
||||
|
||||
|
@ -3302,14 +3325,15 @@ TextBlock::TextBlock(const style::font &font, const QString &str, QFixed minResi
|
|||
}
|
||||
}
|
||||
|
||||
QStackTextEngine engine(str.mid(_from, length), blockFont->f);
|
||||
QString part = str.mid(_from, length);
|
||||
QStackTextEngine engine(part, blockFont->f);
|
||||
engine.itemize();
|
||||
|
||||
QTextLayout layout(&engine);
|
||||
layout.beginLayout();
|
||||
layout.createLine();
|
||||
|
||||
BlockParser parser(&engine, this, minResizeWidth, _from);
|
||||
BlockParser parser(&engine, this, minResizeWidth, _from, part);
|
||||
|
||||
layout.endLayout();
|
||||
}
|
||||
|
@ -3671,7 +3695,7 @@ void initLinkSets() {
|
|||
|
||||
namespace {
|
||||
// accent char list taken from https://github.com/aristus/accent-folding
|
||||
inline QChar chNoAccent(int32 code) {
|
||||
inline QChar chNoAccent(int32 code) {
|
||||
switch (code) {
|
||||
case 7834: return QChar(97);
|
||||
case 193: return QChar(97);
|
||||
|
@ -4395,7 +4419,7 @@ QString textAccentFold(const QString &text) {
|
|||
result[i] = noAccent;
|
||||
} else {
|
||||
if (copying) result[i] = *ch;
|
||||
++ch, ++i;
|
||||
++ch, ++i;
|
||||
if (copying) result[i] = *ch;
|
||||
}
|
||||
} else {
|
||||
|
@ -4478,8 +4502,7 @@ goodCanBreakEntity = canBreakEntity;\
|
|||
#undef MARK_GOOD_AS_LEVEL
|
||||
|
||||
int elen = 0;
|
||||
EmojiPtr e = emojiFromText(ch, end, elen);
|
||||
if (e) {
|
||||
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;
|
||||
|
|
|
@ -323,6 +323,8 @@ public:
|
|||
virtual bool fullDisplayed() const {
|
||||
return true;
|
||||
}
|
||||
virtual void setFullDisplayed(bool full) {
|
||||
}
|
||||
virtual QString encoded() const {
|
||||
return QString();
|
||||
}
|
||||
|
@ -364,6 +366,10 @@ public:
|
|||
return _fullDisplayed;
|
||||
}
|
||||
|
||||
void setFullDisplayed(bool full) {
|
||||
_fullDisplayed = full;
|
||||
}
|
||||
|
||||
QString encoded() const {
|
||||
QUrl u(_url), good(u.isValid() ? u.toEncoded() : QString());
|
||||
QString result(good.isValid() ? QString::fromUtf8(good.toEncoded()) : _url);
|
||||
|
@ -680,6 +686,8 @@ const TextLinkPtr &textlnkOver();
|
|||
void textlnkDown(const TextLinkPtr &lnk);
|
||||
const TextLinkPtr &textlnkDown();
|
||||
|
||||
bool textlnkDrawOver(const TextLinkPtr &lnk);
|
||||
|
||||
// textcmd
|
||||
QString textcmdSkipBlock(ushort w, ushort h);
|
||||
QString textcmdStartLink(ushort lnkIndex);
|
||||
|
|
|
@ -148,6 +148,9 @@ QRect myrtlrect(const QRect &r) { \
|
|||
void rtlupdate(const QRect &r) { \
|
||||
update(myrtlrect(r)); \
|
||||
} \
|
||||
void rtlupdate(int x, int y, int w, int h) { \
|
||||
update(myrtlrect(x, y, w, h)); \
|
||||
} \
|
||||
protected: \
|
||||
void enterEvent(QEvent *e) { \
|
||||
TWidget *p(tparent()); \
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -33,7 +33,7 @@ enum DragState {
|
|||
};
|
||||
|
||||
class HistoryWidget;
|
||||
class HistoryInner : public QWidget {
|
||||
class HistoryInner : public TWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
@ -66,10 +66,10 @@ public:
|
|||
void touchScrollUpdated(const QPoint &screenPos);
|
||||
QPoint mapMouseToItem(QPoint p, HistoryItem *item);
|
||||
|
||||
int32 recountHeight(HistoryItem *resizedItem);
|
||||
int32 recountHeight(const HistoryItem *resizedItem);
|
||||
void updateSize();
|
||||
|
||||
void updateMsg(const HistoryItem *msg);
|
||||
void repaintItem(const HistoryItem *item);
|
||||
|
||||
bool canCopySelected() const;
|
||||
bool canDeleteSelected() const;
|
||||
|
@ -80,7 +80,6 @@ public:
|
|||
void selectItem(HistoryItem *item);
|
||||
|
||||
void itemRemoved(HistoryItem *item);
|
||||
void itemReplaced(HistoryItem *oldItem, HistoryItem *newItem);
|
||||
|
||||
void updateBotInfo(bool recount = true);
|
||||
|
||||
|
@ -99,7 +98,7 @@ public:
|
|||
void notifyMigrateUpdated();
|
||||
|
||||
~HistoryInner();
|
||||
|
||||
|
||||
public slots:
|
||||
|
||||
void onUpdateSelected();
|
||||
|
@ -115,6 +114,7 @@ public slots:
|
|||
void showContextInFolder();
|
||||
void openContextFile();
|
||||
void saveContextFile();
|
||||
void saveContextGif();
|
||||
void copyContextText();
|
||||
void copySelectedText();
|
||||
|
||||
|
@ -186,7 +186,7 @@ private:
|
|||
bool _touchScroll, _touchSelect, _touchInProgress;
|
||||
QPoint _touchStart, _touchPrevPos, _touchPos;
|
||||
QTimer _touchSelectTimer;
|
||||
|
||||
|
||||
TouchScrollState _touchScrollState;
|
||||
bool _touchPrevPosValid, _touchWaitingAcceleration;
|
||||
QPoint _touchSpeed;
|
||||
|
@ -249,7 +249,7 @@ private:
|
|||
|
||||
};
|
||||
|
||||
class BotKeyboard : public QWidget {
|
||||
class BotKeyboard : public TWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
@ -267,7 +267,7 @@ public:
|
|||
bool hasMarkup() const;
|
||||
bool forceReply() const;
|
||||
|
||||
bool hoverStep(float64 ms);
|
||||
void step_selected(uint64 ms, bool timer);
|
||||
void resizeToWidth(int32 width, int32 maxOuterHeight);
|
||||
|
||||
bool maximizeSize() const;
|
||||
|
@ -308,13 +308,13 @@ private:
|
|||
|
||||
typedef QMap<int32, uint64> Animations;
|
||||
Animations _animations;
|
||||
Animation _hoverAnim;
|
||||
Animation _a_selected;
|
||||
|
||||
const style::botKeyboardButton *_st;
|
||||
|
||||
};
|
||||
|
||||
class HistoryHider : public TWidget, public Animated {
|
||||
class HistoryHider : public TWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
@ -324,7 +324,7 @@ public:
|
|||
HistoryHider(MainWidget *parent); // send path from command line argument
|
||||
HistoryHider(MainWidget *parent, const QString &url, const QString &text); // share url
|
||||
|
||||
bool animStep(float64 ms);
|
||||
void step_appearance(float64 ms, bool timer);
|
||||
bool withConfirm() const;
|
||||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
|
@ -362,7 +362,10 @@ private:
|
|||
|
||||
BoxButton _send, _cancel;
|
||||
PeerData *offered;
|
||||
|
||||
anim::fvalue a_opacity;
|
||||
Animation _a_appearance;
|
||||
|
||||
QRect box;
|
||||
bool hiding;
|
||||
|
||||
|
@ -386,6 +389,11 @@ public:
|
|||
|
||||
};
|
||||
|
||||
enum TextUpdateEventsFlags {
|
||||
TextUpdateEventsSaveDraft = 0x01,
|
||||
TextUpdateEventsSendTyping = 0x02,
|
||||
};
|
||||
|
||||
class HistoryWidget : public TWidget, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -415,7 +423,6 @@ public:
|
|||
void contextMenuEvent(QContextMenuEvent *e);
|
||||
|
||||
void updateTopBarSelection();
|
||||
void checkMentionDropdown();
|
||||
|
||||
void paintTopBar(QPainter &p, float64 over, int32 decreaseWidth);
|
||||
void topBarClick();
|
||||
|
@ -427,7 +434,6 @@ public:
|
|||
void peerMessagesUpdated(PeerId peer);
|
||||
void peerMessagesUpdated();
|
||||
|
||||
void msgUpdated(const HistoryItem *msg);
|
||||
void newUnreadMsg(History *history, HistoryItem *item);
|
||||
void historyToDown(History *history);
|
||||
void historyWasRead(bool force = true);
|
||||
|
@ -444,6 +450,10 @@ public:
|
|||
|
||||
void destroyData();
|
||||
|
||||
void updateFieldPlaceholder();
|
||||
void updateInlineBotQuery();
|
||||
void updateStickersByEmoji();
|
||||
|
||||
void uploadImage(const QImage &img, PrepareMediaType type, FileLoadForceConfirmType confirm = FileLoadNoForceConfirm, const QString &source = QString(), bool withText = false);
|
||||
void uploadFile(const QString &file, PrepareMediaType type, FileLoadForceConfirmType confirm = FileLoadNoForceConfirm, bool withText = false); // with confirmation
|
||||
void uploadFiles(const QStringList &files, PrepareMediaType type);
|
||||
|
@ -471,7 +481,7 @@ public:
|
|||
HistoryItem *atTopImportantMsg(int32 &bottomUnderScrollTop) const;
|
||||
|
||||
void animShow(const QPixmap &bgAnimCache, const QPixmap &bgAnimTopBarCache, bool back = false);
|
||||
bool animStep_show(float64 ms);
|
||||
void step_show(float64 ms, bool timer);
|
||||
void animStop();
|
||||
|
||||
void updateWideMode();
|
||||
|
@ -483,14 +493,12 @@ public:
|
|||
void noSelectingScroll();
|
||||
|
||||
bool touchScroll(const QPoint &delta);
|
||||
|
||||
uint64 animActiveTime(const HistoryItem *msg) const;
|
||||
|
||||
uint64 animActiveTimeStart(const HistoryItem *msg) const;
|
||||
void stopAnimActive();
|
||||
|
||||
void fillSelectedItems(SelectedItemSet &sel, bool forDelete = true);
|
||||
void itemRemoved(HistoryItem *item);
|
||||
void itemReplaced(HistoryItem *oldItem, HistoryItem *newItem);
|
||||
void itemResized(HistoryItem *item, bool scrollToIt);
|
||||
|
||||
void updateScrollColors();
|
||||
|
||||
|
@ -510,14 +518,14 @@ public:
|
|||
void updatePreview();
|
||||
void previewCancel();
|
||||
|
||||
bool recordStep(float64 ms);
|
||||
bool recordingStep(float64 ms);
|
||||
void step_record(float64 ms, bool timer);
|
||||
void step_recording(float64 ms, bool timer);
|
||||
void stopRecording(bool send);
|
||||
|
||||
void onListEscapePressed();
|
||||
|
||||
void sendBotCommand(const QString &cmd, MsgId replyTo);
|
||||
void insertBotCommand(const QString &cmd);
|
||||
bool insertBotCommand(const QString &cmd, bool specialGif);
|
||||
|
||||
bool eventFilter(QObject *obj, QEvent *e);
|
||||
void updateBotKeyboard(History *h = 0);
|
||||
|
@ -542,6 +550,8 @@ public:
|
|||
|
||||
void updateNotifySettings();
|
||||
|
||||
void saveGif(DocumentData *doc);
|
||||
|
||||
bool contentOverlapped(const QRect &globalRect);
|
||||
|
||||
void grabStart() {
|
||||
|
@ -555,9 +565,21 @@ public:
|
|||
resizeEvent(0);
|
||||
}
|
||||
|
||||
void notifyBotCommandsChanged(UserData *user);
|
||||
void notifyUserIsBotChanged(UserData *user);
|
||||
void notifyMigrateUpdated(PeerData *peer);
|
||||
bool isItemVisible(HistoryItem *item);
|
||||
|
||||
void ui_repaintHistoryItem(const HistoryItem *item);
|
||||
void ui_repaintInlineItem(const LayoutInlineItem *gif);
|
||||
bool ui_isInlineItemVisible(const LayoutInlineItem *layout);
|
||||
bool ui_isInlineItemBeingChosen();
|
||||
|
||||
void notify_historyItemLayoutChanged(const HistoryItem *item);
|
||||
void notify_automaticLoadSettingsChangedGif();
|
||||
void notify_botCommandsChanged(UserData *user);
|
||||
void notify_inlineBotRequesting(bool requesting);
|
||||
void notify_userIsBotChanged(UserData *user);
|
||||
void notify_migrateUpdated(PeerData *peer);
|
||||
void notify_clipStopperHidden(ClipStopperType type);
|
||||
void notify_historyItemResized(const HistoryItem *item, bool scrollToIt);
|
||||
|
||||
~HistoryWidget();
|
||||
|
||||
|
@ -622,11 +644,14 @@ public slots:
|
|||
void onCmdStart();
|
||||
|
||||
void activate();
|
||||
void onStickersUpdated();
|
||||
void onMentionHashtagOrBotCommandInsert(QString str);
|
||||
void onTextChange();
|
||||
|
||||
void onFieldTabbed();
|
||||
void onStickerSend(DocumentData *sticker);
|
||||
void onPhotoSend(PhotoData *photo);
|
||||
void onInlineResultSend(InlineResult *result, UserData *bot);
|
||||
|
||||
void onVisibleChanged();
|
||||
|
||||
|
@ -638,7 +663,7 @@ public slots:
|
|||
|
||||
void onFieldFocused();
|
||||
void onFieldResize();
|
||||
void onFieldCursorChanged();
|
||||
void onCheckMentionDropdown();
|
||||
void onScrollTimer();
|
||||
|
||||
void onForwardSelected();
|
||||
|
@ -659,6 +684,8 @@ public slots:
|
|||
void onRecordDone(QByteArray result, qint32 samples);
|
||||
void onRecordUpdate(qint16 level, qint32 samples);
|
||||
|
||||
void onUpdateHistoryItems();
|
||||
|
||||
private:
|
||||
|
||||
MsgId _replyToId;
|
||||
|
@ -668,6 +695,9 @@ private:
|
|||
IconedButton _replyForwardPreviewCancel;
|
||||
void updateReplyToName();
|
||||
|
||||
void sendExistingDocument(DocumentData *doc, const QString &caption);
|
||||
void sendExistingPhoto(PhotoData *photo, const QString &caption);
|
||||
|
||||
void drawField(Painter &p);
|
||||
void drawRecordButton(Painter &p);
|
||||
void drawRecording(Painter &p);
|
||||
|
@ -691,10 +721,12 @@ private:
|
|||
QList<MsgId> _replyReturns;
|
||||
|
||||
bool messagesFailed(const RPCError &error, mtpRequestId requestId);
|
||||
void updateListSize(int32 addToY = 0, bool initial = false, bool loadedDown = false, HistoryItem *resizedItem = 0, bool scrollToIt = false);
|
||||
void updateListSize(int32 addToY = 0, bool initial = false, bool loadedDown = false, const HistoryItem *resizedItem = 0, bool scrollToIt = false);
|
||||
void addMessagesToFront(PeerData *peer, const QVector<MTPMessage> &messages, const QVector<MTPMessageGroup> *collapsed);
|
||||
void addMessagesToBack(PeerData *peer, const QVector<MTPMessage> &messages, const QVector<MTPMessageGroup> *collapsed);
|
||||
|
||||
void saveGifDone(DocumentData *doc, const MTPBool &result);
|
||||
|
||||
void reportSpamDone(PeerData *peer, const MTPBool &result, mtpRequestId request);
|
||||
bool reportSpamFail(const RPCError &error, mtpRequestId request);
|
||||
|
||||
|
@ -707,13 +739,16 @@ private:
|
|||
|
||||
void countHistoryShowFrom();
|
||||
|
||||
mtpRequestId _stickersUpdateRequest;
|
||||
void stickersGot(const MTPmessages_AllStickers &stickers);
|
||||
bool stickersFailed(const RPCError &error);
|
||||
|
||||
mtpRequestId _stickersUpdateRequest;
|
||||
mtpRequestId _savedGifsUpdateRequest;
|
||||
void savedGifsGot(const MTPmessages_SavedGifs &gifs);
|
||||
bool savedGifsFailed(const RPCError &error);
|
||||
|
||||
void writeDraft(MsgId *replyTo = 0, const QString *text = 0, const MessageCursor *cursor = 0, bool *previewCancelled = 0);
|
||||
void setFieldText(const QString &text);
|
||||
void setFieldText(const QString &text, int32 textUpdateEventsFlags = 0, bool clearUndoHistory = true);
|
||||
|
||||
QStringList getMediasFromMime(const QMimeData *d);
|
||||
|
||||
|
@ -740,10 +775,19 @@ private:
|
|||
History *_migrated, *_history;
|
||||
bool _histInited; // initial updateListSize() called
|
||||
|
||||
int32 _lastScroll;
|
||||
uint64 _lastScrolled;
|
||||
QTimer _updateHistoryItems; // gifs optimization
|
||||
|
||||
IconedButton _toHistoryEnd;
|
||||
CollapseButton _collapseComments;
|
||||
|
||||
MentionsDropdown _attachMention;
|
||||
UserData *_inlineBot;
|
||||
QString _inlineBotUsername;
|
||||
mtpRequestId _inlineBotResolveRequestId;
|
||||
void inlineBotResolveDone(const MTPcontacts_ResolvedPeer &result);
|
||||
bool inlineBotResolveFail(QString name, const RPCError &error);
|
||||
|
||||
bool isBotStart() const;
|
||||
bool isBlocked() const;
|
||||
|
@ -755,11 +799,13 @@ private:
|
|||
|
||||
FlatButton _send, _unblock, _botStart, _joinChannel, _muteUnmute;
|
||||
mtpRequestId _unblockRequest, _reportSpamRequest;
|
||||
IconedButton _attachDocument, _attachPhoto, _attachEmoji, _kbShow, _kbHide, _cmdStart;
|
||||
IconedButton _attachDocument, _attachPhoto;
|
||||
EmojiButton _attachEmoji;
|
||||
IconedButton _kbShow, _kbHide, _cmdStart;
|
||||
FlatCheckbox _broadcast;
|
||||
bool _cmdStartShown;
|
||||
MessageField _field;
|
||||
Animation _recordAnim, _recordingAnim;
|
||||
Animation _a_record, _a_recording;
|
||||
bool _recording, _inRecord, _inField, _inReply;
|
||||
anim::ivalue a_recordingLevel;
|
||||
int32 _recordingSamples;
|
||||
|
@ -782,7 +828,7 @@ private:
|
|||
int32 _selCount; // < 0 - text selected, focus list, not _field
|
||||
|
||||
TaskQueue _fileLoader;
|
||||
bool _synthedTextUpdate;
|
||||
int32 _textUpdateEventsFlags;
|
||||
|
||||
int64 _serviceImageCacheSize;
|
||||
QString _confirmSource;
|
||||
|
|
|
@ -52,27 +52,27 @@ namespace {
|
|||
}
|
||||
}
|
||||
|
||||
IntroWidget::IntroWidget(Window *window) : TWidget(window),
|
||||
_langChangeTo(0),
|
||||
_a_stage(animFunc(this, &IntroWidget::animStep_stage)),
|
||||
_cacheHideIndex(0),
|
||||
_cacheShowIndex(0),
|
||||
_a_show(animFunc(this, &IntroWidget::animStep_show)),
|
||||
wnd(window),
|
||||
steps(new IntroSteps(this)),
|
||||
phone(0),
|
||||
code(0),
|
||||
signup(0),
|
||||
pwdcheck(0),
|
||||
current(0),
|
||||
moving(0),
|
||||
_callTimeout(60),
|
||||
_registered(false),
|
||||
_hasRecovery(false),
|
||||
_codeByTelegram(false),
|
||||
_back(this, st::setClose),
|
||||
_backFrom(0), _backTo(0) {
|
||||
setGeometry(QRect(0, st::titleHeight, wnd->width(), wnd->height() - st::titleHeight));
|
||||
IntroWidget::IntroWidget(Window *window) : TWidget(window)
|
||||
, _langChangeTo(0)
|
||||
, _a_stage(animation(this, &IntroWidget::step_stage))
|
||||
, _cacheHideIndex(0)
|
||||
, _cacheShowIndex(0)
|
||||
, _a_show(animation(this, &IntroWidget::step_show))
|
||||
, steps(new IntroSteps(this))
|
||||
, phone(0)
|
||||
, code(0)
|
||||
, signup(0)
|
||||
, pwdcheck(0)
|
||||
, current(0)
|
||||
, moving(0)
|
||||
, _callTimeout(60)
|
||||
, _registered(false)
|
||||
, _hasRecovery(false)
|
||||
, _codeByTelegram(false)
|
||||
, _back(this, st::setClose)
|
||||
, _backFrom(0)
|
||||
, _backTo(0) {
|
||||
setGeometry(QRect(0, st::titleHeight, App::wnd()->width(), App::wnd()->height() - st::titleHeight));
|
||||
|
||||
connect(&_back, SIGNAL(clicked()), this, SLOT(onIntroBack()));
|
||||
_back.hide();
|
||||
|
@ -162,7 +162,7 @@ void IntroWidget::prepareMove() {
|
|||
|
||||
_backTo = stages[current + moving]->hasBack() ? 1 : 0;
|
||||
_backFrom = stages[current]->hasBack() ? 1 : 0;
|
||||
animStep_stage(0);
|
||||
_a_stage.step();
|
||||
if (_backFrom > 0 || _backTo > 0) {
|
||||
_back.show();
|
||||
} else {
|
||||
|
@ -227,13 +227,11 @@ void IntroWidget::animShow(const QPixmap &bgAnimCache, bool back) {
|
|||
show();
|
||||
}
|
||||
|
||||
bool IntroWidget::animStep_show(float64 ms) {
|
||||
void IntroWidget::step_show(float64 ms, bool timer) {
|
||||
float64 dt = ms / st::slideDuration;
|
||||
bool res = true;
|
||||
if (dt >= 1) {
|
||||
_a_show.stop();
|
||||
|
||||
res = false;
|
||||
a_coordUnder.finish();
|
||||
a_coordOver.finish();
|
||||
a_shadow.finish();
|
||||
|
@ -253,21 +251,19 @@ bool IntroWidget::animStep_show(float64 ms) {
|
|||
a_coordOver.update(dt, st::slideFunction);
|
||||
a_shadow.update(dt, st::slideFunction);
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
if (timer) update();
|
||||
}
|
||||
|
||||
void IntroWidget::animStop_show() {
|
||||
void IntroWidget::stop_show() {
|
||||
_a_show.stop();
|
||||
}
|
||||
|
||||
bool IntroWidget::animStep_stage(float64 ms) {
|
||||
bool res = true;
|
||||
|
||||
void IntroWidget::step_stage(float64 ms, bool timer) {
|
||||
float64 fullDuration = st::introSlideDelta + st::introSlideDuration, dt = ms / fullDuration;
|
||||
float64 dt1 = (ms > st::introSlideDuration) ? 1 : (ms / st::introSlideDuration), dt2 = (ms > st::introSlideDelta) ? (ms - st::introSlideDelta) / (st::introSlideDuration) : 0;
|
||||
if (dt >= 1) {
|
||||
res = false;
|
||||
_a_stage.stop();
|
||||
|
||||
a_coordShow.finish();
|
||||
a_opacityShow.finish();
|
||||
|
||||
|
@ -292,8 +288,7 @@ bool IntroWidget::animStep_stage(float64 ms) {
|
|||
_back.setOpacity(1);
|
||||
}
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
if (timer) update();
|
||||
}
|
||||
|
||||
void IntroWidget::paintEvent(QPaintEvent *e) {
|
||||
|
@ -414,7 +409,7 @@ void IntroWidget::mousePressEvent(QMouseEvent *e) {
|
|||
}
|
||||
|
||||
void IntroWidget::finish(const MTPUser &user, const QImage &photo) {
|
||||
wnd->setupMain(true, &user);
|
||||
App::wnd()->setupMain(true, &user);
|
||||
if (!photo.isNull()) {
|
||||
App::app()->uploadProfilePhoto(photo, MTP::authedId());
|
||||
}
|
||||
|
|
|
@ -44,10 +44,10 @@ public:
|
|||
void updateWideMode();
|
||||
|
||||
void animShow(const QPixmap &bgAnimCache, bool back = false);
|
||||
bool animStep_show(float64 ms);
|
||||
void animStop_show();
|
||||
void step_show(float64 ms, bool timer);
|
||||
void stop_show();
|
||||
|
||||
bool animStep_stage(float64 ms);
|
||||
void step_stage(float64 ms, bool timer);
|
||||
|
||||
QRect innerRect() const;
|
||||
QString currentCountry() const;
|
||||
|
@ -108,7 +108,6 @@ private:
|
|||
anim::ivalue a_coordUnder, a_coordOver;
|
||||
anim::fvalue a_shadow;
|
||||
|
||||
Window *wnd;
|
||||
IntroSteps *steps;
|
||||
IntroPhone *phone;
|
||||
IntroCode *code;
|
||||
|
|
|
@ -72,12 +72,15 @@ void CodeInput::correctValue(const QString &was, QString &now) {
|
|||
if (strict) emit codeEntered();
|
||||
}
|
||||
|
||||
IntroCode::IntroCode(IntroWidget *parent) : IntroStage(parent), errorAlpha(0),
|
||||
next(this, lang(lng_intro_next), st::btnIntroNext),
|
||||
_desc(st::introTextSize.width()),
|
||||
_noTelegramCode(this, lang(lng_code_no_telegram), st::introLink),
|
||||
_noTelegramCodeRequestId(0),
|
||||
code(this, st::inpIntroCode, lang(lng_code_ph)), waitTillCall(intro()->getCallTimeout()) {
|
||||
IntroCode::IntroCode(IntroWidget *parent) : IntroStage(parent)
|
||||
, a_errorAlpha(0)
|
||||
, _a_error(animation(this, &IntroCode::step_error))
|
||||
, next(this, lang(lng_intro_next), st::btnIntroNext)
|
||||
, _desc(st::introTextSize.width())
|
||||
, _noTelegramCode(this, lang(lng_code_no_telegram), st::introLink)
|
||||
, _noTelegramCodeRequestId(0)
|
||||
, code(this, st::inpIntroCode, lang(lng_code_ph))
|
||||
, waitTillCall(intro()->getCallTimeout()) {
|
||||
setVisible(false);
|
||||
setGeometry(parent->innerRect());
|
||||
|
||||
|
@ -132,8 +135,8 @@ void IntroCode::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
p.drawText(QRect(textRect.left(), code.y() + code.height() + st::introCallSkip, st::introTextSize.width(), st::introErrHeight), callText, style::al_center);
|
||||
}
|
||||
if (animating() || error.length()) {
|
||||
p.setOpacity(errorAlpha.current());
|
||||
if (_a_error.animating() || error.length()) {
|
||||
p.setOpacity(a_errorAlpha.current());
|
||||
p.setFont(st::introErrFont->f);
|
||||
p.setPen(st::introErrColor->p);
|
||||
p.drawText(QRect(textRect.left(), next.y() + next.height() + st::introErrTop, st::introTextSize.width(), st::introErrHeight), error, style::al_center);
|
||||
|
@ -151,32 +154,30 @@ void IntroCode::resizeEvent(QResizeEvent *e) {
|
|||
|
||||
void IntroCode::showError(const QString &err) {
|
||||
if (!err.isEmpty()) code.notaBene();
|
||||
if (!animating() && err == error) return;
|
||||
if (!_a_error.animating() && err == error) return;
|
||||
|
||||
if (err.length()) {
|
||||
error = err;
|
||||
errorAlpha.start(1);
|
||||
a_errorAlpha.start(1);
|
||||
} else {
|
||||
errorAlpha.start(0);
|
||||
a_errorAlpha.start(0);
|
||||
}
|
||||
anim::start(this);
|
||||
_a_error.start();
|
||||
}
|
||||
|
||||
bool IntroCode::animStep(float64 ms) {
|
||||
void IntroCode::step_error(float64 ms, bool timer) {
|
||||
float64 dt = ms / st::introErrDuration;
|
||||
|
||||
bool res = true;
|
||||
if (dt >= 1) {
|
||||
res = false;
|
||||
errorAlpha.finish();
|
||||
if (!errorAlpha.current()) {
|
||||
_a_error.stop();
|
||||
a_errorAlpha.finish();
|
||||
if (!a_errorAlpha.current()) {
|
||||
error = "";
|
||||
}
|
||||
} else {
|
||||
errorAlpha.update(dt, st::introErrFunc);
|
||||
a_errorAlpha.update(dt, st::introErrFunc);
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
if (timer) update();
|
||||
}
|
||||
|
||||
void IntroCode::activate() {
|
||||
|
@ -185,7 +186,7 @@ void IntroCode::activate() {
|
|||
callTimer.start(1000);
|
||||
}
|
||||
error = "";
|
||||
errorAlpha = anim::fvalue(0);
|
||||
a_errorAlpha = anim::fvalue(0);
|
||||
sentCode = QString();
|
||||
show();
|
||||
code.setDisabled(false);
|
||||
|
|
|
@ -42,7 +42,7 @@ protected:
|
|||
|
||||
};
|
||||
|
||||
class IntroCode : public IntroStage, public Animated, public RPCSender {
|
||||
class IntroCode : public IntroStage, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
@ -52,7 +52,7 @@ public:
|
|||
void paintEvent(QPaintEvent *e);
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
|
||||
bool animStep(float64 ms);
|
||||
void step_error(float64 ms, bool timer);
|
||||
|
||||
void activate();
|
||||
void prepareShow();
|
||||
|
@ -86,7 +86,8 @@ private:
|
|||
void stopCheck();
|
||||
|
||||
QString error;
|
||||
anim::fvalue errorAlpha;
|
||||
anim::fvalue a_errorAlpha;
|
||||
Animation _a_error;
|
||||
|
||||
FlatButton next;
|
||||
|
||||
|
|
|
@ -45,13 +45,16 @@ namespace {
|
|||
};
|
||||
}
|
||||
|
||||
IntroPhone::IntroPhone(IntroWidget *parent) : IntroStage(parent),
|
||||
errorAlpha(0), changed(false),
|
||||
next(this, lang(lng_intro_next), st::btnIntroNext),
|
||||
country(this, st::introCountry),
|
||||
phone(this, st::inpIntroPhone), code(this, st::inpIntroCountryCode),
|
||||
_signup(this, lng_phone_notreg(lt_signup_start, textcmdStartLink(1), lt_signup_end, textcmdStopLink()), st::introErrLabel, st::introErrLabelTextStyle),
|
||||
_showSignup(false) {
|
||||
IntroPhone::IntroPhone(IntroWidget *parent) : IntroStage(parent)
|
||||
, a_errorAlpha(0)
|
||||
, _a_error(animation(this, &IntroPhone::step_error))
|
||||
, changed(false)
|
||||
, next(this, lang(lng_intro_next), st::btnIntroNext)
|
||||
, country(this, st::introCountry)
|
||||
, phone(this, st::inpIntroPhone)
|
||||
, code(this, st::inpIntroCountryCode)
|
||||
, _signup(this, lng_phone_notreg(lt_signup_start, textcmdStartLink(1), lt_signup_end, textcmdStopLink()), st::introErrLabel, st::introErrLabelTextStyle)
|
||||
, _showSignup(false) {
|
||||
setVisible(false);
|
||||
setGeometry(parent->innerRect());
|
||||
|
||||
|
@ -92,9 +95,9 @@ void IntroPhone::paintEvent(QPaintEvent *e) {
|
|||
p.setFont(st::introFont->f);
|
||||
p.drawText(textRect, lang(lng_phone_desc), style::al_bottom);
|
||||
}
|
||||
if (animating() || error.length()) {
|
||||
if (_a_error.animating() || error.length()) {
|
||||
int32 errorY = _showSignup ? ((phone.y() + phone.height() + next.y() - st::introErrFont->height) / 2) : (next.y() + next.height() + st::introErrTop);
|
||||
p.setOpacity(errorAlpha.current());
|
||||
p.setOpacity(a_errorAlpha.current());
|
||||
p.setFont(st::introErrFont->f);
|
||||
p.setPen(st::introErrColor->p);
|
||||
p.drawText(QRect(textRect.x(), errorY, textRect.width(), st::introErrFont->height), error, style::al_top);
|
||||
|
@ -123,36 +126,34 @@ void IntroPhone::showError(const QString &err, bool signUp) {
|
|||
_showSignup = signUp;
|
||||
}
|
||||
|
||||
if (!animating() && err == error) return;
|
||||
if (!_a_error.animating() && err == error) return;
|
||||
|
||||
if (err.length()) {
|
||||
error = err;
|
||||
errorAlpha.start(1);
|
||||
a_errorAlpha.start(1);
|
||||
} else {
|
||||
errorAlpha.start(0);
|
||||
a_errorAlpha.start(0);
|
||||
}
|
||||
_signup.hide();
|
||||
anim::start(this);
|
||||
_a_error.start();
|
||||
}
|
||||
|
||||
bool IntroPhone::animStep(float64 ms) {
|
||||
void IntroPhone::step_error(float64 ms, bool timer) {
|
||||
float64 dt = ms / st::introErrDuration;
|
||||
|
||||
bool res = true;
|
||||
if (dt >= 1) {
|
||||
res = false;
|
||||
errorAlpha.finish();
|
||||
if (!errorAlpha.current()) {
|
||||
_a_error.stop();
|
||||
a_errorAlpha.finish();
|
||||
if (!a_errorAlpha.current()) {
|
||||
error = "";
|
||||
_signup.hide();
|
||||
} else if (!error.isEmpty() && _showSignup) {
|
||||
_signup.show();
|
||||
}
|
||||
} else {
|
||||
errorAlpha.update(dt, st::introErrFunc);
|
||||
a_errorAlpha.update(dt, st::introErrFunc);
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
if (timer) update();
|
||||
}
|
||||
|
||||
void IntroPhone::countryChanged() {
|
||||
|
@ -293,7 +294,7 @@ void IntroPhone::selectCountry(const QString &c) {
|
|||
|
||||
void IntroPhone::activate() {
|
||||
error = "";
|
||||
errorAlpha = anim::fvalue(0);
|
||||
a_errorAlpha = anim::fvalue(0);
|
||||
show();
|
||||
enableAll(true);
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
#include "gui/countryinput.h"
|
||||
#include "intro.h"
|
||||
|
||||
class IntroPhone : public IntroStage, public Animated, public RPCSender {
|
||||
class IntroPhone : public IntroStage, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
@ -35,7 +35,7 @@ public:
|
|||
void paintEvent(QPaintEvent *e);
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
|
||||
bool animStep(float64 ms);
|
||||
void step_error(float64 ms, bool timer);
|
||||
|
||||
void selectCountry(const QString &country);
|
||||
|
||||
|
@ -67,7 +67,8 @@ private:
|
|||
void showError(const QString &err, bool signUp = false);
|
||||
|
||||
QString error;
|
||||
anim::fvalue errorAlpha;
|
||||
anim::fvalue a_errorAlpha;
|
||||
Animation _a_error;
|
||||
|
||||
bool changed;
|
||||
FlatButton next;
|
||||
|
|
|
@ -30,18 +30,19 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
#include "intro/intropwdcheck.h"
|
||||
#include "intro/intro.h"
|
||||
|
||||
IntroPwdCheck::IntroPwdCheck(IntroWidget *parent) : IntroStage(parent),
|
||||
errorAlpha(0),
|
||||
_next(this, lang(lng_intro_submit), st::btnIntroNext),
|
||||
_salt(parent->getPwdSalt()),
|
||||
_hasRecovery(parent->getHasRecovery()),
|
||||
_hint(parent->getPwdHint()),
|
||||
_pwdField(this, st::inpIntroPassword, lang(lng_signin_password)),
|
||||
_codeField(this, st::inpIntroPassword, lang(lng_signin_code)),
|
||||
_toRecover(this, lang(lng_signin_recover)),
|
||||
_toPassword(this, lang(lng_signin_try_password)),
|
||||
_reset(this, lang(lng_signin_reset_account), st::btnRedLink),
|
||||
sentRequest(0) {
|
||||
IntroPwdCheck::IntroPwdCheck(IntroWidget *parent) : IntroStage(parent)
|
||||
, a_errorAlpha(0)
|
||||
, _a_error(animation(this, &IntroPwdCheck::step_error))
|
||||
, _next(this, lang(lng_intro_submit), st::btnIntroNext)
|
||||
, _salt(parent->getPwdSalt())
|
||||
, _hasRecovery(parent->getHasRecovery())
|
||||
, _hint(parent->getPwdHint())
|
||||
, _pwdField(this, st::inpIntroPassword, lang(lng_signin_password))
|
||||
, _codeField(this, st::inpIntroPassword, lang(lng_signin_code))
|
||||
, _toRecover(this, lang(lng_signin_recover))
|
||||
, _toPassword(this, lang(lng_signin_try_password))
|
||||
, _reset(this, lang(lng_signin_reset_account), st::btnRedLink)
|
||||
, sentRequest(0) {
|
||||
setVisible(false);
|
||||
setGeometry(parent->innerRect());
|
||||
|
||||
|
@ -86,8 +87,8 @@ void IntroPwdCheck::paintEvent(QPaintEvent *e) {
|
|||
} else if (!_hint.isEmpty()) {
|
||||
_hintText.drawElided(p, _pwdField.x(), _pwdField.y() + _pwdField.height() + st::introFinishSkip, _pwdField.width(), 1, style::al_top);
|
||||
}
|
||||
if (animating() || error.length()) {
|
||||
p.setOpacity(errorAlpha.current());
|
||||
if (_a_error.animating() || error.length()) {
|
||||
p.setOpacity(a_errorAlpha.current());
|
||||
|
||||
QRect errRect((width() - st::introErrWidth) / 2, (_pwdField.y() + _pwdField.height() + st::introFinishSkip + st::introFont->height + _next.y() - st::introErrHeight) / 2, st::introErrWidth, st::introErrHeight);
|
||||
p.setFont(st::introErrFont->f);
|
||||
|
@ -111,32 +112,30 @@ void IntroPwdCheck::resizeEvent(QResizeEvent *e) {
|
|||
}
|
||||
|
||||
void IntroPwdCheck::showError(const QString &err) {
|
||||
if (!animating() && err == error) return;
|
||||
if (!_a_error.animating() && err == error) return;
|
||||
|
||||
if (err.length()) {
|
||||
error = err;
|
||||
errorAlpha.start(1);
|
||||
a_errorAlpha.start(1);
|
||||
} else {
|
||||
errorAlpha.start(0);
|
||||
a_errorAlpha.start(0);
|
||||
}
|
||||
anim::start(this);
|
||||
_a_error.start();
|
||||
}
|
||||
|
||||
bool IntroPwdCheck::animStep(float64 ms) {
|
||||
void IntroPwdCheck::step_error(float64 ms, bool timer) {
|
||||
float64 dt = ms / st::introErrDuration;
|
||||
|
||||
bool res = true;
|
||||
if (dt >= 1) {
|
||||
res = false;
|
||||
errorAlpha.finish();
|
||||
if (!errorAlpha.current()) {
|
||||
_a_error.stop();
|
||||
a_errorAlpha.finish();
|
||||
if (!a_errorAlpha.current()) {
|
||||
error = "";
|
||||
}
|
||||
} else {
|
||||
errorAlpha.update(dt, st::introErrFunc);
|
||||
a_errorAlpha.update(dt, st::introErrFunc);
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
if (timer) update();
|
||||
}
|
||||
|
||||
void IntroPwdCheck::activate() {
|
||||
|
@ -289,14 +288,14 @@ void IntroPwdCheck::onToRecover() {
|
|||
update();
|
||||
} else {
|
||||
ConfirmBox *box = new InformBox(lang(lng_signin_no_email_forgot));
|
||||
App::wnd()->showLayer(box);
|
||||
Ui::showLayer(box);
|
||||
connect(box, SIGNAL(destroyed(QObject*)), this, SLOT(onToReset()));
|
||||
}
|
||||
}
|
||||
|
||||
void IntroPwdCheck::onToPassword() {
|
||||
ConfirmBox *box = new InformBox(lang(lng_signin_cant_email_forgot));
|
||||
App::wnd()->showLayer(box);
|
||||
Ui::showLayer(box);
|
||||
connect(box, SIGNAL(destroyed(QObject*)), this, SLOT(onToReset()));
|
||||
}
|
||||
|
||||
|
@ -319,7 +318,7 @@ void IntroPwdCheck::onReset() {
|
|||
if (sentRequest) return;
|
||||
ConfirmBox *box = new ConfirmBox(lang(lng_signin_sure_reset), lang(lng_signin_reset), st::attentionBoxButton);
|
||||
connect(box, SIGNAL(confirmed()), this, SLOT(onResetSure()));
|
||||
App::wnd()->showLayer(box);
|
||||
Ui::showLayer(box);
|
||||
}
|
||||
|
||||
void IntroPwdCheck::onResetSure() {
|
||||
|
@ -335,7 +334,7 @@ bool IntroPwdCheck::deleteFail(const RPCError &error) {
|
|||
}
|
||||
|
||||
void IntroPwdCheck::deleteDone(const MTPBool &v) {
|
||||
App::wnd()->hideLayer();
|
||||
Ui::hideLayer();
|
||||
intro()->onIntroNext();
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
#include "gui/flatinput.h"
|
||||
#include "intro.h"
|
||||
|
||||
class IntroPwdCheck : public IntroStage, public Animated, public RPCSender {
|
||||
class IntroPwdCheck : public IntroStage, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
@ -35,7 +35,7 @@ public:
|
|||
void paintEvent(QPaintEvent *e);
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
|
||||
bool animStep(float64 ms);
|
||||
void step_error(float64 ms, bool timer);
|
||||
|
||||
void activate();
|
||||
void deactivate();
|
||||
|
@ -69,7 +69,8 @@ private:
|
|||
bool deleteFail(const RPCError &error);
|
||||
|
||||
QString error;
|
||||
anim::fvalue errorAlpha;
|
||||
anim::fvalue a_errorAlpha;
|
||||
Animation _a_error;
|
||||
|
||||
FlatButton _next;
|
||||
|
||||
|
|
|
@ -30,12 +30,15 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
#include "intro/introsignup.h"
|
||||
#include "intro/intro.h"
|
||||
|
||||
IntroSignup::IntroSignup(IntroWidget *parent) : IntroStage(parent),
|
||||
errorAlpha(0), a_photo(0),
|
||||
next(this, lang(lng_intro_finish), st::btnIntroNext),
|
||||
first(this, st::inpIntroName, lang(lng_signup_firstname)),
|
||||
last(this, st::inpIntroName, lang(lng_signup_lastname)),
|
||||
_invertOrder(langFirstNameGoesSecond()) {
|
||||
IntroSignup::IntroSignup(IntroWidget *parent) : IntroStage(parent)
|
||||
, a_errorAlpha(0)
|
||||
, a_photoOver(0)
|
||||
, _a_error(animation(this, &IntroSignup::step_error))
|
||||
, _a_photo(animation(this, &IntroSignup::step_photo))
|
||||
, next(this, lang(lng_intro_finish), st::btnIntroNext)
|
||||
, first(this, st::inpIntroName, lang(lng_signup_firstname))
|
||||
, last(this, st::inpIntroName, lang(lng_signup_lastname))
|
||||
, _invertOrder(langFirstNameGoesSecond()) {
|
||||
setVisible(false);
|
||||
setGeometry(parent->innerRect());
|
||||
|
||||
|
@ -54,9 +57,8 @@ void IntroSignup::mouseMoveEvent(QMouseEvent *e) {
|
|||
if (photoOver != _photoOver) {
|
||||
_photoOver = photoOver;
|
||||
if (_photoSmall.isNull()) {
|
||||
a_photo.start(_photoOver ? 1 : 0);
|
||||
errorAlpha.restart();
|
||||
anim::start(this);
|
||||
a_photoOver.start(_photoOver ? 1 : 0);
|
||||
_a_photo.start();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,7 +92,7 @@ void IntroSignup::mousePressEvent(QMouseEvent *e) {
|
|||
}
|
||||
PhotoCropBox *box = new PhotoCropBox(img, PeerId(0));
|
||||
connect(box, SIGNAL(ready(const QImage &)), this, SLOT(onPhotoReady(const QImage &)));
|
||||
App::wnd()->showLayer(box);
|
||||
Ui::showLayer(box);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,8 +109,8 @@ void IntroSignup::paintEvent(QPaintEvent *e) {
|
|||
p.setFont(st::introFont->f);
|
||||
p.drawText(textRect, lang(lng_signup_desc), style::al_bottom);
|
||||
}
|
||||
if (animating() || error.length()) {
|
||||
p.setOpacity(errorAlpha.current());
|
||||
if (_a_error.animating() || error.length()) {
|
||||
p.setOpacity(a_errorAlpha.current());
|
||||
|
||||
QRect errRect;
|
||||
if (_invertOrder) {
|
||||
|
@ -124,17 +126,17 @@ void IntroSignup::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
|
||||
if (_photoSmall.isNull()) {
|
||||
if (a_photo.current() < 1) {
|
||||
if (a_photoOver.current() < 1) {
|
||||
QRect pix(st::setPhotoImg);
|
||||
pix.moveTo(pix.x() + (pix.width() - st::introPhotoSize) / 2, pix.y() + (pix.height() - st::introPhotoSize) / 2);
|
||||
pix.setSize(QSize(st::introPhotoSize, st::introPhotoSize));
|
||||
p.drawPixmap(QPoint(_phLeft, _phTop), App::sprite(), pix);
|
||||
}
|
||||
if (a_photo.current() > 0) {
|
||||
if (a_photoOver.current() > 0) {
|
||||
QRect pix(st::setOverPhotoImg);
|
||||
pix.moveTo(pix.x() + (pix.width() - st::introPhotoSize) / 2, pix.y() + (pix.height() - st::introPhotoSize) / 2);
|
||||
pix.setSize(QSize(st::introPhotoSize, st::introPhotoSize));
|
||||
p.setOpacity(a_photo.current());
|
||||
p.setOpacity(a_photoOver.current());
|
||||
p.drawPixmap(QPoint(_phLeft, _phTop), App::sprite(), pix);
|
||||
p.setOpacity(1);
|
||||
}
|
||||
|
@ -160,35 +162,42 @@ void IntroSignup::resizeEvent(QResizeEvent *e) {
|
|||
}
|
||||
|
||||
void IntroSignup::showError(const QString &err) {
|
||||
if (!animating() && err == error) return;
|
||||
if (!_a_error.animating() && err == error) return;
|
||||
|
||||
if (err.length()) {
|
||||
error = err;
|
||||
errorAlpha.start(1);
|
||||
a_errorAlpha.start(1);
|
||||
} else {
|
||||
errorAlpha.start(0);
|
||||
a_errorAlpha.start(0);
|
||||
}
|
||||
a_photo.restart();
|
||||
anim::start(this);
|
||||
_a_error.start();
|
||||
}
|
||||
|
||||
bool IntroSignup::animStep(float64 ms) {
|
||||
void IntroSignup::step_error(float64 ms, bool timer) {
|
||||
float64 dt = ms / st::introErrDuration;
|
||||
|
||||
bool res = true;
|
||||
if (dt >= 1) {
|
||||
res = false;
|
||||
errorAlpha.finish();
|
||||
if (!errorAlpha.current()) {
|
||||
_a_error.stop();
|
||||
a_errorAlpha.finish();
|
||||
if (!a_errorAlpha.current()) {
|
||||
error = "";
|
||||
}
|
||||
a_photo.finish();
|
||||
} else {
|
||||
errorAlpha.update(dt, st::introErrFunc);
|
||||
a_photo.update(dt, anim::linear);
|
||||
a_errorAlpha.update(dt, st::introErrFunc);
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
if (timer) update();
|
||||
}
|
||||
|
||||
void IntroSignup::step_photo(float64 ms, bool timer) {
|
||||
float64 dt = ms / st::introErrDuration;
|
||||
|
||||
if (dt >= 1) {
|
||||
_a_photo.stop();
|
||||
a_photoOver.finish();
|
||||
} else {
|
||||
a_photoOver.update(dt, anim::linear);
|
||||
}
|
||||
if (timer) update();
|
||||
}
|
||||
|
||||
void IntroSignup::activate() {
|
||||
|
|
|
@ -25,7 +25,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
#include "gui/flatinput.h"
|
||||
#include "intro.h"
|
||||
|
||||
class IntroSignup : public IntroStage, public Animated, public RPCSender {
|
||||
class IntroSignup : public IntroStage, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
@ -37,7 +37,8 @@ public:
|
|||
void mouseMoveEvent(QMouseEvent *e);
|
||||
void mousePressEvent(QMouseEvent *e);
|
||||
|
||||
bool animStep(float64 ms);
|
||||
void step_error(float64 ms, bool timer);
|
||||
void step_photo(float64 ms, bool timer);
|
||||
|
||||
void activate();
|
||||
void deactivate();
|
||||
|
@ -60,7 +61,9 @@ private:
|
|||
void stopCheck();
|
||||
|
||||
QString error;
|
||||
anim::fvalue errorAlpha, a_photo;
|
||||
anim::fvalue a_errorAlpha, a_photoOver;
|
||||
Animation _a_error;
|
||||
Animation _a_photo;
|
||||
|
||||
FlatButton next;
|
||||
|
||||
|
|
|
@ -81,6 +81,17 @@ LangString langCounted(ushort key0, ushort tag, float64 value);
|
|||
const char *langKeyName(LangKey key);
|
||||
|
||||
inline LangString langDayOfMonth(const QDate &date) {
|
||||
QDate c(QDate::currentDate());
|
||||
int32 month = date.month(), day = date.day(), year = date.year(), cyear = c.year(), cmonth = c.month();
|
||||
if (year != cyear) {
|
||||
if (year > cyear + 1 || cyear > year + 1 || (year == cyear + 1 && month + 12 > cmonth + 3) || (cyear == year + 1 && cmonth + 12 > month + 3)) {
|
||||
return (month > 0 && month <= 12) ? lng_month_day_year(lt_month, lang(LangKey(lng_month1_small + month - 1)), lt_day, QString::number(day), lt_year, QString::number(year)) : qsl("MONTH_ERR");
|
||||
}
|
||||
}
|
||||
return (month > 0 && month <= 12) ? lng_month_day(lt_month, lang(LangKey(lng_month1_small + month - 1)), lt_day, QString::number(day)) : qsl("MONTH_ERR");
|
||||
}
|
||||
|
||||
inline LangString langDayOfMonthFull(const QDate &date) {
|
||||
QDate c(QDate::currentDate());
|
||||
int32 month = date.month(), day = date.day(), year = date.year(), cyear = c.year(), cmonth = c.month();
|
||||
if (year != cyear) {
|
||||
|
@ -91,6 +102,28 @@ inline LangString langDayOfMonth(const QDate &date) {
|
|||
return (month > 0 && month <= 12) ? lng_month_day(lt_month, lang(LangKey(lng_month1 + month - 1)), lt_day, QString::number(day)) : qsl("MONTH_ERR");
|
||||
}
|
||||
|
||||
inline LangString langMonth(const QDate &date) {
|
||||
QDate c(QDate::currentDate());
|
||||
int32 month = date.month(), day = date.day(), year = date.year(), cyear = c.year(), cmonth = c.month();
|
||||
if (year != cyear) {
|
||||
if (year > cyear + 1 || cyear > year + 1 || (year == cyear + 1 && month + 12 > cmonth + 3) || (cyear == year + 1 && cmonth + 12 > month + 3)) {
|
||||
return (month > 0 && month <= 12) ? lng_month_year(lt_month, lang(LangKey(lng_month1_small + month - 1)), lt_year, QString::number(year)) : qsl("MONTH_ERR");
|
||||
}
|
||||
}
|
||||
return (month > 0 && month <= 12) ? lang(LangKey(lng_month1_small + month - 1)) : qsl("MONTH_ERR");
|
||||
}
|
||||
|
||||
inline LangString langMonthFull(const QDate &date) {
|
||||
QDate c(QDate::currentDate());
|
||||
int32 month = date.month(), day = date.day(), year = date.year(), cyear = c.year(), cmonth = c.month();
|
||||
if (year != cyear) {
|
||||
if (year > cyear + 1 || cyear > year + 1 || (year == cyear + 1 && month + 12 > cmonth + 3) || (cyear == year + 1 && cmonth + 12 > month + 3)) {
|
||||
return (month > 0 && month <= 12) ? lng_month_year(lt_month, lang(LangKey(lng_month1 + month - 1)), lt_year, QString::number(year)) : qsl("MONTH_ERR");
|
||||
}
|
||||
}
|
||||
return (month > 0 && month <= 12) ? lang(LangKey(lng_month1 + month - 1)) : qsl("MONTH_ERR");
|
||||
}
|
||||
|
||||
inline LangString langDayOfWeek(const QDate &date) {
|
||||
int32 day = date.dayOfWeek();
|
||||
return (day > 0 && day <= 7) ? lang(LangKey(lng_weekday1 + day - 1)) : qsl("DAY_ERR");
|
||||
|
@ -101,6 +134,14 @@ inline LangString langDayOfWeekFull(const QDate &date) {
|
|||
return (day > 0 && day <= 7) ? lang(LangKey(lng_weekday1_full + day - 1)) : qsl("DAY_ERR");
|
||||
}
|
||||
|
||||
inline LangString langDateTime(const QDateTime &date) {
|
||||
return lng_mediaview_date_time(lt_date, langDayOfMonth(date.date()), lt_time, date.time().toString(cTimeFormat()));
|
||||
}
|
||||
|
||||
inline LangString langDateTimeFull(const QDateTime &date) {
|
||||
return lng_mediaview_date_time(lt_date, langDayOfMonthFull(date.date()), lt_time, date.time().toString(cTimeFormat()));
|
||||
}
|
||||
|
||||
class LangLoader {
|
||||
public:
|
||||
const QString &errors() const;
|
||||
|
|
|
@ -48,6 +48,19 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_month11" = "November";
|
||||
"lng_month12" = "Dezember";
|
||||
|
||||
"lng_month1_small" = "Jan";
|
||||
"lng_month2_small" = "Feb";
|
||||
"lng_month3_small" = "Mär";
|
||||
"lng_month4_small" = "Apr";
|
||||
"lng_month5_small" = "Mai";
|
||||
"lng_month6_small" = "Jun";
|
||||
"lng_month7_small" = "Jul";
|
||||
"lng_month8_small" = "Aug";
|
||||
"lng_month9_small" = "Sept";
|
||||
"lng_month10_small" = "Okt";
|
||||
"lng_month11_small" = "Nov";
|
||||
"lng_month12_small" = "Dez";
|
||||
|
||||
"lng_weekday1" = "Mo";
|
||||
"lng_weekday2" = "Di";
|
||||
"lng_weekday3" = "Mi";
|
||||
|
@ -66,6 +79,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
|
||||
"lng_month_day" = "{day}. {month}";
|
||||
"lng_month_day_year" = "{day} {month}, {year}";
|
||||
"lng_month_year" = "{month}, {year}";
|
||||
|
||||
"lng_box_ok" = "OK";
|
||||
|
||||
|
@ -108,6 +122,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
|
||||
"lng_server_error" = "Interner Serverfehler.";
|
||||
"lng_flood_error" = "Zu viele Versuche, bitte später erneut probieren.";
|
||||
"lng_gif_error" = "Ein Fehler ist beim Laden der GIF-Animation aufgetreten :(";
|
||||
"lng_deleted" = "Gelöschter Kontakt";
|
||||
"lng_deleted_message" = "Gelöschte Nachricht";
|
||||
|
||||
|
@ -470,8 +485,8 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_create_channel_crop" = "Sichtbaren Bereich für Bild wählen";
|
||||
|
||||
"lng_failed_add_participant" = "Kann Teilnehmer nicht hinzufügen. Später erneut versuchen.";
|
||||
"lng_failed_add_not_mutual" = "Wenn man eine Gruppe verlässt, kann nur\nein gemeinsamer Kontakt die Person erneut\neinladen (beide Seiten müssen die Nummer\ndes anderen gespeichert haben).";
|
||||
"lng_failed_add_not_mutual_channel" = "Wenn man einen Kanal verlässt, kann nur\nein gemeinsamer Kontakt die Person erneut\neinladen (beide Seiten müssen die Nummer\ndes anderen gespeichert haben).";
|
||||
"lng_failed_add_not_mutual" = "Wenn man eine Gruppe verlässt, kann nur ein gemeinsamer Kontakt die Person erneut einladen (beide Seiten müssen die Nummer \ndes anderen gespeichert haben).";
|
||||
"lng_failed_add_not_mutual_channel" = "Wenn man einen Kanal verlässt, kann nur ein gemeinsamer Kontakt die Person erneut einladen (beide Seiten müssen die Nummer \ndes anderen gespeichert haben).";
|
||||
|
||||
"lng_sure_delete_contact" = "Bist du sicher, dass du {contact} von deinen Kontakten löschen willst?";
|
||||
"lng_sure_delete_history" = "Sicher, dass du den kompletten Verlauf mit {contact} löschen willst?\n\nDas kann man nicht rückgängig machen.";
|
||||
|
@ -561,6 +576,14 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_media_video" = "Videodatei";
|
||||
"lng_media_audio" = "Sprachnachricht";
|
||||
|
||||
"lng_media_auto_settings" = "Einstellungen für Mediendownloads";
|
||||
"lng_media_auto_photo" = "Automatischer Bilder-Download";
|
||||
"lng_media_auto_audio" = "Automatischer Audio-Download";
|
||||
"lng_media_auto_gif" = "Automatischer GIF-Download";
|
||||
"lng_media_auto_private_chats" = "Chats";
|
||||
"lng_media_auto_groups" = "Gruppen und Kanäle";
|
||||
"lng_media_auto_play" = "Automatisch Abspielen";
|
||||
|
||||
"lng_emoji_category0" = "Häufig genutzt";
|
||||
"lng_emoji_category1" = "Personen";
|
||||
"lng_emoji_category2" = "Natur";
|
||||
|
@ -571,8 +594,13 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_emoji_category7" = "Symbole & Flaggen";
|
||||
|
||||
"lng_switch_stickers" = "Sticker";
|
||||
"lng_switch_stickers_gifs" = "GIFs & Sticker";
|
||||
"lng_switch_emoji" = "Emoji";
|
||||
|
||||
"lng_saved_gifs" = "Gespeicherte GIFs";
|
||||
"lng_inline_bot_results" = "Ergebnisse von {inline_bot}";
|
||||
"lng_inline_bot_no_results" = "Keine Ergebnisse";
|
||||
|
||||
"lng_box_remove" = "Entfernen";
|
||||
|
||||
"lng_custom_stickers" = "Eigene Sticker";
|
||||
|
@ -664,6 +692,8 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_save_file" = "Datei speichern";
|
||||
"lng_save_downloaded" = "{ready} / {total} {mb}";
|
||||
"lng_duration_and_size" = "{duration}, {size}";
|
||||
"lng_duration_played" = "{played} / {duration}";
|
||||
"lng_date_and_duration" = "{date}, {duration}";
|
||||
"lng_choose_images" = "Bilder auswählen";
|
||||
|
||||
"lng_context_view_profile" = "Profil öffnen";
|
||||
|
@ -699,6 +729,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_context_delete_file" = "Datei löschen";
|
||||
"lng_context_close_file" = "Datei schließen";
|
||||
"lng_context_copy_text" = "Text kopieren";
|
||||
"lng_context_save_gif" = "GIF speichern";
|
||||
"lng_context_to_msg" = "Zur Nachricht";
|
||||
"lng_context_reply_msg" = "Antworten";
|
||||
"lng_context_forward_msg" = "Nachricht weiterleiten";
|
||||
|
@ -801,7 +832,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
|
||||
"lng_new_version_wrap" = "Telegram Desktop wurde aktualisiert auf Version {version}\n\n{changes}\n\nGesamter Versionsverlauf:\n{link}";
|
||||
"lng_new_version_minor" = "— Fehlerbehebungen und Softwareoptimierungen";
|
||||
"lng_new_version_text" = "— Sticker-Verwaltung: Ändere die Sortierung deiner Sticker-Pakete, Sortierung wird auf all deinen Geräten synchronisiert \n— Sticker gedrückt halten vor dem Versand für eine Vorschau\n— Neues Kontextmenü für Chats in der Chatliste \n— Neue Emoji werden unterstützt\n\nUnseren deutschsprachigen Infokanal findest du hier: https://telegram.me/TelegramDE";
|
||||
"lng_new_version_text" = "GIF-Revolution: 10x schnelleres Senden und Herunterladen, Autoplay und Speichern von GIFs in einem eigenen Tab im Sticker-Panel.\n\nMehr Infos über GIFs:\n{gifs_link}\n\nInline-Bots: Ein neuer Weg um Bot-Inhalte dem Chat hinzuzufügen. Einfach den Bot-Benutzernamen gefolgt vom Suchbegriff im Eingabefeld eintippen um Echtzeitsuchergebnisse zu erhalten und im Chat zu senden. Probier doch mal “@gif dog” im nächsten Chat aus. Beispiel-Bots: @gif, @wiki, @bing, @vid, @bold.\n\nAusführliche Informationen zu den neuen Inline-Bots:\n{bot_link}\n\nAußerdem neu: Ein neues niedliches Design für Medien, automatische Download-Einstellungen für Bilder, Sprachnachrichten und GIFs.\n\nPS: Unseren deutschsprachigen Infokanal findest du hier: https://telegram.me/TelegramDE";
|
||||
|
||||
"lng_menu_insert_unicode" = "Unicode-Steuerzeichen einfügen";
|
||||
|
||||
|
|
|
@ -48,6 +48,19 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_month11" = "noviembre";
|
||||
"lng_month12" = "diciembre";
|
||||
|
||||
"lng_month1_small" = "ene";
|
||||
"lng_month2_small" = "feb";
|
||||
"lng_month3_small" = "mar";
|
||||
"lng_month4_small" = "abr";
|
||||
"lng_month5_small" = "may";
|
||||
"lng_month6_small" = "jun";
|
||||
"lng_month7_small" = "jul";
|
||||
"lng_month8_small" = "ago";
|
||||
"lng_month9_small" = "sep";
|
||||
"lng_month10_small" = "oct";
|
||||
"lng_month11_small" = "nov";
|
||||
"lng_month12_small" = "dic";
|
||||
|
||||
"lng_weekday1" = "lun";
|
||||
"lng_weekday2" = "mar";
|
||||
"lng_weekday3" = "mié";
|
||||
|
@ -66,6 +79,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
|
||||
"lng_month_day" = "{day} de {month}";
|
||||
"lng_month_day_year" = "{day} de {month} de {year}";
|
||||
"lng_month_year" = "{month}, {year}";
|
||||
|
||||
"lng_box_ok" = "OK";
|
||||
|
||||
|
@ -108,6 +122,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
|
||||
"lng_server_error" = "Error interno del servidor.";
|
||||
"lng_flood_error" = "Muchos intentos. Por favor, reinténtalo más tarde.";
|
||||
"lng_gif_error" = "Ocurrió un error al leer la animación GIF :(";
|
||||
"lng_deleted" = "Desconocido";
|
||||
"lng_deleted_message" = "Mensaje eliminado";
|
||||
|
||||
|
@ -470,13 +485,13 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_create_channel_crop" = "Selecciona el área para la foto del canal";
|
||||
|
||||
"lng_failed_add_participant" = "No se pudo añadir al usuario. Por favor, reinténtalo más tarde.";
|
||||
"lng_failed_add_not_mutual" = "Lo sentimos, si una persona deja un\ngrupo, sólo un contacto mutuo puede \ntraerlo de vuelta (ellos necesitan tener\ntu número, y tú el suyo).";
|
||||
"lng_failed_add_not_mutual_channel" = "Lo sentimos, si una persona deja el canal, \nsólo un contacto mutuo puede volver \na invitarlo (necesitan tener tu \nnúmero y tú el de ellos).";
|
||||
"lng_failed_add_not_mutual" = "Lo sentimos, si una persona deja el grupo, sólo un contacto mutuo puede volver a invitarlo (necesitan tener tu número y tú el suyo).";
|
||||
"lng_failed_add_not_mutual_channel" = "Lo sentimos, si una persona deja el canal, sólo un contacto mutuo puede volver a invitarlo (necesitan tener tu número y tú el suyo).";
|
||||
|
||||
"lng_sure_delete_contact" = "¿Quieres eliminar a {contact} de tu lista de contactos?";
|
||||
"lng_sure_delete_history" = "¿Quieres eliminar todo el historial de mensajes con {contact}?\n\nEsta acción no se puede deshacer.";
|
||||
"lng_sure_delete_history" = "¿Quieres borrar todo el historial de mensajes con {contact}?\n\nEsta acción no se puede deshacer.";
|
||||
"lng_sure_delete_group_history" = "¿Quieres borrar todo el historial en «{group}»?\n\nEsta acción no se puede deshacer.";
|
||||
"lng_sure_delete_and_exit" = "¿Quieres eliminar todo el historial de mensajes y dejar el grupo «{group}»?\n\nEsta acción no se puede deshacer.";
|
||||
"lng_sure_delete_and_exit" = "¿Quieres borrar todo el historial de mensajes y dejar el grupo «{group}»?\n\nEsta acción no se puede deshacer.";
|
||||
"lng_sure_leave_channel" = "¿Quieres dejar este canal?";
|
||||
"lng_sure_delete_channel" = "¿Quieres eliminar este canal? Todos los miembros y mensajes se perderán.";
|
||||
"lng_sure_leave_group" = "¿Quieres salir del grupo?\nNo puedes deshacer esta acción.";
|
||||
|
@ -561,6 +576,14 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_media_video" = "Vídeo";
|
||||
"lng_media_audio" = "Mensaje de voz";
|
||||
|
||||
"lng_media_auto_settings" = "Ajustes de descarga automática de multimedia";
|
||||
"lng_media_auto_photo" = "Descarga automática de fotos";
|
||||
"lng_media_auto_audio" = "Descarga automática de audio";
|
||||
"lng_media_auto_gif" = "Descarga automática de GIF";
|
||||
"lng_media_auto_private_chats" = "Chats";
|
||||
"lng_media_auto_groups" = "Grupos y canales";
|
||||
"lng_media_auto_play" = "Autorreproducir";
|
||||
|
||||
"lng_emoji_category0" = "Uso frecuente";
|
||||
"lng_emoji_category1" = "Personas";
|
||||
"lng_emoji_category2" = "Naturaleza";
|
||||
|
@ -571,8 +594,13 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_emoji_category7" = "Símbolos y banderas";
|
||||
|
||||
"lng_switch_stickers" = "Stickers";
|
||||
"lng_switch_stickers_gifs" = "GIF y stickers";
|
||||
"lng_switch_emoji" = "Emoji";
|
||||
|
||||
"lng_saved_gifs" = "GIF guardados";
|
||||
"lng_inline_bot_results" = "Resultados de {inline_bot}";
|
||||
"lng_inline_bot_no_results" = "Sin resultados";
|
||||
|
||||
"lng_box_remove" = "Eliminar";
|
||||
|
||||
"lng_custom_stickers" = "Stickers personalizados";
|
||||
|
@ -616,7 +644,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_broadcast_ph" = "Difunde un mensaje...";
|
||||
"lng_record_cancel" = "Suelta fuera de aquí para cancelar";
|
||||
"lng_empty_history" = "";
|
||||
"lng_willbe_history" = "Por favor, selecciona un chat para comenzar";
|
||||
"lng_willbe_history" = "Selecciona un chat para comenzar";
|
||||
"lng_message_with_from" = "[c]{from}:[/c] {message}";
|
||||
"lng_from_you" = "Tú";
|
||||
"lng_bot_description" = "¿Qué puede hacer este bot?";
|
||||
|
@ -664,6 +692,8 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_save_file" = "Guardar archivo";
|
||||
"lng_save_downloaded" = "{ready} / {total} {mb}";
|
||||
"lng_duration_and_size" = "{duration}, {size}";
|
||||
"lng_duration_played" = "{played} / {duration}";
|
||||
"lng_date_and_duration" = "{date}, {duration}";
|
||||
"lng_choose_images" = "Elegir imágenes";
|
||||
|
||||
"lng_context_view_profile" = "Ver información";
|
||||
|
@ -699,6 +729,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_context_delete_file" = "Eliminar archivo";
|
||||
"lng_context_close_file" = "Cerrar archivo";
|
||||
"lng_context_copy_text" = "Copiar texto";
|
||||
"lng_context_save_gif" = "Guardar GIF";
|
||||
"lng_context_to_msg" = "Ir al mensaje";
|
||||
"lng_context_reply_msg" = "Responder";
|
||||
"lng_context_forward_msg" = "Reenviar mensaje";
|
||||
|
@ -717,7 +748,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_send_image_too_large" = "No se pudo enviar el archivo, porque es más grande que 1.5 GB :(";
|
||||
"lng_send_folder" = "No se pudo enviar «{name}», porque es un directorio :(";
|
||||
|
||||
"lng_forward_choose" = "Elegir destinatario...";
|
||||
"lng_forward_choose" = "Elige un destinatario...";
|
||||
"lng_forward_cant" = "Lo sentimos, no puedes reenviar aquí :(";
|
||||
"lng_forward_confirm" = "¿Reenviar a {recipient}?";
|
||||
"lng_forward_share_contact" = "¿Compartir contacto con {recipient}?";
|
||||
|
@ -801,7 +832,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
|
||||
"lng_new_version_wrap" = "Telegram Desktop ha sido actualizada a la versión {version}\n\n{changes}\n\nEl historial completo está disponible aquí:\n{link}";
|
||||
"lng_new_version_minor" = "— Corrección de errores y otras mejoras menores";
|
||||
"lng_new_version_text" = "— Administra los stickers: ordena manualmente tus packs de stickers. El orden de los packs se sincronizará en todos tus dispositivos \n— Haz clic y mantén en un sticker para ver una vista previa antes de enviar\n— Nuevo menú contextual para los chats en la lista de chats \n— Soporte de todos los emojis existentes";
|
||||
"lng_new_version_text" = "Revolución del GIF: envío y descarga 10 veces más rápido, reproducción automática, guarda tus GIF favoritos en una pestaña especial en el panel de stickers.\n\nMás sobre los GIF:\n{gifs_link}\n\nBots integrados: una nueva forma para añadir contenidos en los chats. Escribe el alias del bot y tu solicitud, en el campo de escritura, para obtener resultados inmediatamente y enviarlos a tu compañero de chat. Prueba escribiendo “@gif dog” en un chat. Algunos ejemplos: @gif, @wiki, @bing, @vid, @bold.\n\nMás sobre los bots integrados:\n{bots_link}\n\nTambién encontrarás un lindo nuevo diseño para la multimedia y ajustes de descarga automática para fotos, mensajes de voz y GIF.";
|
||||
|
||||
"lng_menu_insert_unicode" = "Insertar caracteres de control Unicode";
|
||||
|
||||
|
|
|
@ -48,6 +48,19 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_month11" = "Novembre";
|
||||
"lng_month12" = "Dicembre";
|
||||
|
||||
"lng_month1_small" = "Gen";
|
||||
"lng_month2_small" = "Feb";
|
||||
"lng_month3_small" = "Mar";
|
||||
"lng_month4_small" = "Apr";
|
||||
"lng_month5_small" = "Mag";
|
||||
"lng_month6_small" = "Giu";
|
||||
"lng_month7_small" = "Lug";
|
||||
"lng_month8_small" = "Ago";
|
||||
"lng_month9_small" = "Set";
|
||||
"lng_month10_small" = "Ott";
|
||||
"lng_month11_small" = "Nov";
|
||||
"lng_month12_small" = "Dic";
|
||||
|
||||
"lng_weekday1" = "Lun";
|
||||
"lng_weekday2" = "Mar";
|
||||
"lng_weekday3" = "Mer";
|
||||
|
@ -66,6 +79,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
|
||||
"lng_month_day" = "{day} {month}";
|
||||
"lng_month_day_year" = "{day} {month} {year}";
|
||||
"lng_month_year" = "{month}, {year}";
|
||||
|
||||
"lng_box_ok" = "Ok";
|
||||
|
||||
|
@ -108,6 +122,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
|
||||
"lng_server_error" = "Errore interno del server.";
|
||||
"lng_flood_error" = "Troppi tentativi. Per favore riprova più tardi.";
|
||||
"lng_gif_error" = "C'è stato un errore nel leggere la GIF :(";
|
||||
"lng_deleted" = "Sconosciuto";
|
||||
"lng_deleted_message" = "Messaggio eliminato";
|
||||
|
||||
|
@ -134,7 +149,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_code_ph" = "Codice";
|
||||
"lng_code_desc" = "Abbiamo inviato un messaggio col codice\ndi attivazione al tuo telefono. Inseriscilo qui";
|
||||
"lng_code_telegram" = "Per favore inserisci il codice che hai\nappena ricevuto nell'altra app di [b]Telegram[/b].";
|
||||
"lng_code_no_telegram" = "Invia codice tramite SMS";
|
||||
"lng_code_no_telegram" = "Invia codice via SMS";
|
||||
"lng_code_call" = "Telegram ti chiamerà tra {minutes}:{seconds}";
|
||||
"lng_code_calling" = "Richiedendo una telefonata da Telegram..";
|
||||
"lng_code_called" = "Telegram ti ha chiamato";
|
||||
|
@ -470,8 +485,8 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_create_channel_crop" = "Seleziona un riquadro per la foto del canale";
|
||||
|
||||
"lng_failed_add_participant" = "Impossibile aggiungere l'utente. Riprova più tardi.";
|
||||
"lng_failed_add_not_mutual" = "Spiacenti, se una persona lascia un gruppo,\nsolo un contatto in comune può reinvitarla\n(chi ti invita deve avere il tuo contatto\nsu Telegram, e viceversa).";
|
||||
"lng_failed_add_not_mutual_channel" = "Spiacenti, se una persona lascia un canale,\nsolo un contatto in comune può reinvitarla\n(chi ti invita deve avere il tuo contatto\nsu Telegram, e viceversa).";
|
||||
"lng_failed_add_not_mutual" = "Spiacenti, se una persona lascia un gruppo, solo un contatto in comune può reinvitarla (chi ti invita deve avere il tuo numero, e viceversa).";
|
||||
"lng_failed_add_not_mutual_channel" = "Spiacenti, se una persona lascia un canale, solo un contatto in comune può reinvitarla (chi ti invita deve avere il tuo numero, e viceversa).";
|
||||
|
||||
"lng_sure_delete_contact" = "Sicuro di volere eliminare {contact} dalla tua lista dei contatti?";
|
||||
"lng_sure_delete_history" = "Sicuro di voler eliminare tutta la cronologia dei messaggi con {contact}?\n\nQuesta azione non può essere annullata.";
|
||||
|
@ -496,7 +511,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_action_kick_user" = "{from} ha rimosso {user}";
|
||||
"lng_action_user_left" = "{from} ha lasciato il gruppo";
|
||||
"lng_action_user_joined" = "{from} si è unito al gruppo";
|
||||
"lng_action_user_joined_by_link" = "{from} si è unito al gruppo tramite link di invito";
|
||||
"lng_action_user_joined_by_link" = "{from} si è unito al gruppo via link di invito";
|
||||
"lng_action_user_registered" = "{from} si è unito a Telegram";
|
||||
"lng_action_removed_photo" = "{from} ha rimosso la foto del gruppo";
|
||||
"lng_action_removed_photo_channel" = "Foto del canale rimossa";
|
||||
|
@ -556,11 +571,19 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_media_type_links" = "Link condivisi";
|
||||
|
||||
"lng_media_open_with" = "Apri con";
|
||||
"lng_media_download" = "Download";
|
||||
"lng_media_download" = "Scarica";
|
||||
"lng_media_cancel" = "Annulla";
|
||||
"lng_media_video" = "Video";
|
||||
"lng_media_audio" = "Nota vocale";
|
||||
|
||||
"lng_media_auto_settings" = "Impostazioni di download automatico";
|
||||
"lng_media_auto_photo" = "Download automatico foto";
|
||||
"lng_media_auto_audio" = "Download automatico audio";
|
||||
"lng_media_auto_gif" = "Download automatico GIF";
|
||||
"lng_media_auto_private_chats" = "Chat";
|
||||
"lng_media_auto_groups" = "Gruppi e canali";
|
||||
"lng_media_auto_play" = "Autoriproduzione";
|
||||
|
||||
"lng_emoji_category0" = "Utilizzate di frequente";
|
||||
"lng_emoji_category1" = "Persone";
|
||||
"lng_emoji_category2" = "Natura";
|
||||
|
@ -571,8 +594,13 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_emoji_category7" = "Simboli e bandiere";
|
||||
|
||||
"lng_switch_stickers" = "Sticker";
|
||||
"lng_switch_stickers_gifs" = "GIF e Sticker";
|
||||
"lng_switch_emoji" = "Emoji";
|
||||
|
||||
"lng_saved_gifs" = "GIF salvate";
|
||||
"lng_inline_bot_results" = "Risultati da {inline_bot}";
|
||||
"lng_inline_bot_no_results" = "Nessun risultato";
|
||||
|
||||
"lng_box_remove" = "Rimuovi";
|
||||
|
||||
"lng_custom_stickers" = "Sticker personalizzati";
|
||||
|
@ -664,6 +692,8 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_save_file" = "Salva file";
|
||||
"lng_save_downloaded" = "{ready} / {total} {mb}";
|
||||
"lng_duration_and_size" = "{duration}, {size}";
|
||||
"lng_duration_played" = "{played} / {duration}";
|
||||
"lng_date_and_duration" = "{date}, {duration}";
|
||||
"lng_choose_images" = "Scegli immagini";
|
||||
|
||||
"lng_context_view_profile" = "Visualizza profilo";
|
||||
|
@ -699,6 +729,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_context_delete_file" = "Elimina file";
|
||||
"lng_context_close_file" = "Chiudi file";
|
||||
"lng_context_copy_text" = "Copia testo";
|
||||
"lng_context_save_gif" = "Salva GIF";
|
||||
"lng_context_to_msg" = "Vai al messaggio";
|
||||
"lng_context_reply_msg" = "Rispondi";
|
||||
"lng_context_forward_msg" = "Inoltra messaggio";
|
||||
|
@ -801,7 +832,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
|
||||
"lng_new_version_wrap" = "Telegram Desktop si è aggiornato alla versione {version}\n\n{changes}\n\nLa cronologia degli aggiornamenti è disponibile qui:\n{link}";
|
||||
"lng_new_version_minor" = "— Bug fix e altri miglioramenti minori";
|
||||
"lng_new_version_text" = "— Gestione degli sticker: Riordina manualmente i tuoi set di sticker, ora sono sincronizzati tra i tuoi dispositivi\n— Clicca e tieni premuto su uno sticker per visualizzare l'anteprima prima di inviarlo\n— Nuovo menu contestuale per le chat nella lista chat\n— Tutte le nuove emoji ora sono supportate";
|
||||
"lng_new_version_text" = "Rivoluzione GIF: L'invio e il download delle GIF sono ora 10 volte più veloci, riproduci automaticamente le GIF e salva le tue GIF preferite in una pagina dedicata nel pannello sticker.\n\nPiù info sulle GIF:\n{gifs_link}\n\n@-Bot: Un nuovo modo di aggiungere contenuto dai bot in qualsiasi chat. Scrivi l'username di un bot e la tua domanda nel campo di scrittura per ricevere risultati immediati e inviarli nella chat. Prova a scrivere “@gif dog” nella tua prossima chat. Bot di esempio: @gif, @wiki, @bing, @vid, @bold.\n\nPiù info sui @-Bot:\n{bots_link}\n\nInoltre in questa versione: Nuovo design per i media, impostazioni di download automatico per foto, note vocali e GIF.";
|
||||
|
||||
"lng_menu_insert_unicode" = "Inserisci carattere di controllo Unicode";
|
||||
|
||||
|
|
|
@ -48,6 +48,19 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_month11" = "11월";
|
||||
"lng_month12" = "12월";
|
||||
|
||||
"lng_month1_small" = "1월";
|
||||
"lng_month2_small" = "2월";
|
||||
"lng_month3_small" = "3월";
|
||||
"lng_month4_small" = "4월";
|
||||
"lng_month5_small" = "5월";
|
||||
"lng_month6_small" = "6월";
|
||||
"lng_month7_small" = "7월";
|
||||
"lng_month8_small" = "8월";
|
||||
"lng_month9_small" = "9월";
|
||||
"lng_month10_small" = "10월";
|
||||
"lng_month11_small" = "11월";
|
||||
"lng_month12_small" = "12월";
|
||||
|
||||
"lng_weekday1" = "월";
|
||||
"lng_weekday2" = "화";
|
||||
"lng_weekday3" = "수";
|
||||
|
@ -66,6 +79,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
|
||||
"lng_month_day" = "{month} {day}일";
|
||||
"lng_month_day_year" = "{month} {day}, {year}";
|
||||
"lng_month_year" = "{month}, {year}";
|
||||
|
||||
"lng_box_ok" = "확인";
|
||||
|
||||
|
@ -108,6 +122,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
|
||||
"lng_server_error" = "내부 서버 오류";
|
||||
"lng_flood_error" = "시도가 너무 많습니다. 나중에 다시 시도해주세요.";
|
||||
"lng_gif_error" = "GIF 애니메이션을 읽는 동안 에러가 발생하였습니다.";
|
||||
"lng_deleted" = "알 수 없음";
|
||||
"lng_deleted_message" = "삭제된 메시지";
|
||||
|
||||
|
@ -470,8 +485,8 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_create_channel_crop" = "채널프로필 사진으로 사용할 사각영역을 선택하세요";
|
||||
|
||||
"lng_failed_add_participant" = "사용자를 추가 하지 못하였습니다. 나중에 다시 시도해주세요";
|
||||
"lng_failed_add_not_mutual" = "죄송합니다. 그룹방에서 대화상대방이 나갔을 경우, \n상대 전화번호가 있는 분만 초대가 가능합니다. \n(서로 전화번호가 등록되어져 있어야만 가능)";
|
||||
"lng_failed_add_not_mutual_channel" = "죄송합니다. 채널에서 대화상대방이 나갔을 경우,\n상대 전화번호가 있는 분만 초대가 가능합니다.\n(서로 전화번호가 등록되어져 있어야만 가능)";
|
||||
"lng_failed_add_not_mutual" = "죄송합니다. 그룹방에서 대화상대방이 나갔을 경우, 상대 전화번호가 있는 분만 초대가 가능합니다. (서로 전화번호가 등록되어져 있어야만 가능)";
|
||||
"lng_failed_add_not_mutual_channel" = "죄송합니다. 채널에서 대화상대방이 나갔을 경우, 상대 전화번호가 있는 분만 초대가 가능합니다. (서로 전화번호가 등록되어져 있어야만 가능)";
|
||||
|
||||
"lng_sure_delete_contact" = "{contact} 님을 주소록에서 \n삭제하시겠습니까?";
|
||||
"lng_sure_delete_history" = "{contact} 님과 관련된 모든 메시지를 \n삭제하시겠습니까?\n\n삭제 하실 경우 취소가 불가능합니다.";
|
||||
|
@ -561,6 +576,14 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_media_video" = "비디오 파일";
|
||||
"lng_media_audio" = "음성 메시지";
|
||||
|
||||
"lng_media_auto_settings" = "미디어 자동 다운로드 설정";
|
||||
"lng_media_auto_photo" = "사진 자동 다운로드";
|
||||
"lng_media_auto_audio" = "음성 메시지 자동 다운로드";
|
||||
"lng_media_auto_gif" = "GIF 자동 다운로드";
|
||||
"lng_media_auto_private_chats" = "비밀대화";
|
||||
"lng_media_auto_groups" = "그룹과 채널";
|
||||
"lng_media_auto_play" = "자동재생";
|
||||
|
||||
"lng_emoji_category0" = "자주 사용";
|
||||
"lng_emoji_category1" = "사람";
|
||||
"lng_emoji_category2" = "자연";
|
||||
|
@ -571,8 +594,13 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_emoji_category7" = "심볼 및 국기";
|
||||
|
||||
"lng_switch_stickers" = "스티커";
|
||||
"lng_switch_stickers_gifs" = "GIF & 스티커";
|
||||
"lng_switch_emoji" = "이모티콘";
|
||||
|
||||
"lng_saved_gifs" = "저장된 GIF";
|
||||
"lng_inline_bot_results" = "{inline_bot} 결과";
|
||||
"lng_inline_bot_no_results" = "결과 없음";
|
||||
|
||||
"lng_box_remove" = "삭제";
|
||||
|
||||
"lng_custom_stickers" = "커스텀 스티커";
|
||||
|
@ -664,6 +692,8 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_save_file" = "파일 저장";
|
||||
"lng_save_downloaded" = "{ready} / {total} {mb}";
|
||||
"lng_duration_and_size" = "{duration}, {size}";
|
||||
"lng_duration_played" = "{played} / {duration}";
|
||||
"lng_date_and_duration" = "{date}, {duration}";
|
||||
"lng_choose_images" = "이미지 선택";
|
||||
|
||||
"lng_context_view_profile" = "프로필 보기";
|
||||
|
@ -699,6 +729,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_context_delete_file" = "파일 삭제";
|
||||
"lng_context_close_file" = "파일 닫기";
|
||||
"lng_context_copy_text" = "텍스트 복사";
|
||||
"lng_context_save_gif" = "GIF 저장";
|
||||
"lng_context_to_msg" = "메시지로 이동";
|
||||
"lng_context_reply_msg" = "답장";
|
||||
"lng_context_forward_msg" = "메시지 전달";
|
||||
|
@ -801,7 +832,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
|
||||
"lng_new_version_wrap" = "텔레그램 데스크탑은 {version} 버전으로 업데이트 되었습니다.\n\n{changes}\n\n전체 버전 히스토리는 아래에서 확인 가능합니다:\n{link}";
|
||||
"lng_new_version_minor" = "— 버그 수정 및 일부 기능 향상";
|
||||
"lng_new_version_text" = "— 스티커관리 : 스티커팩을 순서를 수동으로 변경하여, 연결된 모든 기기에 동기화 \n— 스티커를 지속하여 누를 경우 전송전 프리뷰 기능 추가\n— 채팅목록에 채팅관련 메뉴 추가\n— 기존 이모티콘 지원";
|
||||
"lng_new_version_text" = "GIF 혁명: 10배 빠른 전송, 다운로드 및 자동재생이 가능하며, 스티커 패널에서 즐겨찾는 GIF를 저장가능\n\nGIF에 대한 자세한 정보:\n{gifs_link}\n\n@-봇 : 모든 대화에 봇 기능을 추가 할 수 있습니다. 봇 아이디를 입력란에 같이 입력해주시면 즉시 결과값을 확인 할 수 있습니다.“@gif dog”와 같은 명령어를 입력란에 같이 입력해보세요. 예시:@gif, @wiki, @bing, @vid, @bold.\n\n@-봇에 대한 자세한 정보\n{bots_link}\n\n업데이트 추가사항: 미디어, 사진, 음성메시지 및 GIF 파일 자동다운로드 설정화면 새로운 디자인 적용";
|
||||
|
||||
"lng_menu_insert_unicode" = "유니코드 문자를 입력하세요.";
|
||||
|
||||
|
|
|
@ -48,6 +48,19 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_month11" = "november";
|
||||
"lng_month12" = "december";
|
||||
|
||||
"lng_month1_small" = "jan";
|
||||
"lng_month2_small" = "feb";
|
||||
"lng_month3_small" = "mrt";
|
||||
"lng_month4_small" = "apr";
|
||||
"lng_month5_small" = "mei";
|
||||
"lng_month6_small" = "jun";
|
||||
"lng_month7_small" = "jul";
|
||||
"lng_month8_small" = "aug";
|
||||
"lng_month9_small" = "sep";
|
||||
"lng_month10_small" = "okt";
|
||||
"lng_month11_small" = "nov";
|
||||
"lng_month12_small" = "dec";
|
||||
|
||||
"lng_weekday1" = "ma";
|
||||
"lng_weekday2" = "di";
|
||||
"lng_weekday3" = "wo";
|
||||
|
@ -66,6 +79,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
|
||||
"lng_month_day" = "{day} {month}";
|
||||
"lng_month_day_year" = "{day} {month}, {year}";
|
||||
"lng_month_year" = "{month}, {year}";
|
||||
|
||||
"lng_box_ok" = "Ok";
|
||||
|
||||
|
@ -108,6 +122,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
|
||||
"lng_server_error" = "Interne serverfout.";
|
||||
"lng_flood_error" = "Teveel pogingen. Probeer het later opnieuw.";
|
||||
"lng_gif_error" = "Er is iets een fout opgetreden bij het lezen van de GIF :(";
|
||||
"lng_deleted" = "Onbekend";
|
||||
"lng_deleted_message" = "Verwijderd bericht";
|
||||
|
||||
|
@ -217,7 +232,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_settings_section_general" = "Algemeen";
|
||||
"lng_settings_change_lang" = "Taal wijzigen";
|
||||
"lng_languages" = "Talen";
|
||||
"lng_sure_save_language" = "Telegram moet herstarten om de taal te wijzigen";
|
||||
"lng_sure_save_language" = "Opnieuw starten om de taal te wijzen?";
|
||||
"lng_settings_auto_update" = "Automatisch bijwerken";
|
||||
"lng_settings_current_version" = "Versie {version}";
|
||||
"lng_settings_check_now" = "Controleer op updates";
|
||||
|
@ -470,8 +485,8 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_create_channel_crop" = "Kies een vierkant voor de kanaalfoto";
|
||||
|
||||
"lng_failed_add_participant" = "Gebruiker toevoegen mislukt. Probeer het later.";
|
||||
"lng_failed_add_not_mutual" = "Iemand die de groep verlaat kan alleen\nDoor een wederzijds contact \nworden toegevoegd \n(opgeslagen nummers) ";
|
||||
"lng_failed_add_not_mutual_channel" = "Iemand die het kanaal verlaat kan alleen\nDoor een wederzijds contact \nworden toegevoegd \n(opgeslagen nummers) ";
|
||||
"lng_failed_add_not_mutual" = "Iemand die de groep verlaat kan alleen door een wederzijds contact worden toegevoegd (opgeslagen nummers)";
|
||||
"lng_failed_add_not_mutual_channel" = "Iemand die het kanaal verlaat kan alleen door een wederzijds contact worden toegevoegd (opgeslagen nummers)";
|
||||
|
||||
"lng_sure_delete_contact" = "{contact} echt verwijderen uit contacten?";
|
||||
"lng_sure_delete_history" = "Geschiedenis met {contact} echt wissen? \n\nDeze actie kan niet ongedaan worden gemaakt.";
|
||||
|
@ -561,6 +576,14 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_media_video" = "Video";
|
||||
"lng_media_audio" = "Spraakbericht";
|
||||
|
||||
"lng_media_auto_settings" = "Instellingen voor media-downloads";
|
||||
"lng_media_auto_photo" = "Foto's automatisch downloaden";
|
||||
"lng_media_auto_audio" = "Audio automatisch downloaden";
|
||||
"lng_media_auto_gif" = "GIF's automatisch downloaden";
|
||||
"lng_media_auto_private_chats" = "Chats";
|
||||
"lng_media_auto_groups" = "Groepen en kanalen";
|
||||
"lng_media_auto_play" = "Automatisch afspelen";
|
||||
|
||||
"lng_emoji_category0" = "Veelgebruikt";
|
||||
"lng_emoji_category1" = "Mensen";
|
||||
"lng_emoji_category2" = "Natuur";
|
||||
|
@ -571,8 +594,13 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_emoji_category7" = "Symbolen en vlaggen";
|
||||
|
||||
"lng_switch_stickers" = "Stickers";
|
||||
"lng_switch_stickers_gifs" = "GIF's & stickers";
|
||||
"lng_switch_emoji" = "Emoji";
|
||||
|
||||
"lng_saved_gifs" = "Opgeslagen GIF's";
|
||||
"lng_inline_bot_results" = "Resultaten van {inline_bot}";
|
||||
"lng_inline_bot_no_results" = "Geen resultaten";
|
||||
|
||||
"lng_box_remove" = "Verwijder";
|
||||
|
||||
"lng_custom_stickers" = "Aangepaste stickers";
|
||||
|
@ -664,6 +692,8 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_save_file" = "Bestand opslaan";
|
||||
"lng_save_downloaded" = "{ready} / {total} {mb}";
|
||||
"lng_duration_and_size" = "{duration}, {size}";
|
||||
"lng_duration_played" = "{played} / {duration}";
|
||||
"lng_date_and_duration" = "{date}, {duration}";
|
||||
"lng_choose_images" = "Afbeeldingen kiezen";
|
||||
|
||||
"lng_context_view_profile" = "Profiel weergeven";
|
||||
|
@ -699,6 +729,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_context_delete_file" = "Bestand verwijderen";
|
||||
"lng_context_close_file" = "Bestand sluiten";
|
||||
"lng_context_copy_text" = "Tekst kopiëren";
|
||||
"lng_context_save_gif" = "GIF opslaan";
|
||||
"lng_context_to_msg" = "Naar bericht gaan";
|
||||
"lng_context_reply_msg" = "Antwoord";
|
||||
"lng_context_forward_msg" = "Bericht doorsturen";
|
||||
|
@ -801,7 +832,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
|
||||
"lng_new_version_wrap" = "Telegram is bijgewerkt naar versie {version}\n\n{changes} \n\nVolledige versiegeschiedenis is hier te vinden:\n{link}";
|
||||
"lng_new_version_minor" = "— Probleemoplossing en andere kleine verbeteringen";
|
||||
"lng_new_version_text" = "— Stickerbeheer: Je kunt nu handmatig je stickerbundels sorteren, de volgorde synchroniseren we voor je, over al je apparaten.\n— Klik en hou een sticker vast om een voorbeeld weer te geven voor het versturen.\n— Nieuw contextmenu voor chats in het chats-overzicht\n— Ondersteuning voor alle bestaande emoji";
|
||||
"lng_new_version_text" = "GIF-revolutie: 10 keer zo snel GIF's sturen en downloaden. Speel ze automatisch af en sla je favorieten op in het stickerpaneel.\n\nMeer over GIFs:\n{gifs_link}\n\nInline-bots: Voeg botcontent toe aan chats op een nieuwe manier! Geef in het invoerveld de naam van een bot en je commando in en stuur de resultaten naar je chatpartner. Probeer het eens met “@gif dog”. Voorbeelden: @gif, @wiki, @bing, @vid, @bold.\n\nMeer over inline-bots:\n{bots_link}\n\nIn deze release hebben we nog meer voor je. Een nieuw design voor media en automatische download-instellingen voor foto's, spraakberichten en GIF's.";
|
||||
|
||||
"lng_menu_insert_unicode" = "Unicode-besturingsteken invoegen";
|
||||
|
||||
|
|
|
@ -48,6 +48,19 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_month11" = "Novembro";
|
||||
"lng_month12" = "Dezembro";
|
||||
|
||||
"lng_month1_small" = "Jan";
|
||||
"lng_month2_small" = "Fev";
|
||||
"lng_month3_small" = "Mar";
|
||||
"lng_month4_small" = "Abr";
|
||||
"lng_month5_small" = "Mai";
|
||||
"lng_month6_small" = "Jun";
|
||||
"lng_month7_small" = "Jul";
|
||||
"lng_month8_small" = "Ago";
|
||||
"lng_month9_small" = "Set";
|
||||
"lng_month10_small" = "Out";
|
||||
"lng_month11_small" = "Nov";
|
||||
"lng_month12_small" = "Dez";
|
||||
|
||||
"lng_weekday1" = "Seg";
|
||||
"lng_weekday2" = "Ter";
|
||||
"lng_weekday3" = "Qua";
|
||||
|
@ -66,6 +79,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
|
||||
"lng_month_day" = "{month} {day}";
|
||||
"lng_month_day_year" = "{day} {month}, {year}";
|
||||
"lng_month_year" = "{month}, {year}";
|
||||
|
||||
"lng_box_ok" = "OK";
|
||||
|
||||
|
@ -108,6 +122,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
|
||||
"lng_server_error" = "Erro interno do servidor.";
|
||||
"lng_flood_error" = "Muitas tentativas. Por favor, tente novamente mais tarde.";
|
||||
"lng_gif_error" = "Um erro ocorreu com a animação do GIF :(";
|
||||
"lng_deleted" = "Desconhecido";
|
||||
"lng_deleted_message" = "Mensagem apagada";
|
||||
|
||||
|
@ -342,7 +357,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_connection_try_ipv6" = "Tentando conexão via IPv6";
|
||||
"lng_connection_host_ph" = "Nome do host";
|
||||
"lng_connection_port_ph" = "Porta";
|
||||
"lng_connection_user_ph" = "Nome de usuário";
|
||||
"lng_connection_user_ph" = "Usuário";
|
||||
"lng_connection_password_ph" = "Senha";
|
||||
"lng_connection_save" = "Salvar";
|
||||
"lng_settings_show_sessions" = "Exibir todas as sessões";
|
||||
|
@ -448,7 +463,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_create_group_next" = "Próximo";
|
||||
"lng_create_group_create" = "Criar";
|
||||
"lng_create_group_title" = "Novo Grupo";
|
||||
"lng_create_group_about" = "Grupos são ideais para comunidades menores, \neles podem ter até {count:_not_used|# membro|# membros}";
|
||||
"lng_create_group_about" = "Grupos são ideais para comunidades menores,\ncom até {count:_not_used|# membro|# membros}";
|
||||
"lng_create_channel_title" = "Novo Canal";
|
||||
"lng_create_channel_about" = "Canais são uma ferramenta para transmitir suas mensagens para audiências ilimitadas";
|
||||
"lng_create_public_channel_title" = "Canal Público";
|
||||
|
@ -470,8 +485,8 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_create_channel_crop" = "Selecione uma área para a foto do canal";
|
||||
|
||||
"lng_failed_add_participant" = "Usuário não pôde ser adicionado. Tente novamente mais tarde.";
|
||||
"lng_failed_add_not_mutual" = "Se uma pessoa deixou o grupo, apenas um\ncontato mútuo pode colocá-la novamente\n(eles precisam do seu número na agenda\ndo telefone e você do número deles).";
|
||||
"lng_failed_add_not_mutual_channel" = "Se uma pessoa deixou o canal, apenas um\ncontato mútuo pode colocá-la novamente\n(eles precisam do seu número na agenda\ndo telefone e você do número deles).";
|
||||
"lng_failed_add_not_mutual" = "Se uma pessoa deixou o grupo, apenas um contato mútuo pode colocá-la novamente (eles precisam do seu número na agenda do telefone e você do número deles).";
|
||||
"lng_failed_add_not_mutual_channel" = "Se uma pessoa deixou o canal, apenas um contato mútuo pode colocá-la novamente (eles precisam do seu número na agenda do telefone e você do número deles).";
|
||||
|
||||
"lng_sure_delete_contact" = "Você tem certeza que deseja remover {contact} da sua lista de contatos?";
|
||||
"lng_sure_delete_history" = "Você tem certeza que deseja apagar todo o seu histórico de mensagens com {contact}?\n\nEssa ação não pode ser desfeita.";
|
||||
|
@ -561,6 +576,14 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_media_video" = "Vídeo";
|
||||
"lng_media_audio" = "Mensagem de voz";
|
||||
|
||||
"lng_media_auto_settings" = "Configurações do download automático de mídia";
|
||||
"lng_media_auto_photo" = "Baixar foto automaticamente";
|
||||
"lng_media_auto_audio" = "Baixar mensagem de voz automaticamente";
|
||||
"lng_media_auto_gif" = "Baixar GIF autometicamente";
|
||||
"lng_media_auto_private_chats" = "Conversas privadas";
|
||||
"lng_media_auto_groups" = "Grupos e canais";
|
||||
"lng_media_auto_play" = "Reproduzir automaticamente";
|
||||
|
||||
"lng_emoji_category0" = "Frequentemente usado";
|
||||
"lng_emoji_category1" = "Pessoas";
|
||||
"lng_emoji_category2" = "Natureza";
|
||||
|
@ -571,8 +594,13 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_emoji_category7" = "Símbolos e Bandeiras";
|
||||
|
||||
"lng_switch_stickers" = "Stickers";
|
||||
"lng_switch_stickers_gifs" = "GIFs e Stickers";
|
||||
"lng_switch_emoji" = "Emoji";
|
||||
|
||||
"lng_saved_gifs" = "GIFs Salvos";
|
||||
"lng_inline_bot_results" = "Resultados de {inline_bot}";
|
||||
"lng_inline_bot_no_results" = "Nenhum resultado";
|
||||
|
||||
"lng_box_remove" = "Remover";
|
||||
|
||||
"lng_custom_stickers" = "Stickers customizados";
|
||||
|
@ -664,6 +692,8 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_save_file" = "Salvar arquivo";
|
||||
"lng_save_downloaded" = "{ready} / {total} {mb}";
|
||||
"lng_duration_and_size" = "{duration}, {size}";
|
||||
"lng_duration_played" = "{played} / {duration}";
|
||||
"lng_date_and_duration" = "{date}, {duration}";
|
||||
"lng_choose_images" = "Escolher imagens";
|
||||
|
||||
"lng_context_view_profile" = "Ver perfil";
|
||||
|
@ -699,6 +729,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
"lng_context_delete_file" = "Apagar Arquivo";
|
||||
"lng_context_close_file" = "Fechar Arquivo";
|
||||
"lng_context_copy_text" = "Copiar Texto";
|
||||
"lng_context_save_gif" = "Salvar GIF";
|
||||
"lng_context_to_msg" = "Ir Para Mensagem";
|
||||
"lng_context_reply_msg" = "Responder";
|
||||
"lng_context_forward_msg" = "Encaminhar Mensagem";
|
||||
|
@ -801,7 +832,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
|
||||
"lng_new_version_wrap" = "Telegram Desktop foi atualizado para a versão {version}\n\n{changes}\n\nHistórico completo de mudanças disponível aqui:\n{link}";
|
||||
"lng_new_version_minor" = "— Resolução de bugs e outras melhorias menores";
|
||||
"lng_new_version_text" = "— Gerenciamento de stickers: rearranje manualmente seus pacotes de sticker, a ordem dos pacotes agora é sincronizada entre todos os dispositivos\n— Clique e segure sobre um sticker para pré-visualizar antes de enviar\n— Novo menu de contexto para os chats na lista de chats \n— Suporte para todos os emojis existentes";
|
||||
"lng_new_version_text" = "Revolução dos GIFs: download e envio 10x mais rápido, reprodução automática, salve seus GIFs favoritos em um guia dedicada no painel de stickers.\n\nMais sobre GIFs:\n{gifs_link}\n\nBots integrados: Uma nova maneira de adicionar conteúdo de um bot a qualquer conversa. Digite o nome de usuário do bot seguido do comando no campo de texto para obter resultados imediatos e enviá-los na conversa. Experimente digitar “@gif dog” na sua próxima conversa. Bots de exemplo: @gif, @wiki, @bing, @vid, @bold.\n\nMais sobre bots integrados:\n{bots_link}\n\nTambém nessa versão: Novo design para mídias, configuração de download automático para fotos, mensagens de voz e GIFs.";
|
||||
|
||||
"lng_menu_insert_unicode" = "Inserir caractere de controle Unicode";
|
||||
|
||||
|
|
|
@ -29,15 +29,15 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
|||
|
||||
BackgroundWidget::BackgroundWidget(QWidget *parent, LayeredWidget *w) : TWidget(parent)
|
||||
, w(w)
|
||||
, aBackground(0)
|
||||
, aBackgroundFunc(anim::easeOutCirc)
|
||||
, a_bg(0)
|
||||
, _a_background(animation(this, &BackgroundWidget::step_background))
|
||||
, hiding(false)
|
||||
, shadow(st::boxShadow) {
|
||||
w->setParent(this);
|
||||
if (App::app()) App::app()->mtpPause();
|
||||
setGeometry(0, 0, App::wnd()->width(), App::wnd()->height());
|
||||
aBackground.start(1);
|
||||
anim::start(this);
|
||||
a_bg.start(1);
|
||||
_a_background.start();
|
||||
show();
|
||||
connect(w, SIGNAL(closed()), this, SLOT(onInnerClose()));
|
||||
connect(w, SIGNAL(resized()), this, SLOT(update()));
|
||||
|
@ -46,7 +46,7 @@ BackgroundWidget::BackgroundWidget(QWidget *parent, LayeredWidget *w) : TWidget(
|
|||
}
|
||||
|
||||
void BackgroundWidget::showFast() {
|
||||
animStep(st::layerSlideDuration + 1);
|
||||
_a_background.step(getms() + st::layerSlideDuration + 1);
|
||||
update();
|
||||
}
|
||||
|
||||
|
@ -58,10 +58,10 @@ void BackgroundWidget::paintEvent(QPaintEvent *e) {
|
|||
if (!trivial) {
|
||||
p.setClipRect(e->rect());
|
||||
}
|
||||
p.setOpacity(st::layerAlpha * aBackground.current());
|
||||
p.setOpacity(st::layerAlpha * a_bg.current());
|
||||
p.fillRect(rect(), st::layerBg->b);
|
||||
|
||||
p.setOpacity(aBackground.current());
|
||||
p.setOpacity(a_bg.current());
|
||||
shadow.paint(p, w->geometry(), st::boxShadowShift);
|
||||
}
|
||||
|
||||
|
@ -90,7 +90,7 @@ bool BackgroundWidget::onInnerClose() {
|
|||
_hidden.pop_back();
|
||||
w->show();
|
||||
resizeEvent(0);
|
||||
w->animStep(1);
|
||||
w->showStep(1);
|
||||
update();
|
||||
return false;
|
||||
}
|
||||
|
@ -101,8 +101,8 @@ void BackgroundWidget::startHide() {
|
|||
|
||||
hiding = true;
|
||||
if (App::wnd()) App::wnd()->setInnerFocus();
|
||||
aBackground.start(0);
|
||||
anim::start(this);
|
||||
a_bg.start(0);
|
||||
_a_background.start();
|
||||
w->startHide();
|
||||
}
|
||||
|
||||
|
@ -139,7 +139,7 @@ void BackgroundWidget::replaceInner(LayeredWidget *n) {
|
|||
connect(w, SIGNAL(destroyed(QObject*)), this, SLOT(boxDestroyed(QObject*)));
|
||||
w->show();
|
||||
resizeEvent(0);
|
||||
w->animStep(1);
|
||||
w->showStep(1);
|
||||
update();
|
||||
}
|
||||
|
||||
|
@ -150,28 +150,25 @@ void BackgroundWidget::showLayerLast(LayeredWidget *n) {
|
|||
connect(n, SIGNAL(resized()), this, SLOT(update()));
|
||||
connect(n, SIGNAL(destroyed(QObject*)), this, SLOT(boxDestroyed(QObject*)));
|
||||
n->parentResized();
|
||||
n->animStep(1);
|
||||
n->showStep(1);
|
||||
n->hide();
|
||||
update();
|
||||
}
|
||||
|
||||
bool BackgroundWidget::animStep(float64 ms) {
|
||||
void BackgroundWidget::step_background(float64 ms, bool timer) {
|
||||
float64 dt = ms / (hiding ? st::layerHideDuration : st::layerSlideDuration);
|
||||
w->animStep(dt);
|
||||
bool res = true;
|
||||
w->showStep(dt);
|
||||
if (dt >= 1) {
|
||||
aBackground.finish();
|
||||
a_bg.finish();
|
||||
if (hiding) {
|
||||
App::wnd()->layerFinishedHide(this);
|
||||
}
|
||||
anim::stop(this);
|
||||
res = false;
|
||||
_a_background.stop();
|
||||
if (App::app()) App::app()->mtpUnpause();
|
||||
} else {
|
||||
aBackground.update(dt, aBackgroundFunc);
|
||||
a_bg.update(dt, anim::easeOutCirc);
|
||||
}
|
||||
update();
|
||||
return res;
|
||||
if (timer) update();
|
||||
}
|
||||
|
||||
void BackgroundWidget::boxDestroyed(QObject *obj) {
|
||||
|
@ -196,8 +193,9 @@ BackgroundWidget::~BackgroundWidget() {
|
|||
|
||||
StickerPreviewWidget::StickerPreviewWidget(QWidget *parent) : TWidget(parent)
|
||||
, a_shown(0, 0)
|
||||
, _a_shown(animFunc(this, &StickerPreviewWidget::animStep_shown))
|
||||
, _a_shown(animation(this, &StickerPreviewWidget::step_shown))
|
||||
, _doc(0)
|
||||
, _gif(0)
|
||||
, _cacheStatus(CacheNotLoaded) {
|
||||
setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
}
|
||||
|
@ -222,21 +220,20 @@ void StickerPreviewWidget::resizeEvent(QResizeEvent *e) {
|
|||
update();
|
||||
}
|
||||
|
||||
bool StickerPreviewWidget::animStep_shown(float64 ms) {
|
||||
void StickerPreviewWidget::step_shown(float64 ms, bool timer) {
|
||||
float64 dt = ms / st::stickerPreviewDuration;
|
||||
if (dt >= 1) {
|
||||
a_shown.finish();
|
||||
_a_shown.stop();
|
||||
a_shown.finish();
|
||||
if (a_shown.current() < 0.5) hide();
|
||||
} else {
|
||||
a_shown.update(dt, anim::linear);
|
||||
}
|
||||
update();
|
||||
return true;
|
||||
if (timer) update();
|
||||
}
|
||||
|
||||
void StickerPreviewWidget::showPreview(DocumentData *sticker) {
|
||||
if (sticker && !sticker->sticker()) sticker = 0;
|
||||
if (sticker && !sticker->isAnimation() && !sticker->sticker()) sticker = 0;
|
||||
if (sticker) {
|
||||
_cache = QPixmap();
|
||||
if (isHidden() || _a_shown.animating()) {
|
||||
|
@ -249,10 +246,17 @@ void StickerPreviewWidget::showPreview(DocumentData *sticker) {
|
|||
} else if (isHidden()) {
|
||||
return;
|
||||
} else {
|
||||
if (_gif) _cache = currentImage();
|
||||
a_shown.start(0);
|
||||
_a_shown.start();
|
||||
}
|
||||
_doc = sticker;
|
||||
if (_gif) {
|
||||
if (gif()) {
|
||||
delete _gif;
|
||||
}
|
||||
_gif = 0;
|
||||
}
|
||||
_cacheStatus = CacheNotLoaded;
|
||||
}
|
||||
|
||||
|
@ -263,7 +267,10 @@ void StickerPreviewWidget::hidePreview() {
|
|||
QSize StickerPreviewWidget::currentDimensions() const {
|
||||
if (!_doc) return QSize(_cache.width() / cIntRetinaFactor(), _cache.height() / cIntRetinaFactor());
|
||||
|
||||
QSize result(qMax(_doc->dimensions.width(), 1), qMax(_doc->dimensions.height(), 1));
|
||||
QSize result(qMax(convertScale(_doc->dimensions.width()), 1), qMax(convertScale(_doc->dimensions.height()), 1));
|
||||
if (gif() && _gif->ready()) {
|
||||
result = QSize(qMax(convertScale(_gif->width()), 1), qMax(convertScale(_gif->height()), 1));
|
||||
}
|
||||
if (result.width() > st::maxStickerSize) {
|
||||
result.setHeight(qMax(qRound((st::maxStickerSize * result.height()) / result.width()), 1));
|
||||
result.setWidth(st::maxStickerSize);
|
||||
|
@ -276,32 +283,68 @@ QSize StickerPreviewWidget::currentDimensions() const {
|
|||
}
|
||||
|
||||
QPixmap StickerPreviewWidget::currentImage() const {
|
||||
if (_doc && _cacheStatus != CacheLoaded) {
|
||||
bool already = !_doc->already().isEmpty(), hasdata = !_doc->data.isEmpty();
|
||||
if (!_doc->loader && _doc->status != FileFailed && !already && !hasdata) {
|
||||
_doc->save(QString());
|
||||
}
|
||||
if (_doc->sticker()->img->isNull() && (already || hasdata)) {
|
||||
if (already) {
|
||||
_doc->sticker()->img = ImagePtr(_doc->already());
|
||||
} else {
|
||||
_doc->sticker()->img = ImagePtr(_doc->data);
|
||||
if (_doc) {
|
||||
if (_doc->sticker()) {
|
||||
if (_cacheStatus != CacheLoaded) {
|
||||
_doc->checkSticker();
|
||||
if (_doc->sticker()->img->isNull()) {
|
||||
if (_cacheStatus != CacheThumbLoaded && _doc->thumb->loaded()) {
|
||||
QSize s = currentDimensions();
|
||||
_cache = _doc->thumb->pixBlurred(s.width(), s.height());
|
||||
_cacheStatus = CacheThumbLoaded;
|
||||
}
|
||||
} else {
|
||||
QSize s = currentDimensions();
|
||||
_cache = _doc->sticker()->img->pix(s.width(), s.height());
|
||||
_cacheStatus = CacheLoaded;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_doc->sticker()->img->isNull()) {
|
||||
if (_cacheStatus != CacheThumbLoaded) {
|
||||
} else {
|
||||
_doc->automaticLoad(0);
|
||||
if (_doc->loaded()) {
|
||||
if (!_gif && _gif != BadClipReader) {
|
||||
StickerPreviewWidget *that = const_cast<StickerPreviewWidget*>(this);
|
||||
that->_gif = new ClipReader(_doc->location(), _doc->data(), func(that, &StickerPreviewWidget::clipCallback));
|
||||
if (gif()) _gif->setAutoplay();
|
||||
}
|
||||
}
|
||||
if (gif() && _gif->started()) {
|
||||
QSize s = currentDimensions();
|
||||
return _gif->current(s.width(), s.height(), s.width(), s.height(), getms());
|
||||
}
|
||||
if (_cacheStatus != CacheThumbLoaded && _doc->thumb->loaded()) {
|
||||
QSize s = currentDimensions();
|
||||
_cache = _doc->thumb->pixBlurred(s.width(), s.height());
|
||||
_cacheStatus = CacheThumbLoaded;
|
||||
}
|
||||
} else {
|
||||
QSize s = currentDimensions();
|
||||
_cache = _doc->sticker()->img->pix(s.width(), s.height());
|
||||
_cacheStatus = CacheLoaded;
|
||||
}
|
||||
}
|
||||
return _cache;
|
||||
}
|
||||
|
||||
void StickerPreviewWidget::clipCallback(ClipReaderNotification notification) {
|
||||
switch (notification) {
|
||||
case ClipReaderReinit: {
|
||||
if (gif() && _gif->state() == ClipError) {
|
||||
delete _gif;
|
||||
_gif = BadClipReader;
|
||||
}
|
||||
|
||||
if (gif() && _gif->ready() && !_gif->started()) {
|
||||
QSize s = currentDimensions();
|
||||
_gif->start(s.width(), s.height(), s.width(), s.height(), false);
|
||||
}
|
||||
|
||||
update();
|
||||
} break;
|
||||
|
||||
case ClipReaderRepaint: {
|
||||
if (gif() && !_gif->currentDisplayed()) {
|
||||
update();
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
StickerPreviewWidget::~StickerPreviewWidget() {
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ class LayeredWidget : public TWidget {
|
|||
|
||||
public:
|
||||
|
||||
virtual void animStep(float64 ms) {
|
||||
virtual void showStep(float64 ms) {
|
||||
}
|
||||
virtual void parentResized() = 0;
|
||||
virtual void startHide() {
|
||||
|
@ -57,7 +57,7 @@ signals:
|
|||
|
||||
};
|
||||
|
||||
class BackgroundWidget : public TWidget, public Animated {
|
||||
class BackgroundWidget : public TWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
@ -76,7 +76,7 @@ public:
|
|||
void replaceInner(LayeredWidget *n);
|
||||
void showLayerLast(LayeredWidget *n);
|
||||
|
||||
bool animStep(float64 ms);
|
||||
void step_background(float64 ms, bool timer);
|
||||
|
||||
bool canSetFocus() const;
|
||||
void setInnerFocus();
|
||||
|
@ -98,8 +98,9 @@ private:
|
|||
LayeredWidget *w;
|
||||
typedef QList<LayeredWidget*> HiddenLayers;
|
||||
HiddenLayers _hidden;
|
||||
anim::fvalue aBackground;
|
||||
anim::transition aBackgroundFunc;
|
||||
anim::fvalue a_bg;
|
||||
Animation _a_background;
|
||||
|
||||
bool hiding;
|
||||
|
||||
BoxShadow shadow;
|
||||
|
@ -115,7 +116,7 @@ public:
|
|||
void paintEvent(QPaintEvent *e);
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
|
||||
bool animStep_shown(float64 ms);
|
||||
void step_shown(float64 ms, bool timer);
|
||||
|
||||
void showPreview(DocumentData *sticker);
|
||||
void hidePreview();
|
||||
|
@ -130,6 +131,12 @@ private:
|
|||
anim::fvalue a_shown;
|
||||
Animation _a_shown;
|
||||
DocumentData *_doc;
|
||||
ClipReader *_gif;
|
||||
bool gif() const {
|
||||
return (!_gif || _gif == BadClipReader) ? false : true;
|
||||
}
|
||||
|
||||
void clipCallback(ClipReaderNotification notification);
|
||||
|
||||
enum CacheStatus {
|
||||
CacheNotLoaded,
|
||||
|
|
2086
Telegram/SourceFiles/layout.cpp
Normal file
2086
Telegram/SourceFiles/layout.cpp
Normal file
File diff suppressed because it is too large
Load diff
702
Telegram/SourceFiles/layout.h
Normal file
702
Telegram/SourceFiles/layout.h
Normal file
|
@ -0,0 +1,702 @@
|
|||
/*
|
||||
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-2015 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
static const uint32 FullSelection = 0xFFFFFFFF;
|
||||
|
||||
extern TextParseOptions _textNameOptions, _textDlgOptions;
|
||||
extern TextParseOptions _historyTextOptions, _historyBotOptions, _historyTextNoMonoOptions, _historyBotNoMonoOptions;
|
||||
|
||||
const TextParseOptions &itemTextOptions(History *h, PeerData *f);
|
||||
const TextParseOptions &itemTextNoMonoOptions(History *h, PeerData *f);
|
||||
|
||||
enum RoundCorners {
|
||||
NoneCorners = 0x00, // for images
|
||||
BlackCorners,
|
||||
ServiceCorners,
|
||||
ServiceSelectedCorners,
|
||||
SelectedOverlayCorners,
|
||||
DateCorners,
|
||||
DateSelectedCorners,
|
||||
ForwardCorners,
|
||||
MediaviewSaveCorners,
|
||||
EmojiHoverCorners,
|
||||
StickerHoverCorners,
|
||||
BotKeyboardCorners,
|
||||
BotKeyboardOverCorners,
|
||||
BotKeyboardDownCorners,
|
||||
PhotoSelectOverlayCorners,
|
||||
|
||||
DocBlueCorners,
|
||||
DocGreenCorners,
|
||||
DocRedCorners,
|
||||
DocYellowCorners,
|
||||
|
||||
InShadowCorners, // for photos without bg
|
||||
InSelectedShadowCorners,
|
||||
|
||||
MessageInCorners, // with shadow
|
||||
MessageInSelectedCorners,
|
||||
MessageOutCorners,
|
||||
MessageOutSelectedCorners,
|
||||
|
||||
RoundCornersCount
|
||||
};
|
||||
|
||||
static const int32 FileStatusSizeReady = 0x7FFFFFF0;
|
||||
static const int32 FileStatusSizeLoaded = 0x7FFFFFF1;
|
||||
static const int32 FileStatusSizeFailed = 0x7FFFFFF2;
|
||||
|
||||
QString formatSizeText(qint64 size);
|
||||
QString formatDownloadText(qint64 ready, qint64 total);
|
||||
QString formatDurationText(qint64 duration);
|
||||
QString formatDurationAndSizeText(qint64 duration, qint64 size);
|
||||
QString formatGifAndSizeText(qint64 size);
|
||||
QString formatPlayedText(qint64 played, qint64 duration);
|
||||
|
||||
QString documentName(DocumentData *document);
|
||||
int32 documentColorIndex(DocumentData *document, QString &ext);
|
||||
style::color documentColor(int32 colorIndex);
|
||||
style::color documentDarkColor(int32 colorIndex);
|
||||
style::color documentOverColor(int32 colorIndex);
|
||||
style::color documentSelectedColor(int32 colorIndex);
|
||||
style::sprite documentCorner(int32 colorIndex);
|
||||
RoundCorners documentCorners(int32 colorIndex);
|
||||
|
||||
class OverviewPaintContext;
|
||||
class InlinePaintContext;
|
||||
class PaintContext {
|
||||
public:
|
||||
|
||||
PaintContext(uint64 ms, bool selecting) : ms(ms), selecting(selecting) {
|
||||
}
|
||||
uint64 ms;
|
||||
bool selecting;
|
||||
|
||||
virtual const OverviewPaintContext *toOverviewPaintContext() const {
|
||||
return 0;
|
||||
}
|
||||
virtual const InlinePaintContext *toInlinePaintContext() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class LayoutMediaItem;
|
||||
class OverviewItemInfo;
|
||||
|
||||
class LayoutItem {
|
||||
public:
|
||||
LayoutItem() : _maxw(0), _minh(0) {
|
||||
}
|
||||
|
||||
int32 maxWidth() const {
|
||||
return _maxw;
|
||||
}
|
||||
int32 minHeight() const {
|
||||
return _minh;
|
||||
}
|
||||
virtual void initDimensions() = 0;
|
||||
virtual int32 resizeGetHeight(int32 width) {
|
||||
_width = qMin(width, _maxw);
|
||||
_height = _minh;
|
||||
return _height;
|
||||
}
|
||||
|
||||
virtual void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const = 0;
|
||||
virtual void getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const {
|
||||
link = TextLinkPtr();
|
||||
cursor = HistoryDefaultCursorState;
|
||||
}
|
||||
virtual void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const { // from text
|
||||
upon = hasPoint(x, y);
|
||||
symbol = upon ? 0xFFFF : 0;
|
||||
after = false;
|
||||
}
|
||||
virtual void linkOver(const TextLinkPtr &lnk) {
|
||||
}
|
||||
virtual void linkOut(const TextLinkPtr &lnk) {
|
||||
}
|
||||
|
||||
int32 width() const {
|
||||
return _width;
|
||||
}
|
||||
int32 height() const {
|
||||
return _height;
|
||||
}
|
||||
|
||||
bool hasPoint(int32 x, int32 y) const {
|
||||
return (x >= 0 && y >= 0 && x < width() && y < height());
|
||||
}
|
||||
|
||||
virtual ~LayoutItem() {
|
||||
}
|
||||
|
||||
virtual LayoutMediaItem *toLayoutMediaItem() {
|
||||
return 0;
|
||||
}
|
||||
virtual const LayoutMediaItem *toLayoutMediaItem() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual HistoryItem *getItem() const {
|
||||
return 0;
|
||||
}
|
||||
virtual DocumentData *getDocument() const {
|
||||
return 0;
|
||||
}
|
||||
virtual OverviewItemInfo *getOverviewItemInfo() {
|
||||
return 0;
|
||||
}
|
||||
virtual const OverviewItemInfo *getOverviewItemInfo() const {
|
||||
return 0;
|
||||
}
|
||||
MsgId msgId() const {
|
||||
const HistoryItem *item = getItem();
|
||||
return item ? item->id : 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
int32 _width, _height, _maxw, _minh;
|
||||
LayoutItem &operator=(const LayoutItem &);
|
||||
|
||||
};
|
||||
|
||||
class LayoutMediaItem : public LayoutItem {
|
||||
public:
|
||||
LayoutMediaItem(HistoryItem *parent) : _parent(parent) {
|
||||
}
|
||||
|
||||
virtual LayoutMediaItem *toLayoutMediaItem() {
|
||||
return this;
|
||||
}
|
||||
virtual const LayoutMediaItem *toLayoutMediaItem() const {
|
||||
return this;
|
||||
}
|
||||
virtual HistoryItem *getItem() const {
|
||||
return _parent;
|
||||
}
|
||||
|
||||
protected:
|
||||
HistoryItem *_parent;
|
||||
|
||||
};
|
||||
|
||||
class LayoutRadialProgressItem : public LayoutMediaItem {
|
||||
public:
|
||||
LayoutRadialProgressItem(HistoryItem *parent) : LayoutMediaItem(parent)
|
||||
, _radial(0)
|
||||
, a_iconOver(0, 0)
|
||||
, _a_iconOver(animation(this, &LayoutRadialProgressItem::step_iconOver)) {
|
||||
}
|
||||
|
||||
void linkOver(const TextLinkPtr &lnk);
|
||||
void linkOut(const TextLinkPtr &lnk);
|
||||
|
||||
~LayoutRadialProgressItem();
|
||||
|
||||
protected:
|
||||
TextLinkPtr _openl, _savel, _cancell;
|
||||
void setLinks(ITextLink *openl, ITextLink *savel, ITextLink *cancell);
|
||||
|
||||
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;
|
||||
|
||||
};
|
||||
|
||||
class OverviewPaintContext : public PaintContext {
|
||||
public:
|
||||
OverviewPaintContext(uint64 ms, bool selecting) : PaintContext(ms, selecting), isAfterDate(false) {
|
||||
}
|
||||
const OverviewPaintContext *toOverviewPaintContext() const {
|
||||
return this;
|
||||
}
|
||||
bool isAfterDate;
|
||||
|
||||
};
|
||||
|
||||
class OverviewItemInfo {
|
||||
public:
|
||||
OverviewItemInfo() : _top(0) {
|
||||
}
|
||||
int32 top() const {
|
||||
return _top;
|
||||
}
|
||||
void setTop(int32 top) {
|
||||
_top = top;
|
||||
}
|
||||
|
||||
private:
|
||||
int32 _top;
|
||||
|
||||
};
|
||||
|
||||
class LayoutOverviewDate : public LayoutItem {
|
||||
public:
|
||||
LayoutOverviewDate(const QDate &date, bool month);
|
||||
|
||||
virtual void initDimensions();
|
||||
virtual void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const;
|
||||
|
||||
virtual OverviewItemInfo *getOverviewItemInfo() {
|
||||
return &_info;
|
||||
}
|
||||
virtual const OverviewItemInfo *getOverviewItemInfo() const {
|
||||
return &_info;
|
||||
}
|
||||
|
||||
private:
|
||||
OverviewItemInfo _info;
|
||||
|
||||
QDate _date;
|
||||
QString _text;
|
||||
|
||||
};
|
||||
|
||||
class LayoutOverviewPhoto : public LayoutMediaItem {
|
||||
public:
|
||||
LayoutOverviewPhoto(PhotoData *photo, HistoryItem *parent);
|
||||
|
||||
virtual void initDimensions();
|
||||
virtual int32 resizeGetHeight(int32 width);
|
||||
virtual void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const;
|
||||
virtual void getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const;
|
||||
|
||||
private:
|
||||
PhotoData *_data;
|
||||
TextLinkPtr _link;
|
||||
|
||||
mutable QPixmap _pix;
|
||||
mutable bool _goodLoaded;
|
||||
|
||||
};
|
||||
|
||||
class LayoutOverviewVideo : public LayoutAbstractFileItem {
|
||||
public:
|
||||
LayoutOverviewVideo(VideoData *photo, HistoryItem *parent);
|
||||
|
||||
virtual void initDimensions();
|
||||
virtual int32 resizeGetHeight(int32 width);
|
||||
virtual void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const;
|
||||
virtual void getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const;
|
||||
|
||||
protected:
|
||||
virtual float64 dataProgress() const {
|
||||
return _data->progress();
|
||||
}
|
||||
virtual bool dataFinished() const {
|
||||
return !_data->loading();
|
||||
}
|
||||
virtual bool dataLoaded() const {
|
||||
return _data->loaded();
|
||||
}
|
||||
virtual bool iconAnimated() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
VideoData *_data;
|
||||
|
||||
QString _duration;
|
||||
mutable QPixmap _pix;
|
||||
mutable bool _thumbLoaded;
|
||||
|
||||
void updateStatusText() const;
|
||||
|
||||
};
|
||||
|
||||
class LayoutOverviewAudio : public LayoutAbstractFileItem {
|
||||
public:
|
||||
LayoutOverviewAudio(AudioData *audio, HistoryItem *parent);
|
||||
|
||||
virtual void initDimensions();
|
||||
virtual void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const;
|
||||
virtual void getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const;
|
||||
|
||||
virtual OverviewItemInfo *getOverviewItemInfo() {
|
||||
return &_info;
|
||||
}
|
||||
virtual const OverviewItemInfo *getOverviewItemInfo() const {
|
||||
return &_info;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual float64 dataProgress() const {
|
||||
return _data->progress();
|
||||
}
|
||||
virtual bool dataFinished() const {
|
||||
return !_data->loading();
|
||||
}
|
||||
virtual bool dataLoaded() const {
|
||||
return _data->loaded();
|
||||
}
|
||||
virtual bool iconAnimated() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
OverviewItemInfo _info;
|
||||
AudioData *_data;
|
||||
TextLinkPtr _namel;
|
||||
|
||||
mutable Text _name, _details;
|
||||
mutable int32 _nameVersion;
|
||||
|
||||
void updateName() const;
|
||||
bool updateStatusText() const;
|
||||
|
||||
};
|
||||
|
||||
class LayoutOverviewDocument : public LayoutAbstractFileItem {
|
||||
public:
|
||||
LayoutOverviewDocument(DocumentData *document, HistoryItem *parent);
|
||||
|
||||
virtual void initDimensions();
|
||||
virtual void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const;
|
||||
virtual void getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const;
|
||||
|
||||
virtual DocumentData *getDocument() const {
|
||||
return _data;
|
||||
}
|
||||
virtual OverviewItemInfo *getOverviewItemInfo() {
|
||||
return &_info;
|
||||
}
|
||||
virtual const OverviewItemInfo *getOverviewItemInfo() const {
|
||||
return &_info;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual float64 dataProgress() const {
|
||||
return _data->progress();
|
||||
}
|
||||
virtual bool dataFinished() const {
|
||||
return !_data->loading();
|
||||
}
|
||||
virtual bool dataLoaded() const {
|
||||
return _data->loaded();
|
||||
}
|
||||
virtual bool iconAnimated() const {
|
||||
return _data->song() || !_data->loaded() || (_radial && _radial->animating());
|
||||
}
|
||||
|
||||
private:
|
||||
OverviewItemInfo _info;
|
||||
DocumentData *_data;
|
||||
TextLinkPtr _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 LayoutMediaItem {
|
||||
public:
|
||||
LayoutOverviewLink(HistoryMedia *media, HistoryItem *parent);
|
||||
|
||||
virtual void initDimensions();
|
||||
virtual int32 resizeGetHeight(int32 width);
|
||||
virtual void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const;
|
||||
virtual void getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const;
|
||||
|
||||
virtual OverviewItemInfo *getOverviewItemInfo() {
|
||||
return &_info;
|
||||
}
|
||||
virtual const OverviewItemInfo *getOverviewItemInfo() const {
|
||||
return &_info;
|
||||
}
|
||||
|
||||
private:
|
||||
OverviewItemInfo _info;
|
||||
TextLinkPtr _photol;
|
||||
|
||||
QString _title, _letter;
|
||||
int32 _titlew;
|
||||
WebPageData *_page;
|
||||
int32 _pixw, _pixh;
|
||||
Text _text;
|
||||
|
||||
struct Link {
|
||||
Link() : width(0) {
|
||||
}
|
||||
Link(const QString &url, const QString &text);
|
||||
QString text;
|
||||
int32 width;
|
||||
TextLinkPtr lnk;
|
||||
};
|
||||
QVector<Link> _links;
|
||||
|
||||
};
|
||||
|
||||
class InlinePaintContext : public PaintContext {
|
||||
public:
|
||||
InlinePaintContext(uint64 ms, bool selecting, bool paused, bool lastRow)
|
||||
: PaintContext(ms, selecting)
|
||||
, paused(paused)
|
||||
, lastRow(lastRow) {
|
||||
}
|
||||
virtual const InlinePaintContext *toInlinePaintContext() const {
|
||||
return this;
|
||||
}
|
||||
bool paused, lastRow;
|
||||
};
|
||||
|
||||
class LayoutInlineItem : public LayoutItem {
|
||||
public:
|
||||
|
||||
LayoutInlineItem(InlineResult *result, DocumentData *doc, PhotoData *photo);
|
||||
|
||||
virtual void setPosition(int32 position);
|
||||
int32 position() const;
|
||||
|
||||
virtual bool fullLine() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
InlineResult *result() const;
|
||||
DocumentData *document() const;
|
||||
PhotoData *photo() const;
|
||||
void preload();
|
||||
|
||||
void update();
|
||||
|
||||
protected:
|
||||
InlineResult *_result;
|
||||
DocumentData *_doc;
|
||||
PhotoData *_photo;
|
||||
|
||||
int32 _position; // < 0 means removed from layout
|
||||
|
||||
};
|
||||
|
||||
class SendInlineItemLink : public ITextLink {
|
||||
TEXT_LINK_CLASS(SendInlineItemLink)
|
||||
|
||||
public:
|
||||
virtual void onClick(Qt::MouseButton) const {
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class DeleteSavedGifLink : public ITextLink {
|
||||
TEXT_LINK_CLASS(DeleteSavedGifLink)
|
||||
|
||||
public:
|
||||
DeleteSavedGifLink(DocumentData *data) : _data(data) {
|
||||
}
|
||||
virtual void onClick(Qt::MouseButton) const;
|
||||
|
||||
private:
|
||||
DocumentData *_data;
|
||||
|
||||
};
|
||||
|
||||
class LayoutInlineGif : public LayoutInlineItem {
|
||||
public:
|
||||
LayoutInlineGif(InlineResult *result, DocumentData *doc, bool saved);
|
||||
|
||||
virtual void setPosition(int32 position);
|
||||
virtual void initDimensions();
|
||||
|
||||
virtual bool fullLine() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const;
|
||||
virtual void getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const;
|
||||
virtual void linkOver(const TextLinkPtr &lnk);
|
||||
virtual void linkOut(const TextLinkPtr &lnk);
|
||||
|
||||
~LayoutInlineGif();
|
||||
|
||||
private:
|
||||
QSize countFrameSize() const;
|
||||
|
||||
int32 content_width() const;
|
||||
int32 content_height() const;
|
||||
bool content_loading() const;
|
||||
bool content_displayLoading() const;
|
||||
bool content_loaded() const;
|
||||
float64 content_progress() const;
|
||||
void content_automaticLoad() const;
|
||||
void content_forget();
|
||||
FileLocation content_location() const;
|
||||
QByteArray content_data() const;
|
||||
|
||||
enum StateFlags {
|
||||
StateOver = 0x01,
|
||||
StateDeleteOver = 0x02,
|
||||
};
|
||||
int32 _state;
|
||||
|
||||
ClipReader *_gif;
|
||||
TextLinkPtr _send, _delete;
|
||||
bool gif() const {
|
||||
return (!_gif || _gif == BadClipReader) ? false : true;
|
||||
}
|
||||
mutable QPixmap _thumb;
|
||||
void prepareThumb(int32 width, int32 height, const QSize &frame) const;
|
||||
|
||||
void ensureAnimation() const;
|
||||
bool isRadialAnimation(uint64 ms) const;
|
||||
void step_radial(uint64 ms, bool timer);
|
||||
|
||||
void clipCallback(ClipReaderNotification notification);
|
||||
|
||||
struct AnimationData {
|
||||
AnimationData(AnimationCreator creator)
|
||||
: over(false)
|
||||
, radial(creator) {
|
||||
}
|
||||
bool over;
|
||||
FloatAnimation _a_over;
|
||||
RadialAnimation radial;
|
||||
};
|
||||
mutable AnimationData *_animation;
|
||||
mutable FloatAnimation _a_deleteOver;
|
||||
|
||||
};
|
||||
|
||||
class LayoutInlinePhoto : public LayoutInlineItem {
|
||||
public:
|
||||
LayoutInlinePhoto(InlineResult *result, PhotoData *photo);
|
||||
|
||||
virtual void initDimensions();
|
||||
|
||||
virtual bool fullLine() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const;
|
||||
virtual void getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const;
|
||||
|
||||
private:
|
||||
QSize countFrameSize() const;
|
||||
|
||||
int32 content_width() const;
|
||||
int32 content_height() const;
|
||||
bool content_loaded() const;
|
||||
void content_forget();
|
||||
|
||||
TextLinkPtr _send;
|
||||
|
||||
mutable QPixmap _thumb;
|
||||
mutable bool _thumbLoaded;
|
||||
void prepareThumb(int32 width, int32 height, const QSize &frame) const;
|
||||
|
||||
};
|
||||
|
||||
class LayoutInlineWebVideo : public LayoutInlineItem {
|
||||
public:
|
||||
LayoutInlineWebVideo(InlineResult *result);
|
||||
|
||||
virtual void initDimensions();
|
||||
|
||||
virtual void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const;
|
||||
virtual void getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const;
|
||||
|
||||
private:
|
||||
|
||||
TextLinkPtr _send, _link;
|
||||
|
||||
mutable QPixmap _thumb;
|
||||
Text _title, _description;
|
||||
QString _duration;
|
||||
int32 _durationWidth;
|
||||
|
||||
void prepareThumb(int32 width, int32 height) const;
|
||||
|
||||
};
|
||||
|
||||
class LayoutInlineArticle : public LayoutInlineItem {
|
||||
public:
|
||||
LayoutInlineArticle(InlineResult *result, bool withThumb);
|
||||
|
||||
virtual void initDimensions();
|
||||
virtual int32 resizeGetHeight(int32 width);
|
||||
|
||||
virtual void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const;
|
||||
virtual void getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const;
|
||||
|
||||
private:
|
||||
|
||||
TextLinkPtr _send, _url, _link;
|
||||
|
||||
bool _withThumb;
|
||||
mutable QPixmap _thumb;
|
||||
Text _title, _description;
|
||||
QString _letter, _urlText;
|
||||
int32 _urlWidth;
|
||||
|
||||
void prepareThumb(int32 width, int32 height) const;
|
||||
|
||||
};
|
|
@ -135,7 +135,7 @@ TaskQueue::~TaskQueue() {
|
|||
void TaskQueueWorker::onTaskAdded() {
|
||||
if (_inTaskAdded) return;
|
||||
_inTaskAdded = true;
|
||||
|
||||
|
||||
bool someTasksLeft = false;
|
||||
do {
|
||||
TaskPtr task;
|
||||
|
@ -294,13 +294,12 @@ void FileLoadTask::process() {
|
|||
MTPDocument document(MTP_documentEmpty(MTP_long(0)));
|
||||
MTPAudio audio(MTP_audioEmpty(MTP_long(0)));
|
||||
|
||||
bool song = false;
|
||||
bool song = false, gif = false;
|
||||
if (_type != PrepareAudio) {
|
||||
if (filemime == qstr("audio/mp3") || filemime == qstr("audio/m4a") || filemime == qstr("audio/aac") || filemime == qstr("audio/ogg") || filemime == qstr("audio/flac") ||
|
||||
filename.endsWith(qstr(".mp3"), Qt::CaseInsensitive) || filename.endsWith(qstr(".m4a"), Qt::CaseInsensitive) ||
|
||||
filename.endsWith(qstr(".aac"), Qt::CaseInsensitive) || filename.endsWith(qstr(".ogg"), Qt::CaseInsensitive) ||
|
||||
filename.endsWith(qstr(".flac"), Qt::CaseInsensitive)) {
|
||||
|
||||
QImage cover;
|
||||
QByteArray coverBytes, coverFormat;
|
||||
MTPDocumentAttribute audioAttribute = audioReadSongAttributes(_filepath, _content, cover, coverBytes, coverFormat);
|
||||
|
@ -327,9 +326,39 @@ void FileLoadTask::process() {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (filemime == qstr("video/mp4") || filename.endsWith(qstr(".mp4"), Qt::CaseInsensitive) || animated) {
|
||||
QImage cover;
|
||||
MTPDocumentAttribute animatedAttribute = clipReadAnimatedAttributes(_filepath, _content, cover);
|
||||
if (animatedAttribute.type() == mtpc_documentAttributeVideo) {
|
||||
int32 cw = cover.width(), ch = cover.height();
|
||||
if (cw < 20 * ch && ch < 20 * cw) {
|
||||
attributes.push_back(MTP_documentAttributeAnimated());
|
||||
attributes.push_back(animatedAttribute);
|
||||
gif = true;
|
||||
|
||||
QPixmap full = (cw > 90 || ch > 90) ? QPixmap::fromImage(cover.scaled(90, 90, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(cover, Qt::ColorOnly);
|
||||
{
|
||||
QByteArray thumbFormat = "JPG";
|
||||
int32 thumbQuality = 87;
|
||||
|
||||
QBuffer buffer(&thumbdata);
|
||||
full.save(&buffer, thumbFormat, thumbQuality);
|
||||
}
|
||||
|
||||
thumb = full;
|
||||
thumbSize = MTP_photoSize(MTP_string(""), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(full.width()), MTP_int(full.height()), MTP_int(0));
|
||||
|
||||
thumbId = MTP::nonce<uint64>();
|
||||
|
||||
if (filename.endsWith(qstr(".mp4"), Qt::CaseInsensitive)) {
|
||||
filemime = qstr("video/mp4");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!fullimage.isNull() && fullimage.width() > 0 && !song) {
|
||||
if (!fullimage.isNull() && fullimage.width() > 0 && !song && !gif) {
|
||||
int32 w = fullimage.width(), h = fullimage.height();
|
||||
attributes.push_back(MTP_documentAttributeImageSize(MTP_int(w), MTP_int(h)));
|
||||
|
||||
|
@ -387,12 +416,13 @@ void FileLoadTask::process() {
|
|||
_type = PrepareDocument;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_result->type = _type;
|
||||
_result->filepath = _filepath;
|
||||
_result->content = _content;
|
||||
|
||||
_result->filename = filename;
|
||||
_result->filemime = filemime;
|
||||
_result->setFileData(filedata);
|
||||
|
||||
_result->thumbId = thumbId;
|
||||
|
@ -409,23 +439,23 @@ void FileLoadTask::process() {
|
|||
void FileLoadTask::finish() {
|
||||
if (!_result || !_result->filesize) {
|
||||
if (_result) App::main()->onSendFileCancel(_result);
|
||||
App::wnd()->replaceLayer(new InformBox(lang(lng_send_image_empty)));
|
||||
Ui::showLayer(new InformBox(lang(lng_send_image_empty)), KeepOtherLayers);
|
||||
return;
|
||||
}
|
||||
if (_result->filesize == -1) { // dir
|
||||
App::main()->onSendFileCancel(_result);
|
||||
App::wnd()->replaceLayer(new InformBox(lng_send_folder(lt_name, QFileInfo(_filepath).dir().dirName())));
|
||||
Ui::showLayer(new InformBox(lng_send_folder(lt_name, QFileInfo(_filepath).dir().dirName())), KeepOtherLayers);
|
||||
return;
|
||||
}
|
||||
if (_result->filesize > MaxUploadDocumentSize) {
|
||||
App::main()->onSendFileCancel(_result);
|
||||
App::wnd()->replaceLayer(new InformBox(lang(lng_send_image_too_large)));
|
||||
Ui::showLayer(new InformBox(lang(lng_send_image_too_large)), KeepOtherLayers);
|
||||
return;
|
||||
}
|
||||
if (App::main()) {
|
||||
bool confirm = (_confirm == FileLoadAlwaysConfirm) || (_result->photo.type() != mtpc_photoEmpty && _confirm != FileLoadNeverConfirm);
|
||||
if (confirm) {
|
||||
App::wnd()->showLayerLast(new PhotoSendBox(_result));
|
||||
Ui::showLayer(new PhotoSendBox(_result), ShowAfterOtherLayers);
|
||||
} else {
|
||||
if (_result->type == PrepareAuto) {
|
||||
_result->type = (_result->photo.type() != mtpc_photoEmpty) ? PreparePhoto : PrepareDocument;
|
||||
|
|
|
@ -190,9 +190,11 @@ struct FileLoadResult {
|
|||
QByteArray content;
|
||||
|
||||
QString filename;
|
||||
QString filemime;
|
||||
int32 filesize;
|
||||
UploadFileParts fileparts;
|
||||
QByteArray filemd5;
|
||||
int32 partssize;
|
||||
|
||||
uint64 thumbId; // id is always file-id of media, thumbId is file-id of thumb ( == id for photos)
|
||||
QString thumbname;
|
||||
|
@ -205,14 +207,16 @@ struct FileLoadResult {
|
|||
MTPDocument document;
|
||||
|
||||
PreparedPhotoThumbs photoThumbs;
|
||||
QString photoCaption;
|
||||
QString caption;
|
||||
|
||||
QString originalText; // when pasted had an image mime save text mime here to insert if image send was cancelled
|
||||
|
||||
void setFileData(const QByteArray &filedata) {
|
||||
if (!filedata.isEmpty()) {
|
||||
int32 size = filedata.size();
|
||||
for (int32 i = 0, part = 0; i < size; i += UploadPartSize, ++part) {
|
||||
if (filedata.isEmpty()) {
|
||||
partssize = 0;
|
||||
} else {
|
||||
partssize = filedata.size();
|
||||
for (int32 i = 0, part = 0; i < partssize; i += UploadPartSize, ++part) {
|
||||
fileparts.insert(part, filedata.mid(i, UploadPartSize));
|
||||
}
|
||||
filemd5.resize(32);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -65,7 +65,7 @@ namespace Local {
|
|||
|
||||
bool checkPasscode(const QByteArray &passcode);
|
||||
void setPasscode(const QByteArray &passcode);
|
||||
|
||||
|
||||
enum ClearManagerTask {
|
||||
ClearManagerAll = 0xFFFF,
|
||||
ClearManagerDownloads = 0x01,
|
||||
|
@ -129,6 +129,8 @@ namespace Local {
|
|||
|
||||
void writeStickerImage(const StorageKey &location, const QByteArray &data, bool overwrite = true);
|
||||
TaskId startStickerImageLoad(const StorageKey &location, mtpFileLoader *loader);
|
||||
bool willStickerImageLoad(const StorageKey &location);
|
||||
void copyStickerImage(const StorageKey &oldLocation, const StorageKey &newLocation);
|
||||
int32 hasStickers();
|
||||
qint64 storageStickersSize();
|
||||
|
||||
|
@ -137,16 +139,26 @@ namespace Local {
|
|||
int32 hasAudios();
|
||||
qint64 storageAudiosSize();
|
||||
|
||||
void writeWebFile(const QString &url, const QByteArray &data, bool overwrite = true);
|
||||
TaskId startWebFileLoad(const QString &url, webFileLoader *loader);
|
||||
int32 hasWebFiles();
|
||||
qint64 storageWebFilesSize();
|
||||
|
||||
void cancelTask(TaskId id);
|
||||
|
||||
void writeStickers();
|
||||
void readStickers();
|
||||
int32 countStickersHash(bool checkOfficial = false);
|
||||
|
||||
void writeSavedGifs();
|
||||
void readSavedGifs();
|
||||
int32 countSavedGifsHash();
|
||||
|
||||
void writeBackground(int32 id, const QImage &img);
|
||||
bool readBackground();
|
||||
|
||||
void writeRecentHashtags();
|
||||
void readRecentHashtags();
|
||||
void writeRecentHashtagsAndBots();
|
||||
void readRecentHashtagsAndBots();
|
||||
|
||||
void addSavedPeer(PeerData *peer, const QDateTime &position);
|
||||
void removeSavedPeer(PeerData *peer);
|
||||
|
|
|
@ -30,13 +30,6 @@ namespace {
|
|||
|
||||
QMutex debugLogMutex, mainLogMutex;
|
||||
|
||||
class _StreamCreator {
|
||||
public:
|
||||
~_StreamCreator() {
|
||||
logsClose();
|
||||
}
|
||||
};
|
||||
|
||||
QString debugLogEntryStart() {
|
||||
static uint32 logEntry = 0;
|
||||
|
||||
|
@ -45,7 +38,7 @@ namespace {
|
|||
QThread *thread = QThread::currentThread();
|
||||
MTPThread *mtpThread = qobject_cast<MTPThread*>(thread);
|
||||
uint32 threadId = mtpThread ? mtpThread->getThreadId() : 0;
|
||||
|
||||
|
||||
return QString("[%1 %2-%3]").arg(tm.toString("hh:mm:ss.zzz")).arg(QString("%1").arg(threadId, 2, 10, zero)).arg(++logEntry, 7, 10, zero);
|
||||
}
|
||||
}
|
||||
|
@ -179,9 +172,8 @@ void moveOldDataFiles(const QString &wasDir) {
|
|||
}
|
||||
}
|
||||
|
||||
void logsInit() {
|
||||
static _StreamCreator streamCreator;
|
||||
if (mainLogStream) return;
|
||||
bool logsInit() {
|
||||
t_assert(mainLogStream == 0);
|
||||
|
||||
QFile beta(cExeDir() + qsl("TelegramBeta_data/tdata/beta"));
|
||||
if (cBetaVersion()) {
|
||||
|
@ -223,7 +215,9 @@ void logsInit() {
|
|||
#ifdef _DEBUG
|
||||
cForceWorkingDir(cExeDir());
|
||||
#else
|
||||
cForceWorkingDir(psAppDataPath());
|
||||
if(cWorkingDir().isEmpty()){
|
||||
cForceWorkingDir(psAppDataPath());
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (defined Q_OS_LINUX && !defined _DEBUG) // fix first version
|
||||
|
@ -281,6 +275,7 @@ void logsInit() {
|
|||
}
|
||||
|
||||
QDir().setCurrent(cWorkingDir());
|
||||
return true;
|
||||
}
|
||||
|
||||
void logsInitDebug() {
|
||||
|
@ -396,7 +391,7 @@ void logsClose() {
|
|||
}
|
||||
|
||||
QString logVectorLong(const QVector<MTPlong> &ids) {
|
||||
if (!ids.size()) return "[void list]";
|
||||
if (!ids.size()) return "[]";
|
||||
QString idsStr = QString("[%1").arg(ids.cbegin()->v);
|
||||
for (QVector<MTPlong>::const_iterator i = ids.cbegin() + 1, e = ids.cend(); i != e; ++i) {
|
||||
idsStr += QString(", %2").arg(i->v);
|
||||
|
@ -405,7 +400,7 @@ QString logVectorLong(const QVector<MTPlong> &ids) {
|
|||
}
|
||||
|
||||
QString logVectorLong(const QVector<uint64> &ids) {
|
||||
if (!ids.size()) return "[void list]";
|
||||
if (!ids.size()) return "[]";
|
||||
QString idsStr = QString("[%1").arg(*ids.cbegin());
|
||||
for (QVector<uint64>::const_iterator i = ids.cbegin() + 1, e = ids.cend(); i != e; ++i) {
|
||||
idsStr += QString(", %2").arg(*i);
|
||||
|
|
|
@ -77,11 +77,21 @@ class MTPlong;
|
|||
QString logVectorLong(const QVector<MTPlong> &ids);
|
||||
QString logVectorLong(const QVector<uint64> &ids);
|
||||
|
||||
void logWrite(const QString &v);
|
||||
|
||||
#define LOG(msg) (logWrite(QString msg))
|
||||
//usage LOG(("log: %1 %2").arg(1).arg(2))
|
||||
|
||||
void logWrite(const QString &v);
|
||||
static volatile int *t_assert_nullptr = 0;
|
||||
inline void t_noop() {}
|
||||
inline void t_assert_fail(const char *message, const char *file, int32 line) {
|
||||
LOG(("Assertion Failed! %1 %2:%3").arg(message).arg(file).arg(line));
|
||||
*t_assert_nullptr = 0;
|
||||
}
|
||||
#define t_assert_full(condition, message, file, line) ((!(condition)) ? t_assert_fail(message, file, line) : t_noop())
|
||||
#define t_assert_c(condition, comment) t_assert_full(condition, "\"" #condition "\" (" comment ")", __FILE__, __LINE__)
|
||||
#define t_assert(condition) t_assert_full(condition, "\"" #condition "\"", __FILE__, __LINE__)
|
||||
|
||||
void logsInit();
|
||||
bool logsInit();
|
||||
void logsInitDebug();
|
||||
void logsClose();
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue