diff --git a/Telegram/Resources/lang.strings b/Telegram/Resources/lang.strings index 308aa3226..ccf6a8ce0 100644 --- a/Telegram/Resources/lang.strings +++ b/Telegram/Resources/lang.strings @@ -177,19 +177,23 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org "lng_dlg_search_chat" = "Search in this chat"; "lng_dlg_search_for_messages" = "Search for messages"; -"lng_settings_save" = "Save"; +"lng_settings_save" = "SAVE"; "lng_settings_upload" = "Set Profile Photo"; "lng_settings_crop_profile" = "Select a square area for your profile photo"; "lng_settings_uploading_photo" = "Uploading photo.."; -"lng_username_title" = "Change username"; +"lng_username_title" = "Username"; "lng_username_about" = "You can choose a username on Telegram.\nIf you do, other people will be able to find\nyou by this username and contact you\nwithout knowing your phone number.\n\nYou can use a-z, 0-9 and underscores.\nMinimum length is 5 characters."; +"lng_username_choose" = "Choose your username."; "lng_username_invalid" = "This username is invalid."; "lng_username_occupied" = "This username is already occupied."; "lng_username_too_short" = "This username is too short."; "lng_username_bad_symbols" = "This username has bad symbols."; "lng_username_available" = "This username is available."; "lng_username_not_found" = "User @{user} not found."; +"lng_username_link_willbe" = "Such link will open a chat with you:"; +"lng_username_link" = "This link opens a chat with you:"; +"lng_username_copied" = "Link copied to clipboard."; "lng_settings_section_contact_info" = "Contact info"; "lng_settings_phone_number" = "Phone number:"; @@ -228,9 +232,9 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org "lng_settings_scale_auto" = "Auto ({cur})"; "lng_settings_section_chat" = "Chat options"; -"lng_settings_replace_emojis" = "Replace emojis"; +"lng_settings_replace_emojis" = "Replace emoji"; "lng_settings_view_emojis" = "View list"; -"lng_settings_emoji_list" = "List of supported emojis"; +"lng_settings_emoji_list" = "List of supported emoji"; "lng_settings_send_enter" = "Send by Enter"; "lng_settings_send_ctrlenter" = "Send by Ctrl+Enter"; "lng_settings_send_cmdenter" = "Send by Cmd+Enter"; @@ -334,7 +338,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org "lng_connection_port_ph" = "Port"; "lng_connection_user_ph" = "Username"; "lng_connection_password_ph" = "Password"; -"lng_connection_save" = "Save"; +"lng_connection_save" = "SAVE"; "lng_settings_show_sessions" = "Show all sessions"; "lng_settings_reset" = "Terminate all other sessions"; "lng_settings_reset_sure" = "Are you sure you want to terminate\nall other sessions?"; @@ -425,11 +429,11 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org "lng_participant_filter" = "Search"; "lng_participant_invite" = "Invite"; "lng_participant_invite_sorry" = "Sorry, you can only add the first {count:_not_used|# member|# members} to a channel personally.\n\nFrom now on, people will need to join via your invite link."; -"lng_create_group_back" = "Back"; -"lng_create_group_next" = "Next"; -"lng_create_group_create" = "Create"; +"lng_create_group_back" = "BACK"; +"lng_create_group_next" = "NEXT"; +"lng_create_group_create" = "CREATE"; "lng_create_group_title" = "New Group"; -"lng_create_group_about" = "Groups are ideal for smaller communities, they can have up to {count:_not_used|# member|# members}"; +"lng_create_group_about" = "Groups are ideal for smaller communities,\nthey can have up to {count:_not_used|# member|# members}"; "lng_create_channel_title" = "New Channel"; "lng_create_channel_about" = "Channels are a tool for broadcasting your messages to unlimited audiences"; "lng_create_public_channel_title" = "Public Channel"; @@ -438,8 +442,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org "lng_create_private_channel_about" = "Only people with a special invite link may join"; "lng_create_channel_comments" = "Enable Comments"; "lng_create_channel_comments_about" = "If you enable comments, members will be able to discuss your posts in the channel"; -"lng_create_group_save" = "Save"; -"lng_create_group_skip" = "Skip"; +"lng_create_group_skip" = "SKIP"; "lng_create_channel_link_invalid" = "This link is invalid"; "lng_create_channel_link_occupied" = "Sorry, this link is already occupied"; diff --git a/Telegram/Resources/style.txt b/Telegram/Resources/style.txt index b7f9ccbec..c33cbb9a2 100644 --- a/Telegram/Resources/style.txt +++ b/Telegram/Resources/style.txt @@ -61,49 +61,24 @@ wndShadowShift: 1px; layerAlpha: 0.5; layerBG: black; -defaultInputField: InputField { - textFg: black; - textMargins: margins(5px, 5px, 5px, 5px); - textAlign: align(left); - - placeholderFg: #999; - placeholderFgActive: #aaa; - placeholderMargins: margins(2px, 0px, 2px, 0px); - placeholderAlign: align(topleft); - placeholderShift: 50px; - duration: 100; - - borderFg: #e0e0e0; - borderFgActive: #62c0f7; - borderFgError: #e48383; - - border: 1px; - borderActive: 2px; - borderError: 2px; - - font: normalFont; - - height: 32px; -} -dialogsSearchField: InputField(defaultInputField) { - textMargins: margins(34px, 7px, 34px, 7px); - - iconSprite: sprite(227px, 21px, 24px, 24px); - iconPosition: point(6px, 5px); - - width: 240px; - height: 34px; -} - boxWidth: 320px; boxWideWidth: 364px; -boxPadding: margins(26px, 30px, 26px, 16px); +boxPadding: margins(26px, 30px, 26px, 8px); boxMaxListHeight: 600px; -boxFontSize: 13px; +boxFontSize: 14px; boxTextFont: font(boxFontSize); + boxTitleFont: font(boxFontSize semibold); -boxButtonFont: font(boxFontSize semibold); +boxTitlePosition: point(26px, 28px); boxTitleHeight: 54px; + +boxBlueTitleHeight: 54px; +boxBlueTitleBg: #6393b5; +boxBlueTitleAdditionalFg: #dae9f5; +boxBlueTitleAdditionalSkip: 12px; +boxBlueTitlePosition: point(23px, 18px); + +boxButtonFont: font(boxFontSize semibold); defaultBoxButton: BoxButton { textFg: #2f9fea; textFgOver: #2f9fea; @@ -113,7 +88,7 @@ defaultBoxButton: BoxButton { width: -24px; height: 36px; - textTop: 9px; + textTop: 8px; font: boxButtonFont; duration: 200; @@ -127,6 +102,109 @@ attentionBoxButton: BoxButton(defaultBoxButton) { textBgOver: #fff0ed; } boxButtonPadding: margins(12px, 16px, 22px, 16px); +defaultBoxLinkButton: linkButton { + color: #0080c0; + overColor: #0080c0; + downColor: #0073ad; + font: boxTextFont; + overFont: font(boxFontSize underline); +} + +defaultInputArea: InputArea { + textFg: black; + textMargins: margins(5px, 6px, 5px, 4px); + + placeholderFg: #999; + placeholderFgActive: #aaa; + placeholderMargins: margins(2px, 0px, 2px, 0px); + placeholderAlign: align(topleft); + placeholderShift: 50px; + duration: 120; + + borderFg: #e0e0e0; + borderFgActive: #62c0f7; + borderFgError: #e48383; + + border: 1px; + borderActive: 2px; + borderError: 2px; + + font: boxTextFont; + + heightMin: 32px; + heightMax: 128px; +} +defaultInputField: InputField { + textFg: black; + textMargins: margins(5px, 5px, 5px, 5px); + textAlign: align(topleft); + + placeholderFg: #999; + placeholderFgActive: #aaa; + placeholderMargins: margins(2px, 0px, 2px, 0px); + placeholderAlign: align(topleft); + placeholderShift: 50px; + duration: 120; + + borderFg: #e0e0e0; + borderFgActive: #62c0f7; + borderFgError: #e48383; + + border: 1px; + borderActive: 2px; + borderError: 2px; + + font: boxTextFont; + + height: 32px; +} +dialogsSearchField: InputField(defaultInputField) { + textMargins: margins(34px, 7px, 34px, 7px); + + iconSprite: sprite(227px, 21px, 24px, 24px); + iconPosition: point(6px, 5px); + + width: 240px; + height: 34px; +} +defaultCheckbox: Checkbox { + textFg: black; + textBg: white; + + checkFg: #d9d9d9; + checkFgOver: #bfbfbf; + checkFgActive: #4eb3ee; + + width: -46px; + height: 22px; + + textPosition: point(34px, 0px); + diameter: 22px; + thickness: 2px; + checkIcon: sprite(106px, 136px, 14px, 10px); + + font: boxTextFont; + duration: 120; +} +defaultRadiobutton: Radiobutton { + textFg: black; + textBg: white; + + checkFg: #d9d9d9; + checkFgOver: #bfbfbf; + checkFgActive: #4eb3ee; + + width: -46px; + height: 22px; + + textPosition: point(34px, 0px); + diameter: 22px; + thickness: 2px; + checkSkip: 65px; // * 0.1 + + font: boxTextFont; + duration: 120; +} titleBG: #6389a8; titleColor: #0f8dcc;//rgb(20, 136, 210); @@ -643,7 +721,7 @@ setNameInput: flatInput(inpDefFlat) { textMrg: margins(3px, 3px, 3px, 3px); } setErrBG: #ffa5a5; -setErrColor: #800000; +setErrColor: #d84d4d; setErrHeight: 30px; setErrFont: font(fsize); setGoodColor: #008000; @@ -756,9 +834,9 @@ dlgActiveSendImg: sprite(142px, 25px, 17px, 11px); dlgChatImgPos: point(1px, 4px); dlgChatImg: sprite(104px, 26px, 16px, 11px); dlgActiveChatImg: sprite(104px, 37px, 16px, 11px); -dlgChannelImgPos: point(2px, 3px); -dlgChannelImg: sprite(104px, 0px, 14px, 13px); -dlgActiveChannelImg: sprite(104px, 13px, 14px, 13px); +dlgChannelImgPos: point(3px, 4px); +dlgChannelImg: sprite(105px, 1px, 12px, 11px); +dlgActiveChannelImg: sprite(105px, 14px, 12px, 11px); dlgImgSkip: 22px; dlgCheckLeft: 5px; @@ -1259,7 +1337,7 @@ old_boxTitleHeight: 52px; confirmMaxHeight: 320px; confirmCompressedSkip: 10px; addContactPadding: margins(18px, 24px, 18px, 24px); -addContactDelta: 14px; +addContactSkip: 14px; inpAddContact: flatInput(inpDefGray) { height: 42px; textMrg: margins(10px, 5px, 10px, 5px); @@ -1349,8 +1427,6 @@ profileListStatusBottom: 6px; profileHoverBG: #f5f5f5; profileActiveBG: #6294b9; profileSubFont: font(fsize); -profileCheckRect: sprite(78px, 114px, 24px, 24px); -profileCheckActiveRect: sprite(128px, 108px, 24px, 24px); profileCheckDeltaX: 18px; profileCheckDeltaY: 1px; profileListNameFont: font(fsize semibold); @@ -1461,82 +1537,55 @@ contactsFilter: flatInput(dlgFilter) { } inpCountry: flatInput(contactsFilter) { } -newGroupName: flatInput(inpDefGray) { - width: 340px; - height: 42px; - font: font(15px); - textMrg: margins(12px, 4px, 12px, 4px); -} -newGroupLink: flatInput(inpDefFlat) { - width: 340px; - height: 42px; - font: boxTextFont; - textMrg: margins(12px, 4px, 12px, 4px); - bgColor: transparent; - bgActive: transparent; - borderWidth: 2px; - borderColor: #f2f2f2; - borderActive: #80cff9; - borderError: #ed8080; - phColor: #828282; - phFocusColor: #949494; -} + +old_newGroupNamePadding: margins(12px, 15px, 12px, 13px); + newGroupLimitFg: #a4a4a4; newGroupAboutFg: #808080; -newGroupNamePadding: margins(12px, 15px, 12px, 13px); -newGroupPadding: margins(26px, 28px, 26px, 24px); -newGroupSkip: 15px; -newGroupLinkPadding: margins(26px, 27px, 26px, 27px); +newGroupPadding: margins(4px, 6px, 4px, 3px); +newGroupSkip: 17px; +newGroupInfoPadding: margins(0px, -4px, 0px, 1px); + +newGroupLink: InputField(defaultInputField) { + textMargins: margins(0px, 6px, 0px, 4px); +} +newGroupLinkPadding: margins(4px, 27px, 4px, 27px); newGroupLinkTop: -3px; newGroupLinkFont: font(16px); -newGroupPhoto: flatButton(btnDefNext, btnDefBig) { - width: 199px; - height: 42px; - textTop: 9px; - overTextTop: 9px; - downTextTop: 10px; +newGroupPhotoSize: 76px; +newGroupPhotoBg: #4eb5f0; +newGroupPhotoBgOver: #3fa9e7; +newGroupPhotoIcon: sprite(74px, 104px, 30px, 27px); +newGroupPhotoIconPosition: point(23px, 25px); - font: font(17px); - overFont: font(17px); +newGroupNamePosition: point(27px, 20px); +newGroupName: InputField(defaultInputField) { + textMargins: margins(1px, 6px, 1px, 4px); } -newGroupPhotoSize: 96px; -newGroupPhotoSkip: 18px; -newGroupDescriptionSkip: 28px; -newGroupPublicLinkSkip: 27px; -newGroupDescription: flatTextarea(taDefFlat) { - font: font(15px); - bgColor: transparent; - phColor: #828282; - phFocusColor: #949494; + +newGroupDescriptionPadding: margins(0px, 23px, 0px, 14px); +newGroupDescription: InputArea(defaultInputArea) { + textMargins: margins(1px, 6px, 1px, 4px); + heightMax: 115px; } -newGroupDescriptionPadding: margins(5px, 6px, 5px, 6px); + +newGroupPublicLinkPadding: margins(0px, 20px, 0px, 5px); newGroupLinkFadeDuration: 5000; -connectionSkip: 20px; -inpConnectionHost: flatInput(inpDefGray) { - font: font(fsize); - height: 34px; - bgColor: #f2f2f2; - phColor: #949494; - phFocusColor: #a4a4a4; - textMrg: margins(4px, 2px, 5px, 4px); - width: 205px; - - borderWidth: 2px; - borderColor: #f2f2f2; - borderActive: #80cff9; - borderError: #ed8080; +connectionHostInputField: InputField(defaultInputField) { + width: 160px; } -inpConnectionPort: flatInput(inpConnectionHost) { - width: 80px; +connectionPortInputField: InputField(defaultInputField) { + width: 55px; } -inpConnectionUser: flatInput(inpConnectionHost) { - width: 130px; +connectionUserInputField: InputField(defaultInputField) { + width: 95px; } -inpConnectionPassword: flatInput(inpConnectionHost) { - width: 155px; +connectionPasswordInputField: InputField(defaultInputField) { + width: 120px; } +connectionIPv6Skip: 11px; contactsClose: flatButton { color: btnYesColor; @@ -1669,18 +1718,6 @@ dragPadding: margins(20px, 10px, 20px, 10px); dragHeight: 72px; -downloadSkip: 20px; -inpDownloadDir: flatInput(inpDefGray) { - font: font(fsize); - height: 34px; - bgColor: #fff; - textMrg: margins(5px, 2px, 5px, 4px); - width: 295px; - - borderWidth: 2px; - borderColor: #f2f2f2; -} - dpiSlider: slider { color: #ccc; thikness: 2px; @@ -2087,34 +2124,29 @@ minPhotoSize: 100px; maxMediaSize: 420px; maxStickerSize: 256px; -usernameFont: font(14px); -usernameColor: #777; -usernameWidth: 336px; -usernameSkip: 32px; -usernameInput: flatInput(inpAddContact) { - bgColor: transparent; +downloadPathSkip: 10px; + +usernamePadding: margins(23px, 22px, 21px, 12px); +usernameSkip: 49px; +usernameTextStyle: textStyle(defaultTextStyle) { + lineHeight: 20px; } -usernameDone: flatButton(btnSelectDone) { - width: 168px; -} -usernameCancel: flatButton(btnSelectCancel) { - width: 167px; +usernameField: InputField(defaultInputField) { + textMargins: margins(0px, 6px, 0px, 4px); } +usernameDefaultFg: #777; youtubeIcon: sprite(336px, 221px, 60px, 60px); vimeoIcon: sprite(336px, 283px, 60px, 60px); videoIcon: sprite(0px, 340px, 60px, 60px); locationSize: size(320, 240); -langsWidth: 220px; -langsPadding: margins(10px, 10px, 10px, 10px); -langPadding: margins(10px, 10px, 10px, 10px); -langButton: flatCheckbox(rbDefFlat) { +boxOptionListPadding: margins(2px, 20px, 2px, 2px); + +langsWidth: 256px; +langsButton: Radiobutton(defaultRadiobutton) { width: 200px; } -langsCloseButton: flatButton(aboutCloseButton) { - width: langsWidth; -} backgroundPadding: 10px; backgroundSize: size(108px, 193px); diff --git a/Telegram/Resources/style_classes.txt b/Telegram/Resources/style_classes.txt index 715c5a7d8..567967127 100644 --- a/Telegram/Resources/style_classes.txt +++ b/Telegram/Resources/style_classes.txt @@ -286,6 +286,73 @@ BoxButton { duration: number; } +Checkbox { + textFg: color; + textBg: color; + + checkFg: color; + checkFgOver: color; + checkFgActive: color; + + width: number; + height: number; + + textPosition: point; + diameter: number; + thickness: number; + checkIcon: sprite; + + font: font; + duration: number; +} + +Radiobutton { + textFg: color; + textBg: color; + + checkFg: color; + checkFgOver: color; + checkFgActive: color; + + width: number; + height: number; + + textPosition: point; + diameter: number; + thickness: number; + checkSkip: number; + + font: font; + duration: number; +} + +InputArea { + textFg: color; + textMargins: margins; + + placeholderFg: color; + placeholderFgActive: color; + placeholderMargins: margins; + placeholderAlign: align; + placeholderShift: number; + + duration: number; + + borderFg: color; + borderFgActive: color; + borderFgError: color; + + border: number; + borderActive: number; + borderError: number; + + font: font; + + width: number; + heightMin: number; + heightMax: number; +} + InputField { textFg: color; textMargins: margins; diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index ad156f5e7..4f30a9fdd 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -324,7 +324,7 @@ void ApiWrap::gotUserFull(PeerData *peer, const MTPUserFull &result) { } bool ApiWrap::gotPeerFullFailed(PeerData *peer, const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; _fullPeerRequests.remove(peer); return true; @@ -408,7 +408,7 @@ void ApiWrap::gotUsers(const MTPVector &result) { } bool ApiWrap::gotPeerFailed(PeerData *peer, const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; _peerRequests.remove(peer); return true; @@ -582,7 +582,7 @@ void ApiWrap::gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result) } bool ApiWrap::gotStickerSetFail(uint64 setId, const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; _stickerSetRequests.remove(setId); return true; diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index d87e88342..44067891d 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -94,7 +94,7 @@ namespace { HistoryItem *hoveredItem = 0, *pressedItem = 0, *hoveredLinkItem = 0, *pressedLinkItem = 0, *contextItem = 0, *mousedItem = 0; - QPixmap *sprite = 0, *emojis = 0, *emojisLarge = 0; + QPixmap *sprite = 0, *emoji = 0, *emojiLarge = 0; struct CornersPixmaps { CornersPixmaps() { @@ -107,9 +107,9 @@ namespace { CornersMap cornersMap; QImage *cornersMask[4] = { 0 }; - typedef QMap EmojisMap; - EmojisMap mainEmojisMap; - QMap otherEmojisMap; + typedef QMap EmojiMap; + EmojiMap mainEmojiMap; + QMap otherEmojiMap; int32 serviceImageCacheSize = 0; @@ -1919,13 +1919,13 @@ namespace App { if (cRetina()) ::sprite->setDevicePixelRatio(cRetinaFactor()); } emojiInit(); - if (!::emojis) { - ::emojis = new QPixmap(QLatin1String(EName)); - if (cRetina()) ::emojis->setDevicePixelRatio(cRetinaFactor()); + if (!::emoji) { + ::emoji = new QPixmap(QLatin1String(EName)); + if (cRetina()) ::emoji->setDevicePixelRatio(cRetinaFactor()); } - if (!::emojisLarge) { - ::emojisLarge = new QPixmap(QLatin1String(EmojiNames[EIndex + 1])); - if (cRetina()) ::emojisLarge->setDevicePixelRatio(cRetinaFactor()); + if (!::emojiLarge) { + ::emojiLarge = new QPixmap(QLatin1String(EmojiNames[EIndex + 1])); + if (cRetina()) ::emojiLarge->setDevicePixelRatio(cRetinaFactor()); } QImage mask[4]; @@ -1975,10 +1975,10 @@ namespace App { delete ::sprite; ::sprite = 0; - delete ::emojis; - ::emojis = 0; - delete ::emojisLarge; - ::emojisLarge = 0; + delete ::emoji; + ::emoji = 0; + delete ::emojiLarge; + ::emojiLarge = 0; for (int32 j = 0; j < 4; ++j) { for (int32 i = 0; i < RoundCornersCount; ++i) { delete ::corners[i].p[j]; ::corners[i].p[j] = 0; @@ -1991,8 +1991,8 @@ namespace App { } } ::cornersMap.clear(); - mainEmojisMap.clear(); - otherEmojisMap.clear(); + mainEmojiMap.clear(); + otherEmojiMap.clear(); clearAllImages(); } else { @@ -2055,17 +2055,17 @@ namespace App { return *::sprite; } - const QPixmap &emojis() { - return *::emojis; + const QPixmap &emoji() { + return *::emoji; } - const QPixmap &emojisLarge() { - return *::emojisLarge; + const QPixmap &emojiLarge() { + return *::emojiLarge; } const QPixmap &emojiSingle(EmojiPtr emoji, int32 fontHeight) { - EmojisMap *map = &(fontHeight == st::taDefFlat.font->height ? mainEmojisMap : otherEmojisMap[fontHeight]); - EmojisMap::const_iterator i = map->constFind(emojiKey(emoji)); + EmojiMap *map = &(fontHeight == st::taDefFlat.font->height ? mainEmojiMap : otherEmojiMap[fontHeight]); + EmojiMap::const_iterator i = map->constFind(emojiKey(emoji)); if (i == map->cend()) { QImage img(ESize + st::emojiPadding * cIntRetinaFactor() * 2, fontHeight * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied); if (cRetina()) img.setDevicePixelRatio(cRetinaFactor()); diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h index 9fdcfaa6c..3c429b0b4 100644 --- a/Telegram/SourceFiles/app.h +++ b/Telegram/SourceFiles/app.h @@ -205,8 +205,8 @@ namespace App { HistoryItem *mousedItem(); const QPixmap &sprite(); - const QPixmap &emojis(); - const QPixmap &emojisLarge(); + const QPixmap &emoji(); + const QPixmap &emojiLarge(); const QPixmap &emojiSingle(EmojiPtr emoji, int32 fontHeight); void initMedia(); diff --git a/Telegram/SourceFiles/application.cpp b/Telegram/SourceFiles/application.cpp index 8e410f1ff..44d6f1855 100644 --- a/Telegram/SourceFiles/application.cpp +++ b/Telegram/SourceFiles/application.cpp @@ -328,7 +328,7 @@ void Application::chatPhotoDone(PeerId peer, const MTPUpdates &updates) { } bool Application::peerPhotoFail(PeerId peer, const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; LOG(("Application Error: update photo failed %1: %2").arg(error.type()).arg(error.description())); cancelPhotoUpdate(peer); diff --git a/Telegram/SourceFiles/art/sprite.png b/Telegram/SourceFiles/art/sprite.png index 59ccef978..8a40fcf6b 100644 Binary files a/Telegram/SourceFiles/art/sprite.png and b/Telegram/SourceFiles/art/sprite.png differ diff --git a/Telegram/SourceFiles/art/sprite_200x.png b/Telegram/SourceFiles/art/sprite_200x.png index b87d84f1e..00d1e2322 100644 Binary files a/Telegram/SourceFiles/art/sprite_200x.png and b/Telegram/SourceFiles/art/sprite_200x.png differ diff --git a/Telegram/SourceFiles/boxes/abstractbox.cpp b/Telegram/SourceFiles/boxes/abstractbox.cpp index 3aad571fc..c3ff1ac59 100644 --- a/Telegram/SourceFiles/boxes/abstractbox.cpp +++ b/Telegram/SourceFiles/boxes/abstractbox.cpp @@ -65,7 +65,7 @@ bool AbstractBox::paint(QPainter &p) { return result; } -void AbstractBox::paintTitle(Painter &p, const QString &title, bool withShadow) { +void AbstractBox::paintOldTitle(Painter &p, const QString &title, bool withShadow) { if (withShadow) { // paint shadow p.fillRect(0, st::old_boxTitleHeight, width(), st::scrollDef.topsh, st::scrollDef.shColor->b); @@ -77,6 +77,29 @@ void AbstractBox::paintTitle(Painter &p, const QString &title, bool withShadow) p.drawTextLeft(st::old_boxTitlePos.x(), st::old_boxTitlePos.y(), width(), title); } +void AbstractBox::paintTitle(Painter &p, const QString &title) { + // paint box title + p.setFont(st::boxTitleFont); + p.setPen(st::black); + p.drawTextLeft(st::boxTitlePosition.x(), st::boxTitlePosition.y(), width(), title); +} + +void AbstractBox::paintBlueTitle(Painter &p, const QString &title, const QString &additional) { + // paint box title + p.fillRect(0, 0, width(), st::boxBlueTitleHeight, st::boxBlueTitleBg->b); + p.setFont(st::boxTitleFont); + p.setPen(st::white); + + int32 titleWidth = st::boxTitleFont->width(title); + p.drawTextLeft(st::boxBlueTitlePosition.x(), st::boxBlueTitlePosition.y(), width(), title, titleWidth); + + if (!additional.isEmpty()) { + p.setFont(st::boxTextFont); + p.setPen(st::boxBlueTitleAdditionalFg); + p.drawTextLeft(st::boxBlueTitlePosition.x() + titleWidth + st::boxBlueTitleAdditionalSkip, st::boxBlueTitlePosition.y(), width(), additional); + } +} + void AbstractBox::paintGrayTitle(QPainter &p, const QString &title) { // draw box title p.setFont(st::boxFont->f); diff --git a/Telegram/SourceFiles/boxes/abstractbox.h b/Telegram/SourceFiles/boxes/abstractbox.h index 6029a65e0..d2306587f 100644 --- a/Telegram/SourceFiles/boxes/abstractbox.h +++ b/Telegram/SourceFiles/boxes/abstractbox.h @@ -42,7 +42,9 @@ protected: void prepare(); bool paint(QPainter &p); - void paintTitle(Painter &p, const QString &title, bool withShadow); + void paintTitle(Painter &p, const QString &title); + void paintBlueTitle(Painter &p, const QString &title, const QString &additional = QString()); + void paintOldTitle(Painter &p, const QString &title, bool withShadow); void paintGrayTitle(QPainter &p, const QString &title); void setMaxHeight(int32 maxHeight); void resizeMaxHeight(int32 newWidth, int32 maxHeight); diff --git a/Telegram/SourceFiles/boxes/addcontactbox.cpp b/Telegram/SourceFiles/boxes/addcontactbox.cpp index f426106a9..9fff7163c 100644 --- a/Telegram/SourceFiles/boxes/addcontactbox.cpp +++ b/Telegram/SourceFiles/boxes/addcontactbox.cpp @@ -31,7 +31,7 @@ AddContactBox::AddContactBox(QString fname, QString lname, QString phone) : _peer(0), _addButton(this, lang(lng_add_contact), st::btnSelectDone), _retryButton(this, lang(lng_try_other_contact), st::btnSelectDone), - _cancelButton(this, lang(lng_cancel), st::btnSelectCancel), + _cancelButton(this, lang(lng_box_cancel), st::btnSelectCancel), _firstInput(this, st::inpAddContact, lang(lng_signup_firstname), fname), _lastInput(this, st::inpAddContact, lang(lng_signup_lastname), lname), _phoneInput(this, st::inpAddContact, lang(lng_contact_phone), phone.isEmpty() ? phone : App::formatPhone(phone)), @@ -49,7 +49,7 @@ AddContactBox::AddContactBox(PeerData *peer) : _peer(peer), _addButton(this, lang(lng_settings_save), st::btnSelectDone), _retryButton(this, lang(lng_try_other_contact), st::btnSelectDone), - _cancelButton(this, lang(lng_cancel), st::btnSelectCancel), + _cancelButton(this, lang(lng_box_cancel), st::btnSelectCancel), _firstInput(this, st::inpAddContact, lang(peer->isUser() ? lng_signup_firstname : lng_dlg_new_group_name), peer->isUser() ? peer->asUser()->firstName : peer->name), _lastInput(this, st::inpAddContact, lang(lng_signup_lastname), peer->isUser() ? peer->asUser()->lastName : QString()), _phoneInput(this, st::inpAddContact, lang(lng_contact_phone)), @@ -66,7 +66,7 @@ void AddContactBox::initBox() { if (_peer) { if (_peer->isUser()) { _boxTitle = lang(_peer == App::self() ? lng_edit_self_title : lng_edit_contact_title); - setMaxHeight(st::old_boxTitleHeight + st::addContactPadding.top() + 2 * _firstInput.height() + 1 * st::addContactDelta + st::addContactPadding.bottom() + _addButton.height()); + setMaxHeight(st::old_boxTitleHeight + st::addContactPadding.top() + 2 * _firstInput.height() + 1 * st::addContactSkip + st::addContactPadding.bottom() + _addButton.height()); } else if (_peer->isChat()) { _boxTitle = lang(lng_edit_group_title); setMaxHeight(st::old_boxTitleHeight + st::addContactPadding.top() + 1 * _firstInput.height() + st::addContactPadding.bottom() + _addButton.height()); @@ -74,7 +74,7 @@ void AddContactBox::initBox() { } else { bool readyToAdd = !_phoneInput.text().isEmpty() && (!_firstInput.text().isEmpty() || !_lastInput.text().isEmpty()); _boxTitle = lang(readyToAdd ? lng_confirm_contact_data : lng_enter_contact_data); - setMaxHeight(st::old_boxTitleHeight + st::addContactPadding.top() + 3 * _firstInput.height() + 2 * st::addContactDelta + st::addContactPadding.bottom() + _addButton.height()); + setMaxHeight(st::old_boxTitleHeight + st::addContactPadding.top() + 3 * _firstInput.height() + 2 * st::addContactSkip + st::addContactPadding.bottom() + _addButton.height()); } _retryButton.hide(); @@ -168,7 +168,7 @@ void AddContactBox::paintEvent(QPaintEvent *e) { if (paint(p)) return; if (_retryButton.isHidden()) { - paintTitle(p, _boxTitle, true); + paintOldTitle(p, _boxTitle, true); } else { // draw box text p.setPen(st::black->p); @@ -187,12 +187,12 @@ void AddContactBox::paintEvent(QPaintEvent *e) { void AddContactBox::resizeEvent(QResizeEvent *e) { if (_invertOrder) { _lastInput.setGeometry(st::addContactPadding.left(), st::old_boxTitleHeight + st::addContactPadding.top(), width() - st::addContactPadding.left() - st::addContactPadding.right(), _lastInput.height()); - _firstInput.setGeometry(st::addContactPadding.left(), _lastInput.y() + _lastInput.height() + st::addContactDelta, _lastInput.width(), _lastInput.height()); - _phoneInput.setGeometry(st::addContactPadding.left(), _firstInput.y() + _firstInput.height() + st::addContactDelta, _lastInput.width(), _lastInput.height()); + _firstInput.setGeometry(st::addContactPadding.left(), _lastInput.y() + _lastInput.height() + st::addContactSkip, _lastInput.width(), _lastInput.height()); + _phoneInput.setGeometry(st::addContactPadding.left(), _firstInput.y() + _firstInput.height() + st::addContactSkip, _lastInput.width(), _lastInput.height()); } else { _firstInput.setGeometry(st::addContactPadding.left(), st::old_boxTitleHeight + st::addContactPadding.top(), width() - st::addContactPadding.left() - st::addContactPadding.right(), _firstInput.height()); - _lastInput.setGeometry(st::addContactPadding.left(), _firstInput.y() + _firstInput.height() + st::addContactDelta, _firstInput.width(), _firstInput.height()); - _phoneInput.setGeometry(st::addContactPadding.left(), _lastInput.y() + _lastInput.height() + st::addContactDelta, _lastInput.width(), _lastInput.height()); + _lastInput.setGeometry(st::addContactPadding.left(), _firstInput.y() + _firstInput.height() + st::addContactSkip, _firstInput.width(), _firstInput.height()); + _phoneInput.setGeometry(st::addContactPadding.left(), _lastInput.y() + _lastInput.height() + st::addContactSkip, _lastInput.width(), _lastInput.height()); } _cancelButton.move(0, height() - _cancelButton.height()); @@ -246,7 +246,7 @@ void AddContactBox::onSaveSelfDone(const MTPUser &user) { } bool AddContactBox::onSaveSelfFail(const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; QString err(error.type()); QString firstName = textOneLine(_firstInput.text()), lastName = textOneLine(_lastInput.text()); @@ -268,7 +268,7 @@ bool AddContactBox::onSaveSelfFail(const RPCError &error) { } bool AddContactBox::onSaveFail(const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; _addRequest = 0; QString err(error.type()); @@ -345,42 +345,207 @@ void AddContactBox::onRetry() { _phoneInput.setDisabled(false); _retryButton.hide(); _firstInput.setFocus(); - setMaxHeight(st::old_boxTitleHeight + st::addContactPadding.top() + 3 * _firstInput.height() + 2 * st::addContactDelta + st::addContactPadding.bottom() + _addButton.height()); + setMaxHeight(st::old_boxTitleHeight + st::addContactPadding.top() + 3 * _firstInput.height() + 2 * st::addContactSkip + st::addContactPadding.bottom() + _addButton.height()); update(); } +EditNameTitleBox::EditNameTitleBox(PeerData *peer) : +_peer(peer), +_save(this, lang(lng_settings_save), st::defaultBoxButton), +_cancel(this, lang(lng_box_cancel), st::cancelBoxButton), +_first(this, st::defaultInputField, lang(peer->isUser() ? lng_signup_firstname : lng_dlg_new_group_name), peer->isUser() ? peer->asUser()->firstName : peer->name), +_last(this, st::defaultInputField, lang(lng_signup_lastname), peer->isUser() ? peer->asUser()->lastName : QString()), +_invertOrder(!peer->isChat() && langFirstNameGoesSecond()), +_requestId(0) { + if (_invertOrder) { + setTabOrder(&_last, &_first); + } + int32 h = st::boxTitleHeight + st::addContactPadding.top() + _first.height(); + if (_peer->isUser()) { + _boxTitle = lang(_peer == App::self() ? lng_edit_self_title : lng_edit_contact_title); + h += st::addContactSkip + _last.height(); + } else if (_peer->isChat()) { + _boxTitle = lang(lng_edit_group_title); + } + h += st::boxPadding.bottom() + st::addContactPadding.bottom() + st::boxButtonPadding.top() + _save.height() + st::boxButtonPadding.bottom(); + setMaxHeight(h); + + connect(&_save, SIGNAL(clicked()), this, SLOT(onSave())); + connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose())); + + connect(&_first, SIGNAL(submitted(bool)), this, SLOT(onSubmit())); + connect(&_last, SIGNAL(submitted(bool)), this, SLOT(onSubmit())); + + prepare(); +} + +void EditNameTitleBox::hideAll() { + _first.hide(); + _last.hide(); + _save.hide(); + _cancel.hide(); +} + +void EditNameTitleBox::showAll() { + _first.show(); + if (_peer->isChat()) { + _last.hide(); + } else { + _last.show(); + } + _save.show(); + _cancel.show(); +} + +void EditNameTitleBox::showDone() { + (_invertOrder ? _last : _first).setFocus(); +} + +void EditNameTitleBox::onSubmit() { + if (_first.hasFocus()) { + if (_peer->isChat()) { + if (_first.getLastText().trimmed().isEmpty()) { + _first.setFocus(); + _first.showError(); + } else { + onSave(); + } + } else { + _last.setFocus(); + } + } else if (_last.hasFocus()) { + if (_first.getLastText().trimmed().isEmpty()) { + _first.setFocus(); + _first.showError(); + } else if (_last.getLastText().trimmed().isEmpty()) { + _last.setFocus(); + _last.showError(); + } else { + onSave(); + } + } +} + +void EditNameTitleBox::paintEvent(QPaintEvent *e) { + Painter p(this); + if (paint(p)) return; + + paintTitle(p, _boxTitle); +} + +void EditNameTitleBox::resizeEvent(QResizeEvent *e) { + _first.resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - (st::boxButtonPadding.right() - (st::defaultBoxButton.width / 2)), _first.height()); + _last.resize(_first.size()); + if (_invertOrder) { + _last.moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::boxTitleHeight + st::addContactPadding.top()); + _first.moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _last.y() + _last.height() + st::addContactSkip); + } else { + _first.moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::boxTitleHeight + st::addContactPadding.top()); + _last.moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _first.y() + _first.height() + st::addContactSkip); + } + + _save.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _save.height()); + _cancel.moveToRight(st::boxButtonPadding.right() + _save.width() + st::boxButtonPadding.left(), _save.y()); +} + +void EditNameTitleBox::onSave() { + if (_requestId) return; + + QString first = _first.getLastText().trimmed(), last = _last.getLastText().trimmed(); + if (first.isEmpty() && last.isEmpty()) { + if (_invertOrder) { + _last.setFocus(); + _last.showError(); + } else { + _first.setFocus(); + _first.showError(); + } + return; + } + if (first.isEmpty()) { + first = last; + last = QString(); + } + _sentName = first; + if (_peer == App::self()) { + _requestId = MTP::send(MTPaccount_UpdateProfile(MTP_string(first), MTP_string(last)), rpcDone(&EditNameTitleBox::onSaveSelfDone), rpcFail(&EditNameTitleBox::onSaveSelfFail)); + } else if (_peer->isChat()) { + _requestId = MTP::send(MTPmessages_EditChatTitle(_peer->asChat()->inputChat, MTP_string(first)), rpcDone(&EditNameTitleBox::onSaveChatDone), rpcFail(&EditNameTitleBox::onSaveChatFail)); + } +} + +void EditNameTitleBox::onSaveSelfDone(const MTPUser &user) { + App::feedUsers(MTP_vector(1, user)); + emit closed(); +} + +bool EditNameTitleBox::onSaveSelfFail(const RPCError &error) { + if (mtpIsFlood(error)) return false; + + QString err(error.type()); + QString first = textOneLine(_first.getLastText().trimmed()), last = textOneLine(_last.getLastText().trimmed()); + if (err == "NAME_NOT_MODIFIED") { + App::self()->setName(first, last, QString(), textOneLine(App::self()->username)); + emit closed(); + return true; + } else if (err == "FIRSTNAME_INVALID") { + _first.setFocus(); + _first.showError(); + return true; + } else if (err == "LASTNAME_INVALID") { + _last.setFocus(); + _last.showError(); + return true; + } + _first.setFocus(); + return true; +} + +bool EditNameTitleBox::onSaveChatFail(const RPCError &error) { + if (mtpIsFlood(error)) return false; + + _requestId = 0; + QString err(error.type()); + if (err == qstr("CHAT_TITLE_NOT_MODIFIED") || err == qstr("CHAT_NOT_MODIFIED")) { + _peer->updateName(_sentName, QString(), QString()); + emit closed(); + return true; + } else if (err == qstr("NO_CHAT_TITLE")) { + _first.setFocus(); + _first.showError(); + return true; + } + _first.setFocus(); + return true; +} + +void EditNameTitleBox::onSaveChatDone(const MTPUpdates &updates) { + App::main()->sentUpdatesReceived(updates); + emit closed(); +} + EditChannelBox::EditChannelBox(ChannelData *channel) : _channel(channel), -_saveButton(this, lang(lng_settings_save), st::btnSelectDone), -_cancelButton(this, lang(lng_cancel), st::btnSelectCancel), -_title(this, st::inpAddContact, lang(lng_dlg_new_channel_name), _channel->name), -_descriptionOver(false), -a_descriptionBg(st::newGroupName.bgColor->c, st::newGroupName.bgColor->c), -a_descriptionBorder(st::newGroupName.borderColor->c, st::newGroupName.borderColor->c), -a_description(animFunc(this, &EditChannelBox::descriptionAnimStep)), +_save(this, lang(lng_settings_save), st::defaultBoxButton), +_cancel(this, lang(lng_box_cancel), st::cancelBoxButton), +_title(this, st::newGroupName, lang(lng_dlg_new_channel_name), _channel->name), _description(this, st::newGroupDescription, lang(lng_create_group_description), _channel->about), -_publicLink(this, lang(channel->isPublic() ? lng_profile_edit_public_link : lng_profile_create_public_link)), +_publicLink(this, lang(channel->isPublic() ? lng_profile_edit_public_link : lng_profile_create_public_link), st::defaultBoxLinkButton), _saveTitleRequestId(0), _saveDescriptionRequestId(0) { - _boxTitle = lang(lng_edit_channel_title); - - _description.installEventFilter(this); - connect(App::main(), SIGNAL(peerNameChanged(PeerData*, const PeerData::Names&, const PeerData::NameFirstChars&)), this, SLOT(peerUpdated(PeerData*))); setMouseTracking(true); - _description.resize(width() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::newGroupDescriptionPadding.left() - st::newGroupDescriptionPadding.right(), _title.height() - st::newGroupDescriptionPadding.top() - st::newGroupDescriptionPadding.bottom()); - _description.setMinHeight(_description.height()); - _description.setMaxHeight(3 * _description.height() + 2 * st::newGroupDescriptionPadding.top() + 2 * st::newGroupDescriptionPadding.bottom()); + _description.setMaxLength(MaxChannelDescription); + _description.resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - (st::boxButtonPadding.right() - (st::defaultBoxButton.width / 2)), _description.height()); updateMaxHeight(); - _description.setMaxLength(MaxChannelDescription); connect(&_description, SIGNAL(resized()), this, SLOT(onDescriptionResized())); - connect(&_description, SIGNAL(submitted(bool)), this, SLOT(onSave())); + connect(&_description, SIGNAL(submitted(bool)), this, SLOT(onNext())); connect(&_description, SIGNAL(cancelled()), this, SLOT(onClose())); - connect(&_saveButton, SIGNAL(clicked()), this, SLOT(onSave())); - connect(&_cancelButton, SIGNAL(clicked()), this, SLOT(onClose())); + connect(&_save, SIGNAL(clicked()), this, SLOT(onSave())); + connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose())); connect(&_publicLink, SIGNAL(clicked()), this, SLOT(onPublicLink())); @@ -390,16 +555,16 @@ _saveTitleRequestId(0), _saveDescriptionRequestId(0) { void EditChannelBox::hideAll() { _title.hide(); _description.hide(); - _saveButton.hide(); - _cancelButton.hide(); + _save.hide(); + _cancel.hide(); _publicLink.hide(); } void EditChannelBox::showAll() { _title.show(); _description.show(); - _saveButton.show(); - _cancelButton.show(); + _save.show(); + _cancel.show(); _publicLink.show(); } @@ -421,43 +586,7 @@ void EditChannelBox::paintEvent(QPaintEvent *e) { Painter p(this); if (paint(p)) return; - paintTitle(p, _boxTitle, true); - - QRect descRect(descriptionRect()); - if (descRect.intersects(e->rect())) { - p.fillRect(descRect, a_descriptionBg.current()); - if (st::newGroupName.borderWidth) { - QBrush b(a_descriptionBorder.current()); - p.fillRect(descRect.x(), descRect.y(), descRect.width() - st::newGroupName.borderWidth, st::newGroupName.borderWidth, b); - p.fillRect(descRect.x() + descRect.width() - st::newGroupName.borderWidth, descRect.y(), st::newGroupName.borderWidth, descRect.height() - st::newGroupName.borderWidth, b); - p.fillRect(descRect.x() + st::newGroupName.borderWidth, descRect.y() + descRect.height() - st::newGroupName.borderWidth, descRect.width() - st::newGroupName.borderWidth, st::newGroupName.borderWidth, b); - p.fillRect(descRect.x(), descRect.y() + st::newGroupName.borderWidth, st::newGroupName.borderWidth, descRect.height() - st::newGroupName.borderWidth, b); - } - if (descRect.contains(e->rect())) { - return; - } - } - - // paint shadows - p.fillRect(0, size().height() - st::btnSelectCancel.height - st::scrollDef.bottomsh, width(), st::scrollDef.bottomsh, st::scrollDef.shColor->b); - - // paint button sep - p.fillRect(st::btnSelectCancel.width, size().height() - st::btnSelectCancel.height, st::lineWidth, st::btnSelectCancel.height, st::btnSelectSep->b); -} - -bool EditChannelBox::descriptionAnimStep(float64 ms) { - float dt = ms / st::newGroupName.phDuration; - bool res = true; - if (dt >= 1) { - res = false; - a_descriptionBg.finish(); - a_descriptionBorder.finish(); - } else { - a_descriptionBg.update(dt, st::newGroupName.phColorFunc); - a_descriptionBorder.update(dt, st::newGroupName.phColorFunc); - } - update(descriptionRect()); - return res; + paintTitle(p, lang(lng_edit_channel_title)); } void EditChannelBox::peerUpdated(PeerData *peer) { @@ -471,79 +600,33 @@ void EditChannelBox::onDescriptionResized() { update(); } -QRect EditChannelBox::descriptionRect() const { - return rtlrect(_description.x() - st::newGroupDescriptionPadding.left(), _description.y() - st::newGroupDescriptionPadding.top(), _description.width() + st::newGroupDescriptionPadding.left() + st::newGroupDescriptionPadding.right(), _description.height() + st::newGroupDescriptionPadding.top() + st::newGroupDescriptionPadding.bottom(), width()); -} - void EditChannelBox::updateMaxHeight() { - int32 h = st::old_boxTitleHeight + st::newGroupPadding.top() + _title.height(); - h += st::newGroupDescriptionSkip + st::newGroupDescriptionPadding.top() + _description.height() + st::newGroupDescriptionPadding.bottom(); - h += st::newGroupPublicLinkSkip + _publicLink.height(); - h += st::newGroupPadding.bottom() + _saveButton.height(); + int32 h = st::boxTitleHeight + st::newGroupInfoPadding.top() + _title.height(); + h += st::newGroupDescriptionPadding.top() + _description.height() + st::newGroupDescriptionPadding.bottom(); + h += st::newGroupPublicLinkPadding.top() + _publicLink.height() + st::newGroupPublicLinkPadding.bottom(); + h += st::boxPadding.bottom() + st::newGroupInfoPadding.bottom() + st::boxButtonPadding.top() + _save.height() + st::boxButtonPadding.bottom(); setMaxHeight(h); } -bool EditChannelBox::eventFilter(QObject *obj, QEvent *e) { - if (obj == &_description) { - if (e->type() == QEvent::FocusIn) { - a_descriptionBorder.start(st::newGroupName.borderActive->c); - a_descriptionBg.start(st::newGroupName.bgActive->c); - a_description.start(); - } else if (e->type() == QEvent::FocusOut) { - a_descriptionBorder.start(st::newGroupName.borderColor->c); - a_descriptionBg.start(st::newGroupName.bgColor->c); - a_description.start(); - } - } - return AbstractBox::eventFilter(obj, e); -} - void EditChannelBox::resizeEvent(QResizeEvent *e) { - _title.resize(width() - st::newGroupPadding.left() - st::newGroupPadding.right(), _title.height()); - _title.moveToLeft(st::newGroupPadding.left(), st::old_boxTitleHeight + st::newGroupPadding.top(), width()); + _title.resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - (st::boxButtonPadding.right() - (st::defaultBoxButton.width / 2)), _title.height()); + _title.moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::boxTitleHeight + st::newGroupInfoPadding.top() + st::newGroupNamePosition.y()); - _description.moveToLeft(st::newGroupPadding.left() + st::newGroupDescriptionPadding.left(), _title.y() + _title.height() + st::newGroupDescriptionSkip + st::newGroupDescriptionPadding.top(), width()); + _description.moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _title.y() + _title.height() + st::newGroupDescriptionPadding.top()); - _publicLink.moveToLeft(st::newGroupPadding.left(), _description.y() + _description.height() + st::newGroupDescriptionPadding.bottom() + st::newGroupPublicLinkSkip, width()); + _publicLink.moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), _description.y() + _description.height() + st::newGroupDescriptionPadding.bottom() + st::newGroupPublicLinkPadding.top()); - int32 buttonTop = _publicLink.y() + _publicLink.height() + st::newGroupPadding.bottom(); - _cancelButton.move(0, buttonTop); - _saveButton.move(width() - _saveButton.width(), buttonTop); -} - -void EditChannelBox::mouseMoveEvent(QMouseEvent *e) { - updateSelected(e->globalPos()); -} - -void EditChannelBox::updateSelected(const QPoint &cursorGlobalPosition) { - QPoint p(mapFromGlobal(cursorGlobalPosition)); - - bool descriptionOver = descriptionRect().contains(p); - if (descriptionOver != _descriptionOver) { - _descriptionOver = descriptionOver; - } - - setCursor(_descriptionOver ? style::cur_text : style::cur_default); -} - -void EditChannelBox::mousePressEvent(QMouseEvent *e) { - mouseMoveEvent(e); - if (_descriptionOver) { - _description.setFocus(); - } -} - -void EditChannelBox::leaveEvent(QEvent *e) { - updateSelected(QCursor::pos()); + _save.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _save.height()); + _cancel.moveToRight(st::boxButtonPadding.right() + _save.width() + st::boxButtonPadding.left(), _save.y()); } void EditChannelBox::onSave() { if (_saveTitleRequestId || _saveDescriptionRequestId) return; - QString title = _title.text().trimmed(), description = _description.getLastText().trimmed(); + QString title = _title.getLastText().trimmed(), description = _description.getLastText().trimmed(); if (title.isEmpty()) { _title.setFocus(); - _title.notaBene(); + _title.showError(); return; } _sentTitle = title; @@ -571,7 +654,7 @@ bool EditChannelBox::onSaveFail(const RPCError &error, mtpRequestId req) { return true; } else if (err == qstr("NO_CHAT_TITLE")) { _title.setFocus(); - _title.notaBene(); + _title.showError(); return true; } else { _title.setFocus(); diff --git a/Telegram/SourceFiles/boxes/addcontactbox.h b/Telegram/SourceFiles/boxes/addcontactbox.h index 29f452a61..509cf11e6 100644 --- a/Telegram/SourceFiles/boxes/addcontactbox.h +++ b/Telegram/SourceFiles/boxes/addcontactbox.h @@ -75,6 +75,50 @@ private: QString _sentName; }; +class EditNameTitleBox : public AbstractBox, public RPCSender { + Q_OBJECT + +public: + + EditNameTitleBox(PeerData *peer); + void paintEvent(QPaintEvent *e); + void resizeEvent(QResizeEvent *e); + + void setInnerFocus() { + _first.setFocus(); + } + +public slots: + + void onSave(); + void onSubmit(); + +protected: + + void hideAll(); + void showAll(); + void showDone(); + +private: + + void onSaveSelfDone(const MTPUser &user); + bool onSaveSelfFail(const RPCError &error); + + void onSaveChatDone(const MTPUpdates &updates); + bool onSaveChatFail(const RPCError &e); + + PeerData *_peer; + QString _boxTitle; + + BoxButton _save, _cancel; + InputField _first, _last; + + bool _invertOrder; + + mtpRequestId _requestId; + QString _sentName; +}; + class EditChannelBox : public AbstractBox, public RPCSender { Q_OBJECT @@ -84,13 +128,6 @@ public: void keyPressEvent(QKeyEvent *e); void paintEvent(QPaintEvent *e); void resizeEvent(QResizeEvent *e); - void mouseMoveEvent(QMouseEvent *e); - void mousePressEvent(QMouseEvent *e); - void leaveEvent(QEvent *e); - - bool eventFilter(QObject *obj, QEvent *e); - - bool descriptionAnimStep(float64 ms); void setInnerFocus() { if (!_description.hasFocus()) { @@ -114,9 +151,7 @@ protected: private: - QRect descriptionRect() const; void updateMaxHeight(); - void updateSelected(const QPoint &cursorGlobalPosition); void onSaveTitleDone(const MTPUpdates &updates); void onSaveDescriptionDone(const MTPBool &result); @@ -125,15 +160,10 @@ private: void saveDescription(); ChannelData *_channel; - QString _boxTitle; - FlatButton _saveButton, _cancelButton; - FlatInput _title; - - bool _descriptionOver; - anim::cvalue a_descriptionBg, a_descriptionBorder; - Animation a_description; - FlatTextarea _description; + BoxButton _save, _cancel; + InputField _title; + InputArea _description; LinkButton _publicLink; diff --git a/Telegram/SourceFiles/boxes/autolockbox.cpp b/Telegram/SourceFiles/boxes/autolockbox.cpp index 0f271b6c6..93675868c 100644 --- a/Telegram/SourceFiles/boxes/autolockbox.cpp +++ b/Telegram/SourceFiles/boxes/autolockbox.cpp @@ -29,39 +29,39 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org #include "window.h" AutoLockBox::AutoLockBox() : -_done(this, lang(lng_about_done), st::langsCloseButton) { +_close(this, lang(lng_box_ok), st::defaultBoxButton) { bool haveTestLang = (cLang() == languageTest); int32 opts[] = { 60, 300, 3600, 18000 }, cnt = sizeof(opts) / sizeof(opts[0]); - resizeMaxHeight(st::langsWidth, st::old_boxTitleHeight + st::langsPadding.top() + st::langsPadding.bottom() + cnt * (st::langPadding.top() + st::rbDefFlat.height + st::langPadding.bottom()) + _done.height()); + resizeMaxHeight(st::langsWidth, st::boxTitleHeight + cnt * (st::boxOptionListPadding.top() + st::langsButton.height) + st::boxOptionListPadding.bottom() + st::boxPadding.bottom() + st::boxButtonPadding.top() + _close.height() + st::boxButtonPadding.bottom()); - int32 y = st::old_boxTitleHeight + st::langsPadding.top(); + int32 y = st::boxTitleHeight + st::boxOptionListPadding.top(); _options.reserve(cnt); for (int32 i = 0; i < cnt; ++i) { int32 v = opts[i]; - _options.push_back(new FlatRadiobutton(this, qsl("autolock"), v, (v % 3600) ? lng_passcode_autolock_minutes(lt_count, v / 60) : lng_passcode_autolock_hours(lt_count, v / 3600), (cAutoLock() == v), st::langButton)); - _options.back()->move(st::langsPadding.left() + st::langPadding.left(), y + st::langPadding.top()); - y += st::langPadding.top() + _options.back()->height() + st::langPadding.bottom(); + _options.push_back(new Radiobutton(this, qsl("autolock"), v, (v % 3600) ? lng_passcode_autolock_minutes(lt_count, v / 60) : lng_passcode_autolock_hours(lt_count, v / 3600), (cAutoLock() == v), st::langsButton)); + _options.back()->move(st::boxPadding.left() + st::boxOptionListPadding.left(), y); + y += _options.back()->height() + st::boxOptionListPadding.top(); connect(_options.back(), SIGNAL(changed()), this, SLOT(onChange())); } - connect(&_done, SIGNAL(clicked()), this, SLOT(onClose())); + connect(&_close, SIGNAL(clicked()), this, SLOT(onClose())); - _done.move(0, height() - _done.height()); + _close.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _close.height()); prepare(); } void AutoLockBox::hideAll() { - _done.hide(); + _close.hide(); for (int32 i = 0, l = _options.size(); i < l; ++i) { _options[i]->hide(); } } void AutoLockBox::showAll() { - _done.show(); + _close.show(); for (int32 i = 0, l = _options.size(); i < l; ++i) { _options[i]->show(); } @@ -71,7 +71,7 @@ void AutoLockBox::paintEvent(QPaintEvent *e) { Painter p(this); if (paint(p)) return; - paintTitle(p, lang(lng_passcode_autolock), true); + paintTitle(p, lang(lng_passcode_autolock)); } void AutoLockBox::onChange() { diff --git a/Telegram/SourceFiles/boxes/autolockbox.h b/Telegram/SourceFiles/boxes/autolockbox.h index 12edab8e4..827e10365 100644 --- a/Telegram/SourceFiles/boxes/autolockbox.h +++ b/Telegram/SourceFiles/boxes/autolockbox.h @@ -42,6 +42,6 @@ protected: private: - QVector _options; - BottomButton _done; + QVector _options; + BoxButton _close; }; diff --git a/Telegram/SourceFiles/boxes/backgroundbox.cpp b/Telegram/SourceFiles/boxes/backgroundbox.cpp index 7c523c157..b62830b10 100644 --- a/Telegram/SourceFiles/boxes/backgroundbox.cpp +++ b/Telegram/SourceFiles/boxes/backgroundbox.cpp @@ -177,7 +177,7 @@ void BackgroundInner::resizeEvent(QResizeEvent *e) { BackgroundBox::BackgroundBox() : ItemListBox(st::boxScroll), _inner(), _close(this, lang(lng_cancel), st::contactsClose) { - init(&_inner, _close.height(), st::boxFont->height + st::newGroupNamePadding.top() + st::newGroupNamePadding.bottom()); + init(&_inner, _close.height(), st::boxFont->height + st::old_newGroupNamePadding.top() + st::old_newGroupNamePadding.bottom()); connect(&_close, SIGNAL(clicked()), this, SLOT(onClose())); connect(&_inner, SIGNAL(backgroundChosen(int)), this, SLOT(onBackgroundChosen(int))); diff --git a/Telegram/SourceFiles/boxes/confirmbox.cpp b/Telegram/SourceFiles/boxes/confirmbox.cpp index bbb158c6b..ffaa620c1 100644 --- a/Telegram/SourceFiles/boxes/confirmbox.cpp +++ b/Telegram/SourceFiles/boxes/confirmbox.cpp @@ -170,8 +170,8 @@ void ConfirmBox::paintEvent(QPaintEvent *e) { } void ConfirmBox::resizeEvent(QResizeEvent *e) { - _confirm.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _confirm.height(), width()); - _cancel.moveToRight(st::boxButtonPadding.right() + _confirm.width() + st::boxButtonPadding.left(), _confirm.y(), width()); + _confirm.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _confirm.height()); + _cancel.moveToRight(st::boxButtonPadding.right() + _confirm.width() + st::boxButtonPadding.left(), _confirm.y()); } ConfirmLinkBox::ConfirmLinkBox(const QString &url) : ConfirmBox(lang(lng_open_this_link) + qsl("\n\n") + url, lang(lng_open_link)), _url(url) { @@ -196,7 +196,7 @@ a_goodOpacity(0, 0), a_good(animFunc(this, &MaxInviteBox::goodAnimStep)) { _textWidth = st::boxWidth - st::boxPadding.left() - st::boxPadding.right(); _textHeight = qMin(_text.countHeight(_textWidth), 16 * int(st::boxTextStyle.lineHeight)); - setMaxHeight(st::boxPadding.top() + _textHeight + st::newGroupLinkPadding.top() + st::newGroupLink.height + st::newGroupLinkPadding.bottom() + _close.height() + st::boxButtonPadding.bottom()); + setMaxHeight(st::boxPadding.top() + _textHeight + st::boxTextFont->height + st::boxTextFont->height * 2 + st::newGroupLinkPadding.bottom() + _close.height() + st::boxButtonPadding.bottom()); connect(&_close, SIGNAL(clicked()), this, SLOT(onClose())); @@ -269,13 +269,13 @@ void MaxInviteBox::paintEvent(QPaintEvent *e) { if (!_goodTextLink.isEmpty() && a_goodOpacity.current() > 0) { p.setOpacity(a_goodOpacity.current()); p.setPen(st::setGoodColor->p); - p.setFont(st::setErrFont->f); - p.drawText(QRect(st::newGroupPadding.left(), st::boxPadding.top() + _textHeight + st::newGroupLinkTop + st::newGroupLinkFont->height - st::setErrFont->ascent, width() - st::newGroupPadding.left() - st::newGroupPadding.right(), st::setErrFont->height), _goodTextLink, style::al_top); + p.setFont(st::boxTextFont->f); + p.drawTextLeft(st::boxPadding.left(), height() - st::boxButtonPadding.bottom() - _close.height() + st::defaultBoxButton.textTop + st::defaultBoxButton.font->ascent - st::boxTextFont->ascent, width(), _goodTextLink); p.setOpacity(1); } } void MaxInviteBox::resizeEvent(QResizeEvent *e) { - _close.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _close.height(), width()); - _invitationLink = QRect(st::newGroupPadding.left(), st::boxPadding.top() + _textHeight + st::newGroupLinkPadding.top() + (st::newGroupLink.height / 2) - st::newGroupLinkFont->height, width() - st::newGroupPadding.left() - st::newGroupPadding.right(), 2 * st::newGroupLinkFont->height); + _close.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _close.height()); + _invitationLink = myrtlrect(st::boxPadding.left(), st::boxPadding.top() + _textHeight + st::boxTextFont->height, width() - st::boxPadding.left() - (st::boxButtonPadding.right() - (st::defaultBoxButton.width / 2)), 2 * st::boxTextFont->height); } diff --git a/Telegram/SourceFiles/boxes/connectionbox.cpp b/Telegram/SourceFiles/boxes/connectionbox.cpp index b1b69c796..e6c6ca81d 100644 --- a/Telegram/SourceFiles/boxes/connectionbox.cpp +++ b/Telegram/SourceFiles/boxes/connectionbox.cpp @@ -27,25 +27,30 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org #include "mainwidget.h" #include "window.h" -ConnectionBox::ConnectionBox() : - _saveButton(this, lang(lng_connection_save), st::btnSelectDone), - _cancelButton(this, lang(lng_cancel), st::btnSelectCancel), - _hostInput(this, st::inpConnectionHost, lang(lng_connection_host_ph), cConnectionProxy().host), - _portInput(this, st::inpConnectionPort, lang(lng_connection_port_ph), QString::number(cConnectionProxy().port)), - _userInput(this, st::inpConnectionUser, lang(lng_connection_user_ph), cConnectionProxy().user), - _passwordInput(this, st::inpConnectionPassword, lang(lng_connection_password_ph), cConnectionProxy().password), - _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()) { +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_box_cancel), st::cancelBoxButton) { - connect(&_saveButton, SIGNAL(clicked()), this, SLOT(onSave())); - connect(&_cancelButton, SIGNAL(clicked()), this, SLOT(onClose())); + connect(&_save, SIGNAL(clicked()), this, SLOT(onSave())); + connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose())); connect(&_autoRadio, SIGNAL(changed()), this, SLOT(onChange())); connect(&_httpProxyRadio, SIGNAL(changed()), this, SLOT(onChange())); connect(&_tcpProxyRadio, SIGNAL(changed()), this, SLOT(onChange())); + connect(&_hostInput, SIGNAL(submitted(bool)), this, SLOT(onSubmit())); + connect(&_portInput, SIGNAL(submitted(bool)), this, SLOT(onSubmit())); + connect(&_userInput, SIGNAL(submitted(bool)), this, SLOT(onSubmit())); + connect(&_passwordInput, SIGNAL(submitted(bool)), this, SLOT(onSubmit())); + _passwordInput.setEchoMode(QLineEdit::Password); prepare(); @@ -62,8 +67,8 @@ void ConnectionBox::hideAll() { _userInput.hide(); _passwordInput.hide(); - _saveButton.hide(); - _cancelButton.hide(); + _save.hide(); + _cancel.hide(); } void ConnectionBox::showAll() { @@ -72,9 +77,9 @@ void ConnectionBox::showAll() { _tcpProxyRadio.show(); _tryIPv6.show(); - int32 h = st::old_boxTitleHeight + st::connectionSkip + _autoRadio.height() + st::connectionSkip + _httpProxyRadio.height() + st::connectionSkip + _tcpProxyRadio.height() + st::connectionSkip + st::lineWidth + st::connectionSkip + _tryIPv6.height() + st::connectionSkip; + int32 h = st::boxTitleHeight + st::boxOptionListPadding.top() + _autoRadio.height() + st::boxOptionListPadding.top() + _httpProxyRadio.height() + st::boxOptionListPadding.top() + _tcpProxyRadio.height() + st::boxOptionListPadding.top() + st::connectionIPv6Skip + _tryIPv6.height() + st::boxOptionListPadding.bottom() + st::boxPadding.bottom() + st::boxButtonPadding.top() + _save.height() + st::boxButtonPadding.bottom(); if (_httpProxyRadio.checked() || _tcpProxyRadio.checked()) { - h += 2 * st::boxPadding.top() + 2 * _hostInput.height(); + h += 2 * st::boxOptionListPadding.top() + 2 * _hostInput.height(); _hostInput.show(); _portInput.show(); _userInput.show(); @@ -86,10 +91,10 @@ void ConnectionBox::showAll() { _passwordInput.hide(); } - _saveButton.show(); - _cancelButton.show(); + _save.show(); + _cancel.show(); - setMaxHeight(h + _saveButton.height()); + setMaxHeight(h); resizeEvent(0); } @@ -103,52 +108,43 @@ void ConnectionBox::paintEvent(QPaintEvent *e) { Painter p(this); if (paint(p)) return; - paintTitle(p, lang(lng_connection_header), true); - - // paint separator - p.fillRect(st::boxPadding.left(), _tryIPv6.y() - st::connectionSkip - st::lineWidth, width() - st::boxPadding.left() - st::boxPadding.right(), st::lineWidth, st::scrollDef.shColor->b); - - // paint shadow - p.fillRect(0, height() - st::btnSelectCancel.height - st::scrollDef.bottomsh, width(), st::scrollDef.bottomsh, st::scrollDef.shColor->b); - - // paint button sep - p.fillRect(st::btnSelectCancel.width, height() - st::btnSelectCancel.height, st::lineWidth, st::btnSelectCancel.height, st::btnSelectSep->b); + paintTitle(p, lang(lng_connection_header)); } void ConnectionBox::resizeEvent(QResizeEvent *e) { - _autoRadio.move(st::boxPadding.left(), st::old_boxTitleHeight + st::connectionSkip); - _httpProxyRadio.move(st::boxPadding.left(), _autoRadio.y() + _autoRadio.height() + st::connectionSkip); + _autoRadio.moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), st::boxTitleHeight + st::boxOptionListPadding.top()); + _httpProxyRadio.moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), _autoRadio.y() + _autoRadio.height() + st::boxOptionListPadding.top()); int32 inputy = 0; if (_httpProxyRadio.checked()) { - inputy = _httpProxyRadio.y() + _httpProxyRadio.height() + st::boxPadding.top(); - _tcpProxyRadio.move(st::boxPadding.left(), inputy + st::boxPadding.top() + 2 * _hostInput.height() + st::connectionSkip); + inputy = _httpProxyRadio.y() + _httpProxyRadio.height() + st::boxOptionListPadding.top(); + _tcpProxyRadio.moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), inputy + st::boxOptionListPadding.top() + 2 * _hostInput.height() + st::boxOptionListPadding.top()); } else { - _tcpProxyRadio.move(st::boxPadding.left(), _httpProxyRadio.y() + _httpProxyRadio.height() + st::connectionSkip); + _tcpProxyRadio.moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), _httpProxyRadio.y() + _httpProxyRadio.height() + st::boxOptionListPadding.top()); if (_tcpProxyRadio.checked()) { - inputy = _tcpProxyRadio.y() + _tcpProxyRadio.height() + st::boxPadding.top(); + inputy = _tcpProxyRadio.y() + _tcpProxyRadio.height() + st::boxOptionListPadding.top(); } } if (inputy) { - _hostInput.move(st::boxPadding.left() + st::rbDefFlat.textLeft, inputy); - _portInput.move(width() - st::boxPadding.right() - _portInput.width(), inputy); - _userInput.move(st::boxPadding.left() + st::rbDefFlat.textLeft, _hostInput.y() + _hostInput.height() + st::boxPadding.top()); - _passwordInput.move(width() - st::boxPadding.right() - _passwordInput.width(), _userInput.y()); + _hostInput.moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left() + st::defaultRadiobutton.textPosition.x() - st::defaultInputField.textMargins.left(), inputy); + _portInput.moveToRight(st::boxButtonPadding.right() - (st::defaultBoxButton.width / 2), inputy); + _userInput.moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left() + st::defaultRadiobutton.textPosition.x() - st::defaultInputField.textMargins.left(), _hostInput.y() + _hostInput.height() + st::boxOptionListPadding.top()); + _passwordInput.moveToRight(st::boxButtonPadding.right() - (st::defaultBoxButton.width / 2), _userInput.y()); } - int32 tryipv6y = (_tcpProxyRadio.checked() ? (_userInput.y() + _userInput.height()) : (_tcpProxyRadio.y() + _tcpProxyRadio.height())) + st::connectionSkip + st::lineWidth + st::connectionSkip; - _tryIPv6.move(st::boxPadding.left(), tryipv6y); + int32 tryipv6y = (_tcpProxyRadio.checked() ? (_userInput.y() + _userInput.height()) : (_tcpProxyRadio.y() + _tcpProxyRadio.height())) + st::boxOptionListPadding.top() + st::connectionIPv6Skip; + _tryIPv6.moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), tryipv6y); - _saveButton.move(width() - _saveButton.width(), _tryIPv6.y() + _tryIPv6.height() + st::connectionSkip); - _cancelButton.move(0, _saveButton.y()); + _save.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _save.height()); + _cancel.moveToRight(st::boxButtonPadding.right() + _save.width() + st::boxButtonPadding.left(), _save.y()); } void ConnectionBox::onChange() { showAll(); if (_httpProxyRadio.checked() || _tcpProxyRadio.checked()) { _hostInput.setFocus(); - if (_httpProxyRadio.checked() && !_portInput.text().toInt()) { + if (_httpProxyRadio.checked() && !_portInput.getLastText().toInt()) { _portInput.setText(qsl("80")); _portInput.updatePlaceholder(); } @@ -156,13 +152,41 @@ void ConnectionBox::onChange() { update(); } +void ConnectionBox::onSubmit() { + if (_hostInput.hasFocus()) { + if (!_hostInput.getLastText().trimmed().isEmpty()) { + _portInput.setFocus(); + } else { + _hostInput.showError(); + } + } else if (_portInput.hasFocus()) { + if (_portInput.getLastText().trimmed().toInt() > 0) { + _userInput.setFocus(); + } else { + _portInput.showError(); + } + } else if (_userInput.hasFocus()) { + _passwordInput.setFocus(); + } else if (_passwordInput.hasFocus()) { + if (_hostInput.getLastText().trimmed().isEmpty()) { + _hostInput.setFocus(); + _hostInput.showError(); + } else if (_portInput.getLastText().trimmed().toInt() <= 0) { + _portInput.setFocus(); + _portInput.showError(); + } else { + onSave(); + } + } +} + void ConnectionBox::onSave() { if (_httpProxyRadio.checked() || _tcpProxyRadio.checked()) { ConnectionProxy p; - p.host = _hostInput.text().trimmed(); - p.user = _userInput.text().trimmed(); - p.password = _passwordInput.text().trimmed(); - p.port = _portInput.text().toInt(); + p.host = _hostInput.getLastText().trimmed(); + p.user = _userInput.getLastText().trimmed(); + p.password = _passwordInput.getLastText().trimmed(); + p.port = _portInput.getLastText().toInt(); if (p.host.isEmpty()) { _hostInput.setFocus(); return; diff --git a/Telegram/SourceFiles/boxes/connectionbox.h b/Telegram/SourceFiles/boxes/connectionbox.h index b15060a78..7def2ba77 100644 --- a/Telegram/SourceFiles/boxes/connectionbox.h +++ b/Telegram/SourceFiles/boxes/connectionbox.h @@ -20,7 +20,6 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org */ #pragma once -#include "gui/phoneinput.h" #include "abstractbox.h" class ConnectionBox : public AbstractBox { @@ -35,6 +34,7 @@ public: public slots: void onChange(); + void onSubmit(); void onSave(); protected: @@ -45,10 +45,12 @@ protected: private: - FlatButton _saveButton, _cancelButton; - FlatInput _hostInput; + InputField _hostInput; PortInput _portInput; - FlatInput _userInput, _passwordInput; - FlatRadiobutton _autoRadio, _httpProxyRadio, _tcpProxyRadio; - FlatCheckbox _tryIPv6; + InputField _userInput; + MaskedInputField _passwordInput; + Radiobutton _autoRadio, _httpProxyRadio, _tcpProxyRadio; + Checkbox _tryIPv6; + + BoxButton _save, _cancel; }; diff --git a/Telegram/SourceFiles/boxes/contactsbox.cpp b/Telegram/SourceFiles/boxes/contactsbox.cpp index 86b86da3c..fe3cd490d 100644 --- a/Telegram/SourceFiles/boxes/contactsbox.cpp +++ b/Telegram/SourceFiles/boxes/contactsbox.cpp @@ -300,7 +300,7 @@ void ContactsInner::paintDialog(Painter &p, PeerData *peer, ContactData *data, b } else { p.setPen(st::profileListNameColor->p); } - int32 iconw = (_chat || _creating != CreatingGroupNone) ? st::profileCheckRect.pxWidth() : st::contactsImg.pxWidth(); + int32 iconw = (_chat || _creating != CreatingGroupNone) ? st::inviteCheckIcon.pxWidth() : st::contactsImg.pxWidth(); int32 namew = width() - left - st::profileListPhotoSize - st::profileListPadding.width() - st::participantDelta - st::scrollDef.width - iconw; if (peer->isChannel() && peer->asChannel()->isVerified()) { namew -= st::verifiedCheck.pxWidth() + st::verifiedCheckPos.x(); @@ -314,7 +314,7 @@ void ContactsInner::paintDialog(Painter &p, PeerData *peer, ContactData *data, b } } else if (_chat || _creating != CreatingGroupNone) { if (sel || data->check) { - p.drawPixmap(QPoint(width() - st::profileCheckRect.pxWidth() - st::profileCheckDeltaX, st::profileListPadding.height() + (st::profileListPhotoSize - st::profileCheckRect.pxHeight()) / 2 - st::profileCheckDeltaY), App::sprite(), (data->check ? st::profileCheckActiveRect : st::profileCheckRect)); + p.drawPixmap(QPoint(width() - st::inviteCheckIcon.pxWidth() - st::profileCheckDeltaX, st::profileListPadding.height() + (st::profileListPhotoSize - st::inviteCheckIcon.pxHeight()) / 2 - st::profileCheckDeltaY), App::sprite(), (data->check ? st::inviteCheckActiveIcon : st::inviteCheckIcon)); } } else if (sel) { p.drawPixmap(QPoint(width() - st::contactsImg.pxWidth() - st::profileCheckDeltaX, st::profileListPadding.height() + (st::profileListPhotoSize - st::contactsImg.pxHeight()) / 2 - st::profileCheckDeltaY), App::sprite(), st::contactsImg); @@ -1109,7 +1109,7 @@ ContactsBox::ContactsBox(ChannelData *channel, MembersFilter filter, const Membe _addContact(this, lang(lng_add_contact_button), st::contactsAdd), _filter(this, st::contactsFilter, lang(lng_participant_filter)), _next(this, lang(lng_participant_invite), st::btnSelectDone), -_cancel(this, lang(filter == MembersFilterAdmins ? lng_contacts_done : lng_cancel), (filter == MembersFilterAdmins ? st::contactsClose : st::btnSelectCancel)), +_cancel(this, lang(filter == MembersFilterAdmins ? lng_contacts_done : lng_box_cancel), (filter == MembersFilterAdmins ? st::contactsClose : st::btnSelectCancel)), _creationRequestId(0) { init(); } @@ -1118,7 +1118,7 @@ ContactsBox::ContactsBox(ChatData *chat) : ItemListBox(st::boxNoTopScroll), _inn _addContact(this, lang(lng_add_contact_button), st::contactsAdd), _filter(this, st::contactsFilter, lang(lng_participant_filter)), _next(this, lang(lng_participant_invite), st::btnSelectDone), -_cancel(this, lang(lng_cancel), st::btnSelectCancel), +_cancel(this, lang(lng_box_cancel), st::btnSelectCancel), _creationRequestId(0) { init(); } @@ -1127,13 +1127,13 @@ ContactsBox::ContactsBox(UserData *bot) : ItemListBox(st::boxNoTopScroll), _inne _addContact(this, lang(lng_add_contact_button), st::contactsAdd), _filter(this, st::contactsFilter, lang(lng_participant_filter)), _next(this, lang(lng_create_group_next), st::btnSelectDone), -_cancel(this, lang(lng_cancel), st::contactsClose), +_cancel(this, lang(lng_box_cancel), st::contactsClose), _creationRequestId(0) { init(); } void ContactsBox::init() { - ItemListBox::init(&_inner, _cancel.height(), st::contactsAdd.height + st::newGroupNamePadding.top() + _filter.height() + st::newGroupNamePadding.bottom()); + ItemListBox::init(&_inner, _cancel.height(), st::contactsAdd.height + st::old_newGroupNamePadding.top() + _filter.height() + st::old_newGroupNamePadding.bottom()); connect(&_inner, SIGNAL(chosenChanged()), this, SLOT(update())); if (_inner.chat()) { @@ -1224,7 +1224,7 @@ void ContactsBox::peopleReceived(const MTPcontacts_Found &result, mtpRequestId r } bool ContactsBox::peopleFailed(const RPCError &error, mtpRequestId req) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; if (_peopleRequest == req) { _peopleRequest = 0; @@ -1299,26 +1299,26 @@ void ContactsBox::paintEvent(QPaintEvent *e) { bool addingAdmin = _inner.channel() && _inner.channelFilter() == MembersFilterAdmins; if (_inner.chat() || _inner.creating() != CreatingGroupNone) { QString title(lang(addingAdmin ? lng_channel_add_admin : lng_profile_add_participant)); - paintTitle(p, title, true); + paintOldTitle(p, title, true); if (!addingAdmin) { p.setPen(st::newGroupLimitFg); - p.drawTextLeft(st::old_boxTitlePos.x() + st::old_boxTitleFont->width(title) + st::addContactDelta, st::old_boxTitlePos.y(), width(), QString("%1 / %2").arg(_inner.selectedCount()).arg(cMaxGroupCount())); + p.drawTextLeft(st::old_boxTitlePos.x() + st::old_boxTitleFont->width(title) + st::addContactSkip, st::old_boxTitlePos.y(), width(), QString("%1 / %2").arg(_inner.selectedCount()).arg(cMaxGroupCount())); // paint button sep p.fillRect(st::btnSelectCancel.width, size().height() - st::btnSelectCancel.height, st::lineWidth, st::btnSelectCancel.height, st::btnSelectSep->b); } } else if (_inner.bot()) { - paintTitle(p, lang(lng_bot_choose_group), true); + paintOldTitle(p, lang(lng_bot_choose_group), true); } else { - paintTitle(p, lang(lng_contacts_header), true); + paintOldTitle(p, lang(lng_contacts_header), true); } } void ContactsBox::resizeEvent(QResizeEvent *e) { ItemListBox::resizeEvent(e); _addContact.move(width() - _addContact.width(), 0); - _filter.move(st::newGroupNamePadding.left(), _addContact.height() + st::newGroupNamePadding.top()); + _filter.move(st::old_newGroupNamePadding.left(), _addContact.height() + st::old_newGroupNamePadding.top()); _inner.resize(width(), _inner.height()); _next.move(width() - _next.width(), height() - _next.height()); _cancel.move(0, height() - _cancel.height()); @@ -1915,7 +1915,7 @@ void MembersBox::paintEvent(QPaintEvent *e) { if (paint(p)) return; QString title(lang(_inner.filter() == MembersFilterRecent ? lng_channel_members : lng_channel_admins)); - paintTitle(p, title, false); + paintOldTitle(p, title, false); } void MembersBox::resizeEvent(QResizeEvent *e) { @@ -1981,13 +1981,13 @@ void MembersBox::showDone() { NewGroupBox::NewGroupBox() : AbstractBox(), _group(this, qsl("group_type"), 0, lang(lng_create_group_title), true), _channel(this, qsl("group_type"), 1, lang(lng_create_channel_title)), -_aboutGroupWidth(width() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::rbDefFlat.textLeft), +_aboutGroupWidth(width() - st::boxPadding.left() - st::boxPadding.right() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::defaultRadiobutton.textPosition.x()), _aboutGroup(st::normalFont, lng_create_group_about(lt_count, cMaxGroupCount()), _defaultOptions, _aboutGroupWidth), _aboutChannel(st::normalFont, lang(lng_create_channel_about), _defaultOptions, _aboutGroupWidth), -_next(this, lang(lng_create_group_next), st::btnSelectDone), -_cancel(this, lang(lng_cancel), st::btnSelectCancel) { +_next(this, lang(lng_create_group_next), st::defaultBoxButton), +_cancel(this, lang(lng_box_cancel), st::cancelBoxButton) { _aboutGroupHeight = _aboutGroup.countHeight(_aboutGroupWidth); - setMaxHeight(st::newGroupPadding.top() + _group.height() + _aboutGroupHeight + st::newGroupSkip + _channel.height() + _aboutChannel.countHeight(_aboutGroupWidth) + st::newGroupPadding.bottom() + _next.height()); + setMaxHeight(st::boxPadding.top() + st::newGroupPadding.top() + _group.height() + _aboutGroupHeight + st::newGroupSkip + _channel.height() + _aboutChannel.countHeight(_aboutGroupWidth) + st::newGroupPadding.bottom() + st::boxPadding.bottom() + st::boxButtonPadding.top() + _next.height() + st::boxButtonPadding.bottom()); connect(&_next, SIGNAL(clicked()), this, SLOT(onNext())); connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose())); @@ -2027,28 +2027,19 @@ void NewGroupBox::paintEvent(QPaintEvent *e) { p.setPen(st::newGroupAboutFg->p); - QRect aboutGroup(st::newGroupPadding.left() + st::rbDefFlat.textLeft, _group.y() + _group.height(), width() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::rbDefFlat.textLeft, _aboutGroupHeight); - if (rtl()) aboutGroup.setX(width() - aboutGroup.x() - aboutGroup.width()); + QRect aboutGroup = myrtlrect(st::boxPadding.left() + st::newGroupPadding.left() + st::defaultRadiobutton.textPosition.x(), _group.y() + _group.height() + st::lineWidth, width() - st::boxPadding.left() - st::boxPadding.right() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::defaultRadiobutton.textPosition.x(), _aboutGroupHeight); _aboutGroup.draw(p, aboutGroup.x(), aboutGroup.y(), aboutGroup.width()); - QRect aboutChannel(st::newGroupPadding.left() + st::rbDefFlat.textLeft, _channel.y() + _channel.height(), width() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::rbDefFlat.textLeft, _aboutGroupHeight); - if (rtl()) aboutChannel.setX(width() - aboutChannel.x() - aboutChannel.width()); + QRect aboutChannel = myrtlrect(st::boxPadding.left() + st::newGroupPadding.left() + st::defaultRadiobutton.textPosition.x(), _channel.y() + _channel.height() + st::lineWidth, width() - st::boxPadding.left() - st::boxPadding.right() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::defaultRadiobutton.textPosition.x(), _aboutGroupHeight); _aboutChannel.draw(p, aboutChannel.x(), aboutChannel.y(), aboutChannel.width()); - - // paint shadow - p.fillRect(0, height() - st::btnSelectCancel.height - st::scrollDef.bottomsh, width(), st::scrollDef.bottomsh, st::scrollDef.shColor->b); - - // paint button sep - p.fillRect(st::btnSelectCancel.width, height() - st::btnSelectCancel.height, st::lineWidth, st::btnSelectCancel.height, st::btnSelectSep->b); } void NewGroupBox::resizeEvent(QResizeEvent *e) { - _group.moveToLeft(st::newGroupPadding.left(), st::newGroupPadding.top(), width()); - _channel.moveToLeft(st::newGroupPadding.left(), _group.y() + _group.height() + _aboutGroupHeight + st::newGroupSkip, width()); + _group.moveToLeft(st::boxPadding.left() + st::newGroupPadding.left(), st::boxPadding.top() + st::newGroupPadding.top()); + _channel.moveToLeft(st::boxPadding.left() + st::newGroupPadding.left(), _group.y() + _group.height() + _aboutGroupHeight + st::newGroupSkip); - int32 buttonTop = height() - st::btnSelectCancel.height; - _cancel.moveToLeft(0, buttonTop, width()); - _next.moveToRight(0, buttonTop, width()); + _next.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _next.height()); + _cancel.moveToRight(st::boxButtonPadding.right() + _next.width() + st::boxButtonPadding.left(), _next.y()); } void NewGroupBox::onNext() { @@ -2058,33 +2049,25 @@ void NewGroupBox::onNext() { GroupInfoBox::GroupInfoBox(CreatingGroupType creating, bool fromTypeChoose) : AbstractBox(), _creating(creating), a_photoOver(0, 0), -a_photo(animFunc(this, &GroupInfoBox::photoAnimStep)), +_a_photoOver(animFunc(this, &GroupInfoBox::animStep_photoOver)), _photoOver(false), -_descriptionOver(false), -a_descriptionBg(st::newGroupName.bgColor->c, st::newGroupName.bgColor->c), -a_descriptionBorder(st::newGroupName.borderColor->c, st::newGroupName.borderColor->c), -a_description(animFunc(this, &GroupInfoBox::descriptionAnimStep)), -_name(this, st::newGroupName, lang(_creating == CreatingGroupChannel ? lng_dlg_new_channel_name : lng_dlg_new_group_name)), -_photo(this, lang(lng_create_group_photo), st::newGroupPhoto), +_title(this, st::newGroupName, lang(_creating == CreatingGroupChannel ? lng_dlg_new_channel_name : lng_dlg_new_group_name)), _description(this, st::newGroupDescription, lang(lng_create_group_description)), -_next(this, lang(_creating == CreatingGroupChannel ? lng_create_group_create : lng_create_group_next), st::btnSelectDone), -_cancel(this, lang(fromTypeChoose ? lng_create_group_back : lng_cancel), st::btnSelectCancel), +_next(this, lang(_creating == CreatingGroupChannel ? lng_create_group_create : lng_create_group_next), st::defaultBoxButton), +_cancel(this, lang(fromTypeChoose ? lng_create_group_back : lng_box_cancel), st::cancelBoxButton), _creationRequestId(0), _createdChannel(0) { setMouseTracking(true); - _description.resize(width() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::newGroupDescriptionPadding.left() - st::newGroupDescriptionPadding.right(), _name.height() - st::newGroupDescriptionPadding.top() - st::newGroupDescriptionPadding.bottom()); - _description.setMinHeight(_description.height()); - _description.setMaxHeight(3 * _description.height() + 2 * st::newGroupDescriptionPadding.top() + 2 * st::newGroupDescriptionPadding.bottom()); + _description.setMaxLength(MaxChannelDescription); + _description.resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - (st::boxButtonPadding.right() - (st::defaultBoxButton.width / 2)), _description.height()); updateMaxHeight(); - _description.setMaxLength(MaxChannelDescription); connect(&_description, SIGNAL(resized()), this, SLOT(onDescriptionResized())); connect(&_description, SIGNAL(submitted(bool)), this, SLOT(onNext())); connect(&_description, SIGNAL(cancelled()), this, SLOT(onClose())); - _description.installEventFilter(this); - connect(&_photo, SIGNAL(clicked()), this, SLOT(onPhoto())); + connect(&_title, SIGNAL(submitted(bool)), this, SLOT(onNameSubmit())); connect(&_next, SIGNAL(clicked()), this, SLOT(onNext())); connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose())); @@ -2093,16 +2076,14 @@ _creationRequestId(0), _createdChannel(0) { } void GroupInfoBox::hideAll() { - _name.hide(); - _photo.hide(); + _title.hide(); _description.hide(); _cancel.hide(); _next.hide(); } void GroupInfoBox::showAll() { - _name.show(); - _photo.show(); + _title.show(); if (_creating == CreatingGroupChannel) { _description.show(); } else { @@ -2113,24 +2094,7 @@ void GroupInfoBox::showAll() { } void GroupInfoBox::showDone() { - _name.setFocus(); -} - -void GroupInfoBox::keyPressEvent(QKeyEvent *e) { - if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { - if (_name.hasFocus()) { - if (_name.text().trimmed().isEmpty()) { - _name.setFocus(); - _name.notaBene(); - } else if (_description.isHidden()) { - onNext(); - } else { - _description.setFocus(); - } - } - } else { - AbstractBox::keyPressEvent(e); - } + _title.setFocus(); } void GroupInfoBox::paintEvent(QPaintEvent *e) { @@ -2140,57 +2104,39 @@ void GroupInfoBox::paintEvent(QPaintEvent *e) { QRect phRect(photoRect()); if (phRect.intersects(e->rect())) { if (_photoSmall.isNull()) { - int32 s = st::newGroupPhotoSize * cIntRetinaFactor(); - QRect ph(st::setPhotoImg), overph(st::setOverPhotoImg); - if (a_photoOver.current() < 1) { - p.drawPixmapLeft(phRect.topLeft(), width(), App::sprite(), QRect(ph.x() + (ph.width() - s) / 2, ph.y() + (ph.height() - s) / 2, s, s)); - } - if (a_photoOver.current() > 0) { - p.setOpacity(a_photoOver.current()); - p.drawPixmapLeft(phRect.topLeft(), width(), App::sprite(), QRect(overph.x() + (overph.width() - s) / 2, overph.y() + (overph.height() - s) / 2, s, s)); - p.setOpacity(1); + float64 o = a_photoOver.current(); + if (o > 0) { + if (o < 1) { + QColor c; + c.setRedF(st::newGroupPhotoBg->c.redF() * (1. - o) + st::newGroupPhotoBgOver->c.redF() * o); + c.setGreenF(st::newGroupPhotoBg->c.greenF() * (1. - o) + st::newGroupPhotoBgOver->c.greenF() * o); + c.setBlueF(st::newGroupPhotoBg->c.blueF() * (1. - o) + st::newGroupPhotoBgOver->c.blueF() * o); + p.fillRect(phRect, c); + } else { + p.fillRect(phRect, st::newGroupPhotoBgOver->b); + } + } else { + p.fillRect(phRect, st::newGroupPhotoBg->b); } + p.drawSprite(phRect.topLeft() + st::newGroupPhotoIconPosition, st::newGroupPhotoIcon); } else { - p.drawPixmap(st::newGroupPadding.left(), st::newGroupPadding.left(), _photoSmall); + p.drawPixmap(phRect.topLeft(), _photoSmall); } if (phRect.contains(e->rect())) { return; } } - QRect descRect(descriptionRect()); - if (_creating == CreatingGroupChannel && descRect.intersects(e->rect())) { - p.fillRect(descRect, a_descriptionBg.current()); - if (st::newGroupName.borderWidth) { - QBrush b(a_descriptionBorder.current()); - p.fillRect(descRect.x(), descRect.y(), descRect.width() - st::newGroupName.borderWidth, st::newGroupName.borderWidth, b); - p.fillRect(descRect.x() + descRect.width() - st::newGroupName.borderWidth, descRect.y(), st::newGroupName.borderWidth, descRect.height() - st::newGroupName.borderWidth, b); - p.fillRect(descRect.x() + st::newGroupName.borderWidth, descRect.y() + descRect.height() - st::newGroupName.borderWidth, descRect.width() - st::newGroupName.borderWidth, st::newGroupName.borderWidth, b); - p.fillRect(descRect.x(), descRect.y() + st::newGroupName.borderWidth, st::newGroupName.borderWidth, descRect.height() - st::newGroupName.borderWidth, b); - } - if (descRect.contains(e->rect())) { - return; - } - } - - // paint shadow - p.fillRect(0, height() - st::btnSelectCancel.height - st::scrollDef.bottomsh, width(), st::scrollDef.bottomsh, st::scrollDef.shColor->b); - - // paint button sep - p.fillRect(st::btnSelectCancel.width, height() - st::btnSelectCancel.height, st::lineWidth, st::btnSelectCancel.height, st::btnSelectSep->b); } void GroupInfoBox::resizeEvent(QResizeEvent *e) { - int32 nameLeft = st::newGroupPhotoSize + st::newGroupPhotoSkip; - _name.resize(width() - st::newGroupPadding.left() - st::newGroupPadding.right() - nameLeft, _name.height()); - _name.moveToLeft(st::newGroupPadding.left() + nameLeft, st::newGroupPadding.top(), width()); - _photo.moveToLeft(_name.x(), _name.y() + st::newGroupPhotoSize - _photo.height(), width()); + int32 nameLeft = st::newGroupPhotoSize + st::newGroupNamePosition.x(); + _title.resize(width() - st::boxPadding.left() - st::newGroupInfoPadding.left() - (st::boxButtonPadding.right() - (st::defaultBoxButton.width / 2)) - nameLeft, _title.height()); + _title.moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left() + nameLeft, st::boxPadding.top() + st::newGroupInfoPadding.top() + st::newGroupNamePosition.y()); - _description.moveToLeft(st::newGroupPadding.left() + st::newGroupDescriptionPadding.left(), _photo.y() + _photo.height() + st::newGroupDescriptionSkip + st::newGroupDescriptionPadding.top(), width()); + _description.moveToLeft(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::boxPadding.top() + st::newGroupInfoPadding.top() + st::newGroupPhotoSize + st::newGroupDescriptionPadding.top()); - int32 buttonTop = (_creating == CreatingGroupChannel) ? (_description.y() + _description.height() + st::newGroupDescriptionPadding.bottom()) : (_photo.y() + _photo.height()); - buttonTop += st::newGroupPadding.bottom(); - _cancel.move(0, buttonTop); - _next.move(width() - _next.width(), buttonTop); + _next.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _next.height()); + _cancel.moveToRight(st::boxButtonPadding.right() + _next.width() + st::boxButtonPadding.left(), _next.y()); } void GroupInfoBox::mouseMoveEvent(QMouseEvent *e) { @@ -2205,24 +2151,17 @@ void GroupInfoBox::updateSelected(const QPoint &cursorGlobalPosition) { _photoOver = photoOver; if (_photoSmall.isNull()) { a_photoOver.start(_photoOver ? 1 : 0); - a_photo.start(); + _a_photoOver.start(); } } - bool descriptionOver = _photoOver ? false : descriptionRect().contains(p); - if (descriptionOver != _descriptionOver) { - _descriptionOver = descriptionOver; - } - - setCursor(_photoOver ? style::cur_pointer : (_descriptionOver ? style::cur_text : style::cur_default)); + setCursor(_photoOver ? style::cur_pointer : style::cur_default); } void GroupInfoBox::mousePressEvent(QMouseEvent *e) { mouseMoveEvent(e); if (_photoOver) { onPhoto(); - } else if (_descriptionOver) { - _description.setFocus(); } } @@ -2230,22 +2169,7 @@ void GroupInfoBox::leaveEvent(QEvent *e) { updateSelected(QCursor::pos()); } -bool GroupInfoBox::descriptionAnimStep(float64 ms) { - float dt = ms / st::newGroupName.phDuration; - bool res = true; - if (dt >= 1) { - res = false; - a_descriptionBg.finish(); - a_descriptionBorder.finish(); - } else { - a_descriptionBg.update(dt, st::newGroupName.phColorFunc); - a_descriptionBorder.update(dt, st::newGroupName.phColorFunc); - } - update(descriptionRect()); - return res; -} - -bool GroupInfoBox::photoAnimStep(float64 ms) { +bool GroupInfoBox::animStep_photoOver(float64 ms) { float64 dt = ms / st::setPhotoDuration; bool res = true; if (dt >= 1) { @@ -2258,34 +2182,30 @@ bool GroupInfoBox::photoAnimStep(float64 ms) { return res; } -bool GroupInfoBox::eventFilter(QObject *obj, QEvent *e) { - if (obj == &_description) { - if (e->type() == QEvent::FocusIn) { - a_descriptionBorder.start(st::newGroupName.borderActive->c); - a_descriptionBg.start(st::newGroupName.bgActive->c); - a_description.start(); - } else if (e->type() == QEvent::FocusOut) { - a_descriptionBorder.start(st::newGroupName.borderColor->c); - a_descriptionBg.start(st::newGroupName.bgColor->c); - a_description.start(); - } +void GroupInfoBox::onNameSubmit() { + if (_title.getLastText().trimmed().isEmpty()) { + _title.setFocus(); + _title.showError(); + } else if (_description.isHidden()) { + onNext(); + } else { + _description.setFocus(); } - return AbstractBox::eventFilter(obj, e); } void GroupInfoBox::onNext() { if (_creationRequestId) return; - QString name = _name.text().trimmed(); - if (name.isEmpty()) { - _name.setFocus(); - _name.notaBene(); + QString title = _title.getLastText().trimmed(); + if (title.isEmpty()) { + _title.setFocus(); + _title.showError(); return; } if (_creating == CreatingGroupGroup) { - App::wnd()->replaceLayer(new ContactsBox(name, _photoBig)); + App::wnd()->replaceLayer(new ContactsBox(title, _photoBig)); } else { - _creationRequestId = MTP::send(MTPchannels_CreateChannel(MTP_int(MTPmessages_CreateChannel_flag_broadcast), MTP_string(name), MTP_string(_description.getLastText().trimmed()), MTP_vector(0)), rpcDone(&GroupInfoBox::creationDone), rpcFail(&GroupInfoBox::creationFail)); + _creationRequestId = MTP::send(MTPchannels_CreateChannel(MTP_int(MTPmessages_CreateChannel_flag_broadcast), MTP_string(title), MTP_string(_description.getLastText().trimmed()), MTP_vector(0)), rpcDone(&GroupInfoBox::creationDone), rpcFail(&GroupInfoBox::creationFail)); } } @@ -2304,8 +2224,8 @@ bool GroupInfoBox::creationFail(const RPCError &error) { _creationRequestId = 0; if (error.type() == "NO_CHAT_TITLE") { - _name.setFocus(); - _name.notaBene(); + _title.setFocus(); + _title.showError(); return true; } else if (error.type() == "PEER_FLOOD") { App::wnd()->replaceLayer(new InformBox(lng_cant_invite_not_contact_channel(lt_more_info, textcmdLink(qsl("https://telegram.org/faq?_hash=can-39t-send-messages-to-non-contacts"), lang(lng_cant_more_info))))); @@ -2327,18 +2247,14 @@ void GroupInfoBox::onDescriptionResized() { update(); } -QRect GroupInfoBox::descriptionRect() const { - return rtlrect(_description.x() - st::newGroupDescriptionPadding.left(), _description.y() - st::newGroupDescriptionPadding.top(), _description.width() + st::newGroupDescriptionPadding.left() + st::newGroupDescriptionPadding.right(), _description.height() + st::newGroupDescriptionPadding.top() + st::newGroupDescriptionPadding.bottom(), width()); -} - QRect GroupInfoBox::photoRect() const { - return rtlrect(st::newGroupPadding.left(), st::newGroupPadding.top(), st::newGroupPhotoSize, st::newGroupPhotoSize, width()); + return myrtlrect(st::boxPadding.left() + st::newGroupInfoPadding.left(), st::boxPadding.top() + st::newGroupInfoPadding.top(), st::newGroupPhotoSize, st::newGroupPhotoSize); } void GroupInfoBox::updateMaxHeight() { - int32 h = st::newGroupPadding.top() + st::newGroupPhotoSize + st::newGroupPadding.bottom() + _next.height(); + int32 h = st::boxPadding.top() + st::newGroupInfoPadding.top() + st::newGroupPhotoSize + st::boxPadding.bottom() + st::newGroupInfoPadding.bottom() + st::boxButtonPadding.top() + _next.height() + st::boxButtonPadding.bottom(); if (_creating == CreatingGroupChannel) { - h += st::newGroupDescriptionSkip + st::newGroupDescriptionPadding.top() + _description.height() + st::newGroupDescriptionPadding.bottom(); + h += st::newGroupDescriptionPadding.top() + _description.height() + st::newGroupDescriptionPadding.bottom(); } setMaxHeight(h); } @@ -2382,26 +2298,23 @@ _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::newGroupPadding.left() - st::newGroupPadding.right() - st::rbDefFlat.textLeft), +_aboutPublicWidth(width() - st::boxPadding.left() - st::boxPadding.right() - st::newGroupPadding.left() - st::newGroupPadding.right() - 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), -_linkPlaceholder(qsl("telegram.me/")), -_link(this, st::newGroupLink, QString(), channel->username), +_link(this, st::newGroupLink, QString(), channel->username, true), _linkOver(false), -_save(this, lang(lng_create_group_save), st::btnSelectDone), -_skip(this, lang(existing ? lng_cancel : lng_create_group_skip), st::btnSelectCancel), +_save(this, lang(lng_settings_save), st::defaultBoxButton), +_skip(this, lang(existing ? lng_box_cancel : lng_create_group_skip), st::cancelBoxButton), _tooMuchUsernames(false), _saveRequestId(0), _checkRequestId(0), -a_goodOpacity(0, 0), a_good(animFunc(this, &SetupChannelBox::goodAnimStep)) { +a_goodOpacity(0, 0), _a_goodFade(animFunc(this, &SetupChannelBox::animStep_goodFade)) { setMouseTracking(true); _checkRequestId = MTP::send(MTPchannels_CheckUsername(_channel->inputChannel, MTP_string("preston")), RPCDoneHandlerPtr(), rpcFail(&SetupChannelBox::onFirstCheckFail)); - _link.setTextMargin(style::margins(st::newGroupLink.textMrg.left() + st::newGroupLink.font->width(_linkPlaceholder), st::newGroupLink.textMrg.top(), st::newGroupLink.textMrg.right(), st::newGroupLink.textMrg.bottom())); - _aboutPublicHeight = _aboutPublic.countHeight(_aboutPublicWidth); - setMaxHeight(st::newGroupPadding.top() + _public.height() + _aboutPublicHeight + st::newGroupSkip + _private.height() + _aboutPrivate.countHeight(_aboutPublicWidth)/* + st::newGroupSkip + _comments.height() + _aboutComments.countHeight(_aboutPublicWidth)*/ + st::newGroupPadding.bottom() + st::newGroupLinkPadding.top() + _link.height() + st::newGroupLinkPadding.bottom() + _save.height()); + setMaxHeight(st::boxPadding.top() + st::newGroupPadding.top() + _public.height() + _aboutPublicHeight + st::newGroupSkip + _private.height() + _aboutPrivate.countHeight(_aboutPublicWidth)/* + st::newGroupSkip + _comments.height() + _aboutComments.countHeight(_aboutPublicWidth)*/ + st::newGroupSkip + st::newGroupPadding.bottom() + st::newGroupLinkPadding.top() + _link.height() + st::newGroupLinkPadding.bottom() + _save.height()); connect(&_save, SIGNAL(clicked()), this, SLOT(onSave())); connect(&_skip, SIGNAL(clicked()), this, SLOT(onClose())); @@ -2430,7 +2343,7 @@ void SetupChannelBox::hideAll() { void SetupChannelBox::showAll() { _public.show(); _private.show(); -// _comments.show(); + //_comments.show(); if (_public.checked()) { _link.show(); } else { @@ -2449,7 +2362,7 @@ void SetupChannelBox::keyPressEvent(QKeyEvent *e) { if (_link.hasFocus()) { if (_link.text().trimmed().isEmpty()) { _link.setFocus(); - _link.notaBene(); + _link.showError(); } else { onSave(); } @@ -2465,67 +2378,57 @@ void SetupChannelBox::paintEvent(QPaintEvent *e) { p.setPen(st::newGroupAboutFg); - QRect aboutPublic = rtlrect(st::newGroupPadding.left() + st::rbDefFlat.textLeft, _public.y() + _public.height(), width() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::rbDefFlat.textLeft, _aboutPublicHeight, width()); + QRect aboutPublic = myrtlrect(st::boxPadding.left() + st::newGroupPadding.left() + st::defaultRadiobutton.textPosition.x(), _public.y() + _public.height(), width() - st::boxPadding.left() - st::boxPadding.right() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::defaultRadiobutton.textPosition.x(), _aboutPublicHeight); _aboutPublic.draw(p, aboutPublic.x(), aboutPublic.y(), aboutPublic.width()); - QRect aboutPrivate = rtlrect(st::newGroupPadding.left() + st::rbDefFlat.textLeft, _private.y() + _private.height(), width() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::rbDefFlat.textLeft, _aboutPublicHeight, width()); + QRect aboutPrivate = myrtlrect(st::boxPadding.left() + st::newGroupPadding.left() + st::defaultRadiobutton.textPosition.x(), _private.y() + _private.height(), width() - st::boxPadding.left() - st::boxPadding.right() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::defaultRadiobutton.textPosition.x(), _aboutPublicHeight); _aboutPrivate.draw(p, aboutPrivate.x(), aboutPrivate.y(), aboutPrivate.width()); -// QRect aboutComments = rtlrect(st::newGroupPadding.left() + st::rbDefFlat.textLeft, _comments.y() + _comments.height(), width() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::rbDefFlat.textLeft, _aboutPublicHeight, width()); -// _aboutComments.draw(p, aboutComments.x(), aboutComments.y(), aboutComments.width()); + //QRect aboutComments = myrtlrect(st::boxPadding.left() + st::newGroupPadding.left() + st::defaultRadiobutton.textPosition.x(), _comments.y() + _comments.height(), width() - st::boxPadding.left() - st::boxPadding.right() - st::newGroupPadding.left() - st::newGroupPadding.right() - st::defaultRadiobutton.textPosition.x(), _aboutPublicHeight); + //_aboutComments.draw(p, aboutComments.x(), aboutComments.y(), aboutComments.width()); p.setPen(st::black); p.setFont(st::newGroupLinkFont); - p.drawTextLeft(st::newGroupPadding.left(), _link.y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop, width(), lang(_link.isHidden() ? lng_create_group_invite_link : lng_create_group_link)); + p.drawTextLeft(st::boxPadding.left() + st::newGroupPadding.left() + st::newGroupLink.textMargins.left(), _link.y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop, width(), lang(_link.isHidden() ? lng_create_group_invite_link : lng_create_group_link)); if (_link.isHidden()) { QTextOption option(style::al_left); option.setWrapMode(QTextOption::WrapAnywhere); - p.setFont(_linkOver ? st::newGroupLink.font->underline() : st::newGroupLink.font); + p.setFont(_linkOver ? st::boxTextFont->underline() : st::boxTextFont); p.setPen(st::btnDefLink.color); p.drawText(_invitationLink, _channel->invitationUrl, option); if (!_goodTextLink.isEmpty() && a_goodOpacity.current() > 0) { p.setOpacity(a_goodOpacity.current()); - p.setPen(st::setGoodColor->p); - p.setFont(st::setErrFont->f); - p.drawTextRight(st::newGroupPadding.right(), _link.y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop + st::newGroupLinkFont->ascent - st::setErrFont->ascent, width(), _goodTextLink); + p.setPen(st::setGoodColor); + p.setFont(st::boxTextFont); + p.drawTextRight(st::boxButtonPadding.right() - (st::defaultBoxButton.width / 2), _link.y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop + st::newGroupLinkFont->ascent - st::boxTextFont->ascent, width(), _goodTextLink); p.setOpacity(1); } } else { - p.setFont(st::newGroupLink.font); - p.setPen(st::newGroupLink.phColor); - p.drawText(QRect(_link.x() + st::newGroupLink.textMrg.left(), _link.y() + st::newGroupLink.textMrg.top(), _link.width(), _link.height() - st::newGroupLink.textMrg.top() - st::newGroupLink.textMrg.bottom()), _linkPlaceholder, style::al_left); - if (!_errorText.isEmpty()) { - p.setPen(st::setErrColor->p); - p.setFont(st::setErrFont->f); - p.drawTextRight(st::newGroupPadding.right(), _link.y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop + st::newGroupLinkFont->ascent - st::setErrFont->ascent, width(), _errorText); + p.setPen(st::setErrColor); + p.setFont(st::boxTextFont); + p.drawTextRight(st::boxButtonPadding.right() - (st::defaultBoxButton.width / 2), _link.y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop + st::newGroupLinkFont->ascent - st::boxTextFont->ascent, width(), _errorText); } else if (!_goodText.isEmpty()) { - p.setPen(st::setGoodColor->p); - p.setFont(st::setErrFont->f); - p.drawTextRight(st::newGroupPadding.right(), _link.y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop + st::newGroupLinkFont->ascent - st::setErrFont->ascent, width(), _goodText); + p.setPen(st::setGoodColor); + p.setFont(st::boxTextFont); + p.drawTextRight(st::boxButtonPadding.right() - (st::defaultBoxButton.width / 2), _link.y() - st::newGroupLinkPadding.top() + st::newGroupLinkTop + st::newGroupLinkFont->ascent - st::boxTextFont->ascent, width(), _goodText); } } - - // paint shadow - p.fillRect(0, height() - st::btnSelectCancel.height - st::scrollDef.bottomsh, width(), st::scrollDef.bottomsh, st::scrollDef.shColor->b); - - // paint button sep - p.fillRect(st::btnSelectCancel.width, height() - st::btnSelectCancel.height, st::lineWidth, st::btnSelectCancel.height, st::btnSelectSep->b); } void SetupChannelBox::resizeEvent(QResizeEvent *e) { - _public.moveToLeft(st::newGroupPadding.left(), st::newGroupPadding.top(), width()); - _private.moveToLeft(st::newGroupPadding.left(), _public.y() + _public.height() + _aboutPublicHeight + st::newGroupSkip, width()); -// _comments.moveToLeft(st::newGroupPadding.left(), _private.y() + _private.height() + _aboutPrivate.countHeight(_aboutPublicWidth) + st::newGroupSkip, width()); + _public.moveToLeft(st::boxPadding.left() + st::newGroupPadding.left(), st::boxPadding.top() + st::newGroupPadding.top()); + _private.moveToLeft(st::boxPadding.left() + st::newGroupPadding.left(), _public.y() + _public.height() + _aboutPublicHeight + st::newGroupSkip); + //_comments.moveToLeft(st::boxPadding.left() + st::newGroupPadding.left(), _private.y() + _private.height() + _aboutPrivate.countHeight(_aboutPublicWidth) + st::newGroupSkip); -// _link.setGeometry(st::newGroupLinkPadding.left(), _comments.y() + _comments.height() + _aboutComments.countHeight(_aboutPublicWidth) + st::newGroupPadding.bottom() + st::newGroupLinkPadding.top(), width() - st::newGroupPadding.left() - st::newGroupPadding.right(), _link.height()); - _link.setGeometry(st::newGroupLinkPadding.left(), _private.y() + _private.height() + _aboutPrivate.countHeight(_aboutPublicWidth) + st::newGroupPadding.bottom() + st::newGroupLinkPadding.top(), width() - st::newGroupPadding.left() - st::newGroupPadding.right(), _link.height()); - _invitationLink = QRect(_link.x(), _link.y() + (_link.height() / 2) - st::newGroupLinkFont->height, _link.width(), 2 * st::newGroupLinkFont->height); + _link.resize(width() - st::boxPadding.left() - st::newGroupLinkPadding.left() - (st::boxButtonPadding.right() - (st::defaultBoxButton.width / 2)), _link.height()); + //_link.moveToLeft(st::boxPadding.left() + st::newGroupLinkPadding.left(), _comments.y() + _comments.height() + _aboutComments.countHeight(_aboutPublicWidth) + st::newGroupSkip + st::newGroupPadding.bottom() + st::newGroupLinkPadding.top()); + _link.moveToLeft(st::boxPadding.left() + st::newGroupLinkPadding.left(), _private.y() + _private.height() + _aboutPrivate.countHeight(_aboutPublicWidth) + st::newGroupSkip + st::newGroupPadding.bottom() + st::newGroupLinkPadding.top()); + _invitationLink = QRect(_link.x(), _link.y() + (_link.height() / 2) - st::boxTextFont->height, _link.width(), 2 * st::boxTextFont->height); - int32 buttonTop = _link.y() + _link.height() + st::newGroupLinkPadding.bottom(); - _skip.moveToLeft(0, buttonTop, width()); - _save.moveToRight(0, buttonTop, width()); + _save.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _save.height()); + _skip.moveToRight(st::boxButtonPadding.right() + _save.width() + st::boxButtonPadding.left(), _save.y()); } void SetupChannelBox::mouseMoveEvent(QMouseEvent *e) { @@ -2538,7 +2441,7 @@ void SetupChannelBox::mousePressEvent(QMouseEvent *e) { App::app()->clipboard()->setText(_channel->invitationUrl); _goodTextLink = lang(lng_create_channel_link_copied); a_goodOpacity = anim::fvalue(1, 0); - a_good.start(); + _a_goodFade.start(); } } @@ -2557,7 +2460,7 @@ void SetupChannelBox::updateSelected(const QPoint &cursorGlobalPosition) { } } -bool SetupChannelBox::goodAnimStep(float64 ms) { +bool SetupChannelBox::animStep_goodFade(float64 ms) { float dt = ms / st::newGroupLinkFadeDuration; bool res = true; if (dt >= 1) { @@ -2594,7 +2497,7 @@ void SetupChannelBox::onSave() { QString link = _link.text().trimmed(); if (link.isEmpty()) { _link.setFocus(); - _link.notaBene(); + _link.showError(); return; } @@ -2617,7 +2520,7 @@ void SetupChannelBox::onChange() { int32 i, len = name.size(); for (int32 i = 0; i < len; ++i) { QChar ch = name.at(i); - if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z') && (ch < '0' || ch > '9') && ch != '_' && (ch != '@' || i > 0)) { + if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z') && (ch < '0' || ch > '9') && ch != '_') { if (_errorText != lang(lng_create_channel_link_bad_symbols)) { _errorText = lang(lng_create_channel_link_bad_symbols); update(); @@ -2675,7 +2578,7 @@ void SetupChannelBox::onUpdateDone(const MTPBool &result) { } bool SetupChannelBox::onUpdateFail(const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; _saveRequestId = 0; QString err(error.type()); @@ -2685,13 +2588,13 @@ bool SetupChannelBox::onUpdateFail(const RPCError &error) { return true; } else if (err == "USERNAME_INVALID") { _link.setFocus(); - _link.notaBene(); + _link.showError(); _errorText = lang(lng_create_channel_link_invalid); update(); return true; } else if (err == "USERNAME_OCCUPIED" || err == "USERNAMES_UNAVAILABLE") { _link.setFocus(); - _link.notaBene(); + _link.showError(); _errorText = lang(lng_create_channel_link_occupied); update(); return true; @@ -2712,7 +2615,7 @@ void SetupChannelBox::onCheckDone(const MTPBool &result) { } bool SetupChannelBox::onCheckFail(const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; _checkRequestId = 0; QString err(error.type()); @@ -2740,7 +2643,7 @@ bool SetupChannelBox::onCheckFail(const RPCError &error) { } bool SetupChannelBox::onFirstCheckFail(const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; _checkRequestId = 0; QString err(error.type()); diff --git a/Telegram/SourceFiles/boxes/contactsbox.h b/Telegram/SourceFiles/boxes/contactsbox.h index 67a7ce5d9..b198e956f 100644 --- a/Telegram/SourceFiles/boxes/contactsbox.h +++ b/Telegram/SourceFiles/boxes/contactsbox.h @@ -418,10 +418,10 @@ protected: private: - FlatRadiobutton _group, _channel; + Radiobutton _group, _channel; int32 _aboutGroupWidth, _aboutGroupHeight; Text _aboutGroup, _aboutChannel; - FlatButton _next, _cancel; + BoxButton _next, _cancel; }; @@ -431,20 +431,16 @@ class GroupInfoBox : public AbstractBox, public RPCSender { public: GroupInfoBox(CreatingGroupType creating, bool fromTypeChoose); - void keyPressEvent(QKeyEvent *e); void paintEvent(QPaintEvent *e); void resizeEvent(QResizeEvent *e); void mouseMoveEvent(QMouseEvent *e); void mousePressEvent(QMouseEvent *e); void leaveEvent(QEvent *e); - bool eventFilter(QObject *obj, QEvent *e); - - bool descriptionAnimStep(float64 ms); - bool photoAnimStep(float64 ms); + bool animStep_photoOver(float64 ms); void setInnerFocus() { - _name.setFocus(); + _title.setFocus(); } public slots: @@ -453,6 +449,7 @@ public slots: void onPhotoReady(const QImage &img); void onNext(); + void onNameSubmit(); void onDescriptionResized(); protected: @@ -463,7 +460,6 @@ protected: private: - QRect descriptionRect() const; QRect photoRect() const; void updateMaxHeight(); @@ -471,18 +467,15 @@ private: CreatingGroupType _creating; anim::fvalue a_photoOver; - Animation a_photo; - bool _photoOver, _descriptionOver; + Animation _a_photoOver; + bool _photoOver; - anim::cvalue a_descriptionBg, a_descriptionBorder; - Animation a_description; + InputField _title; + InputArea _description; - FlatInput _name; - FlatButton _photo; - FlatTextarea _description; QImage _photoBig; QPixmap _photoSmall; - FlatButton _next, _cancel; + BoxButton _next, _cancel; // channel creation int32 _creationRequestId; @@ -533,20 +526,7 @@ protected: private: void updateSelected(const QPoint &cursorGlobalPosition); - bool goodAnimStep(float64 ms); - - ChannelData *_channel; - bool _existing; - - FlatRadiobutton _public, _private; - FlatCheckbox _comments; - int32 _aboutPublicWidth, _aboutPublicHeight; - Text _aboutPublic, _aboutPrivate, _aboutComments; - QString _linkPlaceholder; - UsernameInput _link; - QRect _invitationLink; - bool _linkOver; - FlatButton _save, _skip; + bool animStep_goodFade(float64 ms); void onUpdateDone(const MTPBool &result); bool onUpdateFail(const RPCError &error); @@ -555,6 +535,18 @@ private: bool onCheckFail(const RPCError &error); bool onFirstCheckFail(const RPCError &error); + ChannelData *_channel; + bool _existing; + + Radiobutton _public, _private; + Checkbox _comments; + int32 _aboutPublicWidth, _aboutPublicHeight; + Text _aboutPublic, _aboutPrivate, _aboutComments; + UsernameInput _link; + QRect _invitationLink; + bool _linkOver; + BoxButton _save, _skip; + bool _tooMuchUsernames; mtpRequestId _saveRequestId, _checkRequestId; @@ -562,7 +554,7 @@ private: QString _goodTextLink; anim::fvalue a_goodOpacity; - Animation a_good; + Animation _a_goodFade; QTimer _checkTimer; }; diff --git a/Telegram/SourceFiles/boxes/downloadpathbox.cpp b/Telegram/SourceFiles/boxes/downloadpathbox.cpp index bbbf26de1..3dc30241e 100644 --- a/Telegram/SourceFiles/boxes/downloadpathbox.cpp +++ b/Telegram/SourceFiles/boxes/downloadpathbox.cpp @@ -28,54 +28,55 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org DownloadPathBox::DownloadPathBox() : _path(cDownloadPath()), - _defaultRadio(this, qsl("dir_type"), 0, lang(lng_download_path_default_radio), _path.isEmpty()), - _tempRadio(this, qsl("dir_type"), 1, lang(lng_download_path_temp_radio), _path == qsl("tmp")), - _dirRadio(this, qsl("dir_type"), 2, lang(lng_download_path_dir_radio), !_path.isEmpty() && _path != qsl("tmp")), - _dirInput(this, st::inpDownloadDir, QString(), (_path.isEmpty() || _path == qsl("tmp")) ? QString() : QDir::toNativeSeparators(_path)), - _saveButton(this, lang(lng_connection_save), st::btnSelectDone), - _cancelButton(this, lang(lng_cancel), st::btnSelectCancel) { + _default(this, qsl("dir_type"), 0, lang(lng_download_path_default_radio), _path.isEmpty()), + _temp(this, qsl("dir_type"), 1, lang(lng_download_path_temp_radio), _path == qsl("tmp")), + _dir(this, qsl("dir_type"), 2, lang(lng_download_path_dir_radio), !_path.isEmpty() && _path != qsl("tmp")), + _pathLink(this, QString(), st::defaultBoxLinkButton), + _save(this, lang(lng_connection_save), st::defaultBoxButton), + _cancel(this, lang(lng_box_cancel), st::cancelBoxButton) { - connect(&_saveButton, SIGNAL(clicked()), this, SLOT(onSave())); - connect(&_cancelButton, SIGNAL(clicked()), this, SLOT(onClose())); + connect(&_save, SIGNAL(clicked()), this, SLOT(onSave())); + connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose())); - connect(&_defaultRadio, SIGNAL(changed()), this, SLOT(onChange())); - connect(&_tempRadio, SIGNAL(changed()), this, SLOT(onChange())); - connect(&_dirRadio, SIGNAL(changed()), this, SLOT(onChange())); - - connect(&_dirInput, SIGNAL(focused()), this, SLOT(onEditPath())); - _dirInput.setCursorPosition(0); + connect(&_default, SIGNAL(changed()), this, SLOT(onChange())); + connect(&_temp, SIGNAL(changed()), this, SLOT(onChange())); + connect(&_dir, SIGNAL(changed()), this, SLOT(onChange())); + connect(&_pathLink, SIGNAL(clicked()), this, SLOT(onEditPath())); + if (!_path.isEmpty() && _path != qsl("tmp")) { + setPathText(QDir::toNativeSeparators(_path)); + } prepare(); } void DownloadPathBox::hideAll() { - _defaultRadio.hide(); - _tempRadio.hide(); - _dirRadio.hide(); + _default.hide(); + _temp.hide(); + _dir.hide(); - _dirInput.hide(); + _pathLink.hide(); - _saveButton.hide(); - _cancelButton.hide(); + _save.hide(); + _cancel.hide(); } void DownloadPathBox::showAll() { - _defaultRadio.show(); - _tempRadio.show(); - _dirRadio.show(); + _default.show(); + _temp.show(); + _dir.show(); - if (_dirRadio.checked()) { - _dirInput.show(); + if (_dir.checked()) { + _pathLink.show(); } else { - _dirInput.hide(); + _pathLink.hide(); } - _saveButton.show(); - _cancelButton.show(); + _save.show(); + _cancel.show(); - int32 h = st::old_boxTitleHeight + st::downloadSkip + _defaultRadio.height() + st::downloadSkip + _tempRadio.height() + st::downloadSkip + _dirRadio.height(); - if (_dirRadio.checked()) h += st::boxPadding.top() + _dirInput.height(); - h += st::downloadSkip + _saveButton.height(); + int32 h = st::boxTitleHeight + st::boxOptionListPadding.top() + _default.height() + st::boxOptionListPadding.top() + _temp.height() + st::boxOptionListPadding.top() + _dir.height(); + if (_dir.checked()) h += st::downloadPathSkip + _pathLink.height(); + h += st::boxOptionListPadding.bottom() + st::boxButtonPadding.top() + _save.height() + st::boxButtonPadding.bottom(); setMaxHeight(h); } @@ -84,42 +85,34 @@ void DownloadPathBox::paintEvent(QPaintEvent *e) { Painter p(this); if (paint(p)) return; - paintTitle(p, lang(lng_download_path_header), true); - - // paint shadows - p.fillRect(0, height() - st::btnSelectCancel.height - st::scrollDef.bottomsh, width(), st::scrollDef.bottomsh, st::scrollDef.shColor->b); - - // paint button sep - p.fillRect(st::btnSelectCancel.width, height() - st::btnSelectCancel.height, st::lineWidth, st::btnSelectCancel.height, st::btnSelectSep->b); + paintTitle(p, lang(lng_download_path_header)); } void DownloadPathBox::resizeEvent(QResizeEvent *e) { - _defaultRadio.move(st::boxPadding.left(), st::old_boxTitleHeight + st::downloadSkip); - _tempRadio.move(st::boxPadding.left(), _defaultRadio.y() + _defaultRadio.height() + st::downloadSkip); - _dirRadio.move(st::boxPadding.left(), _tempRadio.y() + _tempRadio.height() + st::downloadSkip); - int32 inputy = _dirRadio.y() + _dirRadio.height() + st::boxPadding.top(); + _default.moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), st::boxTitleHeight + st::boxOptionListPadding.top()); + _temp.moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), _default.y() + _default.height() + st::boxOptionListPadding.top()); + _dir.moveToLeft(st::boxPadding.left() + st::boxOptionListPadding.left(), _temp.y() + _temp.height() + st::boxOptionListPadding.top()); + int32 inputx = st::boxPadding.left() + st::boxOptionListPadding.left() + st::defaultRadiobutton.textPosition.x(); + int32 inputy = _dir.y() + _dir.height() + st::downloadPathSkip; - _dirInput.move(st::boxPadding.left() + st::rbDefFlat.textLeft, inputy); + _pathLink.moveToLeft(inputx, inputy); - int32 buttony = (_dirRadio.checked() ? (_dirInput.y() + _dirInput.height()) : (_dirRadio.y() + _dirRadio.height())) + st::downloadSkip; - - _saveButton.move(width() - _saveButton.width(), buttony); - _cancelButton.move(0, buttony); + _save.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _save.height()); + _cancel.moveToRight(st::boxButtonPadding.right() + _save.width() + st::boxButtonPadding.left(), _save.y()); } void DownloadPathBox::onChange() { - if (_dirRadio.checked()) { + if (_dir.checked()) { if (_path.isEmpty() || _path == qsl("tmp")) { - (_path.isEmpty() ? _defaultRadio : _tempRadio).setChecked(true); + (_path.isEmpty() ? _default : _temp).setChecked(true); onEditPath(); if (!_path.isEmpty() && _path != qsl("tmp")) { - _dirRadio.setChecked(true); + _dir.setChecked(true); } } else { - _dirInput.setText(QDir::toNativeSeparators(_path)); - _dirInput.setCursorPosition(0); + setPathText(QDir::toNativeSeparators(_path)); } - } else if (_tempRadio.checked()) { + } else if (_temp.checked()) { _path = qsl("tmp"); } else { _path = QString(); @@ -129,8 +122,6 @@ void DownloadPathBox::onChange() { } void DownloadPathBox::onEditPath() { - _dirInput.clearFocus(); - filedialogInit(); QString path, lastPath = cDialogLastPath(); if (!cDownloadPath().isEmpty()) { @@ -139,15 +130,19 @@ void DownloadPathBox::onEditPath() { if (filedialogGetDir(path, lang(lng_download_path_choose))) { if (!path.isEmpty()) { _path = path + '/'; - _dirInput.setText(QDir::toNativeSeparators(_path)); - _dirInput.setCursorPosition(0); + setPathText(QDir::toNativeSeparators(_path)); } } cSetDialogLastPath(lastPath); } void DownloadPathBox::onSave() { - cSetDownloadPath(_defaultRadio.checked() ? QString() : (_tempRadio.checked() ? qsl("tmp") : _path)); + cSetDownloadPath(_default.checked() ? QString() : (_temp.checked() ? qsl("tmp") : _path)); Local::writeUserSettings(); emit closed(); } + +void DownloadPathBox::setPathText(const QString &text) { + int32 availw = st::boxWideWidth - st::boxPadding.left() - st::defaultRadiobutton.textPosition.x() - (st::boxButtonPadding.right() - (st::defaultBoxButton.width / 2)); + _pathLink.setText(st::boxTextFont->elided(text, availw)); +} diff --git a/Telegram/SourceFiles/boxes/downloadpathbox.h b/Telegram/SourceFiles/boxes/downloadpathbox.h index cb09f7016..2b0432f24 100644 --- a/Telegram/SourceFiles/boxes/downloadpathbox.h +++ b/Telegram/SourceFiles/boxes/downloadpathbox.h @@ -44,9 +44,11 @@ protected: private: + void setPathText(const QString &text); + QString _path; - FlatRadiobutton _defaultRadio, _tempRadio, _dirRadio; - FlatInput _dirInput; - FlatButton _saveButton, _cancelButton; + Radiobutton _default, _temp, _dir; + LinkButton _pathLink; + BoxButton _save, _cancel; }; diff --git a/Telegram/SourceFiles/boxes/emojibox.cpp b/Telegram/SourceFiles/boxes/emojibox.cpp index 50cfa112a..106d38944 100644 --- a/Telegram/SourceFiles/boxes/emojibox.cpp +++ b/Telegram/SourceFiles/boxes/emojibox.cpp @@ -142,7 +142,7 @@ void EmojiBox::paintEvent(QPaintEvent *e) { int32 rowSize = i->size(), left = (width() - rowSize * st::emojiReplaceWidth) / 2; for (BlockRow::const_iterator j = i->cbegin(), en = i->cend(); j != en; ++j) { if (j->emoji) { - p.drawPixmap(QPoint(left + (st::emojiReplaceWidth - _esize) / 2, top + (st::emojiReplaceHeight - _blockHeight) / 2), App::emojisLarge(), QRect(j->emoji->x * _esize, j->emoji->y * _esize, _esize, _esize)); + p.drawPixmap(QPoint(left + (st::emojiReplaceWidth - _esize) / 2, top + (st::emojiReplaceHeight - _blockHeight) / 2), App::emojiLarge(), QRect(j->emoji->x * _esize, j->emoji->y * _esize, _esize, _esize)); } QRect trect(left, top + (st::emojiReplaceHeight + _blockHeight) / 2 - st::emojiTextFont->height, st::emojiReplaceWidth, st::emojiTextFont->height); p.drawText(trect, j->text, QTextOption(Qt::AlignHCenter | Qt::AlignTop)); diff --git a/Telegram/SourceFiles/boxes/languagebox.cpp b/Telegram/SourceFiles/boxes/languagebox.cpp index 238a40aa5..a9918515f 100644 --- a/Telegram/SourceFiles/boxes/languagebox.cpp +++ b/Telegram/SourceFiles/boxes/languagebox.cpp @@ -31,16 +31,16 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org #include "langloaderplain.h" LanguageBox::LanguageBox() : -_done(this, lang(lng_about_done), st::langsCloseButton) { +_close(this, lang(lng_box_ok), st::defaultBoxButton) { bool haveTestLang = (cLang() == languageTest); - int32 y = st::old_boxTitleHeight + st::langsPadding.top(); + int32 y = st::boxTitleHeight + st::boxOptionListPadding.top(); _langs.reserve(languageCount + (haveTestLang ? 1 : 0)); if (haveTestLang) { - _langs.push_back(new FlatRadiobutton(this, qsl("lang"), languageTest, qsl("Custom Lang"), (cLang() == languageTest), st::langButton)); - _langs.back()->move(st::langsPadding.left() + st::langPadding.left(), y + st::langPadding.top()); - y += st::langPadding.top() + _langs.back()->height() + st::langPadding.bottom(); + _langs.push_back(new Radiobutton(this, qsl("lang"), languageTest, qsl("Custom Lang"), (cLang() == languageTest), st::langsButton)); + _langs.back()->move(st::boxPadding.left() + st::boxOptionListPadding.left(), y); + y += _langs.back()->height() + st::boxOptionListPadding.top(); connect(_langs.back(), SIGNAL(changed()), this, SLOT(onChange())); } for (int32 i = 0; i < languageCount; ++i) { @@ -51,28 +51,29 @@ _done(this, lang(lng_about_done), st::langsCloseButton) { } else { result.insert(lng_language_name, langOriginal(lng_language_name)); } - _langs.push_back(new FlatRadiobutton(this, qsl("lang"), i, result.value(lng_language_name, LanguageCodes[i] + qsl(" language")), (cLang() == i), st::langButton)); - _langs.back()->move(st::langsPadding.left() + st::langPadding.left(), y + st::langPadding.top()); - y += st::langPadding.top() + _langs.back()->height() + st::langPadding.bottom(); + _langs.push_back(new Radiobutton(this, qsl("lang"), i, result.value(lng_language_name, LanguageCodes[i] + qsl(" language")), (cLang() == i), st::langsButton)); + _langs.back()->move(st::boxPadding.left() + st::boxOptionListPadding.left(), y); + y += _langs.back()->height() + st::boxOptionListPadding.top(); connect(_langs.back(), SIGNAL(changed()), this, SLOT(onChange())); } - resizeMaxHeight(st::langsWidth, st::old_boxTitleHeight + st::langsPadding.top() + st::langsPadding.bottom() + (languageCount + (haveTestLang ? 1 : 0)) * (st::langPadding.top() + st::rbDefFlat.height + st::langPadding.bottom()) + _done.height()); + resizeMaxHeight(st::langsWidth, st::boxTitleHeight + (languageCount + (haveTestLang ? 1 : 0)) * (st::boxOptionListPadding.top() + st::langsButton.height) + st::boxOptionListPadding.bottom() + st::boxPadding.bottom() + st::boxButtonPadding.top() + _close.height() + st::boxButtonPadding.bottom()); - connect(&_done, SIGNAL(clicked()), this, SLOT(onClose())); + connect(&_close, SIGNAL(clicked()), this, SLOT(onClose())); + _close.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _close.height()); prepare(); } void LanguageBox::hideAll() { - _done.hide(); + _close.hide(); for (int32 i = 0, l = _langs.size(); i < l; ++i) { _langs[i]->hide(); } } void LanguageBox::showAll() { - _done.show(); + _close.show(); for (int32 i = 0, l = _langs.size(); i < l; ++i) { _langs[i]->show(); } @@ -100,11 +101,7 @@ void LanguageBox::paintEvent(QPaintEvent *e) { Painter p(this); if (paint(p)) return; - paintTitle(p, lang(lng_languages), true); -} - -void LanguageBox::resizeEvent(QResizeEvent *e) { - _done.move(0, height() - _done.height()); + paintTitle(p, lang(lng_languages)); } void LanguageBox::onChange() { diff --git a/Telegram/SourceFiles/boxes/languagebox.h b/Telegram/SourceFiles/boxes/languagebox.h index aeb08bb45..ce37f417c 100644 --- a/Telegram/SourceFiles/boxes/languagebox.h +++ b/Telegram/SourceFiles/boxes/languagebox.h @@ -30,7 +30,6 @@ public: LanguageBox(); void mousePressEvent(QMouseEvent *e); void paintEvent(QPaintEvent *e); - void resizeEvent(QResizeEvent *e); ~LanguageBox(); public slots: @@ -46,6 +45,6 @@ protected: private: - QVector _langs; - BottomButton _done; + QVector _langs; + BoxButton _close; }; diff --git a/Telegram/SourceFiles/boxes/passcodebox.cpp b/Telegram/SourceFiles/boxes/passcodebox.cpp index b4d02dcde..6bba1adb8 100644 --- a/Telegram/SourceFiles/boxes/passcodebox.cpp +++ b/Telegram/SourceFiles/boxes/passcodebox.cpp @@ -58,8 +58,8 @@ _recover(this, lang(lng_signin_recover)) { } void PasscodeBox::init() { - _about.setRichText(st::usernameFont, lang(_cloudPwd ? lng_cloud_password_about : lng_passcode_about)); - if (!_hint.isEmpty()) _hintText.setText(st::usernameFont, lng_signin_hint(lt_password_hint, _hint)); + _about.setRichText(st::normalFont, lang(_cloudPwd ? lng_cloud_password_about : lng_passcode_about)); + if (!_hint.isEmpty()) _hintText.setText(st::normalFont, lng_signin_hint(lt_password_hint, _hint)); _aboutHeight = _about.countHeight(st::boxWideWidth - st::addContactPadding.left() - st::addContactPadding.right()); _oldPasscode.setEchoMode(QLineEdit::Password); _newPasscode.setEchoMode(QLineEdit::Password); @@ -73,11 +73,11 @@ void PasscodeBox::init() { if (has) { _oldPasscode.show(); _boxTitle = lang(_cloudPwd ? lng_cloud_password_change : lng_passcode_change); - setMaxHeight(st::old_boxTitleHeight + st::addContactPadding.top() + 3 * _oldPasscode.height() + st::usernameSkip * 2 + 1 * st::addContactDelta + (_cloudPwd ? _passwordHint.height() + st::addContactDelta : 0) + _aboutHeight + (_hasRecovery ? ((st::usernameSkip + _recover.height()) / 2) : 0) + st::addContactPadding.bottom() + _saveButton.height()); + setMaxHeight(st::old_boxTitleHeight + st::addContactPadding.top() + 3 * _oldPasscode.height() + st::usernameSkip * 2 + 1 * st::addContactSkip + (_cloudPwd ? _passwordHint.height() + st::addContactSkip : 0) + _aboutHeight + (_hasRecovery ? ((st::usernameSkip + _recover.height()) / 2) : 0) + st::addContactPadding.bottom() + _saveButton.height()); } else { _oldPasscode.hide(); _boxTitle = lang(_cloudPwd ? lng_cloud_password_create : lng_passcode_create); - setMaxHeight(st::old_boxTitleHeight + st::addContactPadding.top() + 2 * _oldPasscode.height() + st::usernameSkip + 1 * st::addContactDelta + (_cloudPwd ? _passwordHint.height() + st::addContactDelta : 0) + _aboutHeight + (_cloudPwd ? st::addContactDelta + _recoverEmail.height() + st::usernameSkip : st::addContactPadding.bottom()) + _saveButton.height()); + setMaxHeight(st::old_boxTitleHeight + st::addContactPadding.top() + 2 * _oldPasscode.height() + st::usernameSkip + 1 * st::addContactSkip + (_cloudPwd ? _passwordHint.height() + st::addContactSkip : 0) + _aboutHeight + (_cloudPwd ? st::addContactSkip + _recoverEmail.height() + st::usernameSkip : st::addContactPadding.bottom()) + _saveButton.height()); } } @@ -187,19 +187,19 @@ void PasscodeBox::paintEvent(QPaintEvent *e) { Painter p(this); if (paint(p)) return; - paintTitle(p, _boxTitle, true); + paintOldTitle(p, _boxTitle, true); // paint shadow p.fillRect(0, height() - st::btnSelectCancel.height - st::scrollDef.bottomsh, width(), st::scrollDef.bottomsh, st::scrollDef.shColor->b); int32 w = width() - st::addContactPadding.left() - st::addContactPadding.right(); - int32 abouty = (_passwordHint.isHidden() ? (_reenterPasscode.isHidden() ? _oldPasscode : _reenterPasscode).y() + st::usernameSkip : _passwordHint.y() + st::addContactDelta) + _oldPasscode.height(); - p.setPen(st::usernameColor->p); + int32 abouty = (_passwordHint.isHidden() ? (_reenterPasscode.isHidden() ? _oldPasscode : _reenterPasscode).y() + st::usernameSkip : _passwordHint.y() + st::addContactSkip) + _oldPasscode.height(); + p.setPen(st::black); _about.draw(p, st::addContactPadding.left(), abouty, w); if (!_hint.isEmpty() && _oldError.isEmpty()) { p.setPen(st::black->p); - _hintText.drawElided(p, st::addContactPadding.left(), _oldPasscode.y() + _oldPasscode.height() + ((st::usernameSkip - st::usernameFont->height) / 2), w, 1, style::al_top); + _hintText.drawElided(p, st::addContactPadding.left(), _oldPasscode.y() + _oldPasscode.height() + ((st::usernameSkip - st::normalFont->height) / 2), w, 1, style::al_top); } if (!_oldError.isEmpty()) { @@ -225,16 +225,16 @@ void PasscodeBox::resizeEvent(QResizeEvent *e) { bool has = _cloudPwd ? (!_curSalt.isEmpty()) : cHasPasscode(); _oldPasscode.setGeometry(st::addContactPadding.left(), st::old_boxTitleHeight + st::addContactPadding.top(), width() - st::addContactPadding.left() - st::addContactPadding.right(), _oldPasscode.height()); _newPasscode.setGeometry(st::addContactPadding.left(), _oldPasscode.y() + ((_turningOff || has) ? (_oldPasscode.height() + st::usernameSkip) : 0), _oldPasscode.width(), _oldPasscode.height()); - _reenterPasscode.setGeometry(st::addContactPadding.left(), _newPasscode.y() + _newPasscode.height() + st::addContactDelta, _newPasscode.width(), _newPasscode.height()); + _reenterPasscode.setGeometry(st::addContactPadding.left(), _newPasscode.y() + _newPasscode.height() + st::addContactSkip, _newPasscode.width(), _newPasscode.height()); _passwordHint.setGeometry(st::addContactPadding.left(), _reenterPasscode.y() + _reenterPasscode.height() + st::usernameSkip, _reenterPasscode.width(), _reenterPasscode.height()); - _recoverEmail.setGeometry(st::addContactPadding.left(), _passwordHint.y() + _passwordHint.height() + st::addContactDelta + _aboutHeight + st::addContactDelta, _passwordHint.width(), _passwordHint.height()); + _recoverEmail.setGeometry(st::addContactPadding.left(), _passwordHint.y() + _passwordHint.height() + st::addContactSkip + _aboutHeight + st::addContactSkip, _passwordHint.width(), _passwordHint.height()); if (!_recover.isHidden()) { if (_turningOff) { _recover.move((width() - _recover.width()) / 2, _oldPasscode.y() + _oldPasscode.height() + st::usernameSkip + _aboutHeight + ((st::usernameSkip - _recover.height()) / 2)); } else { - _recover.move((width() - _recover.width()) / 2, _passwordHint.y() + _passwordHint.height() + st::addContactDelta + _aboutHeight + ((st::usernameSkip - _recover.height()) / 2)); + _recover.move((width() - _recover.width()) / 2, _passwordHint.y() + _passwordHint.height() + st::addContactSkip + _aboutHeight + ((st::usernameSkip - _recover.height()) / 2)); } } @@ -288,7 +288,7 @@ bool PasscodeBox::setPasswordFail(const RPCError &error) { } else if (err == "EMAIL_UNCONFIRMED") { App::wnd()->showLayer(new InformBox(lang(lng_cloud_password_almost))); emit reloadPassword(); - } else if (error.type().startsWith(qsl("FLOOD_WAIT_"))) { + } else if (mtpIsFlood(error)) { if (_oldPasscode.isHidden()) return false; _oldPasscode.selectAll(); @@ -457,7 +457,7 @@ void PasscodeBox::recoverStarted(const MTPauth_PasswordRecovery &result) { } bool PasscodeBox::recoverStartFail(const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; _pattern = QString(); onClose(); @@ -465,7 +465,7 @@ bool PasscodeBox::recoverStartFail(const RPCError &error) { } RecoverBox::RecoverBox(const QString &pattern) : -_submitRequest(0), _pattern(st::usernameFont->elided(lng_signin_recover_hint(lt_recover_email, pattern), st::boxWideWidth - st::addContactPadding.left() - st::addContactPadding.right())), +_submitRequest(0), _pattern(st::normalFont->elided(lng_signin_recover_hint(lt_recover_email, pattern), st::boxWideWidth - st::addContactPadding.left() - st::addContactPadding.right())), _saveButton(this, lang(lng_passcode_submit), st::btnSelectDone), _cancelButton(this, lang(lng_cancel), st::btnSelectCancel), _recoverCode(this, st::inpAddContact, lang(lng_signin_code)) { @@ -508,12 +508,12 @@ void RecoverBox::paintEvent(QPaintEvent *e) { Painter p(this); if (paint(p)) return; - paintTitle(p, lang(lng_signin_recover), true); + paintOldTitle(p, lang(lng_signin_recover), true); // paint shadow p.fillRect(0, height() - st::btnSelectCancel.height - st::scrollDef.bottomsh, width(), st::scrollDef.bottomsh, st::scrollDef.shColor->b); - p.setFont(st::usernameFont->f); + p.setFont(st::normalFont->f); int32 w = width() - st::addContactPadding.left() - st::addContactPadding.right(); p.drawText(QRect(st::addContactPadding.left(), _recoverCode.y() - st::usernameSkip - st::addContactPadding.top(), w, st::addContactPadding.top() + st::usernameSkip), _pattern, style::al_center); @@ -582,7 +582,7 @@ bool RecoverBox::codeSubmitFail(const RPCError &error) { update(); _recoverCode.notaBene(); return true; - } else if (error.type().startsWith(qsl("FLOOD_WAIT_"))) { + } else if (mtpIsFlood(error)) { _error = lang(lng_flood_error); update(); _recoverCode.notaBene(); diff --git a/Telegram/SourceFiles/boxes/sessionsbox.cpp b/Telegram/SourceFiles/boxes/sessionsbox.cpp index 896857501..ed7a9c3c8 100644 --- a/Telegram/SourceFiles/boxes/sessionsbox.cpp +++ b/Telegram/SourceFiles/boxes/sessionsbox.cpp @@ -109,7 +109,7 @@ void SessionsInner::terminateDone(uint64 hash, const MTPBool &result) { } bool SessionsInner::terminateFail(uint64 hash, const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; TerminateButtons::iterator i = _terminateButtons.find(hash); if (i != _terminateButtons.end()) { @@ -176,7 +176,7 @@ _terminateAll(this, lang(lng_sessions_terminate_all)), _terminateBox(0), _shortP void SessionsBox::resizeEvent(QResizeEvent *e) { ScrollableBox::resizeEvent(e); _done.move(0, height() - _done.height()); - _terminateAll.moveToRight(st::sessionPadding.left(), st::old_boxTitleHeight + st::sessionHeight + st::old_boxTitlePos.y() + st::old_boxTitleFont->ascent - st::linkFont->ascent, width()); + _terminateAll.moveToRight(st::sessionPadding.left(), st::old_boxTitleHeight + st::sessionHeight + st::old_boxTitlePos.y() + st::old_boxTitleFont->ascent - st::linkFont->ascent); } void SessionsBox::hideAll() { @@ -204,7 +204,7 @@ void SessionsBox::paintEvent(QPaintEvent *e) { Painter p(this); if (paint(p)) return; - paintTitle(p, lang(lng_sessions_header), true); + paintOldTitle(p, lang(lng_sessions_header), true); p.translate(0, st::old_boxTitleHeight); if (_loading) { @@ -230,7 +230,7 @@ void SessionsBox::paintEvent(QPaintEvent *e) { p.drawTextLeft(x, st::sessionPadding.top() + st::sessionNameFont->height + st::sessionInfoFont->height, w, _current.ip, _current.ipWidth); p.translate(0, st::sessionHeight); if (_list.isEmpty()) { - paintTitle(p, lang(lng_sessions_no_other), true); + paintOldTitle(p, lang(lng_sessions_no_other), true); p.setFont(st::sessionInfoFont->f); p.setPen(st::sessionInfoColor->p); @@ -239,7 +239,7 @@ void SessionsBox::paintEvent(QPaintEvent *e) { // paint shadow p.fillRect(0, height() - st::sessionsCloseButton.height - st::scrollDef.bottomsh - st::sessionHeight - st::old_boxTitleHeight, width(), st::scrollDef.bottomsh, st::scrollDef.shColor->b); } else { - paintTitle(p, lang(lng_sessions_other_header), false); + paintOldTitle(p, lang(lng_sessions_other_header), false); } } } @@ -418,7 +418,7 @@ void SessionsBox::terminateAllDone(const MTPBool &result) { } bool SessionsBox::terminateAllFail(const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; MTP::send(MTPaccount_GetAuthorizations(), rpcDone(&SessionsBox::gotAuthorizations)); if (_shortPollRequest) { diff --git a/Telegram/SourceFiles/boxes/stickersetbox.cpp b/Telegram/SourceFiles/boxes/stickersetbox.cpp index f893d801f..4fecc0143 100644 --- a/Telegram/SourceFiles/boxes/stickersetbox.cpp +++ b/Telegram/SourceFiles/boxes/stickersetbox.cpp @@ -86,7 +86,7 @@ void StickerSetInner::gotSet(const MTPmessages_StickerSet &set) { } bool StickerSetInner::failedSet(const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; _loaded = true; @@ -135,7 +135,7 @@ void StickerSetInner::installDone(const MTPBool &result) { } bool StickerSetInner::installFailed(const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; App::wnd()->showLayer(new InformBox(lang(lng_stickers_not_found))); @@ -234,7 +234,7 @@ _closeStickers(this, lang(lng_close), st::btnStickersAdd) { setMaxHeight(st::stickersMaxHeight); connect(App::main(), SIGNAL(stickersUpdated()), this, SLOT(onStickersUpdated())); - init(&_inner, 0, st::boxFont->height + st::newGroupNamePadding.top() + st::newGroupNamePadding.bottom()); + init(&_inner, 0, st::boxFont->height + st::old_newGroupNamePadding.top() + st::old_newGroupNamePadding.bottom()); connect(&_close, SIGNAL(clicked()), this, SLOT(onClose())); connect(&_addStickers, SIGNAL(clicked()), this, SLOT(onAddStickers())); @@ -315,13 +315,13 @@ void StickerSetBox::paintEvent(QPaintEvent *e) { Painter p(this); if (paint(p)) return; - paintTitle(p, _inner.title(), false); + paintOldTitle(p, _inner.title(), false); } void StickerSetBox::resizeEvent(QResizeEvent *e) { ScrollableBox::resizeEvent(e); _inner.resize(width(), _inner.height()); - _close.moveToRight(0, 0, width()); + _close.moveToRight(0, 0); _addStickers.move((width() - _addStickers.width()) / 2, height() - (st::stickersAddOrShare + _addStickers.height()) / 2); _shareStickers.move((width() - _shareStickers.width()) / 2, height() - (st::stickersAddOrShare + _shareStickers.height()) / 2); _closeStickers.move((width() - _closeStickers.width()) / 2, height() - (st::stickersAddOrShare + _closeStickers.height()) / 2); diff --git a/Telegram/SourceFiles/boxes/usernamebox.cpp b/Telegram/SourceFiles/boxes/usernamebox.cpp index 17f8e76f4..cc9eb064f 100644 --- a/Telegram/SourceFiles/boxes/usernamebox.cpp +++ b/Telegram/SourceFiles/boxes/usernamebox.cpp @@ -26,22 +26,26 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org #include "mainwidget.h" #include "window.h" -UsernameBox::UsernameBox() : -_saveButton(this, lang(lng_settings_save), st::usernameDone), -_cancelButton(this, lang(lng_cancel), st::usernameCancel), -_usernameInput(this, st::inpAddContact, qsl("@username"), App::self()->username), -_saveRequest(0), _checkRequest(0), _about(st::usernameWidth - 2 * st::old_boxTitlePos.x()) { - _about.setRichText(st::usernameFont, lang(lng_username_about)); +UsernameBox::UsernameBox() : AbstractBox(st::boxWidth), +_save(this, lang(lng_settings_save), st::defaultBoxButton), +_cancel(this, lang(lng_box_cancel), st::cancelBoxButton), +_username(this, st::usernameField, qsl("@username"), App::self()->username, false), +_link(this, QString(), st::defaultBoxLinkButton), +_saveRequestId(0), _checkRequestId(0), +_about(st::boxWidth - st::usernamePadding.left()) { _goodText = App::self()->username.isEmpty() ? QString() : lang(lng_username_available); - initBox(); -} -void UsernameBox::initBox() { - resizeMaxHeight(st::usernameWidth, st::old_boxTitleHeight + st::addContactPadding.top() + _usernameInput.height() + st::addContactPadding.bottom() + _about.countHeight(st::usernameWidth - 2 * st::old_boxTitlePos.x()) + st::usernameSkip + _saveButton.height()); + textstyleSet(&st::usernameTextStyle); + _about.setRichText(st::boxTextFont, lang(lng_username_about)); + resizeMaxHeight(st::boxWidth, st::boxBlueTitleHeight + st::usernamePadding.top() + _username.height() + st::usernameSkip + _about.countHeight(st::boxWidth - st::usernamePadding.left() - st::usernamePadding.right()) + 3 * st::usernameTextStyle.lineHeight + st::usernamePadding.bottom() + st::boxButtonPadding.top() + _save.height() + st::boxButtonPadding.bottom()); + textstyleRestore(); - connect(&_saveButton, SIGNAL(clicked()), this, SLOT(onSave())); - connect(&_cancelButton, SIGNAL(clicked()), this, SLOT(onClose())); - connect(&_usernameInput, SIGNAL(changed()), this, SLOT(onChanged())); + connect(&_save, SIGNAL(clicked()), this, SLOT(onSave())); + connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose())); + connect(&_username, SIGNAL(changed()), this, SLOT(onChanged())); + connect(&_username, SIGNAL(submitted(bool)), this, SLOT(onSave())); + + connect(&_link, SIGNAL(clicked()), this, SLOT(onLinkClick())); _checkTimer.setSingleShot(true); connect(&_checkTimer, SIGNAL(timeout()), this, SLOT(onCheck())); @@ -50,87 +54,100 @@ void UsernameBox::initBox() { } void UsernameBox::hideAll() { - _usernameInput.hide(); - _saveButton.hide(); - _cancelButton.hide(); + _username.hide(); + _save.hide(); + _cancel.hide(); + _link.hide(); } void UsernameBox::showAll() { - _usernameInput.show(); - _saveButton.show(); - _cancelButton.show(); + _username.show(); + _save.show(); + _cancel.show(); + updateLinkText(); } void UsernameBox::showDone() { - _usernameInput.setFocus(); -} - -void UsernameBox::keyPressEvent(QKeyEvent *e) { - if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) { - onSave(); - } else { - AbstractBox::keyPressEvent(e); - } + _username.setFocus(); } void UsernameBox::paintEvent(QPaintEvent *e) { Painter p(this); if (paint(p)) return; - paintTitle(p, lang(lng_username_title), true); + paintBlueTitle(p, lang(lng_username_title)); - // paint shadow - p.fillRect(0, height() - st::btnSelectCancel.height - st::scrollDef.bottomsh, width(), st::scrollDef.bottomsh, st::scrollDef.shColor->b); - - // paint button sep - p.fillRect(st::usernameCancel.width, size().height() - st::usernameCancel.height, st::lineWidth, st::usernameCancel.height, st::btnSelectSep->b); - - if (!_errorText.isEmpty()) { - p.setPen(st::setErrColor->p); - p.setFont(st::setErrFont->f); - int32 w = st::setErrFont->width(_errorText); - p.drawText((width() - w) / 2, _usernameInput.y() + _usernameInput.height() + ((st::usernameSkip - st::setErrFont->height) / 2) + st::setErrFont->ascent, _errorText); + if (!_copiedTextLink.isEmpty()) { + p.setPen(st::usernameDefaultFg); + p.setFont(st::boxTextFont); + p.drawTextLeft(st::usernamePadding.left(), _username.y() + _username.height() + ((st::usernameSkip - st::boxTextFont->height) / 2), width(), _copiedTextLink); + } else if (!_errorText.isEmpty()) { + p.setPen(st::setErrColor); + p.setFont(st::boxTextFont); + p.drawTextLeft(st::usernamePadding.left(), _username.y() + _username.height() + ((st::usernameSkip - st::boxTextFont->height) / 2), width(), _errorText); } else if (!_goodText.isEmpty()) { - p.setPen(st::setGoodColor->p); - p.setFont(st::setErrFont->f); - int32 w = st::setErrFont->width(_goodText); - p.drawText((width() - w) / 2, _usernameInput.y() + _usernameInput.height() + ((st::usernameSkip - st::setErrFont->height) / 2) + st::setErrFont->ascent, _goodText); + p.setPen(st::setGoodColor); + p.setFont(st::boxTextFont); + p.drawTextLeft(st::usernamePadding.left(), _username.y() + _username.height() + ((st::usernameSkip - st::boxTextFont->height) / 2), width(), _goodText); + } else { + p.setPen(st::usernameDefaultFg); + p.setFont(st::boxTextFont); + p.drawTextLeft(st::usernamePadding.left(), _username.y() + _username.height() + ((st::usernameSkip - st::boxTextFont->height) / 2), width(), lang(lng_username_choose)); + } + p.setPen(st::black); + textstyleSet(&st::usernameTextStyle); + int32 availw = st::boxWidth - st::usernamePadding.left(), h = _about.countHeight(availw); + _about.draw(p, st::usernamePadding.left(), _username.y() + _username.height() + st::usernameSkip, availw); + textstyleRestore(); + + int32 linky = _username.y() + _username.height() + st::usernameSkip + h + st::usernameTextStyle.lineHeight + ((st::usernameTextStyle.lineHeight - st::boxTextFont->height) / 2); + if (_link.isHidden()) { + p.drawTextLeft(st::usernamePadding.left(), linky, width(), lang(lng_username_link_willbe)); + p.setPen(st::usernameDefaultFg); + p.drawTextLeft(st::usernamePadding.left(), linky + st::usernameTextStyle.lineHeight + ((st::usernameTextStyle.lineHeight - st::boxTextFont->height) / 2), width(), qsl("https://telegram.me/username")); + } else { + p.drawTextLeft(st::usernamePadding.left(), linky, width(), lang(lng_username_link)); } - p.setPen(st::usernameColor->p); - _about.draw(p, st::old_boxTitlePos.x(), _usernameInput.y() + _usernameInput.height() + st::usernameSkip, width() - 2 * st::old_boxTitlePos.x()); } void UsernameBox::resizeEvent(QResizeEvent *e) { - _usernameInput.setGeometry(st::addContactPadding.left(), st::old_boxTitleHeight + st::addContactPadding.top(), width() - st::addContactPadding.left() - st::addContactPadding.right(), _usernameInput.height()); + _username.resize(width() - st::usernamePadding.left() - st::usernamePadding.right(), _username.height()); + _username.moveToLeft(st::usernamePadding.left(), st::boxBlueTitleHeight + st::usernamePadding.top()); - int32 buttonTop = height() - _cancelButton.height(); - _cancelButton.move(0, buttonTop); - _saveButton.move(width() - _saveButton.width(), buttonTop); + textstyleSet(&st::usernameTextStyle); + int32 availw = st::boxWidth - st::usernamePadding.left(), h = _about.countHeight(availw); + textstyleRestore(); + int32 linky = _username.y() + _username.height() + st::usernameSkip + h + st::usernameTextStyle.lineHeight + ((st::usernameTextStyle.lineHeight - st::boxTextFont->height) / 2); + _link.moveToLeft(st::usernamePadding.left(), linky + st::usernameTextStyle.lineHeight + ((st::usernameTextStyle.lineHeight - st::boxTextFont->height) / 2)); + + _save.moveToRight(st::boxButtonPadding.right(), height() - st::boxButtonPadding.bottom() - _save.height()); + _cancel.moveToRight(st::boxButtonPadding.right() + _save.width() + st::boxButtonPadding.left(), _save.y()); } void UsernameBox::onSave() { - if (_saveRequest) return; + if (_saveRequestId) return; _sentUsername = getName(); - _saveRequest = MTP::send(MTPaccount_UpdateUsername(MTP_string(_sentUsername)), rpcDone(&UsernameBox::onUpdateDone), rpcFail(&UsernameBox::onUpdateFail)); + _saveRequestId = MTP::send(MTPaccount_UpdateUsername(MTP_string(_sentUsername)), rpcDone(&UsernameBox::onUpdateDone), rpcFail(&UsernameBox::onUpdateFail)); } void UsernameBox::onCheck() { - if (_checkRequest) { - MTP::cancel(_checkRequest); + if (_checkRequestId) { + MTP::cancel(_checkRequestId); } QString name = getName(); if (name.size() >= MinUsernameLength) { _checkUsername = name; - _checkRequest = MTP::send(MTPaccount_CheckUsername(MTP_string(name)), rpcDone(&UsernameBox::onCheckDone), rpcFail(&UsernameBox::onCheckFail)); + _checkRequestId = MTP::send(MTPaccount_CheckUsername(MTP_string(name)), rpcDone(&UsernameBox::onCheckDone), rpcFail(&UsernameBox::onCheckFail)); } } void UsernameBox::onChanged() { + updateLinkText(); QString name = getName(); if (name.isEmpty()) { if (!_errorText.isEmpty() || !_goodText.isEmpty()) { - _errorText = _goodText = QString(); + _copiedTextLink = _errorText = _goodText = QString(); update(); } _checkTimer.stop(); @@ -139,7 +156,8 @@ void UsernameBox::onChanged() { for (int32 i = 0; i < len; ++i) { QChar ch = name.at(i); if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z') && (ch < '0' || ch > '9') && ch != '_' && (ch != '@' || i > 0)) { - if (_errorText != lang(lng_username_bad_symbols)) { + if (_errorText != lang(lng_username_bad_symbols) || !_copiedTextLink.isEmpty()) { + _copiedTextLink = QString(); _errorText = lang(lng_username_bad_symbols); update(); } @@ -148,14 +166,15 @@ void UsernameBox::onChanged() { } } if (name.size() < MinUsernameLength) { - if (_errorText != lang(lng_username_too_short)) { + if (_errorText != lang(lng_username_too_short) || !_copiedTextLink.isEmpty()) { + _copiedTextLink = QString(); _errorText = lang(lng_username_too_short); update(); } _checkTimer.stop(); } else { - if (!_errorText.isEmpty() || !_goodText.isEmpty()) { - _errorText = _goodText = QString(); + if (!_errorText.isEmpty() || !_goodText.isEmpty() || !_copiedTextLink.isEmpty()) { + _copiedTextLink = _errorText = _goodText = QString(); update(); } _checkTimer.start(UsernameCheckTimeout); @@ -163,50 +182,61 @@ void UsernameBox::onChanged() { } } +void UsernameBox::onLinkClick() { + App::app()->clipboard()->setText(qsl("https://telegram.me/") + getName()); + _copiedTextLink = lang(lng_username_copied); + update(); +} + void UsernameBox::onUpdateDone(const MTPUser &user) { App::feedUsers(MTP_vector(1, user)); emit closed(); } bool UsernameBox::onUpdateFail(const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; - _saveRequest = 0; + _saveRequestId = 0; QString err(error.type()); if (err == "USERNAME_NOT_MODIFIED" || _sentUsername == App::self()->username) { App::self()->setName(textOneLine(App::self()->firstName), textOneLine(App::self()->lastName), textOneLine(App::self()->nameOrPhone), textOneLine(_sentUsername)); emit closed(); return true; } else if (err == "USERNAME_INVALID") { - _usernameInput.setFocus(); - _usernameInput.notaBene(); + _username.setFocus(); + _username.showError(); + _copiedTextLink = QString(); _errorText = lang(lng_username_invalid); + update(); return true; } else if (err == "USERNAME_OCCUPIED" || err == "USERNAMES_UNAVAILABLE") { - _usernameInput.setFocus(); - _usernameInput.notaBene(); + _username.setFocus(); + _username.showError(); + _copiedTextLink = QString(); _errorText = lang(lng_username_occupied); + update(); return true; } - _usernameInput.setFocus(); + _username.setFocus(); return true; } void UsernameBox::onCheckDone(const MTPBool &result) { - _checkRequest = 0; + _checkRequestId = 0; QString newError = (result.v || _checkUsername == App::self()->username) ? QString() : lang(lng_username_occupied); QString newGood = newError.isEmpty() ? lang(lng_username_available) : QString(); - if (_errorText != newError || _goodText != newGood) { + if (_errorText != newError || _goodText != newGood || !_copiedTextLink.isEmpty()) { _errorText = newError; _goodText = newGood; + _copiedTextLink = QString(); update(); } } bool UsernameBox::onCheckFail(const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; - _checkRequest = 0; + _checkRequestId = 0; QString err(error.type()); if (err == "USERNAME_INVALID") { _errorText = lang(lng_username_invalid); @@ -218,10 +248,27 @@ bool UsernameBox::onCheckFail(const RPCError &error) { return true; } _goodText = QString(); - _usernameInput.setFocus(); + _copiedTextLink = QString(); + _username.setFocus(); return true; } QString UsernameBox::getName() const { - return _usernameInput.text().replace('@', QString()).trimmed(); + return _username.text().replace('@', QString()).trimmed(); } + +void UsernameBox::updateLinkText() { + QString uname = getName(); + _link.setText(st::boxTextFont->elided(qsl("https://telegram.me/") + uname, st::boxWidth - st::usernamePadding.left() - st::usernamePadding.right())); + if (uname.isEmpty()) { + if (!_link.isHidden()) { + _link.hide(); + update(); + } + } else { + if (_link.isHidden()) { + _link.show(); + update(); + } + } +} \ No newline at end of file diff --git a/Telegram/SourceFiles/boxes/usernamebox.h b/Telegram/SourceFiles/boxes/usernamebox.h index 1f7f7e28d..c48af468f 100644 --- a/Telegram/SourceFiles/boxes/usernamebox.h +++ b/Telegram/SourceFiles/boxes/usernamebox.h @@ -28,7 +28,6 @@ class UsernameBox : public AbstractBox, public RPCSender { public: UsernameBox(); - void keyPressEvent(QKeyEvent *e); void paintEvent(QPaintEvent *e); void resizeEvent(QResizeEvent *e); @@ -39,6 +38,8 @@ public slots: void onCheck(); void onChanged(); + void onLinkClick(); + protected: void hideAll(); @@ -54,13 +55,14 @@ private: bool onCheckFail(const RPCError &error); QString getName() const; - void initBox(); + void updateLinkText(); - FlatButton _saveButton, _cancelButton; - UsernameInput _usernameInput; + BoxButton _save, _cancel; + UsernameInput _username; + LinkButton _link; - mtpRequestId _saveRequest, _checkRequest; - QString _sentUsername, _checkUsername, _errorText, _goodText; + mtpRequestId _saveRequestId, _checkRequestId; + QString _sentUsername, _checkUsername, _errorText, _goodText, _copiedTextLink; Text _about; QTimer _checkTimer; diff --git a/Telegram/SourceFiles/dialogswidget.cpp b/Telegram/SourceFiles/dialogswidget.cpp index 05c48d2ad..2903caa0b 100644 --- a/Telegram/SourceFiles/dialogswidget.cpp +++ b/Telegram/SourceFiles/dialogswidget.cpp @@ -1726,7 +1726,7 @@ void DialogsWidget::dialogsReceived(const MTPmessages_Dialogs &dialogs, mtpReque } bool DialogsWidget::dialogsFailed(const RPCError &error, mtpRequestId req) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; LOG(("RPC Error: %1 %2: %3").arg(error.code()).arg(error.type()).arg(error.description())); if (_dialogsRequest == req) { @@ -1853,7 +1853,7 @@ void DialogsWidget::contactsReceived(const MTPcontacts_Contacts &contacts) { } bool DialogsWidget::contactsFailed(const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; return true; } @@ -1943,7 +1943,7 @@ void DialogsWidget::peopleReceived(const MTPcontacts_Found &result, mtpRequestId } bool DialogsWidget::searchFailed(const RPCError &error, mtpRequestId req) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; if (_searchRequest == req) { _searchRequest = 0; @@ -1953,7 +1953,7 @@ bool DialogsWidget::searchFailed(const RPCError &error, mtpRequestId req) { } bool DialogsWidget::peopleFailed(const RPCError &error, mtpRequestId req) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; if (_peopleRequest == req) { _peopleRequest = 0; diff --git a/Telegram/SourceFiles/dropdown.cpp b/Telegram/SourceFiles/dropdown.cpp index f023a8d5c..a374a23f2 100644 --- a/Telegram/SourceFiles/dropdown.cpp +++ b/Telegram/SourceFiles/dropdown.cpp @@ -690,7 +690,7 @@ void EmojiColorPicker::drawVariant(Painter &p, int variant) { p.setOpacity(1); } int esize = EmojiSizes[EIndex + 1]; - p.drawPixmapLeft(w.x() + (st::emojiPanSize.width() - (esize / cIntRetinaFactor())) / 2, w.y() + (st::emojiPanSize.height() - (esize / cIntRetinaFactor())) / 2, width(), App::emojisLarge(), QRect(_variants[variant]->x * esize, _variants[variant]->y * esize, esize, esize)); + p.drawPixmapLeft(w.x() + (st::emojiPanSize.width() - (esize / cIntRetinaFactor())) / 2, w.y() + (st::emojiPanSize.height() - (esize / cIntRetinaFactor())) / 2, width(), App::emojiLarge(), QRect(_variants[variant]->x * esize, _variants[variant]->y * esize, esize, esize)); } EmojiPanInner::EmojiPanInner() : _maxHeight(int(st::emojiPanMaxHeight)), @@ -802,7 +802,7 @@ void EmojiPanInner::paintEvent(QPaintEvent *e) { App::roundRect(p, QRect(tl, st::emojiPanSize), st::emojiPanHover, StickerHoverCorners); p.setOpacity(1); } - p.drawPixmapLeft(w.x() + (st::emojiPanSize.width() - (_esize / cIntRetinaFactor())) / 2, w.y() + (st::emojiPanSize.height() - (_esize / cIntRetinaFactor())) / 2, width(), App::emojisLarge(), QRect(_emojis[c][index]->x * _esize, _emojis[c][index]->y * _esize, _esize, _esize)); + p.drawPixmapLeft(w.x() + (st::emojiPanSize.width() - (_esize / cIntRetinaFactor())) / 2, w.y() + (st::emojiPanSize.height() - (_esize / cIntRetinaFactor())) / 2, width(), App::emojiLarge(), QRect(_emojis[c][index]->x * _esize, _emojis[c][index]->y * _esize, _esize, _esize)); } } } @@ -964,7 +964,7 @@ QRect EmojiPanInner::emojiRect(int tab, int sel) { x = st::emojiPanPadding + ((sel % EmojiPanPerRow) * st::emojiPanSize.width()); break; } else { - int cnt = emojiPackCount(emojiTabAtIndex(i)); + int cnt = _counts[i]; int rows = (cnt / EmojiPanPerRow) + ((cnt % EmojiPanPerRow) ? 1 : 0); y += st::emojiPanHeader + rows * st::emojiPanSize.height(); } @@ -1083,10 +1083,11 @@ void EmojiPanInner::fillPanels(QVector &panels) { for (int c = 0; c < emojiTabCount; ++c) { panels.push_back(new EmojiPanel(parentWidget(), lang(LangKey(lng_emoji_category0 + c)), NoneStickerSetId, true, y)); connect(panels.back(), SIGNAL(mousePressed()), this, SLOT(checkPickerHide())); - int cnt = emojiPackCount(emojiTabAtIndex(c)), rows = (cnt / EmojiPanPerRow) + ((cnt % EmojiPanPerRow) ? 1 : 0); + int cnt = _counts[c], rows = (cnt / EmojiPanPerRow) + ((cnt % EmojiPanPerRow) ? 1 : 0); panels.back()->show(); y += st::emojiPanHeader + rows * st::emojiPanSize.height(); } + _picker.raise(); } void EmojiPanInner::refreshPanels(QVector &panels) { @@ -1095,7 +1096,7 @@ void EmojiPanInner::refreshPanels(QVector &panels) { int32 y = 0; for (int c = 0; c < emojiTabCount; ++c) { panels.at(c)->setWantedY(y); - int cnt = emojiPackCount(emojiTabAtIndex(c)), rows = (cnt / EmojiPanPerRow) + ((cnt % EmojiPanPerRow) ? 1 : 0); + int cnt = _counts[c], rows = (cnt / EmojiPanPerRow) + ((cnt % EmojiPanPerRow) ? 1 : 0); y += st::emojiPanHeader + rows * st::emojiPanSize.height(); } } @@ -1972,7 +1973,7 @@ void EmojiPan::paintEvent(QPaintEvent *e) { if (_toCache.isNull()) { if (_cache.isNull()) { - p.fillRect(rtlrect(r.x() + r.width() - st::emojiScroll.width, r.y(), st::emojiScroll.width, e_scroll.height(), width()), st::white->b); + p.fillRect(myrtlrect(r.x() + r.width() - st::emojiScroll.width, r.y(), st::emojiScroll.width, e_scroll.height()), st::white->b); if (_stickersShown) { p.fillRect(r.left(), _iconsTop, r.width(), st::rbEmoji.height, st::emojiPanCategories->b); if (!_icons.isEmpty()) { diff --git a/Telegram/SourceFiles/fileuploader.cpp b/Telegram/SourceFiles/fileuploader.cpp index 7894ff887..4f4f46971 100644 --- a/Telegram/SourceFiles/fileuploader.cpp +++ b/Telegram/SourceFiles/fileuploader.cpp @@ -285,7 +285,7 @@ void FileUploader::partLoaded(const MTPBool &result, mtpRequestId requestId) { } bool FileUploader::partFailed(const RPCError &error, mtpRequestId requestId) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; if (requestsSent.constFind(requestId) != requestsSent.cend() || docRequestsSent.constFind(requestId) != docRequestsSent.cend()) { // failed to upload current file currentFailed(); diff --git a/Telegram/SourceFiles/gui/countryinput.cpp b/Telegram/SourceFiles/gui/countryinput.cpp index fcb06074e..d3ea80ee0 100644 --- a/Telegram/SourceFiles/gui/countryinput.cpp +++ b/Telegram/SourceFiles/gui/countryinput.cpp @@ -536,7 +536,7 @@ void CountrySelect::onFilterUpdate() { void CountrySelect::resizeEvent(QResizeEvent *e) { if (width() != e->oldSize().width()) { - _innerWidth = st::newGroupNamePadding.left() + _filter.width() + st::newGroupNamePadding.right(); + _innerWidth = st::old_newGroupNamePadding.left() + _filter.width() + st::old_newGroupNamePadding.right(); _innerLeft = (width() - _innerWidth) / 2; _list.resize(_innerWidth, _list.height()); @@ -550,9 +550,9 @@ void CountrySelect::resizeEvent(QResizeEvent *e) { } } - _filter.move(_innerLeft + st::newGroupNamePadding.left(), _innerTop + st::contactsAdd.height + st::newGroupNamePadding.top()); - int32 scrollTop = _filter.y() + _filter.height() + st::newGroupNamePadding.bottom(); - int32 scrollHeight = _innerHeight - st::contactsAdd.height - st::newGroupNamePadding.top() - _filter.height() - st::newGroupNamePadding.bottom() - _cancelButton.height(); + _filter.move(_innerLeft + st::old_newGroupNamePadding.left(), _innerTop + st::contactsAdd.height + st::old_newGroupNamePadding.top()); + int32 scrollTop = _filter.y() + _filter.height() + st::old_newGroupNamePadding.bottom(); + int32 scrollHeight = _innerHeight - st::contactsAdd.height - st::old_newGroupNamePadding.top() - _filter.height() - st::old_newGroupNamePadding.bottom() - _cancelButton.height(); _scroll.setGeometry(_innerLeft, scrollTop, _innerWidth, scrollHeight); int btnTop = scrollTop + scrollHeight; diff --git a/Telegram/SourceFiles/gui/flatbutton.cpp b/Telegram/SourceFiles/gui/flatbutton.cpp index 3c495805d..a5e039da7 100644 --- a/Telegram/SourceFiles/gui/flatbutton.cpp +++ b/Telegram/SourceFiles/gui/flatbutton.cpp @@ -301,9 +301,12 @@ _st(st), a_textBgOverOpacity(0), a_textFg(st.textFg->c), _a_over(animFunc(this, &BoxButton::animStep_over)) { if (_st.width <= 0) { resize(_textWidth - _st.width, _st.height); - } else if (_st.width < _textWidth + (_st.height - _st.font->height)) { - _text = _st.font->elided(_fullText, qMax(_st.width - (_st.height - _st.font->height), 1.)); - _textWidth = _st.font->width(_text); + } else { + if (_st.width < _textWidth + (_st.height - _st.font->height)) { + _text = _st.font->elided(_fullText, qMax(_st.width - (_st.height - _st.font->height), 1.)); + _textWidth = _st.font->width(_text); + } + resize(_st.width, _st.height); } connect(this, SIGNAL(stateChanged(int, ButtonStateChangeSource)), this, SLOT(onStateChange(int, ButtonStateChangeSource))); diff --git a/Telegram/SourceFiles/gui/flatcheckbox.cpp b/Telegram/SourceFiles/gui/flatcheckbox.cpp index 48df0deae..70d64cce4 100644 --- a/Telegram/SourceFiles/gui/flatcheckbox.cpp +++ b/Telegram/SourceFiles/gui/flatcheckbox.cpp @@ -127,14 +127,15 @@ bool FlatCheckbox::animStep(float64 ms) { return res; } -class RadiobuttonsGroup : public QSet { - typedef QSet Parent; +template +class TemplateRadiobuttonsGroup : public QMap { + typedef QMap Parent; public: - RadiobuttonsGroup(const QString &name) : _name(name), _val(0) { + TemplateRadiobuttonsGroup(const QString &name) : _name(name), _val(0) { } - void remove(FlatRadiobutton * const &radio); + void remove(Type * const &radio); int32 val() const { return _val; } @@ -148,15 +149,19 @@ private: }; -class Radiobuttons : public QMap { - typedef QMap Parent; +typedef TemplateRadiobuttonsGroup FlatRadiobuttonGroup; +typedef TemplateRadiobuttonsGroup RadiobuttonGroup; + +template +class Radiobuttons : public QMap *> { + typedef QMap *> Parent; public: - RadiobuttonsGroup *reg(const QString &group) { + TemplateRadiobuttonsGroup *reg(const QString &group) { Parent::const_iterator i = constFind(group); if (i == cend()) { - i = insert(group, new RadiobuttonsGroup(group)); + i = insert(group, new TemplateRadiobuttonsGroup(group)); } return i.value(); } @@ -179,39 +184,366 @@ public: }; namespace { - Radiobuttons radioButtons; + Radiobuttons flatRadiobuttons; + Radiobuttons radiobuttons; } -void RadiobuttonsGroup::remove(FlatRadiobutton * const &radio) { +template <> +void TemplateRadiobuttonsGroup::remove(FlatRadiobutton * const &radio) { Parent::remove(radio); if (isEmpty()) { - radioButtons.remove(_name); + flatRadiobuttons.remove(_name); + } +} + +template <> +void TemplateRadiobuttonsGroup::remove(Radiobutton * const &radio) { + Parent::remove(radio); + if (isEmpty()) { + radiobuttons.remove(_name); } } FlatRadiobutton::FlatRadiobutton(QWidget *parent, const QString &group, int32 value, const QString &text, bool checked, const style::flatCheckbox &st) : - FlatCheckbox(parent, text, checked, st), _group(radioButtons.reg(group)), _value(value) { - _group->insert(this); + FlatCheckbox(parent, text, checked, st), _group(flatRadiobuttons.reg(group)), _value(value) { + reinterpret_cast(_group)->insert(this, true); connect(this, SIGNAL(changed()), this, SLOT(onChanged())); if (this->checked()) onChanged(); } void FlatRadiobutton::onChanged() { + FlatRadiobuttonGroup *group = reinterpret_cast(_group); if (checked()) { - int32 uncheck = _group->val(); + int32 uncheck = group->val(); if (uncheck != _value) { - _group->setVal(_value); - for (RadiobuttonsGroup::const_iterator i = _group->cbegin(), e = _group->cend(); i != e; ++i) { - if ((*i)->val() == uncheck) { - (*i)->setChecked(false); + group->setVal(_value); + for (FlatRadiobuttonGroup::const_iterator i = group->cbegin(), e = group->cend(); i != e; ++i) { + if (i.key()->val() == uncheck) { + i.key()->setChecked(false); } } } - } else if (_group->val() == _value) { + } else if (group->val() == _value) { setChecked(true); } } FlatRadiobutton::~FlatRadiobutton() { - _group->remove(this); + reinterpret_cast(_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) { + if (_st.width <= 0) { + resize(_textWidth - _st.width, _st.height); + } else { + if (_st.width < _st.textPosition.x() + _textWidth + (_st.textPosition.x() - _st.diameter)) { + _text = _st.font->elided(_fullText, qMax(_st.width - (_st.textPosition.x() + (_st.textPosition.x() - _st.diameter)), 1.)); + _textWidth = _st.font->width(_text); + } + resize(_st.width, _st.height); + } + _checkRect = myrtlrect(0, 0, _st.diameter, _st.diameter); + + connect(this, SIGNAL(clicked()), this, SLOT(onClicked())); + connect(this, SIGNAL(stateChanged(int, ButtonStateChangeSource)), this, SLOT(onStateChange(int, ButtonStateChangeSource))); + + setCursor(style::cur_pointer); + + setAttribute(Qt::WA_OpaquePaintEvent); +} + +bool Checkbox::checked() const { + return _checked; +} + +void Checkbox::setChecked(bool checked) { + if (_checked != checked) { + _checked = checked; + if (_checked) { + a_checked.start(1); + } else { + a_checked.start(0); + } + _a_checked.start(); + + emit changed(); + } +} + +bool Checkbox::animStep_over(float64 ms) { + float64 dt = ms / _st.duration; + bool res = true; + if (dt >= 1) { + a_over.finish(); + res = false; + } else { + a_over.update(dt, anim::linear); + } + update(_checkRect); + return res; +} + +bool Checkbox::animStep_checked(float64 ms) { + float64 dt = ms / _st.duration; + bool res = true; + if (dt >= 1) { + a_checked.finish(); + res = false; + } else { + a_checked.update(dt, anim::linear); + } + update(_checkRect); + return res; +} + +void Checkbox::paintEvent(QPaintEvent *e) { + Painter p(this); + + float64 over = a_over.current(), checked = a_checked.current(); + bool cnone = (over == 0. && checked == 0.), cover = (over == 1. && checked == 0.), cchecked = (checked == 1.); + bool cbad = !cnone && !cover && !cchecked; + QColor color; + if (cbad) { + float64 onone = (1. - over) * (1. - checked), oover = over * (1. - checked), ochecked = checked; + color.setRedF(_st.checkFg->c.redF() * onone + _st.checkFgOver->c.redF() * oover + _st.checkFgActive->c.redF() * ochecked); + color.setGreenF(_st.checkFg->c.greenF() * onone + _st.checkFgOver->c.greenF() * oover + _st.checkFgActive->c.greenF() * ochecked); + color.setBlueF(_st.checkFg->c.blueF() * onone + _st.checkFgOver->c.blueF() * oover + _st.checkFgActive->c.blueF() * ochecked); + } + + QRect r(e->rect()); + p.setClipRect(r); + p.fillRect(r, _st.textBg->b); + if (_checkRect.intersects(r)) { + p.setRenderHint(QPainter::HighQualityAntialiasing); + + QPen pen; + if (cbad) { + pen = QPen(color); + } else { + pen = (cnone ? _st.checkFg : (cover ? _st.checkFgOver : _st.checkFgActive))->p; + color = (cnone ? _st.checkFg : (cover ? _st.checkFgOver : _st.checkFgActive))->c; + } + pen.setWidth(_st.thickness); + p.setPen(pen); + if (checked > 0) { + color.setAlphaF(checked); + p.setBrush(color); + } else { + p.setBrush(Qt::NoBrush); + } + p.drawRoundedRect(QRectF(_checkRect).marginsRemoved(QMarginsF(_st.thickness / 2, _st.thickness / 2, _st.thickness / 2, _st.thickness / 2)), st::msgRadius, st::msgRadius); + p.setRenderHint(QPainter::HighQualityAntialiasing, false); + + if (checked > 0) { + p.drawSpriteCenter(_checkRect, _st.checkIcon); + } + } + if (_checkRect.contains(r)) return; + + p.setPen(_st.textFg); + p.setFont(_st.font); + p.drawTextLeft(_st.textPosition.x(), _st.textPosition.y(), width(), _text, _textWidth); +} + +void Checkbox::onClicked() { + if (_state & StateDisabled) return; + setChecked(!checked()); +} + +void Checkbox::onStateChange(int oldState, ButtonStateChangeSource source) { + if ((_state & StateOver) && !(oldState & StateOver)) { + a_over.start(1); + _a_over.start(); + } else if (!(_state & StateOver) && (oldState & StateOver)) { + a_over.start(0); + _a_over.start(); + } + if ((_state & StateDisabled) && !(oldState & StateDisabled)) { + setCursor(style::cur_default); + } else if (!(_state & StateDisabled) && (oldState & StateDisabled)) { + setCursor(style::cur_pointer); + } +} + +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) { + if (_st.width <= 0) { + resize(_textWidth - _st.width, _st.height); + } else { + if (_st.width < _st.textPosition.x() + _textWidth + (_st.textPosition.x() - _st.diameter)) { + _text = _st.font->elided(_fullText, qMax(_st.width - (_st.textPosition.x() + (_st.textPosition.x() - _st.diameter)), 1.)); + _textWidth = _st.font->width(_text); + } + resize(_st.width, _st.height); + } + _checkRect = myrtlrect(0, 0, _st.diameter, _st.diameter); + + connect(this, SIGNAL(clicked()), this, SLOT(onClicked())); + connect(this, SIGNAL(stateChanged(int, ButtonStateChangeSource)), this, SLOT(onStateChange(int, ButtonStateChangeSource))); + + setCursor(style::cur_pointer); + + setAttribute(Qt::WA_OpaquePaintEvent); + + reinterpret_cast(_group)->insert(this, true); + if (_checked) onChanged(); +} + +bool Radiobutton::checked() const { + return _checked; +} + +void Radiobutton::setChecked(bool checked) { + if (_checked != checked) { + _checked = checked; + if (_checked) { + a_checked.start(1); + } else { + a_checked.start(0); + } + _a_checked.start(); + + onChanged(); + emit changed(); + } +} + +bool Radiobutton::animStep_over(float64 ms) { + float64 dt = ms / _st.duration; + bool res = true; + if (dt >= 1) { + a_over.finish(); + res = false; + } else { + a_over.update(dt, anim::linear); + } + update(_checkRect); + return res; +} + +bool Radiobutton::animStep_checked(float64 ms) { + float64 dt = ms / _st.duration; + bool res = true; + if (dt >= 1) { + a_checked.finish(); + res = false; + } else { + a_checked.update(dt, anim::linear); + } + update(_checkRect); + return res; +} + +void Radiobutton::paintEvent(QPaintEvent *e) { + Painter p(this); + + float64 over = a_over.current(), checked = a_checked.current(); + bool cnone = (over == 0. && checked == 0.), cover = (over == 1. && checked == 0.), cchecked = (checked == 1.); + bool cbad = !cnone && !cover && !cchecked; + QColor color; + if (cbad) { + float64 onone = (1. - over) * (1. - checked), oover = over * (1. - checked), ochecked = checked; + color.setRedF(_st.checkFg->c.redF() * onone + _st.checkFgOver->c.redF() * oover + _st.checkFgActive->c.redF() * ochecked); + color.setGreenF(_st.checkFg->c.greenF() * onone + _st.checkFgOver->c.greenF() * oover + _st.checkFgActive->c.greenF() * ochecked); + color.setBlueF(_st.checkFg->c.blueF() * onone + _st.checkFgOver->c.blueF() * oover + _st.checkFgActive->c.blueF() * ochecked); + } + + QRect r(e->rect()); + p.setClipRect(r); + p.fillRect(r, _st.textBg->b); + if (_checkRect.intersects(r)) { + p.setRenderHint(QPainter::HighQualityAntialiasing); + + QPen pen; + if (cbad) { + pen = QPen(color); + } else { + pen = (cnone ? _st.checkFg : (cover ? _st.checkFgOver : _st.checkFgActive))->p; + } + pen.setWidth(_st.thickness); + p.setPen(pen); + p.setBrush(Qt::NoBrush); + //int32 skip = qCeil(_st.thickness / 2); + //p.drawEllipse(_checkRect.marginsRemoved(QMargins(skip, skip, skip, skip))); + p.drawEllipse(QRectF(_checkRect).marginsRemoved(QMarginsF(_st.thickness / 2, _st.thickness / 2, _st.thickness / 2, _st.thickness / 2))); + + if (checked > 0) { + p.setPen(Qt::NoPen); + if (cbad) { + p.setBrush(color); + } else { + p.setBrush(cnone ? _st.checkFg : (cover ? _st.checkFgOver : _st.checkFgActive)); + } + float64 skip0 = _checkRect.width() / 2., skip1 = _st.checkSkip / 10., checkSkip = skip0 * (1. - checked) + skip1 * checked; + p.drawEllipse(QRectF(_checkRect).marginsRemoved(QMarginsF(checkSkip, checkSkip, checkSkip, checkSkip))); + //int32 fskip = qFloor(checkSkip), cskip = qCeil(checkSkip); + //if (2 * fskip < _checkRect.width()) { + // if (fskip != cskip) { + // p.setOpacity(float64(cskip) - checkSkip); + // p.drawEllipse(_checkRect.marginsRemoved(QMargins(fskip, fskip, fskip, fskip))); + // p.setOpacity(1.); + // } + // if (2 * cskip < _checkRect.width()) { + // p.drawEllipse(_checkRect.marginsRemoved(QMargins(cskip, cskip, cskip, cskip))); + // } + //} + } + + p.setRenderHint(QPainter::HighQualityAntialiasing, false); + } + if (_checkRect.contains(r)) return; + + p.setPen(_st.textFg); + p.setFont(_st.font); + p.drawTextLeft(_st.textPosition.x(), _st.textPosition.y(), width(), _text, _textWidth); +} + +void Radiobutton::onClicked() { + if (_state & StateDisabled) return; + setChecked(!checked()); +} + +void Radiobutton::onStateChange(int oldState, ButtonStateChangeSource source) { + if ((_state & StateOver) && !(oldState & StateOver)) { + a_over.start(1); + _a_over.start(); + } else if (!(_state & StateOver) && (oldState & StateOver)) { + a_over.start(0); + _a_over.start(); + } + if ((_state & StateDisabled) && !(oldState & StateDisabled)) { + setCursor(style::cur_default); + } else if (!(_state & StateDisabled) && (oldState & StateDisabled)) { + setCursor(style::cur_pointer); + } +} + +void Radiobutton::onChanged() { + RadiobuttonGroup *group = reinterpret_cast(_group); + if (checked()) { + int32 uncheck = group->val(); + if (uncheck != _value) { + group->setVal(_value); + for (RadiobuttonGroup::const_iterator i = group->cbegin(), e = group->cend(); i != e; ++i) { + if (i.key()->val() == uncheck) { + i.key()->setChecked(false); + } + } + } + } else if (group->val() == _value) { + setChecked(true); + } +} + +Radiobutton::~Radiobutton() { + reinterpret_cast(_group)->remove(this); } diff --git a/Telegram/SourceFiles/gui/flatcheckbox.h b/Telegram/SourceFiles/gui/flatcheckbox.h index 840c5d818..c0296e405 100644 --- a/Telegram/SourceFiles/gui/flatcheckbox.h +++ b/Telegram/SourceFiles/gui/flatcheckbox.h @@ -59,7 +59,6 @@ private: }; -class RadiobuttonsGroup; class FlatRadiobutton : public FlatCheckbox { Q_OBJECT @@ -77,7 +76,94 @@ public slots: private: - RadiobuttonsGroup *_group; + void *_group; + int32 _value; + +}; + +class Checkbox : public Button { + Q_OBJECT + +public: + + Checkbox(QWidget *parent, const QString &text, bool checked = false, const style::Checkbox &st = st::defaultCheckbox); + + bool checked() const; + void setChecked(bool checked); + + bool animStep_over(float64 ms); + bool animStep_checked(float64 ms); + + void paintEvent(QPaintEvent *e); + +public slots: + + void onClicked(); + void onStateChange(int oldState, ButtonStateChangeSource source); + +signals: + + void changed(); + +private: + + const style::Checkbox &_st; + anim::fvalue a_over, a_checked; + Animation _a_over, _a_checked; + + QString _text, _fullText; + int32 _textWidth; + QRect _checkRect; + + bool _checked; + +}; + +class Radiobutton : public Button { + Q_OBJECT + +public: + + Radiobutton(QWidget *parent, const QString &group, int32 value, const QString &text, bool checked = false, const style::Radiobutton &st = st::defaultRadiobutton); + + bool checked() const; + void setChecked(bool checked); + + int32 val() const { + return _value; + } + + bool animStep_over(float64 ms); + bool animStep_checked(float64 ms); + + void paintEvent(QPaintEvent *e); + + ~Radiobutton(); + +public slots: + + void onClicked(); + void onStateChange(int oldState, ButtonStateChangeSource source); + +signals: + + void changed(); + +private: + + void onChanged(); + + const style::Radiobutton &_st; + anim::fvalue a_over, a_checked; + Animation _a_over, _a_checked; + + QString _text, _fullText; + int32 _textWidth; + QRect _checkRect; + + bool _checked; + + void *_group; int32 _value; }; diff --git a/Telegram/SourceFiles/gui/flatinput.cpp b/Telegram/SourceFiles/gui/flatinput.cpp index aaa1889fc..1e5cfb7e4 100644 --- a/Telegram/SourceFiles/gui/flatinput.cpp +++ b/Telegram/SourceFiles/gui/flatinput.cpp @@ -25,6 +25,9 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org #include "window.h" #include "countryinput.h" +#include "lang.h" +#include "numbers.h" + namespace { template class InputStyle : public QCommonStyle { @@ -45,12 +48,13 @@ namespace { } }; InputStyle _flatInputStyle; + InputStyle _inputFieldStyle; } FlatInput::FlatInput(QWidget *parent, const style::flatInput &st, const QString &pholder, const QString &v) : QLineEdit(v, parent), -_fullph(pholder), _oldtext(v), _fastph(false), _kev(0), _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) { +_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) { resize(_st.width, _st.height); setFont(_st.font->f); @@ -65,7 +69,7 @@ _fullph(pholder), _oldtext(v), _fastph(false), _kev(0), _customUpDown(false), _p if (App::wnd()) connect(this, SIGNAL(selectionChanged()), App::wnd(), SLOT(updateGlobalMenu())); setStyle(&_flatInputStyle); - setTextMargins(0, 0, 0, 0); + QLineEdit::setTextMargins(0, 0, 0, 0); setContentsMargins(0, 0, 0, 0); setAttribute(Qt::WA_AcceptTouchEvents); @@ -77,7 +81,7 @@ void FlatInput::customUpDown(bool custom) { _customUpDown = custom; } -void FlatInput::setTextMargin(const QMargins &mrg) { +void FlatInput::setTextMargins(const QMargins &mrg) { _st.textMrg = mrg; } @@ -277,7 +281,7 @@ QRect FlatInput::placeholderRect() const { return QRect(_st.textMrg.left() + _st.phPos.x(), _st.textMrg.top() + _st.phPos.y(), width() - _st.textMrg.left() - _st.textMrg.right(), height() - _st.textMrg.top() - _st.textMrg.bottom()); } -void FlatInput::correctValue(QKeyEvent *e, const QString &was) { +void FlatInput::correctValue(const QString &was, QString &now) { } void FlatInput::phPrepare(Painter &p) { @@ -286,34 +290,38 @@ void FlatInput::phPrepare(Painter &p) { } void FlatInput::keyPressEvent(QKeyEvent *e) { - QString was(text()); - _kev = e; + QString wasText(_oldtext); + + bool shift = e->modifiers().testFlag(Qt::ShiftModifier), alt = e->modifiers().testFlag(Qt::AltModifier); + bool ctrl = e->modifiers().testFlag(Qt::ControlModifier) || e->modifiers().testFlag(Qt::MetaModifier), ctrlGood = true; if (_customUpDown && (e->key() == Qt::Key_Up || e->key() == Qt::Key_Down)) { e->ignore(); } else { QLineEdit::keyPressEvent(e); } - if (was == text()) { // call correct manually - correctValue(_kev, was); - _oldtext = text(); - if (was != _oldtext) emit changed(); + QString newText(text()); + if (wasText == newText) { // call correct manually + correctValue(wasText, newText); + _oldtext = newText; + if (wasText != _oldtext) emit changed(); updatePlaceholder(); } if (e->key() == Qt::Key_Escape) { emit cancelled(); } else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) { - emit accepted(); + emit submitted(ctrl && shift); } - _kev = 0; } void FlatInput::onTextEdited() { - QString was(_oldtext); - correctValue(_kev, was); - _oldtext = text(); - if (was != _oldtext) emit changed(); + QString wasText(_oldtext), newText(text()); + + correctValue(wasText, newText); + _oldtext = newText; + if (wasText != _oldtext) emit changed(); updatePlaceholder(); + if (App::wnd()) App::wnd()->updateGlobalMenu(); } @@ -339,24 +347,24 @@ void CountryCodeInput::startErasing(QKeyEvent *e) { } void CountryCodeInput::codeSelected(const QString &code) { - QString old(text()); - setText('+' + code); + QString wasText(getLastText()), newText = '+' + code; + setText(newText); _nosignal = true; - correctValue(0, old); + correctValue(wasText, newText); _nosignal = false; emit changed(); } -void CountryCodeInput::correctValue(QKeyEvent *e, const QString &was) { - QString oldText(text()), newText, addToNumber; - int oldPos(cursorPosition()), newPos(-1), oldLen(oldText.length()), start = 0, digits = 5; +void CountryCodeInput::correctValue(const QString &was, QString &now) { + QString newText, addToNumber; + int oldPos(cursorPosition()), newPos(-1), oldLen(now.length()), start = 0, digits = 5; newText.reserve(oldLen + 1); newText += '+'; - if (oldLen && oldText[0] == '+') { + if (oldLen && now[0] == '+') { ++start; } for (int i = start; i < oldLen; ++i) { - QChar ch(oldText[i]); + QChar ch(now[i]); if (ch.isDigit()) { if (!digits || !--digits) { addToNumber += ch; @@ -376,8 +384,10 @@ void CountryCodeInput::correctValue(QKeyEvent *e, const QString &was) { if (newPos < 0 || newPos > newText.length()) { newPos = newText.length(); } - if (newText != oldText) { + if (newText != now) { + now = newText; setText(newText); + updatePlaceholder(); if (newPos != oldPos) { setCursorPosition(newPos); } @@ -390,43 +400,146 @@ void CountryCodeInput::correctValue(QKeyEvent *e, const QString &was) { } } -UsernameInput::UsernameInput(QWidget *parent, const style::flatInput &st, const QString &ph, const QString &val) : FlatInput(parent, st, ph, val) { +PhoneInput::PhoneInput(QWidget *parent, const style::flatInput &st) : FlatInput(parent, st, lang(lng_phone_ph)) { } -void UsernameInput::correctValue(QKeyEvent *e, const QString &was) { - QString oldText(text()), newText; - int32 newPos = cursorPosition(), from, len = oldText.size(); - for (from = 0; from < len; ++from) { - if (!oldText.at(from).isSpace()) { - break; +void PhoneInput::paintEvent(QPaintEvent *e) { + FlatInput::paintEvent(e); + + Painter p(this); + QString t(text()); + if (!pattern.isEmpty() && !t.isEmpty()) { + QString ph = placeholder().mid(t.size()); + if (!ph.isEmpty()) { + p.setClipRect(rect()); + QRect phRect(placeholderRect()); + int tw = phFont()->width(t); + if (tw < phRect.width()) { + phRect.setLeft(phRect.left() + tw); + phPrepare(p); + p.drawText(phRect, ph, style::al_left); + } } - if (newPos > 0) --newPos; } - len -= from; - if (len > MaxUsernameLength) len = MaxUsernameLength + (oldText.at(from) == '@' ? 1 : 0); - for (int32 to = from + len; to > from;) { - --to; - if (!oldText.at(to).isSpace()) { - break; +} + +void PhoneInput::keyPressEvent(QKeyEvent *e) { + if (e->key() == Qt::Key_Backspace && text().isEmpty()) { + emit voidBackspace(e); + } else { + FlatInput::keyPressEvent(e); + } +} + +void PhoneInput::correctValue(const QString &was, QString &now) { + QString newText; + int oldPos(cursorPosition()), newPos(-1), oldLen(now.length()), digitCount = 0; + for (int i = 0; i < oldLen; ++i) { + if (now[i].isDigit()) { + ++digitCount; } - --len; } - newText = oldText.mid(from, len); - if (newText != oldText) { - setText(newText); + if (digitCount > MaxPhoneTailLength) digitCount = MaxPhoneTailLength; + + bool inPart = !pattern.isEmpty(); + int curPart = -1, leftInPart = 0; + newText.reserve(oldLen); + for (int i = 0; i < oldLen; ++i) { + if (i == oldPos && newPos < 0) { + newPos = newText.length(); + } + + QChar ch(now[i]); + if (ch.isDigit()) { + if (!digitCount--) { + break; + } + if (inPart) { + if (leftInPart) { + --leftInPart; + } else { + newText += ' '; + ++curPart; + inPart = curPart < pattern.size(); + leftInPart = inPart ? (pattern.at(curPart) - 1) : 0; + + ++oldPos; + } + } + newText += ch; + } else if (ch == ' ' || ch == '-' || ch == '(' || ch == ')') { + if (inPart) { + if (leftInPart) { + } else { + newText += ch; + ++curPart; + inPart = curPart < pattern.size(); + leftInPart = inPart ? pattern.at(curPart) : 0; + } + } else { + newText += ch; + } + } + } + int32 newlen = newText.size(); + while (newlen > 0 && newText.at(newlen - 1).isSpace()) { + --newlen; + } + if (newlen < newText.size()) newText = newText.mid(0, newlen); + if (newPos < 0) { + newPos = newText.length(); + } + if (newText != now) { + now = newText; + setText(now); + updatePlaceholder(); setCursorPosition(newPos); } } -InputField::InputField(QWidget *parent, const style::InputField &st, const QString &ph, const QString &val) : TWidget(parent), +void PhoneInput::addedToNumber(const QString &added) { + setFocus(); + QString wasText(getLastText()), newText = added + wasText; + setText(newText); + setCursorPosition(added.length()); + correctValue(wasText, newText); + updatePlaceholder(); +} + +void PhoneInput::onChooseCode(const QString &code) { + pattern = phoneNumberParse(code); + if (!pattern.isEmpty() && pattern.at(0) == code.size()) { + pattern.pop_front(); + } else { + pattern.clear(); + } + if (pattern.isEmpty()) { + setPlaceholder(lang(lng_phone_ph)); + } else { + QString ph; + ph.reserve(20); + for (int i = 0, l = pattern.size(); i < l; ++i) { + ph.append(' '); + ph.append(QString(pattern.at(i), QChar(0x2212))); + } + setPlaceholder(ph); + } + QString newText(getLastText()); + correctValue(newText, newText); + setPlaceholderFast(!pattern.isEmpty()); + updatePlaceholder(); +} + +InputArea::InputArea(QWidget *parent, const style::InputArea &st, const QString &ph, const QString &val) : TWidget(parent), +_maxLength(-1), _inner(this, val), _oldtext(val), -_keyEvent(0), _undoAvailable(false), _redoAvailable(false), +_inHeightCheck(false), +_ctrlEnterSubmit(true), -_fakeMargin(0), _customUpDown(false), _placeholderFull(ph), @@ -434,34 +547,32 @@ _placeholderVisible(val.isEmpty()), a_placeholderLeft(_placeholderVisible ? 0 : st.placeholderShift), a_placeholderOpacity(_placeholderVisible ? 1 : 0), a_placeholderFg(st.placeholderFg->c), -_placeholderFgAnim(animFunc(this, &InputField::placeholderFgStep)), -_placeholderShiftAnim(animFunc(this, &InputField::placeholderShiftStep)), +_a_placeholderFg(animFunc(this, &InputArea::animStep_placeholderFg)), +_a_placeholderShift(animFunc(this, &InputArea::animStep_placeholderShift)), a_borderOpacityActive(0), a_borderFg(st.borderFg->c), -_borderAnim(animFunc(this, &InputField::borderStep)), +_a_border(animFunc(this, &InputArea::animStep_border)), _focused(false), _error(false), -_st(&st), +_st(st), _touchPress(false), _touchRightButton(false), _touchMove(false), -_replacingEmojis(false) { +_correcting(false) { _inner.setAcceptRichText(false); - resize(_st->width, _st->height); + resize(_st.width, _st.heightMin); - _inner.setWordWrapMode(QTextOption::NoWrap); - _inner.setLineWrapMode(QTextEdit::NoWrap); + setAttribute(Qt::WA_OpaquePaintEvent); - _inner.setFont(_st->font->f); - _inner.setAlignment(cRtl() ? Qt::AlignRight : Qt::AlignLeft); + _inner.setFont(_st.font->f); - _placeholder = _st->font->elided(_placeholderFull, width() - _st->textMargins.left() - _st->textMargins.right() - _st->placeholderMargins.left() - _st->placeholderMargins.right() - 1); + _placeholder = _st.font->elided(_placeholderFull, width() - _st.textMargins.left() - _st.textMargins.right() - _st.placeholderMargins.left() - _st.placeholderMargins.right() - 1); QPalette p(palette()); - p.setColor(QPalette::Text, _st->textFg->c); + p.setColor(QPalette::Text, _st.textFg->c); setPalette(p); _inner.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); @@ -483,13 +594,683 @@ _replacingEmojis(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); + heightAutoupdated(); +} + +void InputArea::onTouchTimer() { + _touchRightButton = true; +} + +bool InputArea::heightAutoupdated() { + if (_st.heightMin < 0 || _st.heightMax < 0 || _inHeightCheck) return false; + _inHeightCheck = true; + + myEnsureResized(this); + + int newh = qCeil(_inner.document()->size().height()) + _st.textMargins.top() + _st.textMargins.bottom(); + if (newh > _st.heightMax) { + newh = _st.heightMax; + } else if (newh < _st.heightMin) { + newh = _st.heightMin; + } + if (height() != newh) { + resize(width(), newh); + _inHeightCheck = false; + return true; + } + _inHeightCheck = false; + return false; +} + +void InputArea::checkContentHeight() { + if (heightAutoupdated()) { + emit resized(); + } +} + +InputArea::InputAreaInner::InputAreaInner(InputArea *parent, const QString &val) : QTextEdit(parent) { + if (!val.isEmpty()) { + setPlainText(val); + } +} + +bool InputArea::InputAreaInner::viewportEvent(QEvent *e) { + if (e->type() == QEvent::TouchBegin || e->type() == QEvent::TouchUpdate || e->type() == QEvent::TouchEnd || e->type() == QEvent::TouchCancel) { + QTouchEvent *ev = static_cast(e); + if (ev->device()->type() == QTouchDevice::TouchScreen) { + qobject_cast(parentWidget())->touchEvent(ev); + return QTextEdit::viewportEvent(e); + } + } + return QTextEdit::viewportEvent(e); +} + +void InputArea::touchEvent(QTouchEvent *e) { + switch (e->type()) { + case QEvent::TouchBegin: + if (_touchPress || e->touchPoints().isEmpty()) return; + _touchTimer.start(QApplication::startDragTime()); + _touchPress = true; + _touchMove = _touchRightButton = false; + _touchStart = e->touchPoints().cbegin()->screenPos().toPoint(); + break; + + case QEvent::TouchUpdate: + if (!_touchPress || e->touchPoints().isEmpty()) return; + if (!_touchMove && (e->touchPoints().cbegin()->screenPos().toPoint() - _touchStart).manhattanLength() >= QApplication::startDragDistance()) { + _touchMove = true; + } + break; + + case QEvent::TouchEnd: + if (!_touchPress) return; + if (!_touchMove && window()) { + Qt::MouseButton btn(_touchRightButton ? Qt::RightButton : Qt::LeftButton); + QPoint mapped(mapFromGlobal(_touchStart)), winMapped(window()->mapFromGlobal(_touchStart)); + + if (_touchRightButton) { + QContextMenuEvent contextEvent(QContextMenuEvent::Mouse, mapped, _touchStart); + contextMenuEvent(&contextEvent); + } + } + _touchTimer.stop(); + _touchPress = _touchMove = _touchRightButton = false; + break; + + case QEvent::TouchCancel: + _touchPress = false; + _touchTimer.stop(); + break; + } +} + +void InputArea::paintEvent(QPaintEvent *e) { + Painter p(this); + + QRect r(rect().intersected(e->rect())); + p.fillRect(r, st::white->b); + if (_st.border) { + p.fillRect(0, height() - _st.border, width(), _st.border, _st.borderFg->b); + } + if (_st.borderActive && a_borderOpacityActive.current() > 0) { + p.setOpacity(a_borderOpacityActive.current()); + p.fillRect(0, height() - _st.borderActive, width(), _st.borderActive, a_borderFg.current()); + p.setOpacity(1); + } + + bool drawPlaceholder = _placeholderVisible; + if (_a_placeholderShift.animating()) { + p.setOpacity(a_placeholderOpacity.current()); + drawPlaceholder = true; + } + if (drawPlaceholder) { + p.save(); + p.setClipRect(r); + + 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); +} + +void InputArea::startBorderAnimation() { + a_borderFg.start((_error ? _st.borderFgError : (_focused ? _st.borderFgActive : _st.borderFg))->c); + a_borderOpacityActive.start((_error || _focused) ? 1 : 0); + _a_border.start(); +} + +void InputArea::focusInEvent(QFocusEvent *e) { + _inner.setFocus(); +} + +void InputArea::mousePressEvent(QMouseEvent *e) { + _inner.setFocus(); +} + +void InputArea::contextMenuEvent(QContextMenuEvent *e) { + _inner.contextMenuEvent(e); +} + +void InputArea::InputAreaInner::focusInEvent(QFocusEvent *e) { + f()->focusInInner(); + QTextEdit::focusInEvent(e); + emit f()->focused(); +} + +void InputArea::focusInInner() { + if (!_focused) { + _focused = true; + + a_placeholderFg.start(_st.placeholderFgActive->c); + _a_placeholderFg.start(); + + startBorderAnimation(); + } +} + +void InputArea::InputAreaInner::focusOutEvent(QFocusEvent *e) { + f()->focusOutInner(); + QTextEdit::focusOutEvent(e); + emit f()->blurred(); +} + +void InputArea::focusOutInner() { + if (_focused) { + _focused = false; + + a_placeholderFg.start(_st.placeholderFg->c); + _a_placeholderFg.start(); + + startBorderAnimation(); + } +} + +QSize InputArea::sizeHint() const { + return geometry().size(); +} + +QSize InputArea::minimumSizeHint() const { + return geometry().size(); +} + +QString InputArea::getText(int32 start, int32 end) const { + if (end >= 0 && end <= start) return QString(); + + if (start < 0) start = 0; + bool full = (start == 0) && (end < 0); + + QTextDocument *doc(_inner.document()); + QTextBlock from = full ? doc->begin() : doc->findBlock(start), till = (end < 0) ? doc->end() : doc->findBlock(end); + if (till.isValid()) till = till.next(); + + int32 possibleLen = 0; + for (QTextBlock b = from; b != till; b = b.next()) { + possibleLen += b.length(); + } + QString result; + result.reserve(possibleLen + 1); + if (!full && end < 0) { + end = possibleLen; + } + + for (QTextBlock b = from; b != till; b = b.next()) { + for (QTextBlock::Iterator iter = b.begin(); !iter.atEnd(); ++iter) { + QTextFragment fragment(iter.fragment()); + if (!fragment.isValid()) continue; + + int32 p = full ? 0 : fragment.position(), e = full ? 0 : (p + fragment.length()); + if (!full) { + if (p >= end || e <= start) { + continue; + } + } + + QTextCharFormat f = fragment.charFormat(); + QString emojiText; + QString t(fragment.text()); + if (!full) { + if (p < start) { + t = t.mid(start - p, end - start); + } else if (e > end) { + t = t.mid(0, end - p); + } + } + QChar *ub = t.data(), *uc = ub, *ue = uc + t.size(); + for (; uc != ue; ++uc) { + switch (uc->unicode()) { + case 0xfdd0: // QTextBeginningOfFrame + case 0xfdd1: // QTextEndOfFrame + case QChar::ParagraphSeparator: + case QChar::LineSeparator: + *uc = QLatin1Char('\n'); + break; + case QChar::Nbsp: + *uc = QLatin1Char(' '); + break; + case QChar::ObjectReplacementCharacter: + if (emojiText.isEmpty() && f.isImageFormat()) { + QString imageName = static_cast(&f)->name(); + if (imageName.startsWith(qstr("emoji://e."))) { + if (EmojiPtr emoji = emojiFromUrl(imageName)) { + emojiText = emojiString(emoji); + } + } + } + if (uc > ub) result.append(ub, uc - ub); + if (!emojiText.isEmpty()) result.append(emojiText); + ub = uc + 1; + break; + } + } + if (uc > ub) result.append(ub, uc - ub); + } + result.append('\n'); + } + result.chop(1); + return result; +} + +bool InputArea::hasText() const { + QTextDocument *doc(_inner.document()); + QTextBlock from = doc->begin(), till = doc->end(); + + if (from == till) return false; + + for (QTextBlock::Iterator iter = from.begin(); !iter.atEnd(); ++iter) { + QTextFragment fragment(iter.fragment()); + if (!fragment.isValid()) continue; + if (!fragment.text().isEmpty()) return true; + } + return (from.next() != till); +} + +bool InputArea::isUndoAvailable() const { + return _undoAvailable; +} + +bool InputArea::isRedoAvailable() const { + return _redoAvailable; +} + +void InputArea::insertEmoji(EmojiPtr emoji, QTextCursor c) { + QTextImageFormat imageFormat; + int32 ew = ESize + st::emojiPadding * cIntRetinaFactor() * 2, eh = _st.font->height * cIntRetinaFactor(); + imageFormat.setWidth(ew / cIntRetinaFactor()); + imageFormat.setHeight(eh / cIntRetinaFactor()); + imageFormat.setName(qsl("emoji://e.") + QString::number(emojiKey(emoji), 16)); + imageFormat.setVerticalAlignment(QTextCharFormat::AlignBaseline); + + static QString objectReplacement(QChar::ObjectReplacementCharacter); + c.insertText(objectReplacement, imageFormat); +} + +QVariant InputArea::InputAreaInner::loadResource(int type, const QUrl &name) { + QString imageName = name.toDisplayString(); + if (imageName.startsWith(qstr("emoji://e."))) { + if (EmojiPtr emoji = emojiFromUrl(imageName)) { + return QVariant(App::emojiSingle(emoji, f()->_st.font->height)); + } + } + return QVariant(); +} + +void InputArea::processDocumentContentsChange(int position, int charsAdded) { + int32 emojiPosition = 0, emojiLen = 0; + const EmojiData *emoji = 0; + + QTextDocument *doc(_inner.document()); + QTextCursor c(_inner.textCursor()); + c.joinPreviousEditBlock(); + while (true) { + int32 start = position, end = position + charsAdded; + QTextBlock from = doc->findBlock(start), till = doc->findBlock(end); + if (till.isValid()) till = till.next(); + + for (QTextBlock b = from; b != till; b = b.next()) { + for (QTextBlock::Iterator iter = b.begin(); !iter.atEnd(); ++iter) { + QTextFragment fragment(iter.fragment()); + if (!fragment.isValid()) continue; + + int32 fp = fragment.position(), fe = fp + fragment.length(); + if (fp >= end || fe <= start) { + continue; + } + + QString t(fragment.text()); + const QChar *ch = t.constData(), *e = ch + t.size(); + for (; ch != e; ++ch) { + emoji = emojiFromText(ch, e, emojiLen); + if (emoji) { + emojiPosition = fp + (ch - t.constData()); + break; + } + if (ch + 1 < e && ch->isHighSurrogate() && (ch + 1)->isLowSurrogate()) ++ch; + } + if (emoji) break; + } + if (emoji) break; + } + if (emoji) { + if (!_inner.document()->pageSize().isNull()) { + _inner.document()->setPageSize(QSizeF(0, 0)); + } + + QTextCursor c(doc->docHandle(), emojiPosition); + c.setPosition(emojiPosition + emojiLen, QTextCursor::KeepAnchor); + int32 removedUpto = c.position(); + + insertEmoji(emoji, c); + + charsAdded -= removedUpto - position; + position = emojiPosition + 1; + + emoji = 0; + emojiPosition = 0; + } else { + break; + } + } + c.endEditBlock(); +} + +void InputArea::onDocumentContentsChange(int position, int charsRemoved, int charsAdded) { + if (_correcting) return; + + QString oldtext(_oldtext); + QTextCursor(_inner.document()->docHandle(), 0).joinPreviousEditBlock(); + + QTextCursor c(_inner.document()->docHandle(), 0); + c.movePosition(QTextCursor::End); + int pos = c.position(); + + _correcting = true; + if (_maxLength >= 0) { + QTextCursor c(_inner.document()->docHandle(), 0); + c.movePosition(QTextCursor::End); + int32 fullSize = c.position(), toRemove = fullSize - _maxLength; + if (toRemove > 0) { + if (toRemove > charsAdded) { + if (charsAdded) { + c.setPosition(position); + c.setPosition((position + charsAdded), QTextCursor::KeepAnchor); + c.removeSelectedText(); + } + c.setPosition(fullSize - (toRemove - charsAdded)); + c.setPosition(fullSize, QTextCursor::KeepAnchor); + c.removeSelectedText(); + position = _maxLength; + charsAdded = 0; + charsRemoved += toRemove; + } else { + c.setPosition(position + (charsAdded - toRemove)); + c.setPosition(position + charsAdded, QTextCursor::KeepAnchor); + c.removeSelectedText(); + charsAdded -= toRemove; + } + } + } + _correcting = false; + + QTextCursor(_inner.document()->docHandle(), 0).endEditBlock(); + + if (_inner.document()->availableRedoSteps() > 0) return; + + const int takeBack = 3; + + position -= takeBack; + charsAdded += takeBack; + if (position < 0) { + charsAdded += position; + position = 0; + } + if (charsAdded <= 0) return; + + _correcting = true; + QSizeF s = _inner.document()->pageSize(); + processDocumentContentsChange(position, charsAdded); + if (_inner.document()->pageSize() != s) { + _inner.document()->setPageSize(s); + } + _correcting = false; +} + +void InputArea::onDocumentContentsChanged() { + if (_correcting) return; + + if (_error) { + _error = false; + startBorderAnimation(); + } + + QString curText(getText()); + if (_oldtext != curText) { + _oldtext = curText; + emit changed(); + checkContentHeight(); + } + updatePlaceholder(); + if (App::wnd()) App::wnd()->updateGlobalMenu(); +} + +void InputArea::onUndoAvailable(bool avail) { + _undoAvailable = avail; + if (App::wnd()) App::wnd()->updateGlobalMenu(); +} + +void InputArea::onRedoAvailable(bool avail) { + _redoAvailable = avail; + if (App::wnd()) App::wnd()->updateGlobalMenu(); +} + +bool InputArea::animStep_placeholderFg(float64 ms) { + float dt = ms / _st.duration; + bool res = true; + if (dt >= 1) { + res = false; + a_placeholderFg.finish(); + } else { + a_placeholderFg.update(dt, anim::linear); + } + update(); + return res; +} + +bool InputArea::animStep_placeholderShift(float64 ms) { + float dt = ms / _st.duration; + bool res = true; + if (dt >= 1) { + res = false; + a_placeholderLeft.finish(); + a_placeholderOpacity.finish(); + } else { + a_placeholderLeft.update(dt, anim::linear); + a_placeholderOpacity.update(dt, anim::linear); + } + update(); + return res; +} + +bool InputArea::animStep_border(float64 ms) { + float dt = ms / _st.duration; + bool res = true; + if (dt >= 1) { + res = false; + a_borderFg.finish(); + a_borderOpacityActive.finish(); + } else { + a_borderFg.update(dt, anim::linear); + a_borderOpacityActive.update(dt, anim::linear); + } + update(); + return res; +} + +void InputArea::updatePlaceholder() { + bool placeholderVisible = _oldtext.isEmpty(); + if (placeholderVisible != _placeholderVisible) { + _placeholderVisible = placeholderVisible; + + a_placeholderLeft.start(_placeholderVisible ? 0 : _st.placeholderShift); + a_placeholderOpacity.start(_placeholderVisible ? 1 : 0); + _a_placeholderShift.start(); + } +} + +QMimeData *InputArea::InputAreaInner::createMimeDataFromSelection() const { + QMimeData *result = new QMimeData(); + QTextCursor c(textCursor()); + int32 start = c.selectionStart(), end = c.selectionEnd(); + if (end > start) { + result->setText(f()->getText(start, end)); + } + return result; +} + +void InputArea::customUpDown(bool custom) { + _customUpDown = custom; +} + +void InputArea::InputAreaInner::keyPressEvent(QKeyEvent *e) { + bool shift = e->modifiers().testFlag(Qt::ShiftModifier), alt = e->modifiers().testFlag(Qt::AltModifier); + bool macmeta = (cPlatform() == dbipMac) && e->modifiers().testFlag(Qt::ControlModifier) && !e->modifiers().testFlag(Qt::MetaModifier) && !e->modifiers().testFlag(Qt::AltModifier); + bool ctrl = e->modifiers().testFlag(Qt::ControlModifier) || e->modifiers().testFlag(Qt::MetaModifier), ctrlGood = (ctrl && f()->_ctrlEnterSubmit) || (!ctrl && !shift && !f()->_ctrlEnterSubmit) || (ctrl && shift); + bool enter = (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return); + + if (macmeta && e->key() == Qt::Key_Backspace) { + QTextCursor tc(textCursor()), start(tc); + start.movePosition(QTextCursor::StartOfLine); + tc.setPosition(start.position(), QTextCursor::KeepAnchor); + tc.removeSelectedText(); + } else if (enter && ctrlGood) { + emit f()->submitted(ctrl && shift); + } else if (e->key() == Qt::Key_Escape) { + e->ignore(); + emit f()->cancelled(); + } else if (e->key() == Qt::Key_Tab || e->key() == Qt::Key_Backtab) { + if (alt || ctrl) { + e->ignore(); + } else { + if (!focusNextPrevChild(e->key() == Qt::Key_Tab && !shift)) { + e->ignore(); + } + } + } else if (e->key() == Qt::Key_Search || e == QKeySequence::Find) { + e->ignore(); + } else if (f()->_customUpDown && (e->key() == Qt::Key_Up || e->key() == Qt::Key_Down)) { + e->ignore(); + } else { + QTextCursor tc(textCursor()); + if (enter && ctrl) { + e->setModifiers(e->modifiers() & ~Qt::ControlModifier); + } + QTextEdit::keyPressEvent(e); + if (tc == textCursor()) { + bool check = false; + if (e->key() == Qt::Key_PageUp || e->key() == Qt::Key_Up) { + tc.movePosition(QTextCursor::Start, e->modifiers().testFlag(Qt::ShiftModifier) ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor); + check = true; + } else if (e->key() == Qt::Key_PageDown || e->key() == Qt::Key_Down) { + tc.movePosition(QTextCursor::End, e->modifiers().testFlag(Qt::ShiftModifier) ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor); + check = true; + } + if (check) { + if (tc == textCursor()) { + e->ignore(); + } else { + setTextCursor(tc); + } + } + } + } +} + +void InputArea::InputAreaInner::paintEvent(QPaintEvent *e) { + return QTextEdit::paintEvent(e); +} + +void InputArea::resizeEvent(QResizeEvent *e) { + _placeholder = _st.font->elided(_placeholderFull, width() - _st.textMargins.left() - _st.textMargins.right() - _st.placeholderMargins.left() - _st.placeholderMargins.right() - 1); + _inner.setGeometry(rect().marginsRemoved(_st.textMargins)); + TWidget::resizeEvent(e); + checkContentHeight(); +} + +void InputArea::showError() { + _error = true; + if (hasFocus()) { + startBorderAnimation(); + } else { + _inner.setFocus(); + } +} + +InputField::InputField(QWidget *parent, const style::InputField &st, const QString &ph, const QString &val) : TWidget(parent), +_maxLength(-1), +_inner(this, val), +_oldtext(val), + +_undoAvailable(false), +_redoAvailable(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, &InputField::animStep_placeholderFg)), +_a_placeholderShift(animFunc(this, &InputField::animStep_placeholderShift)), + +a_borderOpacityActive(0), +a_borderFg(st.borderFg->c), +_a_border(animFunc(this, &InputField::animStep_border)), + +_focused(false), _error(false), + +_st(st), + +_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); + + _inner.setFont(_st.font->f); + _inner.setAlignment(_st.textAlign); + + _placeholder = _st.font->elided(_placeholderFull, width() - _st.textMargins.left() - _st.textMargins.right() - _st.placeholderMargins.left() - _st.placeholderMargins.right() - 1); + + QPalette p(palette()); + p.setColor(QPalette::Text, _st.textFg->c); + setPalette(p); + + _inner.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + _inner.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + _inner.setFrameStyle(QFrame::NoFrame | QFrame::Plain); + _inner.viewport()->setAutoFillBackground(false); + + _inner.setContentsMargins(0, 0, 0, 0); + _inner.document()->setDocumentMargin(0); + + setAttribute(Qt::WA_AcceptTouchEvents); + _inner.viewport()->setAttribute(Qt::WA_AcceptTouchEvents); + _touchTimer.setSingleShot(true); + connect(&_touchTimer, SIGNAL(timeout()), this, SLOT(onTouchTimer())); + + connect(_inner.document(), SIGNAL(contentsChange(int, int, int)), this, SLOT(onDocumentContentsChange(int, int, int))); + connect(_inner.document(), SIGNAL(contentsChanged()), this, SLOT(onDocumentContentsChanged())); + 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); } void InputField::onTouchTimer() { _touchRightButton = true; } -InputField::InputFieldInner::InputFieldInner(InputField *parent, const QString &val) : QTextEdit(val, parent) { +InputField::InputFieldInner::InputFieldInner(InputField *parent, const QString &val) : QTextEdit(parent) { + if (!val.isEmpty()) { + setPlainText(val); + } } bool InputField::InputFieldInner::viewportEvent(QEvent *e) { @@ -542,29 +1323,25 @@ void InputField::touchEvent(QTouchEvent *e) { } } -int32 InputField::fakeMargin() const { - return _fakeMargin; -} - void InputField::paintEvent(QPaintEvent *e) { Painter p(this); QRect r(rect().intersected(e->rect())); p.fillRect(r, st::white->b); - if (_st->border) { - p.fillRect(0, height() - _st->border, width(), _st->border, _st->borderFg->b); + if (_st.border) { + p.fillRect(0, height() - _st.border, width(), _st.border, _st.borderFg->b); } - if (_st->borderActive && a_borderOpacityActive.current() > 0) { + if (_st.borderActive && a_borderOpacityActive.current() > 0) { p.setOpacity(a_borderOpacityActive.current()); - p.fillRect(0, height() - _st->borderActive, width(), _st->borderActive, a_borderFg.current()); + p.fillRect(0, height() - _st.borderActive, width(), _st.borderActive, a_borderFg.current()); p.setOpacity(1); } - if (_st->iconSprite.pxWidth()) { - p.drawSpriteLeft(_st->iconPosition, width(), _st->iconSprite); + if (_st.iconSprite.pxWidth()) { + p.drawSpriteLeft(_st.iconPosition, width(), _st.iconSprite); } bool drawPlaceholder = _placeholderVisible; - if (_placeholderShiftAnim.animating()) { + if (_a_placeholderShift.animating()) { p.setOpacity(a_placeholderOpacity.current()); drawPlaceholder = true; } @@ -572,19 +1349,25 @@ void InputField::paintEvent(QPaintEvent *e) { p.save(); p.setClipRect(r); - QRect r(rect().marginsRemoved(_st->textMargins + _st->placeholderMargins)); + 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->f); + p.setFont(_st.font); p.setPen(a_placeholderFg.current()); - p.drawText(r, _placeholder, _st->placeholderAlign); + p.drawText(r, _placeholder, _st.placeholderAlign); p.restore(); } TWidget::paintEvent(e); } +void InputField::startBorderAnimation() { + a_borderFg.start((_error ? _st.borderFgError : (_focused ? _st.borderFgActive : _st.borderFg))->c); + a_borderOpacityActive.start((_error || _focused) ? 1 : 0); + _a_border.start(); +} + void InputField::focusInEvent(QFocusEvent *e) { _inner.setFocus(); } @@ -607,12 +1390,10 @@ void InputField::focusInInner() { if (!_focused) { _focused = true; - a_placeholderFg.start(_st->placeholderFgActive->c); - _placeholderFgAnim.start(); + a_placeholderFg.start(_st.placeholderFgActive->c); + _a_placeholderFg.start(); - a_borderFg.start((_error ? _st->borderFgError : _st->borderFgActive)->c); - a_borderOpacityActive.start(1); - _borderAnim.start(); + startBorderAnimation(); } } @@ -626,12 +1407,10 @@ void InputField::focusOutInner() { if (_focused) { _focused = false; - a_placeholderFg.start(_st->placeholderFg->c); - _placeholderFgAnim.start(); + a_placeholderFg.start(_st.placeholderFg->c); + _a_placeholderFg.start(); - a_borderFg.start((_error ? _st->borderFgError : _st->borderFg)->c); - a_borderOpacityActive.start(_error ? 1 : 0); - _borderAnim.start(); + startBorderAnimation(); } } @@ -744,7 +1523,7 @@ bool InputField::isRedoAvailable() const { void InputField::insertEmoji(EmojiPtr emoji, QTextCursor c) { QTextImageFormat imageFormat; - int32 ew = ESize + st::emojiPadding * cIntRetinaFactor() * 2, eh = _st->font->height * cIntRetinaFactor(); + int32 ew = ESize + st::emojiPadding * cIntRetinaFactor() * 2, eh = _st.font->height * cIntRetinaFactor(); imageFormat.setWidth(ew / cIntRetinaFactor()); imageFormat.setHeight(eh / cIntRetinaFactor()); imageFormat.setName(qsl("emoji://e.") + QString::number(emojiKey(emoji), 16)); @@ -758,7 +1537,7 @@ QVariant InputField::InputFieldInner::loadResource(int type, const QUrl &name) { QString imageName = name.toDisplayString(); if (imageName.startsWith(qstr("emoji://e."))) { if (EmojiPtr emoji = emojiFromUrl(imageName)) { - return QVariant(App::emojiSingle(emoji, f()->_st->font->height)); + return QVariant(App::emojiSingle(emoji, f()->_st.font->height)); } } return QVariant(); @@ -838,17 +1617,6 @@ void InputField::processDocumentContentsChange(int position, int charsAdded) { insertEmoji(emoji, c); - for (Insertions::iterator i = _insertions.begin(), e = _insertions.end(); i != e; ++i) { - if (i->first >= removedUpto) { - i->first -= removedUpto - emojiPosition - 1; - } else if (i->first >= emojiPosition) { - i->second -= removedUpto - emojiPosition; - i->first = emojiPosition + 1; - } else if (i->first + i->second > emojiPosition + 1) { - i->second -= qMin(removedUpto, i->first + i->second) - emojiPosition; - } - } - charsAdded -= removedUpto - position; position = emojiPosition + 1; @@ -862,7 +1630,44 @@ void InputField::processDocumentContentsChange(int position, int charsAdded) { } void InputField::onDocumentContentsChange(int position, int charsRemoved, int charsAdded) { - if (_replacingEmojis) return; + if (_correcting) return; + + QString oldtext(_oldtext); + QTextCursor(_inner.document()->docHandle(), 0).joinPreviousEditBlock(); + + QTextCursor c(_inner.document()->docHandle(), 0); + c.movePosition(QTextCursor::End); + int pos = c.position(); + + _correcting = true; + if (_maxLength >= 0) { + QTextCursor c(_inner.document()->docHandle(), 0); + c.movePosition(QTextCursor::End); + int32 fullSize = c.position(), toRemove = fullSize - _maxLength; + if (toRemove > 0) { + if (toRemove > charsAdded) { + if (charsAdded) { + c.setPosition(position); + c.setPosition((position + charsAdded), QTextCursor::KeepAnchor); + c.removeSelectedText(); + } + c.setPosition(fullSize - (toRemove - charsAdded)); + c.setPosition(fullSize, QTextCursor::KeepAnchor); + c.removeSelectedText(); + position = _maxLength; + charsAdded = 0; + charsRemoved += toRemove; + } else { + c.setPosition(position + (charsAdded - toRemove)); + c.setPosition(position + charsAdded, QTextCursor::KeepAnchor); + c.removeSelectedText(); + charsAdded -= toRemove; + } + } + } + _correcting = false; + + QTextCursor(_inner.document()->docHandle(), 0).endEditBlock(); if (_inner.document()->availableRedoSteps() > 0) return; @@ -876,39 +1681,21 @@ void InputField::onDocumentContentsChange(int position, int charsRemoved, int ch } if (charsAdded <= 0) return; - // _insertions.push_back(Insertion(position, charsAdded)); - _replacingEmojis = true; + _correcting = true; QSizeF s = _inner.document()->pageSize(); processDocumentContentsChange(position, charsAdded); if (_inner.document()->pageSize() != s) { _inner.document()->setPageSize(s); } - _replacingEmojis = false; + _correcting = false; } void InputField::onDocumentContentsChanged() { - if (_replacingEmojis) return; + if (_correcting) return; - if (!_insertions.isEmpty()) { - if (_inner.document()->availableRedoSteps() > 0) { - _insertions.clear(); - } else { - _replacingEmojis = true; - QSizeF s = _inner.document()->pageSize(); - - do { - Insertion i = _insertions.front(); - _insertions.pop_front(); - if (i.second > 0) { - processDocumentContentsChange(i.first, i.second); - } - } while (!_insertions.isEmpty()); - - if (_inner.document()->pageSize() != s) { - _inner.document()->setPageSize(s); - } - _replacingEmojis = false; - } + if (_error) { + _error = false; + startBorderAnimation(); } QString curText(getText()); @@ -930,8 +1717,8 @@ void InputField::onRedoAvailable(bool avail) { if (App::wnd()) App::wnd()->updateGlobalMenu(); } -bool InputField::placeholderFgStep(float64 ms) { - float dt = ms / _st->duration; +bool InputField::animStep_placeholderFg(float64 ms) { + float dt = ms / _st.duration; bool res = true; if (dt >= 1) { res = false; @@ -943,8 +1730,8 @@ bool InputField::placeholderFgStep(float64 ms) { return res; } -bool InputField::placeholderShiftStep(float64 ms) { - float dt = ms / _st->duration; +bool InputField::animStep_placeholderShift(float64 ms) { + float dt = ms / _st.duration; bool res = true; if (dt >= 1) { res = false; @@ -958,8 +1745,8 @@ bool InputField::placeholderShiftStep(float64 ms) { return res; } -bool InputField::borderStep(float64 ms) { - float dt = ms / _st->duration; +bool InputField::animStep_border(float64 ms) { + float dt = ms / _st.duration; bool res = true; if (dt >= 1) { res = false; @@ -972,24 +1759,18 @@ bool InputField::borderStep(float64 ms) { update(); return res; } -const QString &InputField::getLastText() const { - return _oldtext; -} void InputField::updatePlaceholder() { bool placeholderVisible = _oldtext.isEmpty(); if (placeholderVisible != _placeholderVisible) { _placeholderVisible = placeholderVisible; - a_placeholderLeft.start(_placeholderVisible ? 0 : _st->placeholderShift); + a_placeholderLeft.start(_placeholderVisible ? 0 : _st.placeholderShift); a_placeholderOpacity.start(_placeholderVisible ? 1 : 0); - _placeholderShiftAnim.start(); + _a_placeholderShift.start(); } } -void InputField::correctValue(QKeyEvent *e, const QString &was) { -} - QMimeData *InputField::InputFieldInner::createMimeDataFromSelection() const { QMimeData *result = new QMimeData(); QTextCursor c(textCursor()); @@ -1005,7 +1786,7 @@ void InputField::customUpDown(bool custom) { } void InputField::InputFieldInner::keyPressEvent(QKeyEvent *e) { - bool shift = e->modifiers().testFlag(Qt::ShiftModifier); + bool shift = e->modifiers().testFlag(Qt::ShiftModifier), alt = e->modifiers().testFlag(Qt::AltModifier); bool macmeta = (cPlatform() == dbipMac) && e->modifiers().testFlag(Qt::ControlModifier) && !e->modifiers().testFlag(Qt::MetaModifier) && !e->modifiers().testFlag(Qt::AltModifier); bool ctrl = e->modifiers().testFlag(Qt::ControlModifier) || e->modifiers().testFlag(Qt::MetaModifier), ctrlGood = true; bool enter = (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return); @@ -1018,12 +1799,15 @@ void InputField::InputFieldInner::keyPressEvent(QKeyEvent *e) { } else if (enter && ctrlGood) { emit f()->submitted(ctrl && shift); } else if (e->key() == Qt::Key_Escape) { + e->ignore(); emit f()->cancelled(); - } else if (e->key() == Qt::Key_Tab || (ctrl && e->key() == Qt::Key_Backtab)) { - if (ctrl) { + } else if (e->key() == Qt::Key_Tab || e->key() == Qt::Key_Backtab) { + if (alt || ctrl) { e->ignore(); } else { - emit f()->tabbed(); + if (!focusNextPrevChild(e->key() == Qt::Key_Tab && !shift)) { + e->ignore(); + } } } else if (e->key() == Qt::Key_Search || e == QKeySequence::Find) { e->ignore(); @@ -1060,7 +1844,466 @@ void InputField::InputFieldInner::paintEvent(QPaintEvent *e) { } void InputField::resizeEvent(QResizeEvent *e) { - _placeholder = _st->font->elided(_placeholderFull, width() - _st->textMargins.left() - _st->textMargins.right() - _st->placeholderMargins.left() - _st->placeholderMargins.right() - 1); - _inner.setGeometry(rect().marginsRemoved(_st->textMargins)); + _placeholder = _st.font->elided(_placeholderFull, width() - _st.textMargins.left() - _st.textMargins.right() - _st.placeholderMargins.left() - _st.placeholderMargins.right() - 1); + _inner.setGeometry(rect().marginsRemoved(_st.textMargins)); TWidget::resizeEvent(e); } + +void InputField::showError() { + _error = true; + if (hasFocus()) { + startBorderAnimation(); + } else { + _inner.setFocus(); + } +} + +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), + +_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)), + +a_borderOpacityActive(0), +a_borderFg(st.borderFg->c), +_a_border(animFunc(this, &MaskedInputField::animStep_border)), + +_focused(false), _error(false), + +_touchPress(false), +_touchRightButton(false), +_touchMove(false) { + resize(_st.width, _st.height); + + setFont(_st.font->f); + setAlignment(_st.textAlign); + + QPalette p(palette()); + p.setColor(QPalette::Text, _st.textFg->c); + setPalette(p); + + setAttribute(Qt::WA_OpaquePaintEvent); + + connect(this, SIGNAL(textChanged(const QString&)), this, SLOT(onTextChange(const QString&))); + connect(this, SIGNAL(cursorPositionChanged(int,int)), this, SLOT(onCursorPositionChanged(int,int))); + + connect(this, SIGNAL(textEdited(const QString&)), this, SLOT(onTextEdited())); + if (App::wnd()) connect(this, SIGNAL(selectionChanged()), App::wnd(), SLOT(updateGlobalMenu())); + + 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())); + + setTextMargins(_st.textMargins); + updatePlaceholder(); +} + +void MaskedInputField::customUpDown(bool custom) { + _customUpDown = custom; +} + +void MaskedInputField::setTextMargins(const QMargins &mrg) { + _textMargins = mrg; + _placeholder = _st.font->elided(_placeholderFull, width() - _textMargins.left() - _textMargins.right() - _st.placeholderMargins.left() - _st.placeholderMargins.right() - 1); +} + +void MaskedInputField::onTouchTimer() { + _touchRightButton = true; +} + +bool MaskedInputField::event(QEvent *e) { + if (e->type() == QEvent::TouchBegin || e->type() == QEvent::TouchUpdate || e->type() == QEvent::TouchEnd || e->type() == QEvent::TouchCancel) { + QTouchEvent *ev = static_cast(e); + if (ev->device()->type() == QTouchDevice::TouchScreen) { + touchEvent(ev); + return QLineEdit::event(e); + } + } + return QLineEdit::event(e); +} + +void MaskedInputField::touchEvent(QTouchEvent *e) { + switch (e->type()) { + case QEvent::TouchBegin: + if (_touchPress || e->touchPoints().isEmpty()) return; + _touchTimer.start(QApplication::startDragTime()); + _touchPress = true; + _touchMove = _touchRightButton = false; + _touchStart = e->touchPoints().cbegin()->screenPos().toPoint(); + break; + + case QEvent::TouchUpdate: + if (!_touchPress || e->touchPoints().isEmpty()) return; + if (!_touchMove && (e->touchPoints().cbegin()->screenPos().toPoint() - _touchStart).manhattanLength() >= QApplication::startDragDistance()) { + _touchMove = true; + } + break; + + case QEvent::TouchEnd: + if (!_touchPress) return; + if (!_touchMove && window()) { + Qt::MouseButton btn(_touchRightButton ? Qt::RightButton : Qt::LeftButton); + QPoint mapped(mapFromGlobal(_touchStart)), winMapped(window()->mapFromGlobal(_touchStart)); + + if (_touchRightButton) { + QContextMenuEvent contextEvent(QContextMenuEvent::Mouse, mapped, _touchStart); + contextMenuEvent(&contextEvent); + } + } + _touchTimer.stop(); + _touchPress = _touchMove = _touchRightButton = false; + break; + + case QEvent::TouchCancel: + _touchPress = false; + _touchTimer.stop(); + break; + } +} + +QRect MaskedInputField::getTextRect() const { + return rect().marginsRemoved(_textMargins + QMargins(-2, -1, -2, -1)); +} + +void MaskedInputField::paintEvent(QPaintEvent *e) { + Painter p(this); + + QRect r(rect().intersected(e->rect())); + p.fillRect(r, st::white->b); + if (_st.border) { + p.fillRect(0, height() - _st.border, width(), _st.border, _st.borderFg->b); + } + if (_st.borderActive && a_borderOpacityActive.current() > 0) { + p.setOpacity(a_borderOpacityActive.current()); + p.fillRect(0, height() - _st.borderActive, width(), _st.borderActive, a_borderFg.current()); + p.setOpacity(1); + } + if (_st.iconSprite.pxWidth()) { + p.drawSpriteLeft(_st.iconPosition, width(), _st.iconSprite); + } + + p.setClipRect(r); + paintPlaceholder(p); + + QLineEdit::paintEvent(e); +} + +void MaskedInputField::startBorderAnimation() { + a_borderFg.start((_error ? _st.borderFgError : (_focused ? _st.borderFgActive : _st.borderFg))->c); + a_borderOpacityActive.start((_error || _focused) ? 1 : 0); + _a_border.start(); +} + +void MaskedInputField::focusInEvent(QFocusEvent *e) { + if (!_focused) { + _focused = true; + + a_placeholderFg.start(_st.placeholderFgActive->c); + _a_placeholderFg.start(); + + startBorderAnimation(); + } + QLineEdit::focusInEvent(e); + emit focused(); +} + +void MaskedInputField::focusOutEvent(QFocusEvent *e) { + if (_focused) { + _focused = false; + + a_placeholderFg.start(_st.placeholderFg->c); + _a_placeholderFg.start(); + + startBorderAnimation(); + } + QLineEdit::focusOutEvent(e); + emit blurred(); +} + +void MaskedInputField::resizeEvent(QResizeEvent *e) { + _placeholder = _st.font->elided(_placeholderFull, width() - _textMargins.left() - _textMargins.right() - _st.placeholderMargins.left() - _st.placeholderMargins.right() - 1); + QLineEdit::resizeEvent(e); +} + +void MaskedInputField::showError() { + _error = true; + if (hasFocus()) { + startBorderAnimation(); + } else { + setFocus(); + } +} + +QSize MaskedInputField::sizeHint() const { + return geometry().size(); +} + +QSize MaskedInputField::minimumSizeHint() const { + return geometry().size(); +} + +bool MaskedInputField::animStep_placeholderFg(float64 ms) { + float dt = ms / _st.duration; + bool res = true; + if (dt >= 1) { + res = false; + a_placeholderFg.finish(); + } else { + a_placeholderFg.update(dt, anim::linear); + } + update(); + return res; +} + +bool MaskedInputField::animStep_placeholderShift(float64 ms) { + float dt = ms / _st.duration; + bool res = true; + if (dt >= 1) { + res = false; + a_placeholderLeft.finish(); + a_placeholderOpacity.finish(); + } else { + a_placeholderLeft.update(dt, anim::linear); + a_placeholderOpacity.update(dt, anim::linear); + } + update(); + return res; +} + +bool MaskedInputField::animStep_border(float64 ms) { + float dt = ms / _st.duration; + bool res = true; + if (dt >= 1) { + res = false; + a_borderFg.finish(); + a_borderOpacityActive.finish(); + } else { + a_borderFg.update(dt, anim::linear); + a_borderOpacityActive.update(dt, anim::linear); + } + update(); + return res; +} + +void MaskedInputField::setPlaceholder(const QString &placeholder) { + _placeholderFull = placeholder; + resizeEvent(0); + update(); +} + +void MaskedInputField::setPlaceholderFast(bool fast) { + _placeholderFast = fast; + if (_placeholderFast) { + a_placeholderLeft = anim::ivalue(_placeholderVisible ? 0 : _st.placeholderShift, _placeholderVisible ? 0 : _st.placeholderShift); + a_placeholderOpacity = anim::fvalue(_placeholderVisible ? 1 : 0, _placeholderVisible ? 1 : 0); + update(); + } +} + +void MaskedInputField::updatePlaceholder() { + bool placeholderVisible = _oldtext.isEmpty(); + if (placeholderVisible != _placeholderVisible) { + _placeholderVisible = placeholderVisible; + + if (_placeholderFast) { + a_placeholderLeft = anim::ivalue(_placeholderVisible ? 0 : _st.placeholderShift, _placeholderVisible ? 0 : _st.placeholderShift); + a_placeholderOpacity = anim::fvalue(_placeholderVisible ? 1 : 0, _placeholderVisible ? 1 : 0); + update(); + } else { + a_placeholderLeft.start(_placeholderVisible ? 0 : _st.placeholderShift); + a_placeholderOpacity.start(_placeholderVisible ? 1 : 0); + _a_placeholderShift.start(); + } + } +} + +const QString &MaskedInputField::placeholder() const { + return _placeholderFull; +} + +QRect MaskedInputField::placeholderRect() const { + return rect().marginsRemoved(_st.textMargins + _st.placeholderMargins); +} + +void MaskedInputField::correctValue(const QString &was, int32 wasCursor, QString &now, int32 &nowCursor) { +} + +void MaskedInputField::paintPlaceholder(Painter &p) { + bool drawPlaceholder = _placeholderVisible; + if (_a_placeholderShift.animating()) { + p.setOpacity(a_placeholderOpacity.current()); + drawPlaceholder = true; + } + if (drawPlaceholder) { + p.save(); + + QRect phRect(placeholderRect()); + phRect.moveLeft(phRect.left() + a_placeholderLeft.current()); + if (rtl()) phRect.moveLeft(width() - phRect.left() - phRect.width()); + + placeholderPreparePaint(p); + p.drawText(phRect, _placeholder, _st.placeholderAlign); + + p.restore(); + } +} + +void MaskedInputField::placeholderPreparePaint(Painter &p) { + p.setFont(_st.font); + p.setPen(a_placeholderFg.current()); +} + +void MaskedInputField::keyPressEvent(QKeyEvent *e) { + QString wasText(_oldtext); + int32 wasCursor(_oldcursor); + + bool shift = e->modifiers().testFlag(Qt::ShiftModifier), alt = e->modifiers().testFlag(Qt::AltModifier); + bool ctrl = e->modifiers().testFlag(Qt::ControlModifier) || e->modifiers().testFlag(Qt::MetaModifier), ctrlGood = true; + if (_customUpDown && (e->key() == Qt::Key_Up || e->key() == Qt::Key_Down)) { + e->ignore(); + } else { + QLineEdit::keyPressEvent(e); + } + + QString newText(text()); + int32 newCursor(cursorPosition()); + if (wasText == newText && wasCursor == newCursor) { // call correct manually + correctValue(wasText, wasCursor, newText, newCursor); + _oldtext = newText; + _oldcursor = newCursor; + if (wasText != _oldtext) emit changed(); + updatePlaceholder(); + } + if (e->key() == Qt::Key_Escape) { + e->ignore(); + emit cancelled(); + } else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) { + emit submitted(ctrl && shift); + } +} + +void MaskedInputField::onTextEdited() { + QString wasText(_oldtext), newText(text()); + int32 wasCursor(_oldcursor), newCursor(cursorPosition()); + + correctValue(wasText, wasCursor, newText, newCursor); + _oldtext = newText; + _oldcursor = newCursor; + if (wasText != _oldtext) emit changed(); + updatePlaceholder(); + + if (App::wnd()) App::wnd()->updateGlobalMenu(); +} + +void MaskedInputField::onTextChange(const QString &text) { + _oldtext = text; + if (_error) { + _error = false; + startBorderAnimation(); + } + if (App::wnd()) App::wnd()->updateGlobalMenu(); +} + +void MaskedInputField::onCursorPositionChanged(int oldPosition, int position) { + _oldcursor = position; +} + +PortInput::PortInput(QWidget *parent, const style::InputField &st, const QString &ph, const QString &val) : MaskedInputField(parent, st, ph, val) { + if (!val.toInt() || val.toInt() > 65535) { + setText(QString()); + } +} + +void PortInput::correctValue(const QString &was, int32 wasCursor, QString &now, int32 &nowCursor) { + QString newText; + newText.reserve(now.size()); + int32 newCursor = nowCursor; + for (int32 i = 0, l = now.size(); i < l; ++i) { + if (now.at(i).isDigit()) { + newText.append(now.at(i)); + } else if (i < nowCursor) { + --newCursor; + } + } + if (!newText.toInt()) { + newText = QString(); + newCursor = 0; + } else if (newText.toInt() > 65535) { + newText = was; + newCursor = wasCursor; + } + if (newText != now) { + now = newText; + setText(newText); + } + if (newCursor != nowCursor) { + nowCursor = newCursor; + setCursorPosition(newCursor); + } +} + +UsernameInput::UsernameInput(QWidget *parent, const style::InputField &st, const QString &ph, const QString &val, bool isLink) : MaskedInputField(parent, st, ph, val), +_linkPlaceholder(isLink ? qsl("telegram.me/") : QString()) { + if (!_linkPlaceholder.isEmpty()) { + setTextMargins(style::margins(_st.textMargins.left() + _st.font->width(_linkPlaceholder), _st.textMargins.top(), _st.textMargins.right(), _st.textMargins.bottom())); + } +} + +void UsernameInput::paintPlaceholder(Painter &p) { + if (_linkPlaceholder.isEmpty()) { + MaskedInputField::paintPlaceholder(p); + } else { + p.setFont(_st.font); + p.setPen(_st.placeholderFg); + p.drawText(QRect(_st.textMargins.left(), _st.textMargins.top(), width(), height() - _st.textMargins.top() - _st.textMargins.bottom()), _linkPlaceholder, style::al_topleft); + } +} + +void UsernameInput::correctValue(const QString &was, int32 wasCursor, QString &now, int32 &nowCursor) { + QString newText; + int32 newCursor = nowCursor, from, len = now.size(); + for (from = 0; from < len; ++from) { + if (!now.at(from).isSpace()) { + break; + } + if (newCursor > 0) --newCursor; + } + len -= from; + if (len > MaxUsernameLength) len = MaxUsernameLength + (now.at(from) == '@' ? 1 : 0); + for (int32 to = from + len; to > from;) { + --to; + if (!now.at(to).isSpace()) { + break; + } + --len; + } + newText = now.mid(from, len); + if (newCursor > len) { + newCursor = len; + } + if (newText != now) { + now = newText; + setText(newText); + } + if (newCursor != nowCursor) { + nowCursor = newCursor; + setCursorPosition(newCursor); + } +} diff --git a/Telegram/SourceFiles/gui/flatinput.h b/Telegram/SourceFiles/gui/flatinput.h index f9ddf0fe1..3f506c52a 100644 --- a/Telegram/SourceFiles/gui/flatinput.h +++ b/Telegram/SourceFiles/gui/flatinput.h @@ -20,7 +20,6 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org */ #pragma once -#include #include "style.h" #include "animation.h" @@ -56,11 +55,11 @@ public: QSize minimumSizeHint() const; void customUpDown(bool isCustom); - QString getLastText() const { - return text(); + const QString &getLastText() const { + return _oldtext; } - void setTextMargin(const QMargins &mrg); + void setTextMargins(const QMargins &mrg); public slots: @@ -73,13 +72,13 @@ signals: void changed(); void cancelled(); - void accepted(); + void submitted(bool ctrlShiftEnter); void focused(); void blurred(); protected: - virtual void correctValue(QKeyEvent *e, const QString &was); + virtual void correctValue(const QString &was, QString &now); style::font phFont() { return _st.font; @@ -89,9 +88,8 @@ protected: private: - QString _ph, _fullph, _oldtext; + QString _oldtext, _ph, _fullph; bool _fastph; - QKeyEvent *_kev; bool _customUpDown; @@ -117,7 +115,7 @@ public: CountryCodeInput(QWidget *parent, const style::flatInput &st); - public slots: +public slots: void startErasing(QKeyEvent *e); void codeSelected(const QString &code); @@ -129,7 +127,7 @@ signals: protected: - void correctValue(QKeyEvent *e, const QString &was); + void correctValue(const QString &was, QString &now); private: @@ -137,24 +135,41 @@ private: }; - -class UsernameInput : public FlatInput { -public: - - UsernameInput(QWidget *parent, const style::flatInput &st, const QString &ph = QString(), const QString &val = QString()); - -protected: - - void correctValue(QKeyEvent *e, const QString &was); - -}; - -class InputField : public TWidget { +class PhoneInput : public FlatInput { Q_OBJECT public: - InputField(QWidget *parent, const style::InputField &st, const QString &ph = QString(), const QString &val = QString()); + PhoneInput(QWidget *parent, const style::flatInput &st); + + void paintEvent(QPaintEvent *e); + void keyPressEvent(QKeyEvent *e); + +public slots: + + void addedToNumber(const QString &added); + void onChooseCode(const QString &code); + +signals: + + void voidBackspace(QKeyEvent *e); + +protected: + + void correctValue(const QString &was, QString &now); + +private: + + QVector pattern; + +}; + +class InputArea : public TWidget { + Q_OBJECT + +public: + + InputArea(QWidget *parent, const style::InputArea &st, const QString &ph = QString(), const QString &val = QString()); void touchEvent(QTouchEvent *e); void paintEvent(QPaintEvent *e); @@ -163,14 +178,20 @@ public: void contextMenuEvent(QContextMenuEvent *e); void resizeEvent(QResizeEvent *e); - const QString &getLastText() const; + void showError(); + + void setMaxLength(int32 maxLength) { + _maxLength = maxLength; + } + + const QString &getLastText() const { + return _oldtext; + } void updatePlaceholder(); - int32 fakeMargin() const; - - bool placeholderFgStep(float64 ms); - bool placeholderShiftStep(float64 ms); - bool borderStep(float64 ms); + bool animStep_placeholderFg(float64 ms); + bool animStep_placeholderShift(float64 ms); + bool animStep_border(float64 ms); QSize sizeHint() const; QSize minimumSizeHint() const; @@ -190,12 +211,181 @@ public: return _inner.textCursor(); } void setText(const QString &text) { - return _inner.setText(text); + _inner.setText(text); + updatePlaceholder(); } void clear() { - return _inner.clear(); + _inner.clear(); + updatePlaceholder(); + } + bool hasFocus() const { + return _inner.hasFocus(); } +public slots: + + void onTouchTimer(); + + void onDocumentContentsChange(int position, int charsRemoved, int charsAdded); + void onDocumentContentsChanged(); + + void onUndoAvailable(bool avail); + void onRedoAvailable(bool avail); + +signals: + + void changed(); + void submitted(bool ctrlShiftEnter); + void cancelled(); + void tabbed(); + + void focused(); + void blurred(); + void resized(); + +protected: + + void insertEmoji(EmojiPtr emoji, QTextCursor c); + TWidget *tparent() { + return qobject_cast(parentWidget()); + } + const TWidget *tparent() const { + return qobject_cast(parentWidget()); + } + +private: + + int32 _maxLength; + bool heightAutoupdated(); + void checkContentHeight(); + + friend class InputAreaInner; + class InputAreaInner : public QTextEdit { + public: + InputAreaInner(InputArea *parent, const QString &val = QString()); + + bool viewportEvent(QEvent *e); + void focusInEvent(QFocusEvent *e); + void focusOutEvent(QFocusEvent *e); + void keyPressEvent(QKeyEvent *e); + void paintEvent(QPaintEvent *e); + + QMimeData *createMimeDataFromSelection() const; + + QVariant loadResource(int type, const QUrl &name); + + private: + + InputArea *f() const { + return static_cast(parentWidget()); + } + friend class InputArea; + }; + + void focusInInner(); + void focusOutInner(); + + void processDocumentContentsChange(int position, int charsAdded); + + void startBorderAnimation(); + + InputAreaInner _inner; + + QString _oldtext; + + bool _undoAvailable, _redoAvailable, _inHeightCheck, _ctrlEnterSubmit; + + bool _customUpDown; + + QString _placeholder, _placeholderFull; + bool _placeholderVisible; + anim::ivalue a_placeholderLeft; + anim::fvalue a_placeholderOpacity; + anim::cvalue a_placeholderFg; + Animation _a_placeholderFg, _a_placeholderShift; + + anim::fvalue a_borderOpacityActive; + anim::cvalue a_borderFg; + Animation _a_border; + + bool _focused, _error; + + const style::InputArea &_st; + + QTimer _touchTimer; + bool _touchPress, _touchRightButton, _touchMove; + QPoint _touchStart; + + bool _correcting; +}; + +class InputField : public TWidget { + Q_OBJECT + +public: + + InputField(QWidget *parent, const style::InputField &st, const QString &ph = QString(), const QString &val = QString()); + + void touchEvent(QTouchEvent *e); + void paintEvent(QPaintEvent *e); + void focusInEvent(QFocusEvent *e); + void mousePressEvent(QMouseEvent *e); + void contextMenuEvent(QContextMenuEvent *e); + void resizeEvent(QResizeEvent *e); + + void showError(); + + const QString &getLastText() const { + return _oldtext; + } + void updatePlaceholder(); + + bool animStep_placeholderFg(float64 ms); + bool animStep_placeholderShift(float64 ms); + bool animStep_border(float64 ms); + + QSize sizeHint() const; + QSize minimumSizeHint() const; + + QString getText(int32 start = 0, int32 end = -1) const; + bool hasText() const; + + bool isUndoAvailable() const; + bool isRedoAvailable() const; + + void customUpDown(bool isCustom); + + void setTextCursor(const QTextCursor &cursor) { + return _inner.setTextCursor(cursor); + } + QTextCursor textCursor() const { + return _inner.textCursor(); + } + void setText(const QString &text) { + _inner.setText(text); + updatePlaceholder(); + } + void clear() { + _inner.clear(); + updatePlaceholder(); + } + bool hasFocus() const { + return _inner.hasFocus(); + } + void setFocus() { + _inner.setFocus(); + QTextCursor c(_inner.textCursor()); + c.movePosition(QTextCursor::End); + _inner.setTextCursor(c); + } + void clearFocus() { + _inner.clearFocus(); + } + void setCursorPosition(int pos) { + QTextCursor c(_inner.textCursor()); + c.setPosition(pos); + _inner.setTextCursor(c); + } public slots: @@ -219,8 +409,6 @@ signals: protected: - virtual void correctValue(QKeyEvent *e, const QString &was); - void insertEmoji(EmojiPtr emoji, QTextCursor c); TWidget *tparent() { return qobject_cast(parentWidget()); @@ -231,6 +419,8 @@ protected: private: + int32 _maxLength; + friend class InputFieldInner; class InputFieldInner : public QTextEdit { public: @@ -253,20 +443,20 @@ private: } friend class InputField; }; - InputFieldInner _inner; + void focusInInner(); void focusOutInner(); void processDocumentContentsChange(int position, int charsAdded); - QString _oldtext; + void startBorderAnimation(); - QKeyEvent *_keyEvent; + InputFieldInner _inner; + + QString _oldtext; bool _undoAvailable, _redoAvailable; - int32 _fakeMargin; - bool _customUpDown; QString _placeholder, _placeholderFull; @@ -274,22 +464,158 @@ private: anim::ivalue a_placeholderLeft; anim::fvalue a_placeholderOpacity; anim::cvalue a_placeholderFg; - Animation _placeholderFgAnim, _placeholderShiftAnim; + Animation _a_placeholderFg, _a_placeholderShift; anim::fvalue a_borderOpacityActive; anim::cvalue a_borderFg; - Animation _borderAnim; + Animation _a_border; bool _focused, _error; - const style::InputField *_st; + const style::InputField &_st; QTimer _touchTimer; bool _touchPress, _touchRightButton, _touchMove; QPoint _touchStart; - bool _replacingEmojis; - typedef QPair Insertion; - typedef QList Insertions; - Insertions _insertions; + bool _correcting; +}; + +class MaskedInputField : public QLineEdit { + Q_OBJECT + T_WIDGET + +public: + + MaskedInputField(QWidget *parent, const style::InputField &st, const QString &placeholder = QString(), const QString &val = QString()); + + bool event(QEvent *e); + void touchEvent(QTouchEvent *e); + void paintEvent(QPaintEvent *e); + void focusInEvent(QFocusEvent *e); + void focusOutEvent(QFocusEvent *e); + void keyPressEvent(QKeyEvent *e); + void resizeEvent(QResizeEvent *e); + + void showError(); + + void setPlaceholder(const QString &ph); + void setPlaceholderFast(bool fast); + void updatePlaceholder(); + + QRect getTextRect() const; + + bool animStep_placeholderFg(float64 ms); + bool animStep_placeholderShift(float64 ms); + bool animStep_border(float64 ms); + + QSize sizeHint() const; + QSize minimumSizeHint() const; + + void customUpDown(bool isCustom); + const QString &getLastText() const { + return _oldtext; + } + void setText(const QString &text) { + QLineEdit::setText(text); + updatePlaceholder(); + } + void clear() { + QLineEdit::clear(); + updatePlaceholder(); + } + +public slots: + + void onTextChange(const QString &text); + void onCursorPositionChanged(int oldPosition, int position); + + void onTextEdited(); + + void onTouchTimer(); + +signals: + + void changed(); + void cancelled(); + void submitted(bool ctrlShiftEnter); + void focused(); + void blurred(); + +protected: + + virtual void correctValue(const QString &was, int32 wasCursor, QString &now, int32 &nowCursor); + virtual void paintPlaceholder(Painter &p); + + style::font phFont() { + return _st.font; + } + + void placeholderPreparePaint(Painter &p); + const QString &placeholder() const; + QRect placeholderRect() const; + + void setTextMargins(const QMargins &mrg); + const style::InputField &_st; + +private: + + void startBorderAnimation(); + + int32 _maxLength; + + QString _oldtext; + int32 _oldcursor; + + bool _undoAvailable, _redoAvailable; + + bool _customUpDown; + + QString _placeholder, _placeholderFull; + bool _placeholderVisible, _placeholderFast; + anim::ivalue a_placeholderLeft; + anim::fvalue a_placeholderOpacity; + anim::cvalue a_placeholderFg; + Animation _a_placeholderFg, _a_placeholderShift; + + anim::fvalue a_borderOpacityActive; + anim::cvalue a_borderFg; + Animation _a_border; + + bool _focused, _error; + + style::margins _textMargins; + + QTimer _touchTimer; + bool _touchPress, _touchRightButton, _touchMove; + QPoint _touchStart; +}; + +class PortInput : public MaskedInputField { + Q_OBJECT + +public: + + PortInput(QWidget *parent, const style::InputField &st, const QString &ph, const QString &val); + +protected: + + void correctValue(const QString &was, int32 wasCursor, QString &now, int32 &nowCursor); + +}; + +class UsernameInput : public MaskedInputField { +public: + + UsernameInput(QWidget *parent, const style::InputField &st, const QString &ph, const QString &val, bool isLink); + void paintPlaceholder(Painter &p); + +protected: + + void correctValue(const QString &was, int32 wasCursor, QString &now, int32 &nowCursor); + +private: + + QString _linkPlaceholder; + }; diff --git a/Telegram/SourceFiles/gui/flattextarea.cpp b/Telegram/SourceFiles/gui/flattextarea.cpp index e6a88a72a..a5abeba89 100644 --- a/Telegram/SourceFiles/gui/flattextarea.cpp +++ b/Telegram/SourceFiles/gui/flattextarea.cpp @@ -24,12 +24,12 @@ 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(QString(), parent), +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), _replacingEmojis(false) { +_touchPress(false), _touchRightButton(false), _touchMove(false), _correcting(false) { setAcceptRichText(false); resize(_st.width, _st.font->height); @@ -576,6 +576,9 @@ void FlatTextarea::insertFromMimeData(const QMimeData *source) { if (!_inDrop) emit spacedReturnedPasted(); } +void FlatTextarea::correctValue(const QString &was, QString &now) { +} + void FlatTextarea::insertEmoji(EmojiPtr emoji, QTextCursor c) { QTextImageFormat imageFormat; int32 ew = ESize + st::emojiPadding * cIntRetinaFactor() * 2, eh = _st.font->height * cIntRetinaFactor(); @@ -650,17 +653,6 @@ void FlatTextarea::processDocumentContentsChange(int position, int charsAdded) { insertEmoji(emoji, c); - for (Insertions::iterator i = _insertions.begin(), e = _insertions.end(); i != e; ++i) { - if (i->first >= removedUpto) { - i->first -= removedUpto - emojiPosition - 1; - } else if (i->first >= emojiPosition) { - i->second -= removedUpto - emojiPosition; - i->first = emojiPosition + 1; - } else if (i->first + i->second > emojiPosition + 1) { - i->second -= qMin(removedUpto, i->first + i->second) - emojiPosition; - } - } - charsAdded -= removedUpto - position; position = emojiPosition + 1; @@ -673,9 +665,11 @@ void FlatTextarea::processDocumentContentsChange(int position, int charsAdded) { } void FlatTextarea::onDocumentContentsChange(int position, int charsRemoved, int charsAdded) { - if (_replacingEmojis) return; + if (_correcting) return; - _replacingEmojis = true; + QTextCursor(document()->docHandle(), 0).joinPreviousEditBlock(); + + _correcting = true; if (_maxLength >= 0) { QTextCursor c(document()->docHandle(), 0); c.movePosition(QTextCursor::End); @@ -697,7 +691,7 @@ void FlatTextarea::onDocumentContentsChange(int position, int charsRemoved, int } } } - _replacingEmojis = false; + _correcting = false; if (!_links.isEmpty()) { bool changed = false; @@ -715,7 +709,10 @@ void FlatTextarea::onDocumentContentsChange(int position, int charsRemoved, int if (changed) emit linksChanged(); } - if (document()->availableRedoSteps() > 0) return; + if (document()->availableRedoSteps() > 0) { + QTextCursor(document()->docHandle(), 0).endEditBlock(); + return; + } const int takeBack = 3; @@ -725,45 +722,29 @@ void FlatTextarea::onDocumentContentsChange(int position, int charsRemoved, int charsAdded += position; position = 0; } - if (charsAdded <= 0) return; - - // _insertions.push_back(Insertion(position, charsAdded)); - _replacingEmojis = true; + if (charsAdded <= 0) { + QTextCursor(document()->docHandle(), 0).endEditBlock(); + return; + } + _correcting = true; QSizeF s = document()->pageSize(); processDocumentContentsChange(position, charsAdded); if (document()->pageSize() != s) { document()->setPageSize(s); } - _replacingEmojis = false; + _correcting = false; + + QTextCursor(document()->docHandle(), 0).endEditBlock(); } void FlatTextarea::onDocumentContentsChanged() { - if (_replacingEmojis) return; - - if (!_insertions.isEmpty()) { - if (document()->availableRedoSteps() > 0) { - _insertions.clear(); - } else { - _replacingEmojis = true; - QSizeF s = document()->pageSize(); - - do { - Insertion i = _insertions.front(); - _insertions.pop_front(); - if (i.second > 0) { - processDocumentContentsChange(i.first, i.second); - } - } while (!_insertions.isEmpty()); - - if (document()->pageSize() != s) { - document()->setPageSize(s); - } - _replacingEmojis = false; - } - } + if (_correcting) return; QString curText(getText()); + _correcting = true; + correctValue(_oldtext, curText); + _correcting = false; if (_oldtext != curText) { _oldtext = curText; emit changed(); @@ -803,10 +784,6 @@ bool FlatTextarea::animStep(float64 ms) { return res; } -const QString &FlatTextarea::getLastText() const { - return _oldtext; -} - void FlatTextarea::setPlaceholder(const QString &ph) { _ph = ph; _phelided = _st.font->elided(_ph, width() - _st.textMrg.left() - _st.textMrg.right() - _st.phPos.x() - 1); diff --git a/Telegram/SourceFiles/gui/flattextarea.h b/Telegram/SourceFiles/gui/flattextarea.h index 02d3cb139..2a17b95af 100644 --- a/Telegram/SourceFiles/gui/flattextarea.h +++ b/Telegram/SourceFiles/gui/flattextarea.h @@ -46,7 +46,9 @@ public: void setMinHeight(int32 minHeight); void setMaxHeight(int32 maxHeight); - const QString &getLastText() const; + const QString &getLastText() const { + return _oldtext; + } void setPlaceholder(const QString &ph); void updatePlaceholder(); @@ -61,7 +63,6 @@ public: EmojiPtr getSingleEmoji() const; void getMentionHashtagBotCommandStart(QString &start) const; void removeSingleEmoji(); - QString getText(int32 start = 0, int32 end = -1) const; bool hasText() const; bool isUndoAvailable() const; @@ -99,6 +100,9 @@ signals: protected: + QString getText(int32 start = 0, int32 end = -1) const; + virtual void correctValue(const QString &was, QString &now); + void insertEmoji(EmojiPtr emoji, QTextCursor c); QVariant loadResource(int type, const QUrl &name); @@ -130,10 +134,7 @@ private: bool _touchPress, _touchRightButton, _touchMove; QPoint _touchStart; - bool _replacingEmojis; - typedef QPair Insertion; - typedef QList Insertions; - Insertions _insertions; + bool _correcting; typedef QPair LinkRange; typedef QList LinkRanges; diff --git a/Telegram/SourceFiles/gui/phoneinput.cpp b/Telegram/SourceFiles/gui/phoneinput.cpp deleted file mode 100644 index facb89460..000000000 --- a/Telegram/SourceFiles/gui/phoneinput.cpp +++ /dev/null @@ -1,168 +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 "style.h" - -#include "gui/phoneinput.h" -#include "numbers.h" -#include "lang.h" - -PhoneInput::PhoneInput(QWidget *parent, const style::flatInput &st) : FlatInput(parent, st, lang(lng_phone_ph)) { -} - -void PhoneInput::paintEvent(QPaintEvent *e) { - FlatInput::paintEvent(e); - - Painter p(this); - QString t(text()); - if (!pattern.isEmpty() && !t.isEmpty()) { - QString ph = placeholder().mid(t.size()); - if (!ph.isEmpty()) { - p.setClipRect(rect()); - QRect phRect(placeholderRect()); - int tw = phFont()->width(t); - if (tw < phRect.width()) { - phRect.setLeft(phRect.left() + tw); - phPrepare(p); - p.drawText(phRect, ph, style::al_left); - } - } - } -} - -void PhoneInput::correctValue(QKeyEvent *e, const QString &was) { - if (e && e->key() == Qt::Key_Backspace && !was.length()) { - emit voidBackspace(e); - return; - } - QString oldText(text()), newText; - int oldPos(cursorPosition()), newPos(-1), oldLen(oldText.length()), digitCount = 0; - for (int i = 0; i < oldLen; ++i) { - if (oldText[i].isDigit()) { - ++digitCount; - } - } - if (digitCount > MaxPhoneTailLength) digitCount = MaxPhoneTailLength; - - bool inPart = !pattern.isEmpty(); - int curPart = -1, leftInPart = 0; - newText.reserve(oldLen); - for (int i = 0; i < oldLen; ++i) { - if (i == oldPos && newPos < 0) { - newPos = newText.length(); - } - - QChar ch(oldText[i]); - if (ch.isDigit()) { - if (!digitCount--) { - break; - } - if (inPart) { - if (leftInPart) { - --leftInPart; - } else { - newText += ' '; - ++curPart; - inPart = curPart < pattern.size(); - leftInPart = inPart ? (pattern.at(curPart) - 1) : 0; - - ++oldPos; - } - } - newText += ch; - } else if (ch == ' ' || ch == '-' || ch == '(' || ch == ')') { - if (inPart) { - if (leftInPart) { - } else { - newText += ch; - ++curPart; - inPart = curPart < pattern.size(); - leftInPart = inPart ? pattern.at(curPart) : 0; - } - } else { - newText += ch; - } - } - } - int32 newlen = newText.size(); - while (newlen > 0 && newText.at(newlen - 1).isSpace()) { - --newlen; - } - if (newlen < newText.size()) newText = newText.mid(0, newlen); - if (newPos < 0) { - newPos = newText.length(); - } - if (newText != oldText) { - setText(newText); - setCursorPosition(newPos); - } -} - -void PhoneInput::addedToNumber(const QString &added) { - setFocus(); - QString was(text()); - setText(added + text()); - setCursorPosition(added.length()); - correctValue(0, was); - updatePlaceholder(); -} - -void PhoneInput::onChooseCode(const QString &code) { - pattern = phoneNumberParse(code); - if (!pattern.isEmpty() && pattern.at(0) == code.size()) { - pattern.pop_front(); - } else { - pattern.clear(); - } - if (pattern.isEmpty()) { - setPlaceholder(lang(lng_phone_ph)); - } else { - QString ph; - ph.reserve(20); - for (int i = 0, l = pattern.size(); i < l; ++i) { - ph.append(' '); - ph.append(QString(QChar(0x2212)).repeated(pattern.at(i))); - } - setPlaceholder(ph); - } - correctValue(0, text()); - setPlaceholderFast(!pattern.isEmpty()); - updatePlaceholder(); -} - -PortInput::PortInput(QWidget *parent, const style::flatInput &st, const QString &ph, const QString &val) : FlatInput(parent, st, ph, val) { - correctValue(0, QString()); -} - -void PortInput::correctValue(QKeyEvent *e, const QString &was) { - QString oldText(text()), newText(oldText); - - newText.replace(QRegularExpression(qsl("[^\\d]")), QString()); - if (!newText.toInt()) { - newText = QString(); - } else if (newText.toInt() > 65535) { - newText = was; - } - if (newText != oldText) { - setText(newText); - updatePlaceholder(); - } -} diff --git a/Telegram/SourceFiles/gui/phoneinput.h b/Telegram/SourceFiles/gui/phoneinput.h deleted file mode 100644 index f89bd91c3..000000000 --- a/Telegram/SourceFiles/gui/phoneinput.h +++ /dev/null @@ -1,64 +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 "gui/flatinput.h" - -class PhoneInput : public FlatInput { - Q_OBJECT - -public: - - PhoneInput(QWidget *parent, const style::flatInput &st); - - void paintEvent(QPaintEvent *e); - -public slots: - - void addedToNumber(const QString &added); - void onChooseCode(const QString &code); - -signals: - - void voidBackspace(QKeyEvent *e); - -protected: - - void correctValue(QKeyEvent *e, const QString &was); - -private: - - QVector pattern; - -}; - -class PortInput : public FlatInput { - Q_OBJECT - -public: - - PortInput(QWidget *parent, const style::flatInput &st, const QString &ph, const QString &val); - -protected: - - void correctValue(QKeyEvent *e, const QString &was); - -}; diff --git a/Telegram/SourceFiles/gui/text.cpp b/Telegram/SourceFiles/gui/text.cpp index 7ef4cf037..1b2bfb2b9 100644 --- a/Telegram/SourceFiles/gui/text.cpp +++ b/Telegram/SourceFiles/gui/text.cpp @@ -4466,5 +4466,5 @@ LinksInText textParseLinks(const QString &text, int32 flags, bool rich) { // som } void emojiDraw(QPainter &p, EmojiPtr e, int x, int y) { - p.drawPixmap(QPoint(x, y), App::emojis(), QRect(e->x * ESize, e->y * ESize, ESize, ESize)); + p.drawPixmap(QPoint(x, y), App::emoji(), QRect(e->x * ESize, e->y * ESize, ESize, ESize)); } diff --git a/Telegram/SourceFiles/gui/twidget.h b/Telegram/SourceFiles/gui/twidget.h index 11ff79b6c..a51bee937 100644 --- a/Telegram/SourceFiles/gui/twidget.h +++ b/Telegram/SourceFiles/gui/twidget.h @@ -158,11 +158,11 @@ virtual void leaveToChildEvent(QEvent *e) { /* e -- from enterEvent() of child T } \ virtual void enterFromChildEvent(QEvent *e) { /* e -- from leaveEvent() of child TWidget */ \ } \ -void moveToLeft(int x, int y, int outerw) { \ - move(rtl() ? (outerw - x - width()) : x, y); \ +void moveToLeft(int x, int y, int outerw = 0) { \ + move(rtl() ? ((outerw > 0 ? outerw : parentWidget()->width()) - x - width()) : x, y); \ } \ -void moveToRight(int x, int y, int outerw) { \ - move(rtl() ? x : (outerw - x - width()), y); \ +void moveToRight(int x, int y, int outerw = 0) { \ + move(rtl() ? x : ((outerw > 0 ? outerw : parentWidget()->width()) - x - width()), y); \ } \ QPoint myrtlpoint(int x, int y) const { \ return rtlpoint(x, y, width()); \ diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 3d07462cf..34a2a2956 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -1695,8 +1695,8 @@ _clear(this, lang(lng_profile_delete_conversation)) { void ReportSpamPanel::resizeEvent(QResizeEvent *e) { _report.resize(width() - (_hide.width() + st::reportSpamSeparator) * 2, _report.height()); - _report.moveToLeft(_hide.width() + st::reportSpamSeparator, 0, width()); - _hide.moveToRight(0, 0, width()); + _report.moveToLeft(_hide.width() + st::reportSpamSeparator, 0); + _hide.moveToRight(0, 0); _clear.move((width() - _clear.width()) / 2, height() - _clear.height() - ((height() - st::msgFont->height - _clear.height()) / 2)); } @@ -2217,8 +2217,8 @@ void HistoryHider::resizeEvent(QResizeEvent *e) { _cancel.hide(); } box = QRect((width() - w) / 2, (height() - h) / 2, w, h); - _send.moveToRight(width() - (box.x() + box.width()) + st::boxButtonPadding.right(), box.y() + h - st::boxButtonPadding.bottom() - _send.height(), width()); - _cancel.moveToRight(width() - (box.x() + box.width()) + st::boxButtonPadding.right() + _send.width() + st::boxButtonPadding.left(), _send.y(), width()); + _send.moveToRight(width() - (box.x() + box.width()) + st::boxButtonPadding.right(), box.y() + h - st::boxButtonPadding.bottom() - _send.height()); + _cancel.moveToRight(width() - (box.x() + box.width()) + st::boxButtonPadding.right() + _send.width() + st::boxButtonPadding.left(), _send.y()); } bool HistoryHider::offerPeer(PeerId peer) { @@ -2762,7 +2762,7 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) { } bool HistoryWidget::stickersFailed(const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; LOG(("App Fail: Failed to get stickers!")); @@ -3418,7 +3418,7 @@ void HistoryWidget::historyCleared(History *history) { } bool HistoryWidget::messagesFailed(const RPCError &error, mtpRequestId requestId) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; if (error.type() == qstr("CHANNEL_PRIVATE")) { App::main()->showDialogs(); @@ -3820,7 +3820,7 @@ void HistoryWidget::unblockDone(PeerData *peer, const MTPBool &result, mtpReques } bool HistoryWidget::unblockFail(const RPCError &error, mtpRequestId req) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; if (_unblockRequest == req) _unblockRequest = 0; return false; @@ -3874,7 +3874,7 @@ void HistoryWidget::joinDone(const MTPUpdates &result, mtpRequestId req) { } bool HistoryWidget::joinFail(const RPCError &error, mtpRequestId req) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; if (_unblockRequest == req) _unblockRequest = 0; if (error.type() == qstr("CHANNEL_PRIVATE")) { @@ -5119,7 +5119,7 @@ void HistoryWidget::reportSpamDone(PeerData *peer, const MTPBool &result, mtpReq } bool HistoryWidget::reportSpamFail(const RPCError &error, mtpRequestId req) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; if (req == _reportSpamRequest) { _reportSpamRequest = 0; diff --git a/Telegram/SourceFiles/intro/introcode.cpp b/Telegram/SourceFiles/intro/introcode.cpp index caabe3768..ffdc561a6 100644 --- a/Telegram/SourceFiles/intro/introcode.cpp +++ b/Telegram/SourceFiles/intro/introcode.cpp @@ -30,11 +30,11 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org CodeInput::CodeInput(QWidget *parent, const style::flatInput &st, const QString &ph) : FlatInput(parent, st, ph) { } -void CodeInput::correctValue(QKeyEvent *e, const QString &was) { - QString oldText(text()), newText; - int oldPos(cursorPosition()), newPos(-1), oldLen(oldText.length()), digitCount = 0; +void CodeInput::correctValue(const QString &was, QString &now) { + QString newText; + int oldPos(cursorPosition()), newPos(-1), oldLen(now.length()), digitCount = 0; for (int i = 0; i < oldLen; ++i) { - if (oldText[i].isDigit()) { + if (now[i].isDigit()) { ++digitCount; } } @@ -43,7 +43,7 @@ void CodeInput::correctValue(QKeyEvent *e, const QString &was) { newText.reserve(oldLen); for (int i = 0; i < oldLen; ++i) { - QChar ch(oldText[i]); + QChar ch(now[i]); if (ch.isDigit()) { if (!digitCount--) { break; @@ -60,8 +60,10 @@ void CodeInput::correctValue(QKeyEvent *e, const QString &was) { if (newPos < 0) { newPos = newText.length(); } - if (newText != oldText) { - setText(newText); + if (newText != now) { + now = newText; + setText(now); + updatePlaceholder(); if (newPos != oldPos) { setCursorPosition(newPos); } @@ -262,7 +264,7 @@ bool IntroCode::codeSubmitFail(const RPCError &error) { checkRequest.start(1000); sentRequest = MTP::send(MTPaccount_GetPassword(), rpcDone(&IntroCode::gotPassword), rpcFail(&IntroCode::codeSubmitFail)); return true; - } else if (error.type().startsWith(qsl("FLOOD_WAIT_"))) { + } else if (mtpIsFlood(error)) { showError(lang(lng_flood_error)); code.setFocus(); return true; @@ -342,7 +344,7 @@ void IntroCode::noTelegramCodeDone(const MTPBool &result) { } bool IntroCode::noTelegramCodeFail(const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) { + if (mtpIsFlood(error)) { showError(lang(lng_flood_error)); code.setFocus(); return true; diff --git a/Telegram/SourceFiles/intro/introcode.h b/Telegram/SourceFiles/intro/introcode.h index d9cf7b18f..68d8e557d 100644 --- a/Telegram/SourceFiles/intro/introcode.h +++ b/Telegram/SourceFiles/intro/introcode.h @@ -38,7 +38,7 @@ signals: protected: - void correctValue(QKeyEvent *e, const QString &was); + void correctValue(const QString &was, QString &now); }; diff --git a/Telegram/SourceFiles/intro/introphone.cpp b/Telegram/SourceFiles/intro/introphone.cpp index 803a06a9f..46e016689 100644 --- a/Telegram/SourceFiles/intro/introphone.cpp +++ b/Telegram/SourceFiles/intro/introphone.cpp @@ -274,7 +274,7 @@ bool IntroPhone::phoneSubmitFail(const RPCError &error) { showError(lang(lng_bad_phone)); enableAll(true); return true; - } else if (error.type().startsWith(qsl("FLOOD_WAIT_"))) { + } else if (mtpIsFlood(error)) { showError(lang(lng_flood_error)); enableAll(true); return true; diff --git a/Telegram/SourceFiles/intro/introphone.h b/Telegram/SourceFiles/intro/introphone.h index e100c3547..7e559e207 100644 --- a/Telegram/SourceFiles/intro/introphone.h +++ b/Telegram/SourceFiles/intro/introphone.h @@ -22,7 +22,6 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org #include #include "gui/flatbutton.h" -#include "gui/phoneinput.h" #include "gui/countryinput.h" #include "intro.h" diff --git a/Telegram/SourceFiles/intro/intropwdcheck.cpp b/Telegram/SourceFiles/intro/intropwdcheck.cpp index ee75a96d1..8481fbdc0 100644 --- a/Telegram/SourceFiles/intro/intropwdcheck.cpp +++ b/Telegram/SourceFiles/intro/intropwdcheck.cpp @@ -203,7 +203,7 @@ bool IntroPwdCheck::pwdSubmitFail(const RPCError &error) { return true; } else if (err == "PASSWORD_EMPTY") { intro()->onIntroBack(); - } else if (err.startsWith(qsl("FLOOD_WAIT_"))) { + } else if (mtpIsFlood(error)) { showError(lang(lng_flood_error)); _pwdField.notaBene(); return true; @@ -237,7 +237,7 @@ bool IntroPwdCheck::codeSubmitFail(const RPCError &error) { showError(lang(lng_signin_wrong_code)); _codeField.notaBene(); return true; - } else if (err.startsWith(qsl("FLOOD_WAIT_"))) { + } else if (mtpIsFlood(error)) { showError(lang(lng_flood_error)); _codeField.notaBene(); return true; diff --git a/Telegram/SourceFiles/intro/introsignup.cpp b/Telegram/SourceFiles/intro/introsignup.cpp index 538b70107..81b5a0bae 100644 --- a/Telegram/SourceFiles/intro/introsignup.cpp +++ b/Telegram/SourceFiles/intro/introsignup.cpp @@ -265,7 +265,7 @@ bool IntroSignup::nameSubmitFail(const RPCError &error) { showError(lang(lng_bad_name)); last.setFocus(); return true; - } else if (error.type().startsWith(qsl("FLOOD_WAIT_"))) { + } else if (mtpIsFlood(error)) { showError(lang(lng_flood_error)); if (_invertOrder) { first.setFocus(); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index ee8d9b1d8..18f5b4e34 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -89,6 +89,8 @@ void TopBarWidget::onEdit() { if (p) { if (p->isChannel()) { App::wnd()->showLayer(new EditChannelBox(p->asChannel())); + } else if (p->isChat()) { + App::wnd()->showLayer(new EditNameTitleBox(p)); } else { App::wnd()->showLayer(new AddContactBox(p)); } @@ -771,7 +773,7 @@ DragState MainWidget::getDragState(const QMimeData *mime) { } bool MainWidget::leaveChatFailed(PeerData *peer, const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; if (error.type() == qstr("USER_NOT_PARTICIPANT") || error.type() == qstr("CHAT_ID_INVALID")) { // left this chat already deleteConversation(peer); @@ -907,7 +909,7 @@ void MainWidget::kickParticipant(ChatData *chat, UserData *user) { } bool MainWidget::kickParticipantFail(ChatData *chat, const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; error.type(); return false; @@ -1479,7 +1481,7 @@ void MainWidget::itemResized(HistoryItem *row, bool scrollToIt) { } bool MainWidget::overviewFailed(PeerData *peer, const RPCError &error, mtpRequestId req) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; MediaOverviewType type = OverviewCount; for (int32 i = 0; i < OverviewCount; ++i) { @@ -1641,7 +1643,7 @@ void MainWidget::partWasRead(PeerData *peer, const MTPmessages_AffectedHistory & } bool MainWidget::readRequestFail(PeerData *peer, const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; readRequestDone(peer); return false; @@ -2086,7 +2088,7 @@ void MainWidget::serviceHistoryDone(const MTPmessages_Messages &msgs) { } bool MainWidget::serviceHistoryFail(const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; App::wnd()->showDelayedServiceMsgs(); return false; @@ -3612,7 +3614,7 @@ void MainWidget::usernameResolveDone(QPair toProfileStartToken, c } bool MainWidget::usernameResolveFail(QString name, const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; if (error.code() == 400) { App::wnd()->showLayer(new InformBox(lng_username_not_found(lt_user, name))); @@ -3649,7 +3651,7 @@ void MainWidget::inviteCheckDone(QString hash, const MTPChatInvite &invite) { } bool MainWidget::inviteCheckFail(const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; if (error.code() == 400) { App::wnd()->showLayer(new InformBox(lang(lng_group_invite_bad_link))); @@ -3687,7 +3689,7 @@ void MainWidget::inviteImportDone(const MTPUpdates &updates) { } bool MainWidget::inviteImportFail(const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; if (error.code() == 400) { App::wnd()->showLayer(new InformBox(lang(error.type() == qsl("USERS_TOO_MUCH") ? lng_group_invite_no_room : lng_group_invite_bad_link))); @@ -3792,7 +3794,7 @@ void MainWidget::gotNotifySetting(MTPInputNotifyPeer peer, const MTPPeerNotifySe } bool MainWidget::failNotifySetting(MTPInputNotifyPeer peer, const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; gotNotifySetting(peer, MTP_peerNotifySettingsEmpty()); return true; diff --git a/Telegram/SourceFiles/mediaview.cpp b/Telegram/SourceFiles/mediaview.cpp index 3441b1eb8..7f50a466e 100644 --- a/Telegram/SourceFiles/mediaview.cpp +++ b/Telegram/SourceFiles/mediaview.cpp @@ -245,21 +245,21 @@ void MediaView::updateControls() { if (_doc->loader) { _docDownload.hide(); _docSaveAs.hide(); - _docCancel.moveToLeft(_docRect.x() + 2 * st::mvDocPadding + st::mvDocBlue.pxWidth(), _docRect.y() + st::mvDocPadding + st::mvDocLinksTop, width()); + _docCancel.moveToLeft(_docRect.x() + 2 * st::mvDocPadding + st::mvDocBlue.pxWidth(), _docRect.y() + st::mvDocPadding + st::mvDocLinksTop); _docCancel.show(); if (!_docRadialFirst) _docRadialFirst = _docRadialLast = _docRadialStart = getms(); if (!animating()) anim::start(this); anim::step(this); } else { if (_doc->already(true).isEmpty()) { - _docDownload.moveToLeft(_docRect.x() + 2 * st::mvDocPadding + st::mvDocBlue.pxWidth(), _docRect.y() + st::mvDocPadding + st::mvDocLinksTop, width()); + _docDownload.moveToLeft(_docRect.x() + 2 * st::mvDocPadding + st::mvDocBlue.pxWidth(), _docRect.y() + st::mvDocPadding + st::mvDocLinksTop); _docDownload.show(); - _docSaveAs.moveToLeft(_docRect.x() + 2.5 * st::mvDocPadding + st::mvDocBlue.pxWidth() + _docDownload.width(), _docRect.y() + st::mvDocPadding + st::mvDocLinksTop, width()); + _docSaveAs.moveToLeft(_docRect.x() + 2.5 * st::mvDocPadding + st::mvDocBlue.pxWidth() + _docDownload.width(), _docRect.y() + st::mvDocPadding + st::mvDocLinksTop); _docSaveAs.show(); _docCancel.hide(); } else { _docDownload.hide(); - _docSaveAs.moveToLeft(_docRect.x() + 2 * st::mvDocPadding + st::mvDocBlue.pxWidth(), _docRect.y() + st::mvDocPadding + st::mvDocLinksTop, width()); + _docSaveAs.moveToLeft(_docRect.x() + 2 * st::mvDocPadding + st::mvDocBlue.pxWidth(), _docRect.y() + st::mvDocPadding + st::mvDocLinksTop); _docSaveAs.show(); _docCancel.hide(); } @@ -329,13 +329,13 @@ void MediaView::updateDropdown() { _btnToMessage->setVisible(_msgid > 0); _btnShowInFolder->setVisible(_doc && !_doc->already(true).isEmpty()); _btnSaveAs->setVisible(true); - _btnCopy->setVisible((_doc && !_current.isNull()) || (_photo && _photo->full->loaded())); + _btnCopy->setVisible((_doc && (!_current.isNull() || !_currentGif.isNull())) || (_photo && _photo->full->loaded())); _btnForward->setVisible(_canForward); _btnDelete->setVisible(_canDelete || (_photo && App::self() && App::self()->photoId == _photo->id) || (_photo && _photo->peer && _photo->peer->photoId == _photo->id && (_photo->peer->isChat() || (_photo->peer->isChannel() && _photo->peer->asChannel()->amCreator())))); _btnViewAll->setVisible((_overview != OverviewCount) && _history); _btnViewAll->setText(lang(_doc ? lng_mediaview_files_all : lng_mediaview_photos_all)); _dropdown.updateButtons(); - _dropdown.moveToRight(0, height() - _dropdown.height(), width()); + _dropdown.moveToRight(0, height() - _dropdown.height()); } bool MediaView::animStep(float64 msp) { @@ -644,9 +644,11 @@ void MediaView::onCopy() { _dropdown.hideStart(); } if (_doc) { - if (_current.isNull()) return; - - QApplication::clipboard()->setPixmap(_current); + if (!_current.isNull()) { + QApplication::clipboard()->setPixmap(_current); + } else if (!_currentGif.isNull()) { + QApplication::clipboard()->setPixmap(_currentGif.current(_currentGif.w, _currentGif.h, false)); + } } else { if (!_photo || !_photo->full->loaded()) return; @@ -992,8 +994,6 @@ void MediaView::displayDocument(DocumentData *doc, HistoryItem *item) { // empty } void MediaView::paintEvent(QPaintEvent *e) { -// uint64 ms = getms(); - QRect r(e->rect()); QRegion region(e->region()); QVector rs(region.rects()); diff --git a/Telegram/SourceFiles/mtproto/mtp.cpp b/Telegram/SourceFiles/mtproto/mtp.cpp index b13f61f0e..22246480b 100644 --- a/Telegram/SourceFiles/mtproto/mtp.cpp +++ b/Telegram/SourceFiles/mtproto/mtp.cpp @@ -120,7 +120,7 @@ namespace { } bool importFail(const RPCError &error, mtpRequestId req) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; if (globalHandler.onFail && MTP::authedId()) (*globalHandler.onFail)(req, error); // auth import failed return true; @@ -141,7 +141,7 @@ namespace { } bool exportFail(const RPCError &error, mtpRequestId req) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; AuthExportRequests::const_iterator i = authExportRequests.constFind(req); if (i != authExportRequests.cend()) { @@ -556,7 +556,7 @@ namespace _mtp_internal { } bool rpcErrorOccured(mtpRequestId requestId, const RPCFailHandlerPtr &onFail, const RPCError &err) { // return true if need to clean request data - if (err.type().startsWith(qsl("FLOOD_WAIT_"))) { + if (mtpIsFlood(err)) { if (onFail && (*onFail)(requestId, err)) return true; } diff --git a/Telegram/SourceFiles/mtproto/mtpDC.cpp b/Telegram/SourceFiles/mtproto/mtpDC.cpp index 326cc20fc..4b9cc8c9c 100644 --- a/Telegram/SourceFiles/mtproto/mtpDC.cpp +++ b/Telegram/SourceFiles/mtproto/mtpDC.cpp @@ -160,7 +160,7 @@ namespace { mtpConfigLoader()->done(); } bool configFailed(const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; loadingConfig = false; LOG(("MTP Error: failed to get config!")); diff --git a/Telegram/SourceFiles/mtproto/mtpFileLoader.cpp b/Telegram/SourceFiles/mtproto/mtpFileLoader.cpp index 4d2a5aafd..536d54bde 100644 --- a/Telegram/SourceFiles/mtproto/mtpFileLoader.cpp +++ b/Telegram/SourceFiles/mtproto/mtpFileLoader.cpp @@ -292,7 +292,7 @@ void mtpFileLoader::partLoaded(int32 offset, const MTPupload_File &result, mtpRe } bool mtpFileLoader::partFailed(const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; finishFail(); return true; diff --git a/Telegram/SourceFiles/overviewwidget.cpp b/Telegram/SourceFiles/overviewwidget.cpp index 8838d6a83..e32e26581 100644 --- a/Telegram/SourceFiles/overviewwidget.cpp +++ b/Telegram/SourceFiles/overviewwidget.cpp @@ -366,7 +366,7 @@ void OverviewInner::searchReceived(bool fromStart, const MTPmessages_Messages &r } bool OverviewInner::searchFailed(const RPCError &error, mtpRequestId req) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; if (_searchRequest == req) { _searchRequest = 0; diff --git a/Telegram/SourceFiles/passcodewidget.cpp b/Telegram/SourceFiles/passcodewidget.cpp index 00c1509cd..4b77af01e 100644 --- a/Telegram/SourceFiles/passcodewidget.cpp +++ b/Telegram/SourceFiles/passcodewidget.cpp @@ -34,13 +34,13 @@ _passcode(this, st::passcodeInput), _submit(this, lang(lng_passcode_submit), st::passcodeSubmit), _logout(this, lang(lng_passcode_logout)) { setGeometry(QRect(0, st::titleHeight, App::wnd()->width(), App::wnd()->height() - st::titleHeight)); - connect(App::wnd(), SIGNAL(resized(const QSize &)), this, SLOT(onParentResize(const QSize &))); + connect(App::wnd(), SIGNAL(resized(const QSize&)), this, SLOT(onParentResize(const QSize&))); _passcode.setEchoMode(QLineEdit::Password); connect(&_submit, SIGNAL(clicked()), this, SLOT(onSubmit())); connect(&_passcode, SIGNAL(changed()), this, SLOT(onChanged())); - connect(&_passcode, SIGNAL(accepted()), this, SLOT(onSubmit())); + connect(&_passcode, SIGNAL(submitted(bool)), this, SLOT(onSubmit())); connect(&_logout, SIGNAL(clicked()), App::wnd(), SLOT(onLogout())); diff --git a/Telegram/SourceFiles/profilewidget.cpp b/Telegram/SourceFiles/profilewidget.cpp index 9b3797f13..ef4b4bdd1 100644 --- a/Telegram/SourceFiles/profilewidget.cpp +++ b/Telegram/SourceFiles/profilewidget.cpp @@ -340,8 +340,8 @@ void ProfileInner::blockDone(bool blocked, const MTPBool &result) { } bool ProfileInner::blockFail(const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; - + if (mtpIsFlood(error)) return false; + _blockRequest = 0; return false; } diff --git a/Telegram/SourceFiles/settings.cpp b/Telegram/SourceFiles/settings.cpp index 2bbab026e..5b612a5ce 100644 --- a/Telegram/SourceFiles/settings.cpp +++ b/Telegram/SourceFiles/settings.cpp @@ -24,7 +24,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org #include "lang.h" bool gRtl = false; -Qt::LayoutDirection gLangDir = Qt::LeftToRight; +Qt::LayoutDirection gLangDir = gRtl ? Qt::RightToLeft : Qt::LeftToRight; mtpDcOptions gDcOptions; @@ -211,7 +211,7 @@ void settingsParseArgs(int argc, char *argv[]) { RecentEmojiPack &cGetRecentEmojis() { if (cRecentEmojis().isEmpty()) { RecentEmojiPack r; - if (!cRecentEmojisPreload().isEmpty() && false) { + if (!cRecentEmojisPreload().isEmpty()) { RecentEmojisPreload p(cRecentEmojisPreload()); cSetRecentEmojisPreload(RecentEmojisPreload()); r.reserve(p.size()); diff --git a/Telegram/SourceFiles/settingswidget.cpp b/Telegram/SourceFiles/settingswidget.cpp index e3a926992..85a0e5df1 100644 --- a/Telegram/SourceFiles/settingswidget.cpp +++ b/Telegram/SourceFiles/settingswidget.cpp @@ -822,7 +822,7 @@ void SettingsInner::mousePressEvent(QMouseEvent *e) { return; } if (QRect(_uploadPhoto.x() + st::setNameLeft, st::setTop + st::setNameTop, qMin(_uploadPhoto.width() - int(st::setNameLeft), _nameText.maxWidth()), st::setNameFont->height).contains(e->pos())) { - App::wnd()->showLayer(new AddContactBox(self())); + App::wnd()->showLayer(new EditNameTitleBox(self())); } else if (QRect(_left, st::setTop, st::setPhotoSize, st::setPhotoSize).contains(e->pos())) { if (_photoLink) { App::photo(self()->photoId)->full->load(); @@ -938,7 +938,7 @@ void SettingsInner::offPasswordDone(const MTPBool &result) { } bool SettingsInner::offPasswordFail(const RPCError &error) { - if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false; + if (mtpIsFlood(error)) return false; onReloadPassword(); return true; @@ -1459,6 +1459,7 @@ void SettingsInner::onIncludeMuted() { } void SettingsInner::onWindowsNotifications() { + if (cPlatform() != dbipWindows) return; cSetWindowsNotifications(!cWindowsNotifications()); App::wnd()->notifyClearFast(); cSetCustomNotifies(!cWindowsNotifications()); diff --git a/Telegram/Telegram.vcxproj b/Telegram/Telegram.vcxproj index 971426476..9a2473c0c 100644 --- a/Telegram/Telegram.vcxproj +++ b/Telegram/Telegram.vcxproj @@ -340,10 +340,6 @@ true true - - true - true - true true @@ -606,10 +602,6 @@ true true - - true - true - true true @@ -898,10 +890,6 @@ true true - - true - true - true true @@ -1014,7 +1002,6 @@ - @@ -1477,20 +1464,6 @@ $(QTDIR)\bin\moc.exe;%(FullPath) $(QTDIR)\bin\moc.exe;%(FullPath) - - Moc%27ing phoneinput.h... - .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp - "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\..\..\Libraries\ffmpeg-2.6.3" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.0\QtGui" "-fstdafx.h" "-f../../SourceFiles/gui/phoneinput.h" - Moc%27ing phoneinput.h... - Moc%27ing phoneinput.h... - .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp - .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp - "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DAL_LIBTYPE_STATIC -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\..\..\Libraries\libogg-1.3.2\include" "-I.\..\..\Libraries\opus\include" "-I.\..\..\Libraries\opusfile\include" "-I.\..\..\Libraries\mpg123-1.22.1\ports\MSVC++" "-I.\..\..\Libraries\mpg123-1.22.1\src\libmpg123" "-I.\..\..\Libraries\faad2-2.7\include" "-I.\..\..\Libraries\faad2-2.7\common\mp4ff" "-I.\..\..\Libraries\ffmpeg-2.6.3" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.0\QtGui" "-fstdafx.h" "-f../../SourceFiles/gui/phoneinput.h" - "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DAL_LIBTYPE_STATIC -DCUSTOM_API_ID -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG -D_SCL_SECURE_NO_WARNINGS "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\..\..\Libraries\ffmpeg-2.6.3" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.5.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.5.0\QtGui" "-fstdafx.h" "-f../../SourceFiles/gui/phoneinput.h" - $(QTDIR)\bin\moc.exe;%(FullPath) - $(QTDIR)\bin\moc.exe;%(FullPath) - $(QTDIR)\bin\moc.exe;%(FullPath) - Moc%27ing countryinput.h... .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp @@ -2151,4 +2124,4 @@ - + \ No newline at end of file diff --git a/Telegram/Telegram.vcxproj.filters b/Telegram/Telegram.vcxproj.filters index 547bf8990..47eb59868 100644 --- a/Telegram/Telegram.vcxproj.filters +++ b/Telegram/Telegram.vcxproj.filters @@ -84,9 +84,6 @@ gui - - gui - gui @@ -318,15 +315,6 @@ Generated Files\Release - - Generated Files\Deploy - - - Generated Files\Debug - - - Generated Files\Release - Generated Files\Deploy @@ -1023,9 +1011,6 @@ gui - - gui - gui