Dropdown replaced by Ui::DropdownMenu. ScrolledWidget removed.
Ui::DropdownMenu is like Ui::PopupMenu, both based on Ui::Menu.
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 48 KiB |
|
@ -272,36 +272,10 @@ solidScroll: flatScroll {
|
||||||
duration: 150;
|
duration: 150;
|
||||||
hiding: 0;
|
hiding: 0;
|
||||||
}
|
}
|
||||||
|
defaultDropdownDuration: 150;
|
||||||
|
defaultDropdownPadding: margins(10px, 10px, 10px, 10px);
|
||||||
defaultDropdownShadow: icon {{ "dropdown_shadow", windowShadowFg }};
|
defaultDropdownShadow: icon {{ "dropdown_shadow", windowShadowFg }};
|
||||||
defaultPopupMenu: PopupMenu {
|
defaultDropdownShadowShift: 1px;
|
||||||
skip: 5px;
|
|
||||||
|
|
||||||
shadow: defaultDropdownShadow;
|
|
||||||
shadowShift: 1px;
|
|
||||||
|
|
||||||
itemBg: white;
|
|
||||||
itemBgOver: overBg;
|
|
||||||
itemFg: black;
|
|
||||||
itemFgOver: black;
|
|
||||||
itemFgDisabled: #ccc;
|
|
||||||
itemFgShortcut: #999;
|
|
||||||
itemFgShortcutOver: #7c99b2;
|
|
||||||
itemFgShortcutDisabled: #ccc;
|
|
||||||
|
|
||||||
itemPadding: margins(17px, 8px, 17px, 7px);
|
|
||||||
itemFont: normalFont;
|
|
||||||
|
|
||||||
separatorPadding: margins(0px, 5px, 0px, 5px);
|
|
||||||
separatorWidth: 1px;
|
|
||||||
separatorFg: #f1f1f1;
|
|
||||||
|
|
||||||
arrow: icon {{ "dropdown_submenu_arrow", #373737 }};
|
|
||||||
|
|
||||||
duration: 120;
|
|
||||||
|
|
||||||
widthMin: 180px;
|
|
||||||
widthMax: 300px;
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultTooltip: Tooltip {
|
defaultTooltip: Tooltip {
|
||||||
textBg: #eef2f5;
|
textBg: #eef2f5;
|
||||||
|
@ -1088,54 +1062,6 @@ btnUnblock: flatButton(btnSend) {
|
||||||
downColor: #db6352;
|
downColor: #db6352;
|
||||||
}
|
}
|
||||||
|
|
||||||
btnAttachDocument: iconedButton(btnDefIconed) {
|
|
||||||
icon: sprite(218px, 68px, 24px, 24px);
|
|
||||||
iconPos: point(11px, 11px);
|
|
||||||
downIcon: sprite(218px, 68px, 24px, 24px);
|
|
||||||
downIconPos: point(11px, 12px);
|
|
||||||
|
|
||||||
overBgColor: btnWhiteHover;
|
|
||||||
width: 46px;
|
|
||||||
height: 46px;
|
|
||||||
}
|
|
||||||
btnAttachPhoto: iconedButton(btnAttachDocument) {
|
|
||||||
icon: sprite(118px, 0px, 24px, 24px);
|
|
||||||
downIcon: sprite(118px, 0px, 24px, 24px);
|
|
||||||
}
|
|
||||||
btnAttachEmoji: iconedButton(btnAttachDocument) {
|
|
||||||
overBgColor: white;
|
|
||||||
icon: sprite(374px, 344px, 21px, 22px);
|
|
||||||
iconPos: point(6px, 12px);
|
|
||||||
downIcon: sprite(374px, 344px, 21px, 22px);
|
|
||||||
downIconPos: point(6px, 12px);
|
|
||||||
|
|
||||||
width: 33px;
|
|
||||||
}
|
|
||||||
emojiCircle: size(19px, 19px);
|
|
||||||
emojiCirclePeriod: 1500;
|
|
||||||
emojiCircleDuration: 500;
|
|
||||||
emojiCircleTop: 13px;
|
|
||||||
emojiCircleLine: 2px;
|
|
||||||
emojiCircleFg: #b9b9b9;
|
|
||||||
emojiCirclePart: 3.5;
|
|
||||||
btnBotKbShow: iconedButton(btnAttachEmoji) {
|
|
||||||
icon: sprite(375px, 74px, 21px, 21px);
|
|
||||||
iconPos: point(6px, 12px);
|
|
||||||
downIcon: sprite(375px, 74px, 21px, 21px);
|
|
||||||
downIconPos: point(6px, 12px);
|
|
||||||
}
|
|
||||||
btnBotCmdStart: iconedButton(btnAttachEmoji) {
|
|
||||||
icon: sprite(354px, 74px, 21px, 21px);
|
|
||||||
iconPos: point(6px, 12px);
|
|
||||||
downIcon: sprite(354px, 74px, 21px, 21px);
|
|
||||||
downIconPos: point(6px, 12px);
|
|
||||||
}
|
|
||||||
btnBotKbHide: iconedButton(btnAttachEmoji) {
|
|
||||||
icon: sprite(373px, 95px, 23px, 14px);
|
|
||||||
iconPos: point(5px, 17px);
|
|
||||||
downIcon: sprite(373px, 95px, 23px, 14px);
|
|
||||||
downIconPos: point(5px, 17px);
|
|
||||||
}
|
|
||||||
silentToggle: flatCheckbox {
|
silentToggle: flatCheckbox {
|
||||||
textColor: black;
|
textColor: black;
|
||||||
bgColor: white;
|
bgColor: white;
|
||||||
|
@ -1158,15 +1084,6 @@ silentToggle: flatCheckbox {
|
||||||
|
|
||||||
imagePos: point(6px, 12px);
|
imagePos: point(6px, 12px);
|
||||||
}
|
}
|
||||||
btnRecordAudio: sprite(379px, 390px, 16px, 24px);
|
|
||||||
btnRecordAudioActive: sprite(379px, 366px, 16px, 24px);
|
|
||||||
recordSignalColor: #f17077;
|
|
||||||
recordSignalMin: 5px;
|
|
||||||
recordSignalMax: 12px;
|
|
||||||
recordCancel: #aaa;
|
|
||||||
recordCancelActive: #ec6466;
|
|
||||||
recordFont: font(13px);
|
|
||||||
recordTextTop: 14px;
|
|
||||||
|
|
||||||
replySkip: 51px;
|
replySkip: 51px;
|
||||||
replyColor: #377aae;
|
replyColor: #377aae;
|
||||||
|
@ -1418,68 +1335,6 @@ connectingBG: #fffe;
|
||||||
connectingColor: #777;
|
connectingColor: #777;
|
||||||
connectingPadding: margins(5px, 5px, 5px, 5px);
|
connectingPadding: margins(5px, 5px, 5px, 5px);
|
||||||
|
|
||||||
dropdownDef: dropdown {
|
|
||||||
border: 1px;
|
|
||||||
borderColor: #ebebeb;
|
|
||||||
|
|
||||||
padding: margins(10px, 10px, 10px, 10px);
|
|
||||||
shadow: defaultDropdownShadow;
|
|
||||||
shadowShift: 1px;
|
|
||||||
|
|
||||||
duration: 150;
|
|
||||||
width: 0px;
|
|
||||||
}
|
|
||||||
defaultInnerDropdown: InnerDropdown {
|
|
||||||
padding: margins(10px, 10px, 10px, 10px);
|
|
||||||
shadow: defaultDropdownShadow;
|
|
||||||
shadowShift: 1px;
|
|
||||||
|
|
||||||
duration: 150;
|
|
||||||
}
|
|
||||||
|
|
||||||
dropdownAttachDocument: iconedButton(btnAttachDocument) {
|
|
||||||
iconPos: point(14px, 13px);
|
|
||||||
downIconPos: point(14px, 14px);
|
|
||||||
|
|
||||||
width: 172px;
|
|
||||||
height: 49px;
|
|
||||||
|
|
||||||
color: black;
|
|
||||||
|
|
||||||
font: font(16px);
|
|
||||||
|
|
||||||
textPos: point(50px, 13px);
|
|
||||||
downTextPos: point(50px, 14px);
|
|
||||||
}
|
|
||||||
dropdownAttachPhoto: iconedButton(dropdownAttachDocument) {
|
|
||||||
icon: sprite(118px, 0px, 24px, 24px);
|
|
||||||
downIcon: sprite(118px, 0px, 24px, 24px);
|
|
||||||
}
|
|
||||||
dropdownMediaPhotos: iconedButton(dropdownAttachPhoto) {
|
|
||||||
width: 200px;
|
|
||||||
}
|
|
||||||
dropdownMediaVideos: iconedButton(dropdownMediaPhotos) {
|
|
||||||
icon: sprite(92px, 348px, 24px, 24px);
|
|
||||||
downIcon: sprite(92px, 348px, 24px, 24px);
|
|
||||||
}
|
|
||||||
dropdownMediaSongs: iconedButton(dropdownMediaPhotos) {
|
|
||||||
icon: sprite(60px, 374px, 24px, 26px);
|
|
||||||
downIcon: sprite(60px, 374px, 24px, 26px);
|
|
||||||
iconPos: point(12px, 12px);
|
|
||||||
downIconPos: point(12px, 13px);
|
|
||||||
}
|
|
||||||
dropdownMediaDocuments: iconedButton(dropdownAttachDocument) {
|
|
||||||
width: 200px;
|
|
||||||
}
|
|
||||||
dropdownMediaAudios: iconedButton(dropdownMediaDocuments) {
|
|
||||||
icon: sprite(62px, 348px, 24px, 24px);
|
|
||||||
downIcon: sprite(62px, 348px, 24px, 24px);
|
|
||||||
}
|
|
||||||
dropdownMediaLinks: iconedButton(dropdownMediaDocuments) {
|
|
||||||
icon: sprite(372px, 414px, 24px, 24px);
|
|
||||||
downIcon: sprite(372px, 414px, 24px, 24px);
|
|
||||||
}
|
|
||||||
|
|
||||||
dragFont: font(28px semibold);
|
dragFont: font(28px semibold);
|
||||||
dragSubfont: font(20px semibold);
|
dragSubfont: font(20px semibold);
|
||||||
dragColor: #777;
|
dragColor: #777;
|
||||||
|
@ -1720,49 +1575,6 @@ mvControlMargin: 0px;
|
||||||
mvControlSize: 90px;
|
mvControlSize: 90px;
|
||||||
mvIconSize: size(60px, 56px);
|
mvIconSize: size(60px, 56px);
|
||||||
|
|
||||||
mvDropdown: dropdown(dropdownDef) {
|
|
||||||
shadow: icon {};
|
|
||||||
padding: margins(11px, 12px, 11px, 12px);
|
|
||||||
|
|
||||||
border: 0px;
|
|
||||||
width: 182px;
|
|
||||||
}
|
|
||||||
mvButton: iconedButton(btnDefIconed) {
|
|
||||||
bgColor: #383838;
|
|
||||||
overBgColor: #505050;
|
|
||||||
font: font(fsize);
|
|
||||||
|
|
||||||
opacity: 1.;
|
|
||||||
overOpacity: 1.;
|
|
||||||
|
|
||||||
width: -32px;
|
|
||||||
height: 36px;
|
|
||||||
|
|
||||||
color: white;
|
|
||||||
|
|
||||||
textPos: point(16px, 9px);
|
|
||||||
downTextPos: point(16px, 10px);
|
|
||||||
|
|
||||||
duration: 0;
|
|
||||||
}
|
|
||||||
mvPopupMenu: PopupMenu(defaultPopupMenu) {
|
|
||||||
shadow: icon {};
|
|
||||||
|
|
||||||
itemBg: #383838;
|
|
||||||
itemBgOver: #505050;
|
|
||||||
itemFg: white;
|
|
||||||
itemFgOver: white;
|
|
||||||
itemFgDisabled: #999;
|
|
||||||
itemFgShortcut: #eee;
|
|
||||||
itemFgShortcutOver: #fff;
|
|
||||||
itemFgShortcutDisabled: #999;
|
|
||||||
|
|
||||||
separatorFg: #484848;
|
|
||||||
}
|
|
||||||
mvContextButton: iconedButton(mvButton) {
|
|
||||||
bgColor: #383838E6;
|
|
||||||
overBgColor: #505050E7;
|
|
||||||
}
|
|
||||||
mvWaitHide: 2000;
|
mvWaitHide: 2000;
|
||||||
mvHideDuration: 1000;
|
mvHideDuration: 1000;
|
||||||
mvShowDuration: 200;
|
mvShowDuration: 200;
|
||||||
|
@ -1818,23 +1630,6 @@ macAlwaysThisAppTop: 4;
|
||||||
macAppHintTop: 8;
|
macAppHintTop: 8;
|
||||||
macCautionIconSize: 16;
|
macCautionIconSize: 16;
|
||||||
|
|
||||||
btnContext: iconedButton(btnDefIconed) {
|
|
||||||
bgColor: white;
|
|
||||||
overBgColor: btnWhiteHover;
|
|
||||||
font: font(14px);
|
|
||||||
|
|
||||||
opacity: 1.;
|
|
||||||
overOpacity: 1.;
|
|
||||||
|
|
||||||
width: -32px;
|
|
||||||
height: 36px;
|
|
||||||
|
|
||||||
color: black;
|
|
||||||
|
|
||||||
textPos: point(16px, 7px);
|
|
||||||
downTextPos: point(16px, 8px);
|
|
||||||
}
|
|
||||||
|
|
||||||
radialSize: size(50px, 50px);
|
radialSize: size(50px, 50px);
|
||||||
radialLine: 3px;
|
radialLine: 3px;
|
||||||
radialDuration: 350;
|
radialDuration: 350;
|
||||||
|
|
|
@ -227,59 +227,6 @@ switcher {
|
||||||
duration: int;
|
duration: int;
|
||||||
}
|
}
|
||||||
|
|
||||||
dropdown {
|
|
||||||
border: pixels;
|
|
||||||
borderColor: color;
|
|
||||||
|
|
||||||
padding: margins;
|
|
||||||
shadow: icon;
|
|
||||||
shadowShift: pixels;
|
|
||||||
|
|
||||||
duration: int;
|
|
||||||
width: pixels;
|
|
||||||
}
|
|
||||||
|
|
||||||
InnerDropdown {
|
|
||||||
padding: margins;
|
|
||||||
shadow: icon;
|
|
||||||
shadowShift: pixels;
|
|
||||||
|
|
||||||
duration: int;
|
|
||||||
width: pixels;
|
|
||||||
|
|
||||||
scrollMargin: margins;
|
|
||||||
scrollPadding: margins;
|
|
||||||
}
|
|
||||||
|
|
||||||
PopupMenu {
|
|
||||||
skip: pixels;
|
|
||||||
|
|
||||||
shadow: icon;
|
|
||||||
shadowShift: pixels;
|
|
||||||
|
|
||||||
itemBg: color;
|
|
||||||
itemBgOver: color;
|
|
||||||
itemFg: color;
|
|
||||||
itemFgOver: color;
|
|
||||||
itemFgDisabled: color;
|
|
||||||
itemFgShortcut: color;
|
|
||||||
itemFgShortcutOver: color;
|
|
||||||
itemFgShortcutDisabled: color;
|
|
||||||
itemPadding: margins;
|
|
||||||
itemFont: font;
|
|
||||||
|
|
||||||
separatorPadding: margins;
|
|
||||||
separatorWidth: pixels;
|
|
||||||
separatorFg: color;
|
|
||||||
|
|
||||||
arrow: icon;
|
|
||||||
|
|
||||||
duration: int;
|
|
||||||
|
|
||||||
widthMin: pixels;
|
|
||||||
widthMax: pixels;
|
|
||||||
}
|
|
||||||
|
|
||||||
Tooltip {
|
Tooltip {
|
||||||
textBg: color;
|
textBg: color;
|
||||||
textFg: color;
|
textFg: color;
|
||||||
|
|
BIN
Telegram/Resources/icons/media_type_file.png
Normal file
After Width: | Height: | Size: 417 B |
BIN
Telegram/Resources/icons/media_type_file@2x.png
Normal file
After Width: | Height: | Size: 829 B |
BIN
Telegram/Resources/icons/media_type_link.png
Normal file
After Width: | Height: | Size: 450 B |
BIN
Telegram/Resources/icons/media_type_link@2x.png
Normal file
After Width: | Height: | Size: 884 B |
BIN
Telegram/Resources/icons/media_type_photo.png
Normal file
After Width: | Height: | Size: 451 B |
BIN
Telegram/Resources/icons/media_type_photo@2x.png
Normal file
After Width: | Height: | Size: 918 B |
BIN
Telegram/Resources/icons/media_type_song.png
Normal file
After Width: | Height: | Size: 577 B |
BIN
Telegram/Resources/icons/media_type_song@2x.png
Normal file
After Width: | Height: | Size: 1 KiB |
BIN
Telegram/Resources/icons/media_type_video.png
Normal file
After Width: | Height: | Size: 302 B |
BIN
Telegram/Resources/icons/media_type_video@2x.png
Normal file
After Width: | Height: | Size: 605 B |
BIN
Telegram/Resources/icons/media_type_voice.png
Normal file
After Width: | Height: | Size: 421 B |
BIN
Telegram/Resources/icons/media_type_voice@2x.png
Normal file
After Width: | Height: | Size: 779 B |
BIN
Telegram/Resources/icons/send_control_bot_command.png
Normal file
After Width: | Height: | Size: 400 B |
BIN
Telegram/Resources/icons/send_control_bot_command@2x.png
Normal file
After Width: | Height: | Size: 904 B |
BIN
Telegram/Resources/icons/send_control_bot_keyboard.png
Normal file
After Width: | Height: | Size: 308 B |
BIN
Telegram/Resources/icons/send_control_bot_keyboard@2x.png
Normal file
After Width: | Height: | Size: 643 B |
BIN
Telegram/Resources/icons/send_control_bot_keyboard_hide.png
Normal file
After Width: | Height: | Size: 160 B |
BIN
Telegram/Resources/icons/send_control_bot_keyboard_hide@2x.png
Normal file
After Width: | Height: | Size: 263 B |
BIN
Telegram/Resources/icons/send_control_emoji.png
Normal file
After Width: | Height: | Size: 227 B |
BIN
Telegram/Resources/icons/send_control_emoji@2x.png
Normal file
After Width: | Height: | Size: 360 B |
BIN
Telegram/Resources/icons/send_control_record.png
Normal file
After Width: | Height: | Size: 408 B |
BIN
Telegram/Resources/icons/send_control_record@2x.png
Normal file
After Width: | Height: | Size: 680 B |
|
@ -28,7 +28,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
#include "boxes/confirmbox.h"
|
#include "boxes/confirmbox.h"
|
||||||
#include "ui/filedialog.h"
|
#include "ui/filedialog.h"
|
||||||
#include "ui/popupmenu.h"
|
#include "ui/widgets/tooltip.h"
|
||||||
#include "langloaderplain.h"
|
#include "langloaderplain.h"
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
#include "autoupdater.h"
|
#include "autoupdater.h"
|
||||||
|
@ -926,7 +926,7 @@ void AppClass::onAppStateChanged(Qt::ApplicationState state) {
|
||||||
_window->updateIsActive((state == Qt::ApplicationActive) ? Global::OnlineFocusTimeout() : Global::OfflineBlurTimeout());
|
_window->updateIsActive((state == Qt::ApplicationActive) ? Global::OnlineFocusTimeout() : Global::OfflineBlurTimeout());
|
||||||
}
|
}
|
||||||
if (state != Qt::ApplicationActive) {
|
if (state != Qt::ApplicationActive) {
|
||||||
PopupTooltip::Hide();
|
Ui::Tooltip::Hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -201,7 +201,7 @@ void ScrollableBox::resizeEvent(QResizeEvent *e) {
|
||||||
AbstractBox::resizeEvent(e);
|
AbstractBox::resizeEvent(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScrollableBox::init(ScrolledWidget *inner, int bottomSkip, int topSkip) {
|
void ScrollableBox::init(TWidget *inner, int bottomSkip, int topSkip) {
|
||||||
_bottomSkip = bottomSkip;
|
_bottomSkip = bottomSkip;
|
||||||
_topSkip = topSkip;
|
_topSkip = topSkip;
|
||||||
_scroll->setOwnedWidget(inner);
|
_scroll->setOwnedWidget(inner);
|
||||||
|
|
|
@ -105,7 +105,7 @@ public:
|
||||||
ScrollableBox(const style::flatScroll &scroll, int w = st::boxWideWidth);
|
ScrollableBox(const style::flatScroll &scroll, int w = st::boxWideWidth);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void init(ScrolledWidget *inner, int bottomSkip = st::boxScrollSkip, int topSkip = st::boxTitleHeight);
|
void init(TWidget *inner, int bottomSkip = st::boxScrollSkip, int topSkip = st::boxTitleHeight);
|
||||||
void setScrollSkips(int bottomSkip = st::boxScrollSkip, int topSkip = st::boxTitleHeight);
|
void setScrollSkips(int bottomSkip = st::boxScrollSkip, int topSkip = st::boxTitleHeight);
|
||||||
|
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
|
|
|
@ -54,7 +54,7 @@ void BackgroundBox::onBackgroundChosen(int index) {
|
||||||
onClose();
|
onClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
BackgroundBox::Inner::Inner(QWidget *parent) : ScrolledWidget(parent)
|
BackgroundBox::Inner::Inner(QWidget *parent) : TWidget(parent)
|
||||||
, _bgCount(0)
|
, _bgCount(0)
|
||||||
, _rows(0)
|
, _rows(0)
|
||||||
, _over(-1)
|
, _over(-1)
|
||||||
|
|
|
@ -42,7 +42,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
// This class is hold in header because it requires Qt preprocessing.
|
// This class is hold in header because it requires Qt preprocessing.
|
||||||
class BackgroundBox::Inner : public ScrolledWidget, public RPCSender, private base::Subscriber {
|
class BackgroundBox::Inner : public TWidget, public RPCSender, private base::Subscriber {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -555,7 +555,7 @@ ContactsBox::Inner::ContactData::ContactData(PeerData *peer, base::lambda_wrap<v
|
||||||
: checkbox(std_::make_unique<Ui::RoundImageCheckbox>(st::contactsPhotoCheckbox, std_::move(updateCallback), PaintUserpicCallback(peer))) {
|
: checkbox(std_::make_unique<Ui::RoundImageCheckbox>(st::contactsPhotoCheckbox, std_::move(updateCallback), PaintUserpicCallback(peer))) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ContactsBox::Inner::Inner(QWidget *parent, CreatingGroupType creating) : ScrolledWidget(parent)
|
ContactsBox::Inner::Inner(QWidget *parent, CreatingGroupType creating) : TWidget(parent)
|
||||||
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
||||||
, _newItemHeight(creating == CreatingGroupNone ? st::contactsNewItemHeight : 0)
|
, _newItemHeight(creating == CreatingGroupNone ? st::contactsNewItemHeight : 0)
|
||||||
, _creating(creating)
|
, _creating(creating)
|
||||||
|
@ -565,7 +565,7 @@ ContactsBox::Inner::Inner(QWidget *parent, CreatingGroupType creating) : Scrolle
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
ContactsBox::Inner::Inner(QWidget *parent, ChannelData *channel, MembersFilter membersFilter, const MembersAlreadyIn &already) : ScrolledWidget(parent)
|
ContactsBox::Inner::Inner(QWidget *parent, ChannelData *channel, MembersFilter membersFilter, const MembersAlreadyIn &already) : TWidget(parent)
|
||||||
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
||||||
, _channel(channel)
|
, _channel(channel)
|
||||||
, _membersFilter(membersFilter)
|
, _membersFilter(membersFilter)
|
||||||
|
@ -583,7 +583,7 @@ namespace {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ContactsBox::Inner::Inner(QWidget *parent, ChatData *chat, MembersFilter membersFilter) : ScrolledWidget(parent)
|
ContactsBox::Inner::Inner(QWidget *parent, ChatData *chat, MembersFilter membersFilter) : TWidget(parent)
|
||||||
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
||||||
, _chat(chat)
|
, _chat(chat)
|
||||||
, _membersFilter(membersFilter)
|
, _membersFilter(membersFilter)
|
||||||
|
@ -615,7 +615,7 @@ void ContactsBox::Inner::addDialogsToList(FilterCallback callback) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ContactsBox::Inner::Inner(QWidget *parent, UserData *bot) : ScrolledWidget(parent)
|
ContactsBox::Inner::Inner(QWidget *parent, UserData *bot) : TWidget(parent)
|
||||||
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
||||||
, _bot(bot)
|
, _bot(bot)
|
||||||
, _allAdmins(this, lang(lng_chat_all_members_admins), false, st::contactsAdminCheckbox)
|
, _allAdmins(this, lang(lng_chat_all_members_admins), false, st::contactsAdminCheckbox)
|
||||||
|
|
|
@ -132,7 +132,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
// This class is hold in header because it requires Qt preprocessing.
|
// This class is hold in header because it requires Qt preprocessing.
|
||||||
class ContactsBox::Inner : public ScrolledWidget, public RPCSender, private base::Subscriber {
|
class ContactsBox::Inner : public TWidget, public RPCSender, private base::Subscriber {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -97,7 +97,7 @@ void MembersBox::onAdminAdded() {
|
||||||
_loadTimer.start(ReloadChannelMembersTimeout);
|
_loadTimer.start(ReloadChannelMembersTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
MembersBox::Inner::Inner(QWidget *parent, ChannelData *channel, MembersFilter filter) : ScrolledWidget(parent)
|
MembersBox::Inner::Inner(QWidget *parent, ChannelData *channel, MembersFilter filter) : TWidget(parent)
|
||||||
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
||||||
, _newItemHeight((channel->amCreator() && (channel->membersCount() < (channel->isMegagroup() ? Global::MegagroupSizeMax() : Global::ChatSizeMax()) || (!channel->isMegagroup() && !channel->isPublic()) || filter == MembersFilter::Admins)) ? st::contactsNewItemHeight : 0)
|
, _newItemHeight((channel->amCreator() && (channel->membersCount() < (channel->isMegagroup() ? Global::MegagroupSizeMax() : Global::ChatSizeMax()) || (!channel->isMegagroup() && !channel->isPublic()) || filter == MembersFilter::Admins)) ? st::contactsNewItemHeight : 0)
|
||||||
, _newItemSel(false)
|
, _newItemSel(false)
|
||||||
|
|
|
@ -61,7 +61,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
// This class is hold in header because it requires Qt preprocessing.
|
// This class is hold in header because it requires Qt preprocessing.
|
||||||
class MembersBox::Inner : public ScrolledWidget, public RPCSender, private base::Subscriber {
|
class MembersBox::Inner : public TWidget, public RPCSender, private base::Subscriber {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -242,7 +242,7 @@ void SessionsBox::onTerminateAll() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SessionsBox::Inner::Inner(QWidget *parent, SessionsBox::List *list, SessionsBox::Data *current) : ScrolledWidget(parent)
|
SessionsBox::Inner::Inner(QWidget *parent, SessionsBox::List *list, SessionsBox::Data *current) : TWidget(parent)
|
||||||
, _list(list)
|
, _list(list)
|
||||||
, _current(current)
|
, _current(current)
|
||||||
, _terminating(0)
|
, _terminating(0)
|
||||||
|
|
|
@ -72,7 +72,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
// This class is hold in header because it requires Qt preprocessing.
|
// This class is hold in header because it requires Qt preprocessing.
|
||||||
class SessionsBox::Inner : public ScrolledWidget, public RPCSender {
|
class SessionsBox::Inner : public TWidget, public RPCSender {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -289,7 +289,7 @@ void ShareBox::onScroll() {
|
||||||
_inner->setVisibleTopBottom(scrollTop, scrollTop + scroll->height());
|
_inner->setVisibleTopBottom(scrollTop, scrollTop + scroll->height());
|
||||||
}
|
}
|
||||||
|
|
||||||
ShareBox::Inner::Inner(QWidget *parent, ShareBox::FilterCallback &&filterCallback) : ScrolledWidget(parent)
|
ShareBox::Inner::Inner(QWidget *parent, ShareBox::FilterCallback &&filterCallback) : TWidget(parent)
|
||||||
, _filterCallback(std_::move(filterCallback))
|
, _filterCallback(std_::move(filterCallback))
|
||||||
, _chatsIndexed(std_::make_unique<Dialogs::IndexedList>(Dialogs::SortMode::Add)) {
|
, _chatsIndexed(std_::make_unique<Dialogs::IndexedList>(Dialogs::SortMode::Add)) {
|
||||||
_rowsTop = st::shareRowsTop;
|
_rowsTop = st::shareRowsTop;
|
||||||
|
|
|
@ -113,7 +113,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
// This class is hold in header because it requires Qt preprocessing.
|
// This class is hold in header because it requires Qt preprocessing.
|
||||||
class ShareBox::Inner : public ScrolledWidget, public RPCSender, private base::Subscriber {
|
class ShareBox::Inner : public TWidget, public RPCSender, private base::Subscriber {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -498,7 +498,7 @@ void StickersBox::showAll() {
|
||||||
ItemListBox::showAll();
|
ItemListBox::showAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
StickersBox::Inner::Inner(QWidget *parent, StickersBox::Section section) : ScrolledWidget(parent)
|
StickersBox::Inner::Inner(QWidget *parent, StickersBox::Section section) : TWidget(parent)
|
||||||
, _section(section)
|
, _section(section)
|
||||||
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
||||||
, _a_shifting(animation(this, &Inner::step_shifting))
|
, _a_shifting(animation(this, &Inner::step_shifting))
|
||||||
|
@ -511,7 +511,7 @@ StickersBox::Inner::Inner(QWidget *parent, StickersBox::Section section) : Scrol
|
||||||
setup();
|
setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
StickersBox::Inner::Inner(QWidget *parent, const Stickers::Order &archivedIds) : ScrolledWidget(parent)
|
StickersBox::Inner::Inner(QWidget *parent, const Stickers::Order &archivedIds) : TWidget(parent)
|
||||||
, _section(StickersBox::Section::ArchivedPart)
|
, _section(StickersBox::Section::ArchivedPart)
|
||||||
, _archivedIds(archivedIds)
|
, _archivedIds(archivedIds)
|
||||||
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
||||||
|
|
|
@ -103,7 +103,7 @@ private:
|
||||||
int32 stickerPacksCount(bool includeDisabledOfficial = false);
|
int32 stickerPacksCount(bool includeDisabledOfficial = false);
|
||||||
|
|
||||||
// This class is hold in header because it requires Qt preprocessing.
|
// This class is hold in header because it requires Qt preprocessing.
|
||||||
class StickersBox::Inner : public ScrolledWidget, public RPCSender, private base::Subscriber {
|
class StickersBox::Inner : public TWidget, public RPCSender, private base::Subscriber {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -147,7 +147,7 @@ void StickerSetBox::resizeEvent(QResizeEvent *e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StickerSetBox::Inner::Inner(QWidget *parent, const MTPInputStickerSet &set) : ScrolledWidget(parent)
|
StickerSetBox::Inner::Inner(QWidget *parent, const MTPInputStickerSet &set) : TWidget(parent)
|
||||||
, _input(set) {
|
, _input(set) {
|
||||||
switch (set.type()) {
|
switch (set.type()) {
|
||||||
case mtpc_inputStickerSetID: _setId = set.c_inputStickerSetID().vid.v; _setAccess = set.c_inputStickerSetID().vaccess_hash.v; break;
|
case mtpc_inputStickerSetID: _setId = set.c_inputStickerSetID().vid.v; _setAccess = set.c_inputStickerSetID().vaccess_hash.v; break;
|
||||||
|
|
|
@ -65,7 +65,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
// This class is hold in header because it requires Qt preprocessing.
|
// This class is hold in header because it requires Qt preprocessing.
|
||||||
class StickerSetBox::Inner : public ScrolledWidget, public RPCSender, private base::Subscriber {
|
class StickerSetBox::Inner : public TWidget, public RPCSender, private base::Subscriber {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -27,7 +27,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "core/qthelp_regex.h"
|
#include "core/qthelp_regex.h"
|
||||||
#include "core/qthelp_url.h"
|
#include "core/qthelp_url.h"
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
#include "ui/popupmenu.h"
|
#include "ui/widgets/tooltip.h"
|
||||||
|
|
||||||
QString UrlClickHandler::copyToClipboardContextItemText() const {
|
QString UrlClickHandler::copyToClipboardContextItemText() const {
|
||||||
return lang(isEmail() ? lng_context_copy_email : lng_context_copy_link);
|
return lang(isEmail() ? lng_context_copy_email : lng_context_copy_link);
|
||||||
|
@ -64,7 +64,7 @@ QString tryConvertUrlToLocal(QString url) {
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void UrlClickHandler::doOpen(QString url) {
|
void UrlClickHandler::doOpen(QString url) {
|
||||||
PopupTooltip::Hide();
|
Ui::Tooltip::Hide();
|
||||||
|
|
||||||
if (isEmail(url)) {
|
if (isEmail(url)) {
|
||||||
QUrl u(qstr("mailto:") + url);
|
QUrl u(qstr("mailto:") + url);
|
||||||
|
|
|
@ -25,7 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "dialogs/dialogs_layout.h"
|
#include "dialogs/dialogs_layout.h"
|
||||||
#include "styles/style_dialogs.h"
|
#include "styles/style_dialogs.h"
|
||||||
#include "ui/buttons/round_button.h"
|
#include "ui/buttons/round_button.h"
|
||||||
#include "ui/popupmenu.h"
|
#include "ui/widgets/popup_menu.h"
|
||||||
#include "data/data_drafts.h"
|
#include "data/data_drafts.h"
|
||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
|
@ -639,7 +639,7 @@ void DialogsInner::contextMenuEvent(QContextMenuEvent *e) {
|
||||||
if (!history) return;
|
if (!history) return;
|
||||||
_menuPeer = history->peer;
|
_menuPeer = history->peer;
|
||||||
|
|
||||||
_menu = new PopupMenu();
|
_menu = new Ui::PopupMenu();
|
||||||
_menu->addAction(lang((_menuPeer->isChat() || _menuPeer->isMegagroup()) ? lng_context_view_group : (_menuPeer->isUser() ? lng_context_view_profile : lng_context_view_channel)), this, SLOT(onContextProfile()))->setEnabled(true);
|
_menu->addAction(lang((_menuPeer->isChat() || _menuPeer->isMegagroup()) ? lng_context_view_group : (_menuPeer->isUser() ? lng_context_view_profile : lng_context_view_channel)), this, SLOT(onContextProfile()))->setEnabled(true);
|
||||||
_menu->addAction(lang(menuPeerMuted() ? lng_enable_notifications_from_tray : lng_disable_notifications_from_tray), this, SLOT(onContextToggleNotifications()))->setEnabled(true);
|
_menu->addAction(lang(menuPeerMuted() ? lng_enable_notifications_from_tray : lng_disable_notifications_from_tray), this, SLOT(onContextToggleNotifications()))->setEnabled(true);
|
||||||
_menu->addAction(lang(lng_profile_search_messages), this, SLOT(onContextSearch()))->setEnabled(true);
|
_menu->addAction(lang(lng_profile_search_messages), this, SLOT(onContextSearch()))->setEnabled(true);
|
||||||
|
|
|
@ -30,10 +30,10 @@ class IndexedList;
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class RoundButton;
|
class RoundButton;
|
||||||
|
class PopupMenu;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
class MainWidget;
|
class MainWidget;
|
||||||
class PopupMenu;
|
|
||||||
|
|
||||||
enum DialogsSearchRequestType {
|
enum DialogsSearchRequestType {
|
||||||
DialogsSearchFromStart,
|
DialogsSearchFromStart,
|
||||||
|
@ -230,7 +230,7 @@ private:
|
||||||
PeerData *_menuPeer = nullptr;
|
PeerData *_menuPeer = nullptr;
|
||||||
PeerData *_menuActionPeer = nullptr;
|
PeerData *_menuActionPeer = nullptr;
|
||||||
|
|
||||||
PopupMenu *_menu = nullptr;
|
Ui::PopupMenu *_menu = nullptr;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,456 +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-2016 John Preston, https://desktop.telegram.org
|
|
||||||
*/
|
|
||||||
#include "stdafx.h"
|
|
||||||
#include "dropdown.h"
|
|
||||||
|
|
||||||
#include "styles/style_stickers.h"
|
|
||||||
#include "boxes/confirmbox.h"
|
|
||||||
#include "boxes/stickersetbox.h"
|
|
||||||
#include "inline_bots/inline_bot_result.h"
|
|
||||||
#include "inline_bots/inline_bot_layout_item.h"
|
|
||||||
#include "dialogs/dialogs_layout.h"
|
|
||||||
#include "historywidget.h"
|
|
||||||
#include "localstorage.h"
|
|
||||||
#include "lang.h"
|
|
||||||
#include "mainwindow.h"
|
|
||||||
#include "apiwrap.h"
|
|
||||||
#include "mainwidget.h"
|
|
||||||
|
|
||||||
Dropdown::Dropdown(QWidget *parent, const style::dropdown &st) : TWidget(parent)
|
|
||||||
, _st(st)
|
|
||||||
, _width(_st.width)
|
|
||||||
, a_opacity(0)
|
|
||||||
, _a_appearance(animation(this, &Dropdown::step_appearance))
|
|
||||||
, _shadow(_st.shadow) {
|
|
||||||
resetButtons();
|
|
||||||
|
|
||||||
_hideTimer.setSingleShot(true);
|
|
||||||
connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(hideStart()));
|
|
||||||
|
|
||||||
if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) {
|
|
||||||
connect(App::wnd()->windowHandle(), SIGNAL(activeChanged()), this, SLOT(onWndActiveChanged()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dropdown::ignoreShow(bool ignore) {
|
|
||||||
_ignore = ignore;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dropdown::onWndActiveChanged() {
|
|
||||||
if (!App::wnd()->windowHandle()->isActive() && !isHidden()) {
|
|
||||||
leaveEvent(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IconedButton *Dropdown::addButton(IconedButton *button) {
|
|
||||||
button->setParent(this);
|
|
||||||
|
|
||||||
int32 nw = _st.padding.left() + _st.padding.right() + button->width();
|
|
||||||
if (nw > _width) {
|
|
||||||
_width = nw;
|
|
||||||
for (int32 i = 0, l = _buttons.size(); i < l; ++i) _buttons[i]->resize(_width - _st.padding.left() - _st.padding.right(), _buttons[i]->height());
|
|
||||||
} else {
|
|
||||||
button->resize(_width - _st.padding.left() - _st.padding.right(), button->height());
|
|
||||||
}
|
|
||||||
if (!button->isHidden()) {
|
|
||||||
if (_height > _st.padding.top() + _st.padding.bottom()) {
|
|
||||||
_height += _st.border;
|
|
||||||
}
|
|
||||||
_height += button->height();
|
|
||||||
}
|
|
||||||
_buttons.push_back(button);
|
|
||||||
connect(button, SIGNAL(stateChanged(int, ButtonStateChangeSource)), this, SLOT(buttonStateChanged(int, ButtonStateChangeSource)));
|
|
||||||
|
|
||||||
resize(_width, _height);
|
|
||||||
|
|
||||||
return button;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dropdown::resetButtons() {
|
|
||||||
_width = qMax(_st.padding.left() + _st.padding.right(), int(_st.width));
|
|
||||||
_height = _st.padding.top() + _st.padding.bottom();
|
|
||||||
for (int32 i = 0, l = _buttons.size(); i < l; ++i) {
|
|
||||||
delete _buttons[i];
|
|
||||||
}
|
|
||||||
_buttons.clear();
|
|
||||||
resize(_width, _height);
|
|
||||||
|
|
||||||
_selected = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dropdown::updateButtons() {
|
|
||||||
int32 top = _st.padding.top(), starttop = top;
|
|
||||||
for (Buttons::const_iterator i = _buttons.cbegin(), e = _buttons.cend(); i != e; ++i) {
|
|
||||||
if (!(*i)->isHidden()) {
|
|
||||||
(*i)->move(_st.padding.left(), top);
|
|
||||||
if ((*i)->width() != _width - _st.padding.left() - _st.padding.right()) {
|
|
||||||
(*i)->resize(_width - _st.padding.left() - _st.padding.right(), (*i)->height());
|
|
||||||
}
|
|
||||||
top += (*i)->height() + _st.border;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_height = top + _st.padding.bottom() - (top > starttop ? _st.border : 0);
|
|
||||||
resize(_width, _height);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dropdown::resizeEvent(QResizeEvent *e) {
|
|
||||||
int32 top = _st.padding.top();
|
|
||||||
for (Buttons::const_iterator i = _buttons.cbegin(), e = _buttons.cend(); i != e; ++i) {
|
|
||||||
if (!(*i)->isHidden()) {
|
|
||||||
(*i)->move(_st.padding.left(), top);
|
|
||||||
top += (*i)->height() + _st.border;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dropdown::paintEvent(QPaintEvent *e) {
|
|
||||||
Painter p(this);
|
|
||||||
|
|
||||||
if (_a_appearance.animating()) {
|
|
||||||
p.setOpacity(a_opacity.current());
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw shadow
|
|
||||||
QRect r(_st.padding.left(), _st.padding.top(), _width - _st.padding.left() - _st.padding.right(), _height - _st.padding.top() - _st.padding.bottom());
|
|
||||||
_shadow.paint(p, r, _st.shadowShift);
|
|
||||||
|
|
||||||
if (!_buttons.isEmpty() && _st.border > 0) { // paint separators
|
|
||||||
p.setPen(_st.borderColor->p);
|
|
||||||
int32 top = _st.padding.top(), i = 0, l = _buttons.size();
|
|
||||||
for (; i < l; ++i) {
|
|
||||||
if (!_buttons.at(i)->isHidden()) break;
|
|
||||||
}
|
|
||||||
if (i < l) {
|
|
||||||
top += _buttons.at(i)->height();
|
|
||||||
for (++i; i < l; ++i) {
|
|
||||||
if (!_buttons.at(i)->isHidden()) {
|
|
||||||
p.fillRect(_st.padding.left(), top, _width - _st.padding.left() - _st.padding.right(), _st.border, _st.borderColor->b);
|
|
||||||
top += _st.border + _buttons.at(i)->height();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dropdown::enterEvent(QEvent *e) {
|
|
||||||
_hideTimer.stop();
|
|
||||||
if (_hiding) showStart();
|
|
||||||
return TWidget::enterEvent(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dropdown::leaveEvent(QEvent *e) {
|
|
||||||
if (_a_appearance.animating()) {
|
|
||||||
hideStart();
|
|
||||||
} else {
|
|
||||||
_hideTimer.start(300);
|
|
||||||
}
|
|
||||||
return TWidget::leaveEvent(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dropdown::keyPressEvent(QKeyEvent *e) {
|
|
||||||
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
|
|
||||||
if (_selected >= 0 && _selected < _buttons.size()) {
|
|
||||||
emit _buttons[_selected]->clicked();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else if (e->key() == Qt::Key_Escape) {
|
|
||||||
hideStart();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ((e->key() != Qt::Key_Up && e->key() != Qt::Key_Down) || _buttons.size() < 1) return;
|
|
||||||
|
|
||||||
bool none = (_selected < 0 || _selected >= _buttons.size());
|
|
||||||
int32 delta = (e->key() == Qt::Key_Down ? 1 : -1);
|
|
||||||
int32 newSelected = none ? (e->key() == Qt::Key_Down ? 0 : _buttons.size() - 1) : (_selected + delta);
|
|
||||||
if (newSelected < 0) {
|
|
||||||
newSelected = _buttons.size() - 1;
|
|
||||||
} else if (newSelected >= _buttons.size()) {
|
|
||||||
newSelected = 0;
|
|
||||||
}
|
|
||||||
int32 startFrom = newSelected;
|
|
||||||
while (_buttons.at(newSelected)->isHidden()) {
|
|
||||||
newSelected += delta;
|
|
||||||
if (newSelected < 0) {
|
|
||||||
newSelected = _buttons.size() - 1;
|
|
||||||
} else if (newSelected >= _buttons.size()) {
|
|
||||||
newSelected = 0;
|
|
||||||
}
|
|
||||||
if (newSelected == startFrom) return;
|
|
||||||
}
|
|
||||||
if (!none) {
|
|
||||||
_buttons[_selected]->setOver(false);
|
|
||||||
}
|
|
||||||
_selected = newSelected;
|
|
||||||
_buttons[_selected]->setOver(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dropdown::buttonStateChanged(int oldState, ButtonStateChangeSource source) {
|
|
||||||
if (source == ButtonByUser) {
|
|
||||||
for (int32 i = 0, l = _buttons.size(); i < l; ++i) {
|
|
||||||
if (_buttons[i]->getState() & Button::StateOver) {
|
|
||||||
if (i != _selected) {
|
|
||||||
_buttons[i]->setOver(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (source == ButtonByHover) {
|
|
||||||
bool found = false;
|
|
||||||
for (int32 i = 0, l = _buttons.size(); i < l; ++i) {
|
|
||||||
if (_buttons[i]->getState() & Button::StateOver) {
|
|
||||||
found = true;
|
|
||||||
if (i != _selected) {
|
|
||||||
int32 sel = _selected;
|
|
||||||
_selected = i;
|
|
||||||
if (sel >= 0 && sel < _buttons.size()) {
|
|
||||||
_buttons[sel]->setOver(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
_selected = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dropdown::otherEnter() {
|
|
||||||
_hideTimer.stop();
|
|
||||||
showStart();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dropdown::otherLeave() {
|
|
||||||
if (_a_appearance.animating()) {
|
|
||||||
hideStart();
|
|
||||||
} else {
|
|
||||||
_hideTimer.start(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dropdown::fastHide() {
|
|
||||||
if (_a_appearance.animating()) {
|
|
||||||
_a_appearance.stop();
|
|
||||||
}
|
|
||||||
a_opacity = anim::fvalue(0, 0);
|
|
||||||
_hideTimer.stop();
|
|
||||||
hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dropdown::adjustButtons() {
|
|
||||||
for (Buttons::const_iterator i = _buttons.cbegin(), e = _buttons.cend(); i != e; ++i) {
|
|
||||||
(*i)->setOpacity(a_opacity.current());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dropdown::hideStart() {
|
|
||||||
_hiding = true;
|
|
||||||
a_opacity.start(0);
|
|
||||||
_a_appearance.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dropdown::hideFinish() {
|
|
||||||
emit hiding();
|
|
||||||
hide();
|
|
||||||
for (Buttons::const_iterator i = _buttons.cbegin(), e = _buttons.cend(); i != e; ++i) {
|
|
||||||
(*i)->clearState();
|
|
||||||
}
|
|
||||||
_selected = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dropdown::showStart() {
|
|
||||||
if (!isHidden() && a_opacity.current() == 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_selected = -1;
|
|
||||||
_hiding = false;
|
|
||||||
show();
|
|
||||||
a_opacity.start(1);
|
|
||||||
_a_appearance.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dropdown::step_appearance(float64 ms, bool timer) {
|
|
||||||
float64 dt = ms / _st.duration;
|
|
||||||
if (dt >= 1) {
|
|
||||||
_a_appearance.stop();
|
|
||||||
a_opacity.finish();
|
|
||||||
if (_hiding) {
|
|
||||||
hideFinish();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
a_opacity.update(dt, anim::linear);
|
|
||||||
}
|
|
||||||
adjustButtons();
|
|
||||||
if (timer) update();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Dropdown::eventFilter(QObject *obj, QEvent *e) {
|
|
||||||
if (e->type() == QEvent::Enter) {
|
|
||||||
otherEnter();
|
|
||||||
} else if (e->type() == QEvent::Leave) {
|
|
||||||
otherLeave();
|
|
||||||
} else if (e->type() == QEvent::MouseButtonPress && static_cast<QMouseEvent*>(e)->button() == Qt::LeftButton) {
|
|
||||||
if (isHidden() || _hiding) {
|
|
||||||
otherEnter();
|
|
||||||
} else {
|
|
||||||
otherLeave();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
DragArea::DragArea(QWidget *parent) : TWidget(parent)
|
|
||||||
, _hiding(false)
|
|
||||||
, _in(false)
|
|
||||||
, a_opacity(0)
|
|
||||||
, a_color(st::dragColor->c)
|
|
||||||
, _a_appearance(animation(this, &DragArea::step_appearance))
|
|
||||||
, _shadow(st::boxShadow) {
|
|
||||||
setMouseTracking(true);
|
|
||||||
setAcceptDrops(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DragArea::mouseMoveEvent(QMouseEvent *e) {
|
|
||||||
if (_hiding) return;
|
|
||||||
|
|
||||||
bool newIn = QRect(st::dragPadding.left(), st::dragPadding.top(), width() - st::dragPadding.left() - st::dragPadding.right(), height() - st::dragPadding.top() - st::dragPadding.bottom()).contains(e->pos());
|
|
||||||
if (newIn != _in) {
|
|
||||||
_in = newIn;
|
|
||||||
a_opacity.start(1);
|
|
||||||
a_color.start((_in ? st::dragDropColor : st::dragColor)->c);
|
|
||||||
_a_appearance.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DragArea::dragMoveEvent(QDragMoveEvent *e) {
|
|
||||||
QRect r(st::dragPadding.left(), st::dragPadding.top(), width() - st::dragPadding.left() - st::dragPadding.right(), height() - st::dragPadding.top() - st::dragPadding.bottom());
|
|
||||||
bool newIn = r.contains(e->pos());
|
|
||||||
if (newIn != _in) {
|
|
||||||
_in = newIn;
|
|
||||||
a_opacity.start(1);
|
|
||||||
a_color.start((_in ? st::dragDropColor : st::dragColor)->c);
|
|
||||||
_a_appearance.start();
|
|
||||||
}
|
|
||||||
e->setDropAction(_in ? Qt::CopyAction : Qt::IgnoreAction);
|
|
||||||
e->accept();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DragArea::setText(const QString &text, const QString &subtext) {
|
|
||||||
_text = text;
|
|
||||||
_subtext = subtext;
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DragArea::paintEvent(QPaintEvent *e) {
|
|
||||||
Painter p(this);
|
|
||||||
|
|
||||||
if (_a_appearance.animating()) {
|
|
||||||
p.setOpacity(a_opacity.current());
|
|
||||||
}
|
|
||||||
|
|
||||||
QRect r(st::dragPadding.left(), st::dragPadding.top(), width() - st::dragPadding.left() - st::dragPadding.right(), height() - st::dragPadding.top() - st::dragPadding.bottom());
|
|
||||||
|
|
||||||
// draw shadow
|
|
||||||
_shadow.paint(p, r, st::boxShadowShift);
|
|
||||||
|
|
||||||
p.fillRect(r, st::white->b);
|
|
||||||
|
|
||||||
p.setPen(a_color.current());
|
|
||||||
|
|
||||||
p.setFont(st::dragFont->f);
|
|
||||||
p.drawText(QRect(0, (height() - st::dragHeight) / 2, width(), st::dragFont->height), _text, QTextOption(style::al_top));
|
|
||||||
|
|
||||||
p.setFont(st::dragSubfont->f);
|
|
||||||
p.drawText(QRect(0, (height() + st::dragHeight) / 2 - st::dragSubfont->height, width(), st::dragSubfont->height * 2), _subtext, QTextOption(style::al_top));
|
|
||||||
}
|
|
||||||
|
|
||||||
void DragArea::dragEnterEvent(QDragEnterEvent *e) {
|
|
||||||
static_cast<HistoryWidget*>(parentWidget())->dragEnterEvent(e);
|
|
||||||
e->setDropAction(Qt::IgnoreAction);
|
|
||||||
e->accept();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DragArea::dragLeaveEvent(QDragLeaveEvent *e) {
|
|
||||||
static_cast<HistoryWidget*>(parentWidget())->dragLeaveEvent(e);
|
|
||||||
_in = false;
|
|
||||||
a_opacity.start(_hiding ? 0 : 1);
|
|
||||||
a_color.start((_in ? st::dragDropColor : st::dragColor)->c);
|
|
||||||
_a_appearance.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DragArea::dropEvent(QDropEvent *e) {
|
|
||||||
static_cast<HistoryWidget*>(parentWidget())->dropEvent(e);
|
|
||||||
if (e->isAccepted()) {
|
|
||||||
emit dropped(e->mimeData());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DragArea::otherEnter() {
|
|
||||||
showStart();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DragArea::otherLeave() {
|
|
||||||
hideStart();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DragArea::fastHide() {
|
|
||||||
if (_a_appearance.animating()) {
|
|
||||||
_a_appearance.stop();
|
|
||||||
}
|
|
||||||
a_opacity = anim::fvalue(0, 0);
|
|
||||||
hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DragArea::hideStart() {
|
|
||||||
_hiding = true;
|
|
||||||
_in = false;
|
|
||||||
a_opacity.start(0);
|
|
||||||
a_color.start((_in ? st::dragDropColor : st::dragColor)->c);
|
|
||||||
_a_appearance.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DragArea::hideFinish() {
|
|
||||||
hide();
|
|
||||||
_in = false;
|
|
||||||
a_color = anim::cvalue(st::dragColor->c);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DragArea::showStart() {
|
|
||||||
_hiding = false;
|
|
||||||
show();
|
|
||||||
a_opacity.start(1);
|
|
||||||
a_color.start((_in ? st::dragDropColor : st::dragColor)->c);
|
|
||||||
_a_appearance.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DragArea::step_appearance(float64 ms, bool timer) {
|
|
||||||
float64 dt = ms / st::dropdownDef.duration;
|
|
||||||
if (dt >= 1) {
|
|
||||||
a_opacity.finish();
|
|
||||||
a_color.finish();
|
|
||||||
if (_hiding) {
|
|
||||||
hideFinish();
|
|
||||||
}
|
|
||||||
_a_appearance.stop();
|
|
||||||
} else {
|
|
||||||
a_opacity.update(dt, anim::linear);
|
|
||||||
a_color.update(dt, anim::linear);
|
|
||||||
}
|
|
||||||
if (timer) update();
|
|
||||||
}
|
|
|
@ -24,6 +24,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
|
#include "styles/style_history.h"
|
||||||
|
|
||||||
FieldAutocomplete::FieldAutocomplete(QWidget *parent) : TWidget(parent)
|
FieldAutocomplete::FieldAutocomplete(QWidget *parent) : TWidget(parent)
|
||||||
, _scroll(this, st::mentionScroll)
|
, _scroll(this, st::mentionScroll)
|
||||||
|
@ -333,7 +334,7 @@ void FieldAutocomplete::updateFiltered(bool resetScroll) {
|
||||||
void FieldAutocomplete::rowsUpdated(const internal::MentionRows &mrows, const internal::HashtagRows &hrows, const internal::BotCommandRows &brows, const StickerPack &srows, bool resetScroll) {
|
void FieldAutocomplete::rowsUpdated(const internal::MentionRows &mrows, const internal::HashtagRows &hrows, const internal::BotCommandRows &brows, const StickerPack &srows, bool resetScroll) {
|
||||||
if (mrows.isEmpty() && hrows.isEmpty() && brows.isEmpty() && srows.isEmpty()) {
|
if (mrows.isEmpty() && hrows.isEmpty() && brows.isEmpty() && srows.isEmpty()) {
|
||||||
if (!isHidden()) {
|
if (!isHidden()) {
|
||||||
hideStart();
|
hideAnimated();
|
||||||
}
|
}
|
||||||
_mrows.clear();
|
_mrows.clear();
|
||||||
_hrows.clear();
|
_hrows.clear();
|
||||||
|
@ -354,7 +355,7 @@ void FieldAutocomplete::rowsUpdated(const internal::MentionRows &mrows, const in
|
||||||
update();
|
update();
|
||||||
if (hidden) {
|
if (hidden) {
|
||||||
hide();
|
hide();
|
||||||
showStart();
|
showAnimated();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -394,7 +395,7 @@ void FieldAutocomplete::recount(bool resetScroll) {
|
||||||
if (resetScroll) _inner->clearSel();
|
if (resetScroll) _inner->clearSel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FieldAutocomplete::fastHide() {
|
void FieldAutocomplete::hideFast() {
|
||||||
if (_a_appearance.animating()) {
|
if (_a_appearance.animating()) {
|
||||||
_a_appearance.stop();
|
_a_appearance.stop();
|
||||||
}
|
}
|
||||||
|
@ -403,18 +404,20 @@ void FieldAutocomplete::fastHide() {
|
||||||
hideFinish();
|
hideFinish();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FieldAutocomplete::hideStart() {
|
void FieldAutocomplete::hideAnimated() {
|
||||||
if (!_hiding) {
|
if (isHidden() || _hiding) {
|
||||||
if (_cache.isNull()) {
|
return;
|
||||||
_scroll->show();
|
|
||||||
_cache = myGrab(this);
|
|
||||||
}
|
|
||||||
_scroll->hide();
|
|
||||||
_hiding = true;
|
|
||||||
a_opacity.start(0);
|
|
||||||
setAttribute(Qt::WA_OpaquePaintEvent, false);
|
|
||||||
_a_appearance.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_cache.isNull()) {
|
||||||
|
_scroll->show();
|
||||||
|
_cache = myGrab(this);
|
||||||
|
}
|
||||||
|
_scroll->hide();
|
||||||
|
_hiding = true;
|
||||||
|
a_opacity.start(0);
|
||||||
|
setAttribute(Qt::WA_OpaquePaintEvent, false);
|
||||||
|
_a_appearance.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FieldAutocomplete::hideFinish() {
|
void FieldAutocomplete::hideFinish() {
|
||||||
|
@ -424,7 +427,7 @@ void FieldAutocomplete::hideFinish() {
|
||||||
_inner->clearSel(true);
|
_inner->clearSel(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FieldAutocomplete::showStart() {
|
void FieldAutocomplete::showAnimated() {
|
||||||
if (!isHidden() && a_opacity.current() == 1 && !_hiding) {
|
if (!isHidden() && a_opacity.current() == 1 && !_hiding) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -441,7 +444,7 @@ void FieldAutocomplete::showStart() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FieldAutocomplete::step_appearance(float64 ms, bool timer) {
|
void FieldAutocomplete::step_appearance(float64 ms, bool timer) {
|
||||||
float64 dt = ms / st::dropdownDef.duration;
|
float64 dt = ms / st::defaultDropdownDuration;
|
||||||
if (dt >= 1) {
|
if (dt >= 1) {
|
||||||
_a_appearance.stop();
|
_a_appearance.stop();
|
||||||
a_opacity.finish();
|
a_opacity.finish();
|
||||||
|
@ -544,7 +547,7 @@ void FieldAutocompleteInner::paintEvent(QPaintEvent *e) {
|
||||||
int32 atwidth = st::mentionFont->width('@'), hashwidth = st::mentionFont->width('#');
|
int32 atwidth = st::mentionFont->width('@'), hashwidth = st::mentionFont->width('#');
|
||||||
int32 mentionleft = 2 * st::mentionPadding.left() + st::mentionPhotoSize;
|
int32 mentionleft = 2 * st::mentionPadding.left() + st::mentionPhotoSize;
|
||||||
int32 mentionwidth = width() - mentionleft - 2 * st::mentionPadding.right();
|
int32 mentionwidth = width() - mentionleft - 2 * st::mentionPadding.right();
|
||||||
int32 htagleft = st::btnAttachPhoto.width + st::taMsgField.textMrg.left() - st::lineWidth, htagwidth = width() - st::mentionPadding.right() - htagleft - st::mentionScroll.width;
|
int32 htagleft = st::historyAttachPhoto.width + st::taMsgField.textMrg.left() - st::lineWidth, htagwidth = width() - st::mentionPadding.right() - htagleft - st::mentionScroll.width;
|
||||||
|
|
||||||
if (!_srows->isEmpty()) {
|
if (!_srows->isEmpty()) {
|
||||||
int32 rows = rowscount(_srows->size(), _stickersPerRow);
|
int32 rows = rowscount(_srows->size(), _stickersPerRow);
|
||||||
|
@ -650,7 +653,7 @@ void FieldAutocompleteInner::paintEvent(QPaintEvent *e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p.setFont(st::mentionFont->f);
|
p.setFont(st::mentionFont);
|
||||||
if (!first.isEmpty()) {
|
if (!first.isEmpty()) {
|
||||||
p.setPen((selected ? st::mentionFgOverActive : st::mentionFgActive)->p);
|
p.setPen((selected ? st::mentionFgOverActive : st::mentionFgActive)->p);
|
||||||
p.drawText(htagleft, i * st::mentionHeight + st::mentionTop + st::mentionFont->ascent, first);
|
p.drawText(htagleft, i * st::mentionHeight + st::mentionTop + st::mentionFont->ascent, first);
|
||||||
|
|
|
@ -39,8 +39,6 @@ class FieldAutocomplete final : public TWidget {
|
||||||
public:
|
public:
|
||||||
FieldAutocomplete(QWidget *parent);
|
FieldAutocomplete(QWidget *parent);
|
||||||
|
|
||||||
void fastHide();
|
|
||||||
|
|
||||||
bool clearFilteredBotCommands();
|
bool clearFilteredBotCommands();
|
||||||
void showFiltered(PeerData *peer, QString query, bool addInlineBots);
|
void showFiltered(PeerData *peer, QString query, bool addInlineBots);
|
||||||
void showStickers(EmojiPtr emoji);
|
void showStickers(EmojiPtr emoji);
|
||||||
|
@ -75,6 +73,8 @@ public:
|
||||||
return rect().contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
|
return rect().contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hideFast();
|
||||||
|
|
||||||
~FieldAutocomplete();
|
~FieldAutocomplete();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
@ -86,15 +86,15 @@ signals:
|
||||||
void moderateKeyActivate(int key, bool *outHandled) const;
|
void moderateKeyActivate(int key, bool *outHandled) const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void hideStart();
|
void showAnimated();
|
||||||
void hideFinish();
|
void hideAnimated();
|
||||||
|
|
||||||
void showStart();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void paintEvent(QPaintEvent *e) override;
|
void paintEvent(QPaintEvent *e) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void hideFinish();
|
||||||
|
|
||||||
void updateFiltered(bool resetScroll = false);
|
void updateFiltered(bool resetScroll = false);
|
||||||
void recount(bool resetScroll = false);
|
void recount(bool resetScroll = false);
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
using "basic.style";
|
using "basic.style";
|
||||||
using "dialogs/dialogs.style";
|
using "dialogs/dialogs.style";
|
||||||
|
using "ui/widgets/widgets.style";
|
||||||
|
|
||||||
historyPaddingBottom: 10px;
|
historyPaddingBottom: 10px;
|
||||||
|
|
||||||
|
@ -38,16 +39,16 @@ historyToDownBadgeSize: 22px;
|
||||||
historyEmptyDog: icon {{ "history_empty_dog", #ffffff }};
|
historyEmptyDog: icon {{ "history_empty_dog", #ffffff }};
|
||||||
historyEmptySize: 128px;
|
historyEmptySize: 128px;
|
||||||
|
|
||||||
membersInnerScroll: flatScroll(solidScroll) {
|
|
||||||
deltat: 3px;
|
|
||||||
deltab: 3px;
|
|
||||||
round: 1px;
|
|
||||||
width: 8px;
|
|
||||||
deltax: 3px;
|
|
||||||
}
|
|
||||||
membersInnerWidth: 310px;
|
membersInnerWidth: 310px;
|
||||||
membersInnerHeightMax: 360px;
|
membersInnerHeightMax: 360px;
|
||||||
membersInnerDropdown: InnerDropdown(defaultInnerDropdown) {
|
membersInnerDropdown: InnerDropdown(defaultInnerDropdown) {
|
||||||
|
scroll: flatScroll(solidScroll) {
|
||||||
|
deltat: 3px;
|
||||||
|
deltab: 3px;
|
||||||
|
round: 1px;
|
||||||
|
width: 8px;
|
||||||
|
deltax: 3px;
|
||||||
|
}
|
||||||
scrollMargin: margins(0px, 5px, 0px, 5px);
|
scrollMargin: margins(0px, 5px, 0px, 5px);
|
||||||
scrollPadding: margins(0px, 3px, 8px, 3px);
|
scrollPadding: margins(0px, 3px, 8px, 3px);
|
||||||
}
|
}
|
||||||
|
@ -138,3 +139,74 @@ historyPeer8NameFg: #ce671b; // orange
|
||||||
historyPeer8UserpicBg: #f7b37c;
|
historyPeer8UserpicBg: #f7b37c;
|
||||||
historyPeer8UserpicFg: #de8d62;
|
historyPeer8UserpicFg: #de8d62;
|
||||||
historyPeer8UserpicPerson: icon {{ size(120px, 120px), historyPeer8UserpicBg }, { "userpic_person", historyPeer8UserpicFg }};
|
historyPeer8UserpicPerson: icon {{ size(120px, 120px), historyPeer8UserpicBg }, { "userpic_person", historyPeer8UserpicFg }};
|
||||||
|
|
||||||
|
historyMediaTypeFile: icon {{ "media_type_file", #b3b3b3, point(2px, 2px) }};
|
||||||
|
historyMediaTypePhoto: icon {{ "media_type_photo", #bebebe, point(2px, 2px) }};
|
||||||
|
historyMediaTypeVideo: icon {{ "media_type_video", #bebebe, point(2px, 2px) }};
|
||||||
|
historyMediaTypeSong: icon {{ "media_type_song", #bebebe, point(0px, 0px) }};
|
||||||
|
historyMediaTypeVoice: icon {{ "media_type_voice", #bebebe, point(2px, 2px) }};
|
||||||
|
historyMediaTypeLink: icon {{ "media_type_link", #bebebe, point(2px, 2px) }};
|
||||||
|
|
||||||
|
historyAttachDocument: IconButton {
|
||||||
|
width: 46px;
|
||||||
|
height: 46px;
|
||||||
|
|
||||||
|
opacity: 0.78;
|
||||||
|
overOpacity: 1.;
|
||||||
|
|
||||||
|
icon: historyMediaTypeFile;
|
||||||
|
iconPosition: point(9px, 9px);
|
||||||
|
downIconPosition: point(9px, 10px);
|
||||||
|
|
||||||
|
duration: 150;
|
||||||
|
}
|
||||||
|
historyAttachPhoto: IconButton(historyAttachDocument) {
|
||||||
|
icon: historyMediaTypePhoto;
|
||||||
|
}
|
||||||
|
historyAttachEmoji: IconButton(historyAttachDocument) {
|
||||||
|
width: 33px;
|
||||||
|
icon: icon {{ "send_control_emoji", #b9b9b9 }};
|
||||||
|
iconPosition: point(12px, 16px);
|
||||||
|
downIconPosition: point(12px, 16px);
|
||||||
|
}
|
||||||
|
historyEmojiCircle: size(19px, 19px);
|
||||||
|
historyEmojiCirclePeriod: 1500;
|
||||||
|
historyEmojiCircleDuration: 500;
|
||||||
|
historyEmojiCircleTop: 13px;
|
||||||
|
historyEmojiCircleLine: 2px;
|
||||||
|
historyEmojiCircleFg: #b9b9b9;
|
||||||
|
historyEmojiCirclePart: 3.5;
|
||||||
|
historyBotKeyboardShow: IconButton(historyAttachEmoji) {
|
||||||
|
icon: icon {{ "send_control_bot_keyboard", #b3b3b3 }};
|
||||||
|
iconPosition: point(6px, 12px);
|
||||||
|
downIconPosition: point(6px, 12px);
|
||||||
|
}
|
||||||
|
historyBotKeyboardHide: IconButton(historyAttachEmoji) {
|
||||||
|
icon: icon {{ "send_control_bot_keyboard_hide", #b3b3b3 }};
|
||||||
|
iconPosition: point(5px, 17px);
|
||||||
|
downIconPosition: point(5px, 17px);
|
||||||
|
}
|
||||||
|
historyBotCommandStart: IconButton(historyBotKeyboardShow) {
|
||||||
|
icon: icon {{ "send_control_bot_command", #b3b3b3 }};
|
||||||
|
}
|
||||||
|
historyRecordVoice: icon {{ "send_control_record", #b9b9b9 }};
|
||||||
|
historyRecordVoiceActive: icon {{ "send_control_record", #58b2ed }};
|
||||||
|
historyRecordSignalColor: #f17077;
|
||||||
|
historyRecordSignalMin: 5px;
|
||||||
|
historyRecordSignalMax: 12px;
|
||||||
|
historyRecordCancel: #aaa;
|
||||||
|
historyRecordCancelActive: #ec6466;
|
||||||
|
historyRecordFont: font(13px);
|
||||||
|
historyRecordTextTop: 14px;
|
||||||
|
|
||||||
|
historyAttachDropdownMenu: DropdownMenu(defaultDropdownMenu) {
|
||||||
|
menu: Menu(defaultMenu) {
|
||||||
|
skip: 5px;
|
||||||
|
|
||||||
|
itemBgOver: btnWhiteHover;
|
||||||
|
itemIconPosition: point(12px, 6px);
|
||||||
|
itemIconOpacity: 0.78;
|
||||||
|
itemIconOverOpacity: 1.;
|
||||||
|
itemPadding: margins(48px, 11px, 48px, 11px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
175
Telegram/SourceFiles/history/history_drag_area.cpp
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "history/history_drag_area.h"
|
||||||
|
|
||||||
|
#include "styles/style_stickers.h"
|
||||||
|
#include "boxes/confirmbox.h"
|
||||||
|
#include "boxes/stickersetbox.h"
|
||||||
|
#include "inline_bots/inline_bot_result.h"
|
||||||
|
#include "inline_bots/inline_bot_layout_item.h"
|
||||||
|
#include "dialogs/dialogs_layout.h"
|
||||||
|
#include "historywidget.h"
|
||||||
|
#include "localstorage.h"
|
||||||
|
#include "lang.h"
|
||||||
|
#include "mainwindow.h"
|
||||||
|
#include "apiwrap.h"
|
||||||
|
#include "mainwidget.h"
|
||||||
|
|
||||||
|
DragArea::DragArea(QWidget *parent) : TWidget(parent)
|
||||||
|
, _hiding(false)
|
||||||
|
, _in(false)
|
||||||
|
, a_opacity(0)
|
||||||
|
, a_color(st::dragColor->c)
|
||||||
|
, _a_appearance(animation(this, &DragArea::step_appearance))
|
||||||
|
, _shadow(st::boxShadow) {
|
||||||
|
setMouseTracking(true);
|
||||||
|
setAcceptDrops(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DragArea::mouseMoveEvent(QMouseEvent *e) {
|
||||||
|
if (_hiding) return;
|
||||||
|
|
||||||
|
bool newIn = QRect(st::dragPadding.left(), st::dragPadding.top(), width() - st::dragPadding.left() - st::dragPadding.right(), height() - st::dragPadding.top() - st::dragPadding.bottom()).contains(e->pos());
|
||||||
|
if (newIn != _in) {
|
||||||
|
_in = newIn;
|
||||||
|
a_opacity.start(1);
|
||||||
|
a_color.start((_in ? st::dragDropColor : st::dragColor)->c);
|
||||||
|
_a_appearance.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DragArea::dragMoveEvent(QDragMoveEvent *e) {
|
||||||
|
QRect r(st::dragPadding.left(), st::dragPadding.top(), width() - st::dragPadding.left() - st::dragPadding.right(), height() - st::dragPadding.top() - st::dragPadding.bottom());
|
||||||
|
bool newIn = r.contains(e->pos());
|
||||||
|
if (newIn != _in) {
|
||||||
|
_in = newIn;
|
||||||
|
a_opacity.start(1);
|
||||||
|
a_color.start((_in ? st::dragDropColor : st::dragColor)->c);
|
||||||
|
_a_appearance.start();
|
||||||
|
}
|
||||||
|
e->setDropAction(_in ? Qt::CopyAction : Qt::IgnoreAction);
|
||||||
|
e->accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DragArea::setText(const QString &text, const QString &subtext) {
|
||||||
|
_text = text;
|
||||||
|
_subtext = subtext;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DragArea::paintEvent(QPaintEvent *e) {
|
||||||
|
Painter p(this);
|
||||||
|
|
||||||
|
if (_a_appearance.animating()) {
|
||||||
|
p.setOpacity(a_opacity.current());
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect r(st::dragPadding.left(), st::dragPadding.top(), width() - st::dragPadding.left() - st::dragPadding.right(), height() - st::dragPadding.top() - st::dragPadding.bottom());
|
||||||
|
|
||||||
|
// draw shadow
|
||||||
|
_shadow.paint(p, r, st::boxShadowShift);
|
||||||
|
|
||||||
|
p.fillRect(r, st::white->b);
|
||||||
|
|
||||||
|
p.setPen(a_color.current());
|
||||||
|
|
||||||
|
p.setFont(st::dragFont->f);
|
||||||
|
p.drawText(QRect(0, (height() - st::dragHeight) / 2, width(), st::dragFont->height), _text, QTextOption(style::al_top));
|
||||||
|
|
||||||
|
p.setFont(st::dragSubfont->f);
|
||||||
|
p.drawText(QRect(0, (height() + st::dragHeight) / 2 - st::dragSubfont->height, width(), st::dragSubfont->height * 2), _subtext, QTextOption(style::al_top));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DragArea::dragEnterEvent(QDragEnterEvent *e) {
|
||||||
|
static_cast<HistoryWidget*>(parentWidget())->dragEnterEvent(e);
|
||||||
|
e->setDropAction(Qt::IgnoreAction);
|
||||||
|
e->accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DragArea::dragLeaveEvent(QDragLeaveEvent *e) {
|
||||||
|
static_cast<HistoryWidget*>(parentWidget())->dragLeaveEvent(e);
|
||||||
|
_in = false;
|
||||||
|
a_opacity.start(_hiding ? 0 : 1);
|
||||||
|
a_color.start((_in ? st::dragDropColor : st::dragColor)->c);
|
||||||
|
_a_appearance.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DragArea::dropEvent(QDropEvent *e) {
|
||||||
|
static_cast<HistoryWidget*>(parentWidget())->dropEvent(e);
|
||||||
|
if (e->isAccepted()) {
|
||||||
|
emit dropped(e->mimeData());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DragArea::otherEnter() {
|
||||||
|
showStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DragArea::otherLeave() {
|
||||||
|
hideStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DragArea::hideFast() {
|
||||||
|
if (_a_appearance.animating()) {
|
||||||
|
_a_appearance.stop();
|
||||||
|
}
|
||||||
|
a_opacity = anim::fvalue(0, 0);
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DragArea::hideStart() {
|
||||||
|
_hiding = true;
|
||||||
|
_in = false;
|
||||||
|
a_opacity.start(0);
|
||||||
|
a_color.start((_in ? st::dragDropColor : st::dragColor)->c);
|
||||||
|
_a_appearance.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DragArea::hideFinish() {
|
||||||
|
hide();
|
||||||
|
_in = false;
|
||||||
|
a_color = anim::cvalue(st::dragColor->c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DragArea::showStart() {
|
||||||
|
_hiding = false;
|
||||||
|
show();
|
||||||
|
a_opacity.start(1);
|
||||||
|
a_color.start((_in ? st::dragDropColor : st::dragColor)->c);
|
||||||
|
_a_appearance.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DragArea::step_appearance(float64 ms, bool timer) {
|
||||||
|
float64 dt = ms / st::defaultDropdownDuration;
|
||||||
|
if (dt >= 1) {
|
||||||
|
a_opacity.finish();
|
||||||
|
a_color.finish();
|
||||||
|
if (_hiding) {
|
||||||
|
hideFinish();
|
||||||
|
}
|
||||||
|
_a_appearance.stop();
|
||||||
|
} else {
|
||||||
|
a_opacity.update(dt, anim::linear);
|
||||||
|
a_color.update(dt, anim::linear);
|
||||||
|
}
|
||||||
|
if (timer) update();
|
||||||
|
}
|
|
@ -23,78 +23,6 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "ui/twidget.h"
|
#include "ui/twidget.h"
|
||||||
#include "ui/effects/rect_shadow.h"
|
#include "ui/effects/rect_shadow.h"
|
||||||
|
|
||||||
class Dropdown : public TWidget {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
Dropdown(QWidget *parent, const style::dropdown &st = st::dropdownDef);
|
|
||||||
|
|
||||||
IconedButton *addButton(IconedButton *button);
|
|
||||||
void resetButtons();
|
|
||||||
void updateButtons();
|
|
||||||
|
|
||||||
void resizeEvent(QResizeEvent *e);
|
|
||||||
void paintEvent(QPaintEvent *e);
|
|
||||||
|
|
||||||
void enterEvent(QEvent *e);
|
|
||||||
void leaveEvent(QEvent *e);
|
|
||||||
void keyPressEvent(QKeyEvent *e);
|
|
||||||
void otherEnter();
|
|
||||||
void otherLeave();
|
|
||||||
|
|
||||||
void fastHide();
|
|
||||||
void ignoreShow(bool ignore = true);
|
|
||||||
|
|
||||||
void step_appearance(float64 ms, bool timer);
|
|
||||||
|
|
||||||
bool eventFilter(QObject *obj, QEvent *e);
|
|
||||||
|
|
||||||
bool overlaps(const QRect &globalRect) {
|
|
||||||
if (isHidden() || _a_appearance.animating()) return false;
|
|
||||||
|
|
||||||
return QRect(_st.padding.left(),
|
|
||||||
_st.padding.top(),
|
|
||||||
_width - _st.padding.left() - _st.padding.right(),
|
|
||||||
_height - _st.padding.top() - _st.padding.bottom()
|
|
||||||
).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void hiding();
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void hideStart();
|
|
||||||
void hideFinish();
|
|
||||||
|
|
||||||
void showStart();
|
|
||||||
void onWndActiveChanged();
|
|
||||||
|
|
||||||
void buttonStateChanged(int oldState, ButtonStateChangeSource source);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void adjustButtons();
|
|
||||||
|
|
||||||
bool _ignore = false;
|
|
||||||
|
|
||||||
typedef QVector<IconedButton*> Buttons;
|
|
||||||
Buttons _buttons;
|
|
||||||
|
|
||||||
int32 _selected = -1;
|
|
||||||
|
|
||||||
const style::dropdown &_st;
|
|
||||||
|
|
||||||
int32 _width, _height;
|
|
||||||
bool _hiding = false;
|
|
||||||
|
|
||||||
anim::fvalue a_opacity;
|
|
||||||
Animation _a_appearance;
|
|
||||||
|
|
||||||
QTimer _hideTimer;
|
|
||||||
|
|
||||||
Ui::RectShadow _shadow;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class DragArea : public TWidget {
|
class DragArea : public TWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
@ -106,8 +34,6 @@ public:
|
||||||
void otherEnter();
|
void otherEnter();
|
||||||
void otherLeave();
|
void otherLeave();
|
||||||
|
|
||||||
void fastHide();
|
|
||||||
|
|
||||||
void step_appearance(float64 ms, bool timer);
|
void step_appearance(float64 ms, bool timer);
|
||||||
|
|
||||||
bool overlaps(const QRect &globalRect) {
|
bool overlaps(const QRect &globalRect) {
|
||||||
|
@ -120,6 +46,8 @@ public:
|
||||||
).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
|
).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hideFast();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void paintEvent(QPaintEvent *e) override;
|
void paintEvent(QPaintEvent *e) override;
|
||||||
void mouseMoveEvent(QMouseEvent *e) override;
|
void mouseMoveEvent(QMouseEvent *e) override;
|
|
@ -29,17 +29,19 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "ui/filedialog.h"
|
#include "ui/filedialog.h"
|
||||||
#include "ui/toast/toast.h"
|
#include "ui/toast/toast.h"
|
||||||
#include "ui/buttons/history_down_button.h"
|
#include "ui/buttons/history_down_button.h"
|
||||||
#include "ui/inner_dropdown.h"
|
#include "ui/buttons/icon_button.h"
|
||||||
|
#include "ui/widgets/inner_dropdown.h"
|
||||||
|
#include "ui/widgets/dropdown_menu.h"
|
||||||
#include "inline_bots/inline_bot_result.h"
|
#include "inline_bots/inline_bot_result.h"
|
||||||
#include "data/data_drafts.h"
|
#include "data/data_drafts.h"
|
||||||
#include "history/history_service_layout.h"
|
#include "history/history_service_layout.h"
|
||||||
#include "history/history_media_types.h"
|
#include "history/history_media_types.h"
|
||||||
|
#include "history/history_drag_area.h"
|
||||||
#include "profile/profile_members_widget.h"
|
#include "profile/profile_members_widget.h"
|
||||||
#include "core/click_handler_types.h"
|
#include "core/click_handler_types.h"
|
||||||
#include "stickers/emoji_pan.h"
|
#include "stickers/emoji_pan.h"
|
||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "dropdown.h"
|
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "passcodewidget.h"
|
#include "passcodewidget.h"
|
||||||
|
@ -52,6 +54,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "window/chat_background.h"
|
#include "window/chat_background.h"
|
||||||
#include "observer_peer.h"
|
#include "observer_peer.h"
|
||||||
#include "core/qthelp_regex.h"
|
#include "core/qthelp_regex.h"
|
||||||
|
#include "ui/widgets/popup_menu.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -1154,7 +1157,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
||||||
isUponSelected = hasSelected;
|
isUponSelected = hasSelected;
|
||||||
}
|
}
|
||||||
|
|
||||||
_menu = new PopupMenu();
|
_menu = new Ui::PopupMenu();
|
||||||
|
|
||||||
_contextMenuLnk = ClickHandler::getActive();
|
_contextMenuLnk = ClickHandler::getActive();
|
||||||
HistoryItem *item = App::hoveredItem() ? App::hoveredItem() : App::hoveredLinkItem();
|
HistoryItem *item = App::hoveredItem() ? App::hoveredItem() : App::hoveredLinkItem();
|
||||||
|
@ -1698,7 +1701,7 @@ void HistoryInner::toggleScrollDateShown() {
|
||||||
_scrollDateShown = !_scrollDateShown;
|
_scrollDateShown = !_scrollDateShown;
|
||||||
auto from = _scrollDateShown ? 0. : 1.;
|
auto from = _scrollDateShown ? 0. : 1.;
|
||||||
auto to = _scrollDateShown ? 1. : 0.;
|
auto to = _scrollDateShown ? 1. : 0.;
|
||||||
_scrollDateOpacity.start([this] { repaintScrollDateCallback(); }, from, to, st::btnAttachEmoji.duration);
|
_scrollDateOpacity.start([this] { repaintScrollDateCallback(); }, from, to, st::historyAttachPhoto.duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryInner::repaintScrollDateCallback() {
|
void HistoryInner::repaintScrollDateCallback() {
|
||||||
|
@ -1749,7 +1752,7 @@ void HistoryInner::leaveEvent(QEvent *e) {
|
||||||
App::hoveredItem(nullptr);
|
App::hoveredItem(nullptr);
|
||||||
}
|
}
|
||||||
ClickHandler::clearActive();
|
ClickHandler::clearActive();
|
||||||
PopupTooltip::Hide();
|
Ui::Tooltip::Hide();
|
||||||
if (!ClickHandler::getPressed() && _cursor != style::cur_default) {
|
if (!ClickHandler::getPressed() && _cursor != style::cur_default) {
|
||||||
_cursor = style::cur_default;
|
_cursor = style::cur_default;
|
||||||
setCursor(_cursor);
|
setCursor(_cursor);
|
||||||
|
@ -1970,7 +1973,7 @@ void HistoryInner::onUpdateSelected() {
|
||||||
dragState = item->getState(m.x(), m.y(), request);
|
dragState = item->getState(m.x(), m.y(), request);
|
||||||
lnkhost = item;
|
lnkhost = item;
|
||||||
if (!dragState.link && m.x() >= st::msgMargin.left() && m.x() < st::msgMargin.left() + st::msgPhotoSize) {
|
if (!dragState.link && m.x() >= st::msgMargin.left() && m.x() < st::msgMargin.left() + st::msgPhotoSize) {
|
||||||
if (HistoryMessage *msg = item->toHistoryMessage()) {
|
if (auto msg = item->toHistoryMessage()) {
|
||||||
if (msg->hasFromPhoto()) {
|
if (msg->hasFromPhoto()) {
|
||||||
enumerateUserpics([&dragState, &lnkhost, &point](HistoryMessage *message, int userpicTop) -> bool {
|
enumerateUserpics([&dragState, &lnkhost, &point](HistoryMessage *message, int userpicTop) -> bool {
|
||||||
// stop enumeration if the userpic is above our point
|
// stop enumeration if the userpic is above our point
|
||||||
|
@ -1992,10 +1995,10 @@ void HistoryInner::onUpdateSelected() {
|
||||||
}
|
}
|
||||||
bool lnkChanged = ClickHandler::setActive(dragState.link, lnkhost);
|
bool lnkChanged = ClickHandler::setActive(dragState.link, lnkhost);
|
||||||
if (lnkChanged || dragState.cursor != _dragCursorState) {
|
if (lnkChanged || dragState.cursor != _dragCursorState) {
|
||||||
PopupTooltip::Hide();
|
Ui::Tooltip::Hide();
|
||||||
}
|
}
|
||||||
if (dragState.link || dragState.cursor == HistoryInDateCursorState || dragState.cursor == HistoryInForwardedCursorState) {
|
if (dragState.link || dragState.cursor == HistoryInDateCursorState || dragState.cursor == HistoryInForwardedCursorState) {
|
||||||
PopupTooltip::Show(1000, this);
|
Ui::Tooltip::Show(1000, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Qt::CursorShape cur = style::cur_default;
|
Qt::CursorShape cur = style::cur_default;
|
||||||
|
@ -2611,7 +2614,7 @@ void BotKeyboard::updateStyle(int newWidth) {
|
||||||
void BotKeyboard::clearSelection() {
|
void BotKeyboard::clearSelection() {
|
||||||
if (_impl) {
|
if (_impl) {
|
||||||
if (ClickHandler::setActive(ClickHandlerPtr(), this)) {
|
if (ClickHandler::setActive(ClickHandlerPtr(), this)) {
|
||||||
PopupTooltip::Hide();
|
Ui::Tooltip::Hide();
|
||||||
setCursor(style::cur_default);
|
setCursor(style::cur_default);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2629,7 +2632,7 @@ QString BotKeyboard::tooltipText() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BotKeyboard::updateSelected() {
|
void BotKeyboard::updateSelected() {
|
||||||
PopupTooltip::Show(1000, this);
|
Ui::Tooltip::Show(1000, this);
|
||||||
|
|
||||||
if (!_impl) return;
|
if (!_impl) return;
|
||||||
|
|
||||||
|
@ -2638,7 +2641,7 @@ void BotKeyboard::updateSelected() {
|
||||||
|
|
||||||
auto link = _impl->getState(p.x() - x, p.y() - _st->margin);
|
auto link = _impl->getState(p.x() - x, p.y() - _st->margin);
|
||||||
if (ClickHandler::setActive(link, this)) {
|
if (ClickHandler::setActive(link, this)) {
|
||||||
PopupTooltip::Hide();
|
Ui::Tooltip::Hide();
|
||||||
setCursor(link ? style::cur_pointer : style::cur_default);
|
setCursor(link ? style::cur_pointer : style::cur_default);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2917,19 +2920,19 @@ SilentToggle::SilentToggle(QWidget *parent) : FlatCheckbox(parent, QString(), fa
|
||||||
void SilentToggle::mouseMoveEvent(QMouseEvent *e) {
|
void SilentToggle::mouseMoveEvent(QMouseEvent *e) {
|
||||||
FlatCheckbox::mouseMoveEvent(e);
|
FlatCheckbox::mouseMoveEvent(e);
|
||||||
if (rect().contains(e->pos())) {
|
if (rect().contains(e->pos())) {
|
||||||
PopupTooltip::Show(1000, this);
|
Ui::Tooltip::Show(1000, this);
|
||||||
} else {
|
} else {
|
||||||
PopupTooltip::Hide();
|
Ui::Tooltip::Hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SilentToggle::leaveEvent(QEvent *e) {
|
void SilentToggle::leaveEvent(QEvent *e) {
|
||||||
PopupTooltip::Hide();
|
Ui::Tooltip::Hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SilentToggle::mouseReleaseEvent(QMouseEvent *e) {
|
void SilentToggle::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
FlatCheckbox::mouseReleaseEvent(e);
|
FlatCheckbox::mouseReleaseEvent(e);
|
||||||
PopupTooltip::Show(0, this);
|
Ui::Tooltip::Show(0, this);
|
||||||
PeerData *p = App::main() ? App::main()->peer() : nullptr;
|
PeerData *p = App::main() ? App::main()->peer() : nullptr;
|
||||||
if (p && p->isChannel() && p->notify != UnknownNotifySettings) {
|
if (p && p->isChannel() && p->notify != UnknownNotifySettings) {
|
||||||
App::main()->updateNotifySetting(p, NotifySettingDontChange, checked() ? SilentNotifiesSetSilent : SilentNotifiesSetNotify);
|
App::main()->updateNotifySetting(p, NotifySettingDontChange, checked() ? SilentNotifiesSetSilent : SilentNotifiesSetNotify);
|
||||||
|
@ -2991,20 +2994,20 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
|
||||||
, _botStart(this, lang(lng_bot_start), st::btnSend)
|
, _botStart(this, lang(lng_bot_start), st::btnSend)
|
||||||
, _joinChannel(this, lang(lng_channel_join), st::btnSend)
|
, _joinChannel(this, lang(lng_channel_join), st::btnSend)
|
||||||
, _muteUnmute(this, lang(lng_channel_mute), st::btnSend)
|
, _muteUnmute(this, lang(lng_channel_mute), st::btnSend)
|
||||||
, _attachDocument(this, st::btnAttachDocument)
|
, _attachDocument(this, st::historyAttachDocument)
|
||||||
, _attachPhoto(this, st::btnAttachPhoto)
|
, _attachPhoto(this, st::historyAttachPhoto)
|
||||||
, _attachEmoji(this, st::btnAttachEmoji)
|
, _attachEmoji(this, st::historyAttachEmoji)
|
||||||
, _kbShow(this, st::btnBotKbShow)
|
, _botKeyboardShow(this, st::historyBotKeyboardShow)
|
||||||
, _kbHide(this, st::btnBotKbHide)
|
, _botKeyboardHide(this, st::historyBotKeyboardHide)
|
||||||
, _cmdStart(this, st::btnBotCmdStart)
|
, _botCommandStart(this, st::historyBotCommandStart)
|
||||||
, _silent(this)
|
, _silent(this)
|
||||||
, _field(this, st::taMsgField, lang(lng_message_ph))
|
, _field(this, st::taMsgField, lang(lng_message_ph))
|
||||||
, _a_record(animation(this, &HistoryWidget::step_record))
|
, _a_record(animation(this, &HistoryWidget::step_record))
|
||||||
, _a_recording(animation(this, &HistoryWidget::step_recording))
|
, _a_recording(animation(this, &HistoryWidget::step_recording))
|
||||||
, a_recordCancel(st::recordCancel->c, st::recordCancel->c)
|
, a_recordCancel(st::historyRecordCancel->c, st::historyRecordCancel->c)
|
||||||
, _recordCancelWidth(st::recordFont->width(lang(lng_record_cancel)))
|
, _recordCancelWidth(st::historyRecordFont->width(lang(lng_record_cancel)))
|
||||||
, _kbScroll(this, st::botKbScroll)
|
, _kbScroll(this, st::botKbScroll)
|
||||||
, _attachType(this)
|
, _attachType(this, st::historyAttachDropdownMenu)
|
||||||
, _emojiPan(this)
|
, _emojiPan(this)
|
||||||
, _attachDragDocument(this)
|
, _attachDragDocument(this)
|
||||||
, _attachDragPhoto(this)
|
, _attachDragPhoto(this)
|
||||||
|
@ -3028,8 +3031,8 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
|
||||||
connect(&_joinChannel, SIGNAL(clicked()), this, SLOT(onJoinChannel()));
|
connect(&_joinChannel, SIGNAL(clicked()), this, SLOT(onJoinChannel()));
|
||||||
connect(&_muteUnmute, SIGNAL(clicked()), this, SLOT(onMuteUnmute()));
|
connect(&_muteUnmute, SIGNAL(clicked()), this, SLOT(onMuteUnmute()));
|
||||||
connect(&_silent, SIGNAL(clicked()), this, SLOT(onBroadcastSilentChange()));
|
connect(&_silent, SIGNAL(clicked()), this, SLOT(onBroadcastSilentChange()));
|
||||||
connect(&_attachDocument, SIGNAL(clicked()), this, SLOT(onDocumentSelect()));
|
connect(_attachDocument, SIGNAL(clicked()), this, SLOT(onDocumentSelect()));
|
||||||
connect(&_attachPhoto, SIGNAL(clicked()), this, SLOT(onPhotoSelect()));
|
connect(_attachPhoto, SIGNAL(clicked()), this, SLOT(onPhotoSelect()));
|
||||||
connect(&_field, SIGNAL(submitted(bool)), this, SLOT(onSend(bool)));
|
connect(&_field, SIGNAL(submitted(bool)), this, SLOT(onSend(bool)));
|
||||||
connect(&_field, SIGNAL(cancelled()), this, SLOT(onCancel()));
|
connect(&_field, SIGNAL(cancelled()), this, SLOT(onCancel()));
|
||||||
connect(&_field, SIGNAL(tabbed()), this, SLOT(onFieldTabbed()));
|
connect(&_field, SIGNAL(tabbed()), this, SLOT(onFieldTabbed()));
|
||||||
|
@ -3107,24 +3110,24 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
|
||||||
_reportSpamPanel.move(0, 0);
|
_reportSpamPanel.move(0, 0);
|
||||||
_reportSpamPanel.hide();
|
_reportSpamPanel.hide();
|
||||||
|
|
||||||
_attachDocument.hide();
|
_attachDocument->hide();
|
||||||
_attachPhoto.hide();
|
_attachPhoto->hide();
|
||||||
_attachEmoji.hide();
|
_attachEmoji->hide();
|
||||||
_kbShow.hide();
|
_botKeyboardShow->hide();
|
||||||
_kbHide.hide();
|
_botKeyboardHide->hide();
|
||||||
_silent.hide();
|
_silent.hide();
|
||||||
_cmdStart.hide();
|
_botCommandStart->hide();
|
||||||
|
|
||||||
_attachDocument.installEventFilter(_attachType);
|
_attachDocument->installEventFilter(_attachType);
|
||||||
_attachPhoto.installEventFilter(_attachType);
|
_attachPhoto->installEventFilter(_attachType);
|
||||||
_attachEmoji.installEventFilter(_emojiPan);
|
_attachEmoji->installEventFilter(_emojiPan);
|
||||||
|
|
||||||
connect(&_kbShow, SIGNAL(clicked()), this, SLOT(onKbToggle()));
|
connect(_botKeyboardShow, SIGNAL(clicked()), this, SLOT(onKbToggle()));
|
||||||
connect(&_kbHide, SIGNAL(clicked()), this, SLOT(onKbToggle()));
|
connect(_botKeyboardHide, SIGNAL(clicked()), this, SLOT(onKbToggle()));
|
||||||
connect(&_cmdStart, SIGNAL(clicked()), this, SLOT(onCmdStart()));
|
connect(_botCommandStart, SIGNAL(clicked()), this, SLOT(onCmdStart()));
|
||||||
|
|
||||||
connect(_attachType->addButton(new IconedButton(this, st::dropdownAttachDocument, lang(lng_attach_file))), SIGNAL(clicked()), this, SLOT(onDocumentSelect()));
|
_attachType->addAction(lang(lng_attach_file), this, SLOT(onDocumentSelect()), &st::historyMediaTypeFile);
|
||||||
connect(_attachType->addButton(new IconedButton(this, st::dropdownAttachPhoto, lang(lng_attach_photo))), SIGNAL(clicked()), this, SLOT(onPhotoSelect()));
|
_attachType->addAction(lang(lng_attach_photo), this, SLOT(onPhotoSelect()), &st::historyMediaTypePhoto);
|
||||||
_attachType->hide();
|
_attachType->hide();
|
||||||
_emojiPan->hide();
|
_emojiPan->hide();
|
||||||
_attachDragDocument->hide();
|
_attachDragDocument->hide();
|
||||||
|
@ -3221,7 +3224,7 @@ void HistoryWidget::applyInlineBotQuery(UserData *bot, const QString &query) {
|
||||||
_emojiPan->queryInlineBot(_inlineBot, _peer, query);
|
_emojiPan->queryInlineBot(_inlineBot, _peer, query);
|
||||||
}
|
}
|
||||||
if (!_fieldAutocomplete->isHidden()) {
|
if (!_fieldAutocomplete->isHidden()) {
|
||||||
_fieldAutocomplete->hideStart();
|
_fieldAutocomplete->hideAnimated();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
clearInlineBot();
|
clearInlineBot();
|
||||||
|
@ -3267,7 +3270,7 @@ void HistoryWidget::onTextChange() {
|
||||||
_a_record.stop();
|
_a_record.stop();
|
||||||
_inRecord = _inField = false;
|
_inRecord = _inField = false;
|
||||||
a_recordOver = a_recordDown = anim::fvalue(0, 0);
|
a_recordOver = a_recordDown = anim::fvalue(0, 0);
|
||||||
a_recordCancel = anim::cvalue(st::recordCancel->c, st::recordCancel->c);
|
a_recordCancel = anim::cvalue(st::historyRecordCancel->c, st::historyRecordCancel->c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (updateCmdStartShown()) {
|
if (updateCmdStartShown()) {
|
||||||
|
@ -3541,7 +3544,7 @@ void HistoryWidget::notify_botCommandsChanged(UserData *user) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::notify_inlineBotRequesting(bool requesting) {
|
void HistoryWidget::notify_inlineBotRequesting(bool requesting) {
|
||||||
_attachEmoji.setLoading(requesting);
|
_attachEmoji->setLoading(requesting);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::notify_replyMarkupUpdated(const HistoryItem *item) {
|
void HistoryWidget::notify_replyMarkupUpdated(const HistoryItem *item) {
|
||||||
|
@ -4497,14 +4500,14 @@ void HistoryWidget::updateControlsVisibility() {
|
||||||
_fieldAutocomplete->hide();
|
_fieldAutocomplete->hide();
|
||||||
_field.hide();
|
_field.hide();
|
||||||
_fieldBarCancel.hide();
|
_fieldBarCancel.hide();
|
||||||
_attachDocument.hide();
|
_attachDocument->hide();
|
||||||
_attachPhoto.hide();
|
_attachPhoto->hide();
|
||||||
_attachEmoji.hide();
|
_attachEmoji->hide();
|
||||||
_silent.hide();
|
_silent.hide();
|
||||||
_historyToEnd->hide();
|
_historyToEnd->hide();
|
||||||
_kbShow.hide();
|
_botKeyboardShow->hide();
|
||||||
_kbHide.hide();
|
_botKeyboardHide->hide();
|
||||||
_cmdStart.hide();
|
_botCommandStart->hide();
|
||||||
_attachType->hide();
|
_attachType->hide();
|
||||||
_emojiPan->hide();
|
_emojiPan->hide();
|
||||||
if (_pinnedBar) {
|
if (_pinnedBar) {
|
||||||
|
@ -4556,17 +4559,17 @@ void HistoryWidget::updateControlsVisibility() {
|
||||||
_send.hide();
|
_send.hide();
|
||||||
if (_inlineBotCancel) _inlineBotCancel->hide();
|
if (_inlineBotCancel) _inlineBotCancel->hide();
|
||||||
_botStart.hide();
|
_botStart.hide();
|
||||||
_attachDocument.hide();
|
_attachDocument->hide();
|
||||||
_attachPhoto.hide();
|
_attachPhoto->hide();
|
||||||
_silent.hide();
|
_silent.hide();
|
||||||
_kbScroll.hide();
|
_kbScroll.hide();
|
||||||
_fieldBarCancel.hide();
|
_fieldBarCancel.hide();
|
||||||
_attachDocument.hide();
|
_attachDocument->hide();
|
||||||
_attachPhoto.hide();
|
_attachPhoto->hide();
|
||||||
_attachEmoji.hide();
|
_attachEmoji->hide();
|
||||||
_kbShow.hide();
|
_botKeyboardShow->hide();
|
||||||
_kbHide.hide();
|
_botKeyboardHide->hide();
|
||||||
_cmdStart.hide();
|
_botCommandStart->hide();
|
||||||
_attachType->hide();
|
_attachType->hide();
|
||||||
_emojiPan->hide();
|
_emojiPan->hide();
|
||||||
if (!_field.isHidden()) {
|
if (!_field.isHidden()) {
|
||||||
|
@ -4588,12 +4591,12 @@ void HistoryWidget::updateControlsVisibility() {
|
||||||
_send.hide();
|
_send.hide();
|
||||||
if (_inlineBotCancel) _inlineBotCancel->hide();
|
if (_inlineBotCancel) _inlineBotCancel->hide();
|
||||||
_field.hide();
|
_field.hide();
|
||||||
_attachEmoji.hide();
|
_attachEmoji->hide();
|
||||||
_kbShow.hide();
|
_botKeyboardShow->hide();
|
||||||
_kbHide.hide();
|
_botKeyboardHide->hide();
|
||||||
_cmdStart.hide();
|
_botCommandStart->hide();
|
||||||
_attachDocument.hide();
|
_attachDocument->hide();
|
||||||
_attachPhoto.hide();
|
_attachPhoto->hide();
|
||||||
_silent.hide();
|
_silent.hide();
|
||||||
_kbScroll.hide();
|
_kbScroll.hide();
|
||||||
_fieldBarCancel.hide();
|
_fieldBarCancel.hide();
|
||||||
|
@ -4618,12 +4621,12 @@ void HistoryWidget::updateControlsVisibility() {
|
||||||
}
|
}
|
||||||
if (_recording) {
|
if (_recording) {
|
||||||
_field.hide();
|
_field.hide();
|
||||||
_attachEmoji.hide();
|
_attachEmoji->hide();
|
||||||
_kbShow.hide();
|
_botKeyboardShow->hide();
|
||||||
_kbHide.hide();
|
_botKeyboardHide->hide();
|
||||||
_cmdStart.hide();
|
_botCommandStart->hide();
|
||||||
_attachDocument.hide();
|
_attachDocument->hide();
|
||||||
_attachPhoto.hide();
|
_attachPhoto->hide();
|
||||||
_silent.hide();
|
_silent.hide();
|
||||||
if (_kbShown) {
|
if (_kbShown) {
|
||||||
_kbScroll.show();
|
_kbScroll.show();
|
||||||
|
@ -4634,38 +4637,38 @@ void HistoryWidget::updateControlsVisibility() {
|
||||||
_field.show();
|
_field.show();
|
||||||
if (_kbShown) {
|
if (_kbShown) {
|
||||||
_kbScroll.show();
|
_kbScroll.show();
|
||||||
_attachEmoji.hide();
|
_attachEmoji->hide();
|
||||||
_kbHide.show();
|
_botKeyboardHide->show();
|
||||||
_kbShow.hide();
|
_botKeyboardShow->hide();
|
||||||
_cmdStart.hide();
|
_botCommandStart->hide();
|
||||||
} else if (_kbReplyTo) {
|
} else if (_kbReplyTo) {
|
||||||
_kbScroll.hide();
|
_kbScroll.hide();
|
||||||
_attachEmoji.show();
|
_attachEmoji->show();
|
||||||
_kbHide.hide();
|
_botKeyboardHide->hide();
|
||||||
_kbShow.hide();
|
_botKeyboardShow->hide();
|
||||||
_cmdStart.hide();
|
_botCommandStart->hide();
|
||||||
} else {
|
} else {
|
||||||
_kbScroll.hide();
|
_kbScroll.hide();
|
||||||
_attachEmoji.show();
|
_attachEmoji->show();
|
||||||
_kbHide.hide();
|
_botKeyboardHide->hide();
|
||||||
if (_keyboard.hasMarkup()) {
|
if (_keyboard.hasMarkup()) {
|
||||||
_kbShow.show();
|
_botKeyboardShow->show();
|
||||||
_cmdStart.hide();
|
_botCommandStart->hide();
|
||||||
} else {
|
} else {
|
||||||
_kbShow.hide();
|
_botKeyboardShow->hide();
|
||||||
if (_cmdStartShown) {
|
if (_cmdStartShown) {
|
||||||
_cmdStart.show();
|
_botCommandStart->show();
|
||||||
} else {
|
} else {
|
||||||
_cmdStart.hide();
|
_botCommandStart->hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (cDefaultAttach() == dbidaPhoto) {
|
if (cDefaultAttach() == dbidaPhoto) {
|
||||||
_attachDocument.hide();
|
_attachDocument->hide();
|
||||||
_attachPhoto.show();
|
_attachPhoto->show();
|
||||||
} else {
|
} else {
|
||||||
_attachDocument.show();
|
_attachDocument->show();
|
||||||
_attachPhoto.hide();
|
_attachPhoto->hide();
|
||||||
}
|
}
|
||||||
if (hasSilentToggle()) {
|
if (hasSilentToggle()) {
|
||||||
_silent.show();
|
_silent.show();
|
||||||
|
@ -4692,17 +4695,17 @@ void HistoryWidget::updateControlsVisibility() {
|
||||||
_botStart.hide();
|
_botStart.hide();
|
||||||
_joinChannel.hide();
|
_joinChannel.hide();
|
||||||
_muteUnmute.hide();
|
_muteUnmute.hide();
|
||||||
_attachDocument.hide();
|
_attachDocument->hide();
|
||||||
_attachPhoto.hide();
|
_attachPhoto->hide();
|
||||||
_silent.hide();
|
_silent.hide();
|
||||||
_kbScroll.hide();
|
_kbScroll.hide();
|
||||||
_fieldBarCancel.hide();
|
_fieldBarCancel.hide();
|
||||||
_attachDocument.hide();
|
_attachDocument->hide();
|
||||||
_attachPhoto.hide();
|
_attachPhoto->hide();
|
||||||
_attachEmoji.hide();
|
_attachEmoji->hide();
|
||||||
_kbShow.hide();
|
_botKeyboardShow->hide();
|
||||||
_kbHide.hide();
|
_botKeyboardHide->hide();
|
||||||
_cmdStart.hide();
|
_botCommandStart->hide();
|
||||||
_attachType->hide();
|
_attachType->hide();
|
||||||
_emojiPan->hide();
|
_emojiPan->hide();
|
||||||
_kbScroll.hide();
|
_kbScroll.hide();
|
||||||
|
@ -5219,6 +5222,12 @@ bool HistoryWidget::saveEditMsgFail(History *history, const RPCError &error, mtp
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HistoryWidget::hideSelectorControlsAnimated() {
|
||||||
|
_fieldAutocomplete->hideAnimated();
|
||||||
|
_attachType->hideAnimated();
|
||||||
|
_emojiPan->hideAnimated();
|
||||||
|
}
|
||||||
|
|
||||||
void HistoryWidget::onSend(bool ctrlShiftEnter, MsgId replyTo) {
|
void HistoryWidget::onSend(bool ctrlShiftEnter, MsgId replyTo) {
|
||||||
if (!_history) return;
|
if (!_history) return;
|
||||||
|
|
||||||
|
@ -5244,9 +5253,7 @@ void HistoryWidget::onSend(bool ctrlShiftEnter, MsgId replyTo) {
|
||||||
_saveDraftStart = getms();
|
_saveDraftStart = getms();
|
||||||
onDraftSave();
|
onDraftSave();
|
||||||
|
|
||||||
if (!_fieldAutocomplete->isHidden()) _fieldAutocomplete->hideStart();
|
hideSelectorControlsAnimated();
|
||||||
if (!_attachType->isHidden()) _attachType->hideStart();
|
|
||||||
if (!_emojiPan->isHidden()) _emojiPan->hideStart();
|
|
||||||
|
|
||||||
if (replyTo < 0) cancelReply(lastKeyboardUsed);
|
if (replyTo < 0) cancelReply(lastKeyboardUsed);
|
||||||
if (_previewData && _previewData->pendingTill) previewCancel();
|
if (_previewData && _previewData->pendingTill) previewCancel();
|
||||||
|
@ -5448,14 +5455,14 @@ void HistoryWidget::showAnimated(Window::SlideDirection direction, const Window:
|
||||||
_kbScroll.hide();
|
_kbScroll.hide();
|
||||||
_reportSpamPanel.hide();
|
_reportSpamPanel.hide();
|
||||||
_historyToEnd->hide();
|
_historyToEnd->hide();
|
||||||
_attachDocument.hide();
|
_attachDocument->hide();
|
||||||
_attachPhoto.hide();
|
_attachPhoto->hide();
|
||||||
_attachEmoji.hide();
|
_attachEmoji->hide();
|
||||||
_fieldAutocomplete->hide();
|
_fieldAutocomplete->hide();
|
||||||
_silent.hide();
|
_silent.hide();
|
||||||
_kbShow.hide();
|
_botKeyboardShow->hide();
|
||||||
_kbHide.hide();
|
_botKeyboardHide->hide();
|
||||||
_cmdStart.hide();
|
_botCommandStart->hide();
|
||||||
_field.hide();
|
_field.hide();
|
||||||
_fieldBarCancel.hide();
|
_fieldBarCancel.hide();
|
||||||
_send.hide();
|
_send.hide();
|
||||||
|
@ -5565,16 +5572,16 @@ void HistoryWidget::step_recording(float64 ms, bool timer) {
|
||||||
} else {
|
} else {
|
||||||
a_recordingLevel.update(dt, anim::linear);
|
a_recordingLevel.update(dt, anim::linear);
|
||||||
}
|
}
|
||||||
if (timer) update(_attachDocument.geometry());
|
if (timer) update(_attachDocument->geometry());
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::onPhotoSelect() {
|
void HistoryWidget::onPhotoSelect() {
|
||||||
if (!_history) return;
|
if (!_history) return;
|
||||||
|
|
||||||
_attachDocument.clearState();
|
_attachDocument->clearState();
|
||||||
_attachDocument.hide();
|
_attachDocument->hide();
|
||||||
_attachPhoto.show();
|
_attachPhoto->show();
|
||||||
_attachType->fastHide();
|
_attachType->hideFast();
|
||||||
|
|
||||||
if (cDefaultAttach() != dbidaPhoto) {
|
if (cDefaultAttach() != dbidaPhoto) {
|
||||||
cSetDefaultAttach(dbidaPhoto);
|
cSetDefaultAttach(dbidaPhoto);
|
||||||
|
@ -5599,10 +5606,10 @@ void HistoryWidget::onPhotoSelect() {
|
||||||
void HistoryWidget::onDocumentSelect() {
|
void HistoryWidget::onDocumentSelect() {
|
||||||
if (!_history) return;
|
if (!_history) return;
|
||||||
|
|
||||||
_attachPhoto.clearState();
|
_attachPhoto->clearState();
|
||||||
_attachPhoto.hide();
|
_attachPhoto->hide();
|
||||||
_attachDocument.show();
|
_attachDocument->show();
|
||||||
_attachType->fastHide();
|
_attachType->hideFast();
|
||||||
|
|
||||||
if (cDefaultAttach() != dbidaDocument) {
|
if (cDefaultAttach() != dbidaDocument) {
|
||||||
cSetDefaultAttach(dbidaDocument);
|
cSetDefaultAttach(dbidaDocument);
|
||||||
|
@ -5671,7 +5678,7 @@ void HistoryWidget::mouseMoveEvent(QMouseEvent *e) {
|
||||||
_inField = inField;
|
_inField = inField;
|
||||||
a_recordOver.restart();
|
a_recordOver.restart();
|
||||||
a_recordDown.start(_inField ? 1 : 0);
|
a_recordDown.start(_inField ? 1 : 0);
|
||||||
a_recordCancel.start(_inField ? st::recordCancel->c : st::recordCancelActive->c);
|
a_recordCancel.start(_inField ? st::historyRecordCancel->c : st::historyRecordCancelActive->c);
|
||||||
startAnim = true;
|
startAnim = true;
|
||||||
}
|
}
|
||||||
if (inReplyEdit != _inReplyEdit) {
|
if (inReplyEdit != _inReplyEdit) {
|
||||||
|
@ -5722,7 +5729,7 @@ void HistoryWidget::stopRecording(bool send) {
|
||||||
|
|
||||||
a_recordDown.start(0);
|
a_recordDown.start(0);
|
||||||
a_recordOver.restart();
|
a_recordOver.restart();
|
||||||
a_recordCancel = anim::cvalue(st::recordCancel->c, st::recordCancel->c);
|
a_recordCancel = anim::cvalue(st::historyRecordCancel->c, st::historyRecordCancel->c);
|
||||||
_a_record.start();
|
_a_record.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5960,7 +5967,7 @@ void HistoryWidget::updateDragAreas() {
|
||||||
case DragStateFiles:
|
case DragStateFiles:
|
||||||
_attachDragDocument->otherEnter();
|
_attachDragDocument->otherEnter();
|
||||||
_attachDragDocument->setText(lang(lng_drag_files_here), lang(lng_drag_to_send_files));
|
_attachDragDocument->setText(lang(lng_drag_files_here), lang(lng_drag_to_send_files));
|
||||||
_attachDragPhoto->fastHide();
|
_attachDragPhoto->hideFast();
|
||||||
break;
|
break;
|
||||||
case DragStatePhotoFiles:
|
case DragStatePhotoFiles:
|
||||||
_attachDragDocument->otherEnter();
|
_attachDragDocument->otherEnter();
|
||||||
|
@ -5969,7 +5976,7 @@ void HistoryWidget::updateDragAreas() {
|
||||||
_attachDragPhoto->setText(lang(lng_drag_photos_here), lang(lng_drag_to_send_quick));
|
_attachDragPhoto->setText(lang(lng_drag_photos_here), lang(lng_drag_to_send_quick));
|
||||||
break;
|
break;
|
||||||
case DragStateImage:
|
case DragStateImage:
|
||||||
_attachDragDocument->fastHide();
|
_attachDragDocument->hideFast();
|
||||||
_attachDragPhoto->otherEnter();
|
_attachDragPhoto->otherEnter();
|
||||||
_attachDragPhoto->setText(lang(lng_drag_images_here), lang(lng_drag_to_send_quick));
|
_attachDragPhoto->setText(lang(lng_drag_images_here), lang(lng_drag_to_send_quick));
|
||||||
break;
|
break;
|
||||||
|
@ -6127,10 +6134,10 @@ void HistoryWidget::onFilesDrop(const QMimeData *data) {
|
||||||
void HistoryWidget::onKbToggle(bool manual) {
|
void HistoryWidget::onKbToggle(bool manual) {
|
||||||
auto fieldEnabled = canWriteMessage();
|
auto fieldEnabled = canWriteMessage();
|
||||||
if (_kbShown || _kbReplyTo) {
|
if (_kbShown || _kbReplyTo) {
|
||||||
_kbHide.hide();
|
_botKeyboardHide->hide();
|
||||||
if (_kbShown) {
|
if (_kbShown) {
|
||||||
if (fieldEnabled) {
|
if (fieldEnabled) {
|
||||||
_kbShow.show();
|
_botKeyboardShow->show();
|
||||||
}
|
}
|
||||||
if (manual && _history) {
|
if (manual && _history) {
|
||||||
_history->lastKeyboardHiddenId = _keyboard.forMsgId().msg;
|
_history->lastKeyboardHiddenId = _keyboard.forMsgId().msg;
|
||||||
|
@ -6154,10 +6161,10 @@ void HistoryWidget::onKbToggle(bool manual) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (!_keyboard.hasMarkup() && _keyboard.forceReply()) {
|
} else if (!_keyboard.hasMarkup() && _keyboard.forceReply()) {
|
||||||
_kbHide.hide();
|
_botKeyboardHide->hide();
|
||||||
_kbShow.hide();
|
_botKeyboardShow->hide();
|
||||||
if (fieldEnabled) {
|
if (fieldEnabled) {
|
||||||
_cmdStart.show();
|
_botCommandStart->show();
|
||||||
}
|
}
|
||||||
_kbScroll.hide();
|
_kbScroll.hide();
|
||||||
_kbShown = false;
|
_kbShown = false;
|
||||||
|
@ -6175,8 +6182,8 @@ void HistoryWidget::onKbToggle(bool manual) {
|
||||||
_history->lastKeyboardHiddenId = 0;
|
_history->lastKeyboardHiddenId = 0;
|
||||||
}
|
}
|
||||||
} else if (fieldEnabled) {
|
} else if (fieldEnabled) {
|
||||||
_kbHide.show();
|
_botKeyboardHide->show();
|
||||||
_kbShow.hide();
|
_botKeyboardShow->hide();
|
||||||
_kbScroll.show();
|
_kbScroll.show();
|
||||||
_kbShown = true;
|
_kbShown = true;
|
||||||
|
|
||||||
|
@ -6195,10 +6202,10 @@ void HistoryWidget::onKbToggle(bool manual) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resizeEvent(0);
|
resizeEvent(0);
|
||||||
if (_kbHide.isHidden() && canWriteMessage()) {
|
if (_botKeyboardHide->isHidden() && canWriteMessage()) {
|
||||||
_attachEmoji.show();
|
_attachEmoji->show();
|
||||||
} else {
|
} else {
|
||||||
_attachEmoji.hide();
|
_attachEmoji->hide();
|
||||||
}
|
}
|
||||||
updateField();
|
updateField();
|
||||||
}
|
}
|
||||||
|
@ -6310,13 +6317,13 @@ void HistoryWidget::setMembersShowAreaActive(bool active) {
|
||||||
|
|
||||||
void HistoryWidget::onMembersDropdownShow() {
|
void HistoryWidget::onMembersDropdownShow() {
|
||||||
if (!_membersDropdown) {
|
if (!_membersDropdown) {
|
||||||
_membersDropdown.create(this, st::membersInnerDropdown, st::membersInnerScroll);
|
_membersDropdown.create(this, st::membersInnerDropdown);
|
||||||
_membersDropdown->setOwnedWidget(new Profile::MembersWidget(_membersDropdown, _peer, Profile::MembersWidget::TitleVisibility::Hidden));
|
_membersDropdown->setOwnedWidget(new Profile::MembersWidget(_membersDropdown, _peer, Profile::MembersWidget::TitleVisibility::Hidden));
|
||||||
_membersDropdown->resize(st::membersInnerWidth, _membersDropdown->height());
|
_membersDropdown->resizeToWidth(st::membersInnerWidth);
|
||||||
|
|
||||||
_membersDropdown->setMaxHeight(countMembersDropdownHeightMax());
|
_membersDropdown->setMaxHeight(countMembersDropdownHeightMax());
|
||||||
_membersDropdown->moveToLeft(0, 0);
|
_membersDropdown->moveToLeft(0, 0);
|
||||||
connect(_membersDropdown, SIGNAL(hidden()), this, SLOT(onMembersDropdownHidden()));
|
connect(_membersDropdown, SIGNAL(beforeHidden()), this, SLOT(onMembersDropdownHidden()));
|
||||||
}
|
}
|
||||||
_membersDropdown->otherEnter();
|
_membersDropdown->otherEnter();
|
||||||
}
|
}
|
||||||
|
@ -6436,24 +6443,24 @@ void HistoryWidget::moveFieldControls() {
|
||||||
// (_attachDocument|_attachPhoto) _field (_silent|_cmdStart|_kbShow) (_kbHide|_attachEmoji) [_broadcast] _send
|
// (_attachDocument|_attachPhoto) _field (_silent|_cmdStart|_kbShow) (_kbHide|_attachEmoji) [_broadcast] _send
|
||||||
// (_botStart|_unblock|_joinChannel|_muteUnmute)
|
// (_botStart|_unblock|_joinChannel|_muteUnmute)
|
||||||
|
|
||||||
int buttonsBottom = bottom - _attachDocument.height();
|
int buttonsBottom = bottom - _attachDocument->height();
|
||||||
_attachDocument.move(0, buttonsBottom);
|
_attachDocument->move(0, buttonsBottom);
|
||||||
_attachPhoto.move(0, buttonsBottom);
|
_attachPhoto->move(0, buttonsBottom);
|
||||||
_field.move(_attachDocument.width(), bottom - _field.height() - st::sendPadding);
|
_field.move(_attachDocument->width(), bottom - _field.height() - st::sendPadding);
|
||||||
_send.move(right - _send.width(), buttonsBottom);
|
_send.move(right - _send.width(), buttonsBottom);
|
||||||
if (_inlineBotCancel) _inlineBotCancel->move(_send.pos());
|
if (_inlineBotCancel) _inlineBotCancel->move(_send.pos());
|
||||||
right -= _send.width();
|
right -= _send.width();
|
||||||
_attachEmoji.move(right - _attachEmoji.width(), buttonsBottom);
|
_attachEmoji->move(right - _attachEmoji->width(), buttonsBottom);
|
||||||
_kbHide.move(right - _kbHide.width(), buttonsBottom);
|
_botKeyboardHide->move(right - _botKeyboardHide->width(), buttonsBottom);
|
||||||
right -= _attachEmoji.width();
|
right -= _attachEmoji->width();
|
||||||
_kbShow.move(right - _kbShow.width(), buttonsBottom);
|
_botKeyboardShow->move(right - _botKeyboardShow->width(), buttonsBottom);
|
||||||
_cmdStart.move(right - _cmdStart.width(), buttonsBottom);
|
_botCommandStart->move(right - _botCommandStart->width(), buttonsBottom);
|
||||||
_silent.move(right - _silent.width(), buttonsBottom);
|
_silent.move(right - _silent.width(), buttonsBottom);
|
||||||
|
|
||||||
right = w;
|
right = w;
|
||||||
_fieldBarCancel.move(right - _fieldBarCancel.width(), _field.y() - st::sendPadding - _fieldBarCancel.height());
|
_fieldBarCancel.move(right - _fieldBarCancel.width(), _field.y() - st::sendPadding - _fieldBarCancel.height());
|
||||||
_attachType->move(0, _attachDocument.y() - _attachType->height());
|
_attachType->move(0, _attachDocument->y() - _attachType->height());
|
||||||
_emojiPan->moveBottom(_attachEmoji.y());
|
_emojiPan->moveBottom(_attachEmoji->y());
|
||||||
|
|
||||||
_botStart.setGeometry(0, bottom - _botStart.height(), w, _botStart.height());
|
_botStart.setGeometry(0, bottom - _botStart.height(), w, _botStart.height());
|
||||||
_unblock.setGeometry(0, bottom - _unblock.height(), w, _unblock.height());
|
_unblock.setGeometry(0, bottom - _unblock.height(), w, _unblock.height());
|
||||||
|
@ -6463,11 +6470,11 @@ void HistoryWidget::moveFieldControls() {
|
||||||
|
|
||||||
void HistoryWidget::updateFieldSize() {
|
void HistoryWidget::updateFieldSize() {
|
||||||
bool kbShowShown = _history && !_kbShown && _keyboard.hasMarkup();
|
bool kbShowShown = _history && !_kbShown && _keyboard.hasMarkup();
|
||||||
int fieldWidth = width() - _attachDocument.width();
|
int fieldWidth = width() - _attachDocument->width();
|
||||||
fieldWidth -= _send.width();
|
fieldWidth -= _send.width();
|
||||||
fieldWidth -= _attachEmoji.width();
|
fieldWidth -= _attachEmoji->width();
|
||||||
if (kbShowShown) fieldWidth -= _kbShow.width();
|
if (kbShowShown) fieldWidth -= _botKeyboardShow->width();
|
||||||
if (_cmdStartShown) fieldWidth -= _cmdStart.width();
|
if (_cmdStartShown) fieldWidth -= _botCommandStart->width();
|
||||||
if (hasSilentToggle()) fieldWidth -= _silent.width();
|
if (hasSilentToggle()) fieldWidth -= _silent.width();
|
||||||
|
|
||||||
if (_field.width() != fieldWidth) {
|
if (_field.width() != fieldWidth) {
|
||||||
|
@ -6493,7 +6500,7 @@ void HistoryWidget::inlineBotChanged() {
|
||||||
_inlineBotCancel = std_::make_unique<IconedButton>(this, st::inlineBotCancel);
|
_inlineBotCancel = std_::make_unique<IconedButton>(this, st::inlineBotCancel);
|
||||||
connect(_inlineBotCancel.get(), SIGNAL(clicked()), this, SLOT(onInlineBotCancel()));
|
connect(_inlineBotCancel.get(), SIGNAL(clicked()), this, SLOT(onInlineBotCancel()));
|
||||||
_inlineBotCancel->setGeometry(_send.geometry());
|
_inlineBotCancel->setGeometry(_send.geometry());
|
||||||
_attachEmoji.raise();
|
_attachEmoji->raise();
|
||||||
updateFieldSubmitSettings();
|
updateFieldSubmitSettings();
|
||||||
updateControlsVisibility();
|
updateControlsVisibility();
|
||||||
} else if (!isInlineBot && _inlineBotCancel) {
|
} else if (!isInlineBot && _inlineBotCancel) {
|
||||||
|
@ -7029,7 +7036,7 @@ void HistoryWidget::updateControlsGeometry() {
|
||||||
|
|
||||||
_historyToEnd->moveToRight(st::historyToDownPosition.x(), _scroll.y() + _scroll.height() - _historyToEnd->height() - st::historyToDownPosition.y());
|
_historyToEnd->moveToRight(st::historyToDownPosition.x(), _scroll.y() + _scroll.height() - _historyToEnd->height() - st::historyToDownPosition.y());
|
||||||
|
|
||||||
_emojiPan->setMaxHeight(height() - st::dropdownDef.padding.top() - st::dropdownDef.padding.bottom() - _attachEmoji.height());
|
_emojiPan->setMaxHeight(height() - st::defaultDropdownPadding.top() - st::defaultDropdownPadding.bottom() - _attachEmoji->height());
|
||||||
if (_membersDropdown) {
|
if (_membersDropdown) {
|
||||||
_membersDropdown->setMaxHeight(countMembersDropdownHeightMax());
|
_membersDropdown->setMaxHeight(countMembersDropdownHeightMax());
|
||||||
}
|
}
|
||||||
|
@ -7315,15 +7322,15 @@ void HistoryWidget::updateBotKeyboard(History *h, bool force) {
|
||||||
if (!_a_show.animating()) {
|
if (!_a_show.animating()) {
|
||||||
if (hasMarkup) {
|
if (hasMarkup) {
|
||||||
_kbScroll.show();
|
_kbScroll.show();
|
||||||
_attachEmoji.hide();
|
_attachEmoji->hide();
|
||||||
_kbHide.show();
|
_botKeyboardHide->show();
|
||||||
} else {
|
} else {
|
||||||
_kbScroll.hide();
|
_kbScroll.hide();
|
||||||
_attachEmoji.show();
|
_attachEmoji->show();
|
||||||
_kbHide.hide();
|
_botKeyboardHide->hide();
|
||||||
}
|
}
|
||||||
_kbShow.hide();
|
_botKeyboardShow->hide();
|
||||||
_cmdStart.hide();
|
_botCommandStart->hide();
|
||||||
}
|
}
|
||||||
int32 maxh = hasMarkup ? qMin(_keyboard.height(), int(st::maxFieldHeight) - (int(st::maxFieldHeight) / 2)) : 0;
|
int32 maxh = hasMarkup ? qMin(_keyboard.height(), int(st::maxFieldHeight) - (int(st::maxFieldHeight) / 2)) : 0;
|
||||||
_field.setMaxHeight(st::maxFieldHeight - maxh);
|
_field.setMaxHeight(st::maxFieldHeight - maxh);
|
||||||
|
@ -7338,10 +7345,10 @@ void HistoryWidget::updateBotKeyboard(History *h, bool force) {
|
||||||
} else {
|
} else {
|
||||||
if (!_a_show.animating()) {
|
if (!_a_show.animating()) {
|
||||||
_kbScroll.hide();
|
_kbScroll.hide();
|
||||||
_attachEmoji.show();
|
_attachEmoji->show();
|
||||||
_kbHide.hide();
|
_botKeyboardHide->hide();
|
||||||
_kbShow.show();
|
_botKeyboardShow->show();
|
||||||
_cmdStart.hide();
|
_botCommandStart->hide();
|
||||||
}
|
}
|
||||||
_field.setMaxHeight(st::maxFieldHeight);
|
_field.setMaxHeight(st::maxFieldHeight);
|
||||||
_kbShown = false;
|
_kbShown = false;
|
||||||
|
@ -7354,10 +7361,10 @@ void HistoryWidget::updateBotKeyboard(History *h, bool force) {
|
||||||
} else {
|
} else {
|
||||||
if (!_scroll.isHidden()) {
|
if (!_scroll.isHidden()) {
|
||||||
_kbScroll.hide();
|
_kbScroll.hide();
|
||||||
_attachEmoji.show();
|
_attachEmoji->show();
|
||||||
_kbHide.hide();
|
_botKeyboardHide->hide();
|
||||||
_kbShow.hide();
|
_botKeyboardShow->hide();
|
||||||
_cmdStart.show();
|
_botCommandStart->show();
|
||||||
}
|
}
|
||||||
_field.setMaxHeight(st::maxFieldHeight);
|
_field.setMaxHeight(st::maxFieldHeight);
|
||||||
_kbShown = false;
|
_kbShown = false;
|
||||||
|
@ -7543,9 +7550,7 @@ void HistoryWidget::onInlineResultSend(InlineBots::Result *result, UserData *bot
|
||||||
Local::writeRecentHashtagsAndBots();
|
Local::writeRecentHashtagsAndBots();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_fieldAutocomplete->isHidden()) _fieldAutocomplete->hideStart();
|
hideSelectorControlsAnimated();
|
||||||
if (!_attachType->isHidden()) _attachType->hideStart();
|
|
||||||
if (!_emojiPan->isHidden()) _emojiPan->hideStart();
|
|
||||||
|
|
||||||
_field.setFocus();
|
_field.setFocus();
|
||||||
}
|
}
|
||||||
|
@ -7711,9 +7716,7 @@ bool HistoryWidget::sendExistingDocument(DocumentData *doc, const QString &capti
|
||||||
onCloudDraftSave(); // won't be needed if SendInlineBotResult will clear the cloud draft
|
onCloudDraftSave(); // won't be needed if SendInlineBotResult will clear the cloud draft
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_fieldAutocomplete->isHidden()) _fieldAutocomplete->hideStart();
|
hideSelectorControlsAnimated();
|
||||||
if (!_attachType->isHidden()) _attachType->hideStart();
|
|
||||||
if (!_emojiPan->isHidden()) _emojiPan->hideStart();
|
|
||||||
|
|
||||||
_field.setFocus();
|
_field.setFocus();
|
||||||
return true;
|
return true;
|
||||||
|
@ -7758,9 +7761,7 @@ void HistoryWidget::sendExistingPhoto(PhotoData *photo, const QString &caption)
|
||||||
|
|
||||||
App::historyRegRandom(randomId, newId);
|
App::historyRegRandom(randomId, newId);
|
||||||
|
|
||||||
if (!_fieldAutocomplete->isHidden()) _fieldAutocomplete->hideStart();
|
hideSelectorControlsAnimated();
|
||||||
if (!_attachType->isHidden()) _attachType->hideStart();
|
|
||||||
if (!_emojiPan->isHidden()) _emojiPan->hideStart();
|
|
||||||
|
|
||||||
_field.setFocus();
|
_field.setFocus();
|
||||||
}
|
}
|
||||||
|
@ -8001,7 +8002,7 @@ void HistoryWidget::cancelReplyAfterMediaSend(bool lastKeyboardUsed) {
|
||||||
|
|
||||||
int HistoryWidget::countMembersDropdownHeightMax() const {
|
int HistoryWidget::countMembersDropdownHeightMax() const {
|
||||||
int result = height() - st::membersInnerDropdown.padding.top() - st::membersInnerDropdown.padding.bottom();
|
int result = height() - st::membersInnerDropdown.padding.top() - st::membersInnerDropdown.padding.bottom();
|
||||||
result -= _attachEmoji.height();
|
result -= _attachEmoji->height();
|
||||||
accumulate_min(result, st::membersInnerHeightMax);
|
accumulate_min(result, st::membersInnerHeightMax);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -8221,7 +8222,7 @@ void HistoryWidget::onCancel() {
|
||||||
onFieldBarCancel();
|
onFieldBarCancel();
|
||||||
}
|
}
|
||||||
} else if (!_fieldAutocomplete->isHidden()) {
|
} else if (!_fieldAutocomplete->isHidden()) {
|
||||||
_fieldAutocomplete->hideStart();
|
_fieldAutocomplete->hideAnimated();
|
||||||
} else {
|
} else {
|
||||||
App::main()->showBackFromStack();
|
App::main()->showBackFromStack();
|
||||||
emit cancelled();
|
emit cancelled();
|
||||||
|
@ -8637,36 +8638,36 @@ void HistoryWidget::paintEditHeader(Painter &p, const QRect &rect, int left, int
|
||||||
|
|
||||||
void HistoryWidget::drawRecordButton(Painter &p) {
|
void HistoryWidget::drawRecordButton(Painter &p) {
|
||||||
if (a_recordDown.current() < 1) {
|
if (a_recordDown.current() < 1) {
|
||||||
p.setOpacity(st::btnAttachEmoji.opacity * (1 - a_recordOver.current()) + st::btnAttachEmoji.overOpacity * a_recordOver.current());
|
p.setOpacity(st::historyAttachEmoji.opacity * (1 - a_recordOver.current()) + st::historyAttachEmoji.overOpacity * a_recordOver.current());
|
||||||
p.drawSprite(_send.x() + (_send.width() - st::btnRecordAudio.pxWidth()) / 2, _send.y() + (_send.height() - st::btnRecordAudio.pxHeight()) / 2, st::btnRecordAudio);
|
st::historyRecordVoice.paint(p, _send.x() + (_send.width() - st::historyRecordVoice.width()) / 2, _send.y() + (_send.height() - st::historyRecordVoice.height()) / 2, width());
|
||||||
}
|
}
|
||||||
if (a_recordDown.current() > 0) {
|
if (a_recordDown.current() > 0) {
|
||||||
p.setOpacity(a_recordDown.current());
|
p.setOpacity(a_recordDown.current());
|
||||||
p.drawSprite(_send.x() + (_send.width() - st::btnRecordAudioActive.pxWidth()) / 2, _send.y() + (_send.height() - st::btnRecordAudioActive.pxHeight()) / 2, st::btnRecordAudioActive);
|
st::historyRecordVoiceActive.paint(p, _send.x() + (_send.width() - st::historyRecordVoiceActive.width()) / 2, _send.y() + (_send.height() - st::historyRecordVoiceActive.height()) / 2, width());
|
||||||
}
|
}
|
||||||
p.setOpacity(1);
|
p.setOpacity(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::drawRecording(Painter &p) {
|
void HistoryWidget::drawRecording(Painter &p) {
|
||||||
p.setPen(Qt::NoPen);
|
p.setPen(Qt::NoPen);
|
||||||
p.setBrush(st::recordSignalColor->b);
|
p.setBrush(st::historyRecordSignalColor);
|
||||||
p.setRenderHint(QPainter::HighQualityAntialiasing);
|
p.setRenderHint(QPainter::HighQualityAntialiasing);
|
||||||
float64 delta = qMin(float64(a_recordingLevel.current()) / 0x4000, 1.);
|
float64 delta = qMin(float64(a_recordingLevel.current()) / 0x4000, 1.);
|
||||||
int32 d = 2 * qRound(st::recordSignalMin + (delta * (st::recordSignalMax - st::recordSignalMin)));
|
int32 d = 2 * qRound(st::historyRecordSignalMin + (delta * (st::historyRecordSignalMax - st::historyRecordSignalMin)));
|
||||||
p.drawEllipse(_attachPhoto.x() + (_attachEmoji.width() - d) / 2, _attachPhoto.y() + (_attachPhoto.height() - d) / 2, d, d);
|
p.drawEllipse(_attachPhoto->x() + (_attachEmoji->width() - d) / 2, _attachPhoto->y() + (_attachPhoto->height() - d) / 2, d, d);
|
||||||
p.setRenderHint(QPainter::HighQualityAntialiasing, false);
|
p.setRenderHint(QPainter::HighQualityAntialiasing, false);
|
||||||
|
|
||||||
QString duration = formatDurationText(_recordingSamples / AudioVoiceMsgFrequency);
|
QString duration = formatDurationText(_recordingSamples / AudioVoiceMsgFrequency);
|
||||||
p.setFont(st::recordFont->f);
|
p.setFont(st::historyRecordFont);
|
||||||
|
|
||||||
p.setPen(st::black->p);
|
p.setPen(st::black);
|
||||||
p.drawText(_attachPhoto.x() + _attachEmoji.width(), _attachPhoto.y() + st::recordTextTop + st::recordFont->ascent, duration);
|
p.drawText(_attachPhoto->x() + _attachEmoji->width(), _attachPhoto->y() + st::historyRecordTextTop + st::historyRecordFont->ascent, duration);
|
||||||
|
|
||||||
int32 left = _attachPhoto.x() + _attachEmoji.width() + st::recordFont->width(duration) + ((_send.width() - st::btnRecordAudio.pxWidth()) / 2);
|
int32 left = _attachPhoto->x() + _attachEmoji->width() + st::historyRecordFont->width(duration) + ((_send.width() - st::historyRecordVoice.width()) / 2);
|
||||||
int32 right = width() - _send.width();
|
int32 right = width() - _send.width();
|
||||||
|
|
||||||
p.setPen(a_recordCancel.current());
|
p.setPen(a_recordCancel.current());
|
||||||
p.drawText(left + (right - left - _recordCancelWidth) / 2, _attachPhoto.y() + st::recordTextTop + st::recordFont->ascent, lang(lng_record_cancel));
|
p.drawText(left + (right - left - _recordCancelWidth) / 2, _attachPhoto->y() + st::historyRecordTextTop + st::historyRecordFont->ascent, lang(lng_record_cancel));
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::drawPinnedBar(Painter &p) {
|
void HistoryWidget::drawPinnedBar(Painter &p) {
|
||||||
|
|
|
@ -22,7 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include "localimageloader.h"
|
#include "localimageloader.h"
|
||||||
#include "ui/effects/rect_shadow.h"
|
#include "ui/effects/rect_shadow.h"
|
||||||
#include "ui/popupmenu.h"
|
#include "ui/widgets/tooltip.h"
|
||||||
#include "history/history_common.h"
|
#include "history/history_common.h"
|
||||||
#include "history/field_autocomplete.h"
|
#include "history/field_autocomplete.h"
|
||||||
#include "window/section_widget.h"
|
#include "window/section_widget.h"
|
||||||
|
@ -36,17 +36,20 @@ class Result;
|
||||||
} // namespace InlineBots
|
} // namespace InlineBots
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class HistoryDownButton;
|
|
||||||
class InnerDropdown;
|
class InnerDropdown;
|
||||||
|
class DropdownMenu;
|
||||||
class PlainShadow;
|
class PlainShadow;
|
||||||
|
class PopupMenu;
|
||||||
|
class IconButton;
|
||||||
|
class HistoryDownButton;
|
||||||
|
class EmojiButton;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
class Dropdown;
|
|
||||||
class DragArea;
|
class DragArea;
|
||||||
class EmojiPan;
|
class EmojiPan;
|
||||||
|
|
||||||
class HistoryWidget;
|
class HistoryWidget;
|
||||||
class HistoryInner : public TWidget, public AbstractTooltipShower, private base::Subscriber {
|
class HistoryInner : public TWidget, public Ui::AbstractTooltipShower, private base::Subscriber {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -256,7 +259,7 @@ private:
|
||||||
QTimer _touchScrollTimer;
|
QTimer _touchScrollTimer;
|
||||||
|
|
||||||
// context menu
|
// context menu
|
||||||
PopupMenu *_menu = nullptr;
|
Ui::PopupMenu *_menu = nullptr;
|
||||||
|
|
||||||
// save visible area coords for painting / pressing userpics
|
// save visible area coords for painting / pressing userpics
|
||||||
int _visibleAreaTop = 0;
|
int _visibleAreaTop = 0;
|
||||||
|
@ -351,7 +354,7 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class BotKeyboard : public TWidget, public AbstractTooltipShower, public ClickHandlerHost {
|
class BotKeyboard : public TWidget, public Ui::AbstractTooltipShower, public ClickHandlerHost {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -505,7 +508,7 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class SilentToggle : public FlatCheckbox, public AbstractTooltipShower {
|
class SilentToggle : public FlatCheckbox, public Ui::AbstractTooltipShower {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
SilentToggle(QWidget *parent);
|
SilentToggle(QWidget *parent);
|
||||||
|
@ -868,6 +871,7 @@ private:
|
||||||
|
|
||||||
void cancelReplyAfterMediaSend(bool lastKeyboardUsed);
|
void cancelReplyAfterMediaSend(bool lastKeyboardUsed);
|
||||||
|
|
||||||
|
void hideSelectorControlsAnimated();
|
||||||
int countMembersDropdownHeightMax() const;
|
int countMembersDropdownHeightMax() const;
|
||||||
|
|
||||||
MsgId _replyToId = 0;
|
MsgId _replyToId = 0;
|
||||||
|
@ -1086,9 +1090,12 @@ private:
|
||||||
FlatButton _send, _unblock, _botStart, _joinChannel, _muteUnmute;
|
FlatButton _send, _unblock, _botStart, _joinChannel, _muteUnmute;
|
||||||
mtpRequestId _unblockRequest = 0;
|
mtpRequestId _unblockRequest = 0;
|
||||||
mtpRequestId _reportSpamRequest = 0;
|
mtpRequestId _reportSpamRequest = 0;
|
||||||
IconedButton _attachDocument, _attachPhoto;
|
ChildWidget<Ui::IconButton> _attachDocument;
|
||||||
EmojiButton _attachEmoji;
|
ChildWidget<Ui::IconButton> _attachPhoto;
|
||||||
IconedButton _kbShow, _kbHide, _cmdStart;
|
ChildWidget<Ui::EmojiButton> _attachEmoji;
|
||||||
|
ChildWidget<Ui::IconButton> _botKeyboardShow;
|
||||||
|
ChildWidget<Ui::IconButton> _botKeyboardHide;
|
||||||
|
ChildWidget<Ui::IconButton> _botCommandStart;
|
||||||
SilentToggle _silent;
|
SilentToggle _silent;
|
||||||
bool _cmdStartShown = false;
|
bool _cmdStartShown = false;
|
||||||
MessageField _field;
|
MessageField _field;
|
||||||
|
@ -1115,7 +1122,7 @@ private:
|
||||||
ChildWidget<Ui::InnerDropdown> _membersDropdown = { nullptr };
|
ChildWidget<Ui::InnerDropdown> _membersDropdown = { nullptr };
|
||||||
QTimer _membersDropdownShowTimer;
|
QTimer _membersDropdownShowTimer;
|
||||||
|
|
||||||
ChildWidget<Dropdown> _attachType;
|
ChildWidget<Ui::DropdownMenu> _attachType;
|
||||||
ChildWidget<EmojiPan> _emojiPan;
|
ChildWidget<EmojiPan> _emojiPan;
|
||||||
DragState _attachDrag = DragStateNone;
|
DragState _attachDrag = DragStateNone;
|
||||||
ChildWidget<DragArea> _attachDragDocument, _attachDragPhoto;
|
ChildWidget<DragArea> _attachDragDocument, _attachDragPhoto;
|
||||||
|
|
|
@ -22,6 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
|
|
||||||
#include "styles/style_dialogs.h"
|
#include "styles/style_dialogs.h"
|
||||||
|
#include "styles/style_history.h"
|
||||||
#include "ui/buttons/peer_avatar_button.h"
|
#include "ui/buttons/peer_avatar_button.h"
|
||||||
#include "ui/buttons/round_button.h"
|
#include "ui/buttons/round_button.h"
|
||||||
#include "ui/widgets/shadow.h"
|
#include "ui/widgets/shadow.h"
|
||||||
|
@ -29,7 +30,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "window/section_widget.h"
|
#include "window/section_widget.h"
|
||||||
#include "window/top_bar_widget.h"
|
#include "window/top_bar_widget.h"
|
||||||
#include "data/data_drafts.h"
|
#include "data/data_drafts.h"
|
||||||
#include "dropdown.h"
|
#include "ui/widgets/dropdown_menu.h"
|
||||||
#include "observer_peer.h"
|
#include "observer_peer.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "dialogswidget.h"
|
#include "dialogswidget.h"
|
||||||
|
@ -75,7 +76,7 @@ MainWidget::MainWidget(MainWindow *window) : TWidget(window)
|
||||||
, _topBar(this)
|
, _topBar(this)
|
||||||
, _playerPlaylist(this, Media::Player::Panel::Layout::OnlyPlaylist)
|
, _playerPlaylist(this, Media::Player::Panel::Layout::OnlyPlaylist)
|
||||||
, _playerPanel(this, Media::Player::Panel::Layout::Full)
|
, _playerPanel(this, Media::Player::Panel::Layout::Full)
|
||||||
, _mediaType(this)
|
, _mediaType(this, st::historyAttachDropdownMenu)
|
||||||
, _api(new ApiWrap(this)) {
|
, _api(new ApiWrap(this)) {
|
||||||
setGeometry(QRect(0, st::titleHeight, App::wnd()->width(), App::wnd()->height() - st::titleHeight));
|
setGeometry(QRect(0, st::titleHeight, App::wnd()->width(), App::wnd()->height() - st::titleHeight));
|
||||||
|
|
||||||
|
@ -1382,16 +1383,16 @@ void MainWidget::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mask != _mediaTypeMask) {
|
if (mask != _mediaTypeMask) {
|
||||||
_mediaType->resetButtons();
|
_mediaType->clearActions();
|
||||||
for (int32 i = 0; i < OverviewCount; ++i) {
|
for (int32 i = 0; i < OverviewCount; ++i) {
|
||||||
if (mask & (1 << i)) {
|
if (mask & (1 << i)) {
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case OverviewPhotos: connect(_mediaType->addButton(new IconedButton(this, st::dropdownMediaPhotos, lang(lng_media_type_photos))), SIGNAL(clicked()), this, SLOT(onPhotosSelect())); break;
|
case OverviewPhotos: _mediaType->addAction(lang(lng_media_type_photos), this, SLOT(onPhotosSelect()), &st::historyMediaTypePhoto); break;
|
||||||
case OverviewVideos: connect(_mediaType->addButton(new IconedButton(this, st::dropdownMediaVideos, lang(lng_media_type_videos))), SIGNAL(clicked()), this, SLOT(onVideosSelect())); break;
|
case OverviewVideos: _mediaType->addAction(lang(lng_media_type_videos), this, SLOT(onVideosSelect()), &st::historyMediaTypeVideo); break;
|
||||||
case OverviewMusicFiles: connect(_mediaType->addButton(new IconedButton(this, st::dropdownMediaSongs, lang(lng_media_type_songs))), SIGNAL(clicked()), this, SLOT(onSongsSelect())); break;
|
case OverviewMusicFiles: _mediaType->addAction(lang(lng_media_type_songs), this, SLOT(onSongsSelect()), &st::historyMediaTypeSong); break;
|
||||||
case OverviewFiles: connect(_mediaType->addButton(new IconedButton(this, st::dropdownMediaDocuments, lang(lng_media_type_files))), SIGNAL(clicked()), this, SLOT(onDocumentsSelect())); break;
|
case OverviewFiles: _mediaType->addAction(lang(lng_media_type_files), this, SLOT(onDocumentsSelect()), &st::historyMediaTypeFile); break;
|
||||||
case OverviewVoiceFiles: connect(_mediaType->addButton(new IconedButton(this, st::dropdownMediaAudios, lang(lng_media_type_audios))), SIGNAL(clicked()), this, SLOT(onAudiosSelect())); break;
|
case OverviewVoiceFiles: _mediaType->addAction(lang(lng_media_type_audios), this, SLOT(onAudiosSelect()), &st::historyMediaTypeVoice); break;
|
||||||
case OverviewLinks: connect(_mediaType->addButton(new IconedButton(this, st::dropdownMediaLinks, lang(lng_media_type_links))), SIGNAL(clicked()), this, SLOT(onLinksSelect())); break;
|
case OverviewLinks: _mediaType->addAction(lang(lng_media_type_links), this, SLOT(onLinksSelect()), &st::historyMediaTypeLink); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2912,32 +2913,32 @@ void MainWidget::setMembersShowAreaActive(bool active) {
|
||||||
|
|
||||||
void MainWidget::onPhotosSelect() {
|
void MainWidget::onPhotosSelect() {
|
||||||
if (_overview) _overview->switchType(OverviewPhotos);
|
if (_overview) _overview->switchType(OverviewPhotos);
|
||||||
_mediaType->hideStart();
|
_mediaType->hideAnimated();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::onVideosSelect() {
|
void MainWidget::onVideosSelect() {
|
||||||
if (_overview) _overview->switchType(OverviewVideos);
|
if (_overview) _overview->switchType(OverviewVideos);
|
||||||
_mediaType->hideStart();
|
_mediaType->hideAnimated();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::onSongsSelect() {
|
void MainWidget::onSongsSelect() {
|
||||||
if (_overview) _overview->switchType(OverviewMusicFiles);
|
if (_overview) _overview->switchType(OverviewMusicFiles);
|
||||||
_mediaType->hideStart();
|
_mediaType->hideAnimated();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::onDocumentsSelect() {
|
void MainWidget::onDocumentsSelect() {
|
||||||
if (_overview) _overview->switchType(OverviewFiles);
|
if (_overview) _overview->switchType(OverviewFiles);
|
||||||
_mediaType->hideStart();
|
_mediaType->hideAnimated();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::onAudiosSelect() {
|
void MainWidget::onAudiosSelect() {
|
||||||
if (_overview) _overview->switchType(OverviewVoiceFiles);
|
if (_overview) _overview->switchType(OverviewVoiceFiles);
|
||||||
_mediaType->hideStart();
|
_mediaType->hideAnimated();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::onLinksSelect() {
|
void MainWidget::onLinksSelect() {
|
||||||
if (_overview) _overview->switchType(OverviewLinks);
|
if (_overview) _overview->switchType(OverviewLinks);
|
||||||
_mediaType->hideStart();
|
_mediaType->hideAnimated();
|
||||||
}
|
}
|
||||||
|
|
||||||
Window::TopBarWidget *MainWidget::topBar() {
|
Window::TopBarWidget *MainWidget::topBar() {
|
||||||
|
|
|
@ -39,6 +39,7 @@ class Panel;
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class PeerAvatarButton;
|
class PeerAvatarButton;
|
||||||
class PlainShadow;
|
class PlainShadow;
|
||||||
|
class DropdownMenu;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Window {
|
namespace Window {
|
||||||
|
@ -56,7 +57,6 @@ class DialogsWidget;
|
||||||
class HistoryWidget;
|
class HistoryWidget;
|
||||||
class OverviewWidget;
|
class OverviewWidget;
|
||||||
class HistoryHider;
|
class HistoryHider;
|
||||||
class Dropdown;
|
|
||||||
|
|
||||||
enum StackItemType {
|
enum StackItemType {
|
||||||
HistoryStackItem,
|
HistoryStackItem,
|
||||||
|
@ -609,7 +609,7 @@ private:
|
||||||
int _playerHeight = 0;
|
int _playerHeight = 0;
|
||||||
int _contentScrollAddToY = 0;
|
int _contentScrollAddToY = 0;
|
||||||
|
|
||||||
ChildWidget<Dropdown> _mediaType;
|
ChildWidget<Ui::DropdownMenu> _mediaType;
|
||||||
int32 _mediaTypeMask = 0;
|
int32 _mediaTypeMask = 0;
|
||||||
|
|
||||||
int32 updDate = 0;
|
int32 updDate = 0;
|
||||||
|
|
|
@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include "dialogs/dialogs_layout.h"
|
#include "dialogs/dialogs_layout.h"
|
||||||
#include "styles/style_dialogs.h"
|
#include "styles/style_dialogs.h"
|
||||||
#include "ui/popupmenu.h"
|
#include "ui/widgets/popup_menu.h"
|
||||||
#include "zip.h"
|
#include "zip.h"
|
||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
#include "shortcuts.h"
|
#include "shortcuts.h"
|
||||||
|
@ -185,7 +185,7 @@ void MainWindow::onWindowActiveChanged() {
|
||||||
|
|
||||||
void MainWindow::firstShow() {
|
void MainWindow::firstShow() {
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
trayIconMenu = new PopupMenu();
|
trayIconMenu = new Ui::PopupMenu();
|
||||||
trayIconMenu->deleteOnHide(false);
|
trayIconMenu->deleteOnHide(false);
|
||||||
#else // Q_OS_WIN
|
#else // Q_OS_WIN
|
||||||
trayIconMenu = new QMenu(this);
|
trayIconMenu = new QMenu(this);
|
||||||
|
|
|
@ -29,7 +29,7 @@ class Document;
|
||||||
namespace Media {
|
namespace Media {
|
||||||
namespace Player {
|
namespace Player {
|
||||||
|
|
||||||
class ListWidget : public ScrolledWidget, private base::Subscriber {
|
class ListWidget : public TWidget, private base::Subscriber {
|
||||||
public:
|
public:
|
||||||
ListWidget();
|
ListWidget();
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "media/player/media_player_list.h"
|
#include "media/player/media_player_list.h"
|
||||||
#include "media/player/media_player_instance.h"
|
#include "media/player/media_player_instance.h"
|
||||||
#include "styles/style_overview.h"
|
#include "styles/style_overview.h"
|
||||||
|
#include "styles/style_widgets.h"
|
||||||
#include "styles/style_media_player.h"
|
#include "styles/style_media_player.h"
|
||||||
#include "ui/widgets/shadow.h"
|
#include "ui/widgets/shadow.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
|
@ -34,7 +35,7 @@ namespace Player {
|
||||||
|
|
||||||
Panel::Panel(QWidget *parent, Layout layout) : TWidget(parent)
|
Panel::Panel(QWidget *parent, Layout layout) : TWidget(parent)
|
||||||
, _layout(layout)
|
, _layout(layout)
|
||||||
, _shadow(st::defaultInnerDropdown.shadow)
|
, _shadow(st::defaultDropdownShadow)
|
||||||
, _scroll(this, st::mediaPlayerScroll) {
|
, _scroll(this, st::mediaPlayerScroll) {
|
||||||
_hideTimer.setSingleShot(true);
|
_hideTimer.setSingleShot(true);
|
||||||
connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(onHideStart()));
|
connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(onHideStart()));
|
||||||
|
@ -90,7 +91,7 @@ void Panel::updateControlsGeometry() {
|
||||||
if (scrollHeight > 0) {
|
if (scrollHeight > 0) {
|
||||||
_scroll->setGeometryToRight(contentRight(), scrollTop, width, scrollHeight);
|
_scroll->setGeometryToRight(contentRight(), scrollTop, width, scrollHeight);
|
||||||
}
|
}
|
||||||
if (auto widget = static_cast<ScrolledWidget*>(_scroll->widget())) {
|
if (auto widget = static_cast<TWidget*>(_scroll->widget())) {
|
||||||
widget->resizeToWidth(width);
|
widget->resizeToWidth(width);
|
||||||
onScroll();
|
onScroll();
|
||||||
}
|
}
|
||||||
|
@ -118,7 +119,7 @@ void Panel::scrollPlaylistToCurrentTrack() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panel::onScroll() {
|
void Panel::onScroll() {
|
||||||
if (auto widget = static_cast<ScrolledWidget*>(_scroll->widget())) {
|
if (auto widget = static_cast<TWidget*>(_scroll->widget())) {
|
||||||
int visibleTop = _scroll->scrollTop();
|
int visibleTop = _scroll->scrollTop();
|
||||||
int visibleBottom = visibleTop + _scroll->height();
|
int visibleBottom = visibleTop + _scroll->height();
|
||||||
widget->setVisibleTopBottom(visibleTop, visibleBottom);
|
widget->setVisibleTopBottom(visibleTop, visibleBottom);
|
||||||
|
@ -153,7 +154,7 @@ void Panel::paintEvent(QPaintEvent *e) {
|
||||||
if (animating) {
|
if (animating) {
|
||||||
p.setOpacity(_a_appearance.current(_hiding ? 0. : 1.));
|
p.setOpacity(_a_appearance.current(_hiding ? 0. : 1.));
|
||||||
} else if (_hiding || isHidden()) {
|
} else if (_hiding || isHidden()) {
|
||||||
hidingFinished();
|
hideFinished();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
p.drawPixmap(0, 0, _cache);
|
p.drawPixmap(0, 0, _cache);
|
||||||
|
@ -290,7 +291,7 @@ void Panel::onShowStart() {
|
||||||
void Panel::hideIgnoringEnterEvents() {
|
void Panel::hideIgnoringEnterEvents() {
|
||||||
_ignoringEnterEvents = true;
|
_ignoringEnterEvents = true;
|
||||||
if (isHidden()) {
|
if (isHidden()) {
|
||||||
hidingFinished();
|
hideFinished();
|
||||||
} else {
|
} else {
|
||||||
onHideStart();
|
onHideStart();
|
||||||
}
|
}
|
||||||
|
@ -317,13 +318,13 @@ void Panel::startAnimation() {
|
||||||
void Panel::appearanceCallback() {
|
void Panel::appearanceCallback() {
|
||||||
if (!_a_appearance.animating() && _hiding) {
|
if (!_a_appearance.animating() && _hiding) {
|
||||||
_hiding = false;
|
_hiding = false;
|
||||||
hidingFinished();
|
hideFinished();
|
||||||
} else {
|
} else {
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panel::hidingFinished() {
|
void Panel::hideFinished() {
|
||||||
hide();
|
hide();
|
||||||
_cache = QPixmap();
|
_cache = QPixmap();
|
||||||
performDestroy();
|
performDestroy();
|
||||||
|
|
|
@ -81,7 +81,7 @@ private:
|
||||||
|
|
||||||
void updateSize();
|
void updateSize();
|
||||||
void appearanceCallback();
|
void appearanceCallback();
|
||||||
void hidingFinished();
|
void hideFinished();
|
||||||
int contentLeft() const;
|
int contentLeft() const;
|
||||||
int contentTop() const;
|
int contentTop() const;
|
||||||
int contentRight() const;
|
int contentRight() const;
|
||||||
|
|
|
@ -56,9 +56,6 @@ public:
|
||||||
|
|
||||||
bool overlaps(const QRect &globalRect);
|
bool overlaps(const QRect &globalRect);
|
||||||
|
|
||||||
void otherEnter();
|
|
||||||
void otherLeave();
|
|
||||||
|
|
||||||
QMargins getMargin() const;
|
QMargins getMargin() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -75,6 +72,9 @@ private slots:
|
||||||
void onWindowActiveChanged();
|
void onWindowActiveChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void otherEnter();
|
||||||
|
void otherLeave();
|
||||||
|
|
||||||
void appearanceCallback();
|
void appearanceCallback();
|
||||||
void hidingFinished();
|
void hidingFinished();
|
||||||
void startAnimation();
|
void startAnimation();
|
||||||
|
|
|
@ -110,3 +110,50 @@ mediaviewFileBlue: icon {
|
||||||
mediaviewTransparentBg: #ffffff;
|
mediaviewTransparentBg: #ffffff;
|
||||||
mediaviewTransparentFg: #cccccc;
|
mediaviewTransparentFg: #cccccc;
|
||||||
mediaviewTransparentSize: 4px;
|
mediaviewTransparentSize: 4px;
|
||||||
|
|
||||||
|
mediaviewMenu: Menu(defaultMenu) {
|
||||||
|
itemBg: #383838;
|
||||||
|
itemBgOver: #505050;
|
||||||
|
itemFg: white;
|
||||||
|
itemFgOver: white;
|
||||||
|
itemFgDisabled: #999;
|
||||||
|
itemFgShortcut: #eee;
|
||||||
|
itemFgShortcutOver: #fff;
|
||||||
|
itemFgShortcutDisabled: #999;
|
||||||
|
|
||||||
|
separatorFg: #484848;
|
||||||
|
}
|
||||||
|
mediaviewPopupMenu: PopupMenu(defaultPopupMenu) {
|
||||||
|
shadow: icon {};
|
||||||
|
menu: mediaviewMenu;
|
||||||
|
}
|
||||||
|
mediaviewDropdownMenu: DropdownMenu(defaultDropdownMenu) {
|
||||||
|
menu: mediaviewMenu;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
mvDropdown: dropdown(dropdownDef) {
|
||||||
|
shadow: icon {};
|
||||||
|
padding: margins(11px, 12px, 11px, 12px);
|
||||||
|
|
||||||
|
border: 0px;
|
||||||
|
width: 182px;
|
||||||
|
}
|
||||||
|
mvButton: iconedButton(btnDefIconed) {
|
||||||
|
bgColor: #383838;
|
||||||
|
overBgColor: #505050;
|
||||||
|
font: font(fsize);
|
||||||
|
|
||||||
|
opacity: 1.;
|
||||||
|
overOpacity: 1.;
|
||||||
|
|
||||||
|
width: -32px;
|
||||||
|
height: 36px;
|
||||||
|
|
||||||
|
color: white;
|
||||||
|
|
||||||
|
textPos: point(16px, 9px);
|
||||||
|
downTextPos: point(16px, 10px);
|
||||||
|
|
||||||
|
duration: 0;
|
||||||
|
}
|
||||||
|
*/
|
|
@ -26,7 +26,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "ui/filedialog.h"
|
#include "ui/filedialog.h"
|
||||||
#include "ui/popupmenu.h"
|
#include "ui/widgets/popup_menu.h"
|
||||||
#include "media/media_clip_reader.h"
|
#include "media/media_clip_reader.h"
|
||||||
#include "media/view/media_clip_controller.h"
|
#include "media/view/media_clip_controller.h"
|
||||||
#include "styles/style_mediaview.h"
|
#include "styles/style_mediaview.h"
|
||||||
|
@ -88,7 +88,7 @@ MediaView::MediaView() : TWidget(App::wnd())
|
||||||
, _radial(animation(this, &MediaView::step_radial))
|
, _radial(animation(this, &MediaView::step_radial))
|
||||||
, _lastAction(-st::mvDeltaFromLastAction, -st::mvDeltaFromLastAction)
|
, _lastAction(-st::mvDeltaFromLastAction, -st::mvDeltaFromLastAction)
|
||||||
, _a_state(animation(this, &MediaView::step_state))
|
, _a_state(animation(this, &MediaView::step_state))
|
||||||
, _dropdown(this, st::mvDropdown) {
|
, _dropdown(this, st::mediaviewDropdownMenu) {
|
||||||
TextCustomTagsMap custom;
|
TextCustomTagsMap custom;
|
||||||
custom.insert(QChar('c'), qMakePair(textcmdStartLink(1), textcmdStopLink()));
|
custom.insert(QChar('c'), qMakePair(textcmdStartLink(1), textcmdStopLink()));
|
||||||
_saveMsgText.setRichText(st::medviewSaveMsgFont, lang(lng_mediaview_saved), _textDlgOptions, custom);
|
_saveMsgText.setRichText(st::medviewSaveMsgFont, lang(lng_mediaview_saved), _textDlgOptions, custom);
|
||||||
|
@ -126,32 +126,14 @@ MediaView::MediaView() : TWidget(App::wnd())
|
||||||
_touchTimer.setSingleShot(true);
|
_touchTimer.setSingleShot(true);
|
||||||
connect(&_touchTimer, SIGNAL(timeout()), this, SLOT(onTouchTimer()));
|
connect(&_touchTimer, SIGNAL(timeout()), this, SLOT(onTouchTimer()));
|
||||||
|
|
||||||
_btns.push_back(_btnSaveCancel = _dropdown.addButton(new IconedButton(this, st::mvButton, lang(lng_cancel))));
|
|
||||||
connect(_btnSaveCancel, SIGNAL(clicked()), this, SLOT(onSaveCancel()));
|
|
||||||
_btns.push_back(_btnToMessage = _dropdown.addButton(new IconedButton(this, st::mvButton, lang(lng_context_to_msg))));
|
|
||||||
connect(_btnToMessage, SIGNAL(clicked()), this, SLOT(onToMessage()));
|
|
||||||
_btns.push_back(_btnShowInFolder = _dropdown.addButton(new IconedButton(this, st::mvButton, lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_context_show_in_finder : lng_context_show_in_folder))));
|
|
||||||
connect(_btnShowInFolder, SIGNAL(clicked()), this, SLOT(onShowInFolder()));
|
|
||||||
_btns.push_back(_btnCopy = _dropdown.addButton(new IconedButton(this, st::mvButton, lang(lng_mediaview_copy))));
|
|
||||||
connect(_btnCopy, SIGNAL(clicked()), this, SLOT(onCopy()));
|
|
||||||
_btns.push_back(_btnForward = _dropdown.addButton(new IconedButton(this, st::mvButton, lang(lng_mediaview_forward))));
|
|
||||||
connect(_btnForward, SIGNAL(clicked()), this, SLOT(onForward()));
|
|
||||||
_btns.push_back(_btnDelete = _dropdown.addButton(new IconedButton(this, st::mvButton, lang(lng_mediaview_delete))));
|
|
||||||
connect(_btnDelete, SIGNAL(clicked()), this, SLOT(onDelete()));
|
|
||||||
_btns.push_back(_btnSaveAs = _dropdown.addButton(new IconedButton(this, st::mvButton, lang(lng_mediaview_save_as))));
|
|
||||||
connect(_btnSaveAs, SIGNAL(clicked()), this, SLOT(onSaveAs()));
|
|
||||||
_btns.push_back(_btnViewAll = _dropdown.addButton(new IconedButton(this, st::mvButton, lang(lng_mediaview_photos_all))));
|
|
||||||
connect(_btnViewAll, SIGNAL(clicked()), this, SLOT(onOverview()));
|
|
||||||
|
|
||||||
_dropdown.hide();
|
|
||||||
connect(&_dropdown, SIGNAL(hiding()), this, SLOT(onDropdownHiding()));
|
|
||||||
|
|
||||||
_controlsHideTimer.setSingleShot(true);
|
_controlsHideTimer.setSingleShot(true);
|
||||||
connect(&_controlsHideTimer, SIGNAL(timeout()), this, SLOT(onHideControls()));
|
connect(&_controlsHideTimer, SIGNAL(timeout()), this, SLOT(onHideControls()));
|
||||||
|
|
||||||
connect(&_docDownload, SIGNAL(clicked()), this, SLOT(onDownload()));
|
connect(&_docDownload, SIGNAL(clicked()), this, SLOT(onDownload()));
|
||||||
connect(&_docSaveAs, SIGNAL(clicked()), this, SLOT(onSaveAs()));
|
connect(&_docSaveAs, SIGNAL(clicked()), this, SLOT(onSaveAs()));
|
||||||
connect(&_docCancel, SIGNAL(clicked()), this, SLOT(onSaveCancel()));
|
connect(&_docCancel, SIGNAL(clicked()), this, SLOT(onSaveCancel()));
|
||||||
|
|
||||||
|
connect(_dropdown, SIGNAL(beforeHidden()), this, SLOT(onDropdownHidden()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaView::moveToScreen() {
|
void MediaView::moveToScreen() {
|
||||||
|
@ -400,18 +382,31 @@ void MediaView::updateControls() {
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaView::updateDropdown() {
|
void MediaView::updateActions() {
|
||||||
_btnSaveCancel->setVisible(_doc && _doc->loading());
|
_actions.clear();
|
||||||
_btnToMessage->setVisible(_msgid > 0);
|
|
||||||
_btnShowInFolder->setVisible(_doc && !_doc->filepath(DocumentData::FilePathResolveChecked).isEmpty());
|
if (_doc && _doc->loading()) {
|
||||||
_btnSaveAs->setVisible(true);
|
_actions.push_back({ lang(lng_cancel), SLOT(onSaveCancel()) });
|
||||||
_btnCopy->setVisible((_doc && fileShown()) || (_photo && _photo->loaded()));
|
}
|
||||||
_btnForward->setVisible(_canForward);
|
if (_msgid > 0) {
|
||||||
_btnDelete->setVisible(_canDelete || (_photo && App::self() && _user == App::self()) || (_photo && _photo->peer && _photo->peer->photoId == _photo->id && (_photo->peer->isChat() || (_photo->peer->isChannel() && _photo->peer->asChannel()->amCreator()))));
|
_actions.push_back({ lang(lng_context_to_msg), SLOT(onToMessage()) });
|
||||||
_btnViewAll->setVisible(_history && typeHasMediaOverview(_overview));
|
}
|
||||||
_btnViewAll->setText(lang(_doc ? lng_mediaview_files_all : lng_mediaview_photos_all));
|
if (_doc && !_doc->filepath(DocumentData::FilePathResolveChecked).isEmpty()) {
|
||||||
_dropdown.updateButtons();
|
_actions.push_back({ lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_context_show_in_finder : lng_context_show_in_folder), SLOT(onShowInFolder()) });
|
||||||
_dropdown.moveToRight(0, height() - _dropdown.height());
|
}
|
||||||
|
if ((_doc && fileShown()) || (_photo && _photo->loaded())) {
|
||||||
|
_actions.push_back({ lang(lng_mediaview_copy), SLOT(onCopy()) });
|
||||||
|
}
|
||||||
|
if (_canForward) {
|
||||||
|
_actions.push_back({ lang(lng_mediaview_forward), SLOT(onForward()) });
|
||||||
|
}
|
||||||
|
if (_canDelete || (_photo && App::self() && _user == App::self()) || (_photo && _photo->peer && _photo->peer->photoId == _photo->id && (_photo->peer->isChat() || (_photo->peer->isChannel() && _photo->peer->asChannel()->amCreator())))) {
|
||||||
|
_actions.push_back({ lang(lng_mediaview_delete), SLOT(onDelete()) });
|
||||||
|
}
|
||||||
|
_actions.push_back({ lang(lng_mediaview_save_as), SLOT(onSaveAs()) });
|
||||||
|
if (_history && typeHasMediaOverview(_overview)) {
|
||||||
|
_actions.push_back({ lang(_doc ? lng_mediaview_files_all : lng_mediaview_photos_all), SLOT(onOverview()) });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaView::step_state(uint64 ms, bool timer) {
|
void MediaView::step_state(uint64 ms, bool timer) {
|
||||||
|
@ -662,7 +657,7 @@ void MediaView::activateControls() {
|
||||||
|
|
||||||
void MediaView::onHideControls(bool force) {
|
void MediaView::onHideControls(bool force) {
|
||||||
if (!force) {
|
if (!force) {
|
||||||
if (!_dropdown.isHidden()
|
if (!_dropdown->isHidden()
|
||||||
|| _menu
|
|| _menu
|
||||||
|| _mousePressed
|
|| _mousePressed
|
||||||
|| (_fullScreenVideo && _clipController && _clipController->geometry().contains(_lastMouseMovePos))) {
|
|| (_fullScreenVideo && _clipController && _clipController->geometry().contains(_lastMouseMovePos))) {
|
||||||
|
@ -682,7 +677,7 @@ void MediaView::onHideControls(bool force) {
|
||||||
if (!_a_state.animating()) _a_state.start();
|
if (!_a_state.animating()) _a_state.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaView::onDropdownHiding() {
|
void MediaView::onDropdownHidden() {
|
||||||
setFocus();
|
setFocus();
|
||||||
_ignoringDropdown = true;
|
_ignoringDropdown = true;
|
||||||
_lastMouseMovePos = mapFromGlobal(QCursor::pos());
|
_lastMouseMovePos = mapFromGlobal(QCursor::pos());
|
||||||
|
@ -961,10 +956,7 @@ void MediaView::onOverview() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaView::onCopy() {
|
void MediaView::onCopy() {
|
||||||
if (!_dropdown.isHidden()) {
|
_dropdown->hideAnimated(Ui::DropdownMenu::HideOption::IgnoreShow);
|
||||||
_dropdown.ignoreShow();
|
|
||||||
_dropdown.hideStart();
|
|
||||||
}
|
|
||||||
if (_doc) {
|
if (_doc) {
|
||||||
if (!_current.isNull()) {
|
if (!_current.isNull()) {
|
||||||
QApplication::clipboard()->setPixmap(_current);
|
QApplication::clipboard()->setPixmap(_current);
|
||||||
|
@ -2395,10 +2387,10 @@ void MediaView::contextMenuEvent(QContextMenuEvent *e) {
|
||||||
_menu->deleteLater();
|
_menu->deleteLater();
|
||||||
_menu = 0;
|
_menu = 0;
|
||||||
}
|
}
|
||||||
_menu = new PopupMenu(st::mvPopupMenu);
|
_menu = new Ui::PopupMenu(st::mediaviewPopupMenu);
|
||||||
updateDropdown();
|
updateActions();
|
||||||
for (int32 i = 0, l = _btns.size(); i < l; ++i) {
|
for_const (auto &action, _actions) {
|
||||||
if (!_btns.at(i)->isHidden()) _menu->addAction(_btns.at(i)->getText(), _btns.at(i), SIGNAL(clicked()))->setEnabled(true);
|
_menu->addAction(action.text, this, action.member)->setEnabled(true);
|
||||||
}
|
}
|
||||||
connect(_menu, SIGNAL(destroyed(QObject*)), this, SLOT(onMenuDestroy(QObject*)));
|
connect(_menu, SIGNAL(destroyed(QObject*)), this, SLOT(onMenuDestroy(QObject*)));
|
||||||
_menu->popup(e->globalPos());
|
_menu->popup(e->globalPos());
|
||||||
|
@ -2541,10 +2533,14 @@ void MediaView::receiveMouse() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaView::onDropdown() {
|
void MediaView::onDropdown() {
|
||||||
updateDropdown();
|
updateActions();
|
||||||
_dropdown.ignoreShow(false);
|
_dropdown->clearActions();
|
||||||
_dropdown.showStart();
|
for_const (auto &action, _actions) {
|
||||||
_dropdown.setFocus();
|
_dropdown->addAction(action.text, this, action.member);
|
||||||
|
}
|
||||||
|
_dropdown->moveToRight(0, height() - _dropdown->height());
|
||||||
|
_dropdown->showAnimated();
|
||||||
|
_dropdown->setFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaView::onCheckActive() {
|
void MediaView::onCheckActive() {
|
||||||
|
|
|
@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "dropdown.h"
|
#include "ui/widgets/dropdown_menu.h"
|
||||||
#include "ui/effects/radial_animation.h"
|
#include "ui/effects/radial_animation.h"
|
||||||
|
|
||||||
namespace Media {
|
namespace Media {
|
||||||
|
@ -29,7 +29,9 @@ class Controller;
|
||||||
} // namespace Clip
|
} // namespace Clip
|
||||||
} // namespace Media
|
} // namespace Media
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
class PopupMenu;
|
class PopupMenu;
|
||||||
|
} // namespace Ui
|
||||||
|
|
||||||
struct AudioPlaybackState;
|
struct AudioPlaybackState;
|
||||||
|
|
||||||
|
@ -60,9 +62,6 @@ public:
|
||||||
void mediaOverviewUpdated(PeerData *peer, MediaOverviewType type);
|
void mediaOverviewUpdated(PeerData *peer, MediaOverviewType type);
|
||||||
void documentUpdated(DocumentData *doc);
|
void documentUpdated(DocumentData *doc);
|
||||||
void changingMsgId(HistoryItem *row, MsgId newId);
|
void changingMsgId(HistoryItem *row, MsgId newId);
|
||||||
void updateDocSize();
|
|
||||||
void updateControls();
|
|
||||||
void updateDropdown();
|
|
||||||
|
|
||||||
void showSaveMsgFile();
|
void showSaveMsgFile();
|
||||||
void close();
|
void close();
|
||||||
|
@ -81,9 +80,9 @@ public:
|
||||||
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
|
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
|
||||||
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override;
|
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override;
|
||||||
|
|
||||||
public slots:
|
private slots:
|
||||||
void onHideControls(bool force = false);
|
void onHideControls(bool force = false);
|
||||||
void onDropdownHiding();
|
void onDropdownHidden();
|
||||||
|
|
||||||
void onScreenResized(int screen);
|
void onScreenResized(int screen);
|
||||||
|
|
||||||
|
@ -130,6 +129,10 @@ private slots:
|
||||||
void onVideoPlayProgress(const AudioMsgId &audioId);
|
void onVideoPlayProgress(const AudioMsgId &audioId);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void updateDocSize();
|
||||||
|
void updateControls();
|
||||||
|
void updateActions();
|
||||||
|
|
||||||
void displayPhoto(PhotoData *photo, HistoryItem *item);
|
void displayPhoto(PhotoData *photo, HistoryItem *item);
|
||||||
void displayDocument(DocumentData *doc, HistoryItem *item);
|
void displayDocument(DocumentData *doc, HistoryItem *item);
|
||||||
void displayFinished();
|
void displayFinished();
|
||||||
|
@ -304,10 +307,14 @@ private:
|
||||||
anim::fvalue a_cOpacity;
|
anim::fvalue a_cOpacity;
|
||||||
bool _mousePressed = false;
|
bool _mousePressed = false;
|
||||||
|
|
||||||
PopupMenu *_menu = nullptr;
|
Ui::PopupMenu *_menu = nullptr;
|
||||||
Dropdown _dropdown;
|
ChildWidget<Ui::DropdownMenu> _dropdown;
|
||||||
IconedButton *_btnSaveCancel, *_btnToMessage, *_btnShowInFolder, *_btnSaveAs, *_btnCopy, *_btnForward, *_btnDelete, *_btnViewAll;
|
|
||||||
QList<IconedButton*> _btns;
|
struct ActionData {
|
||||||
|
QString text;
|
||||||
|
const char *member;
|
||||||
|
};
|
||||||
|
QList<ActionData> _actions;
|
||||||
|
|
||||||
bool _receiveMouse = true;
|
bool _receiveMouse = true;
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "boxes/confirmbox.h"
|
#include "boxes/confirmbox.h"
|
||||||
#include "boxes/photocropbox.h"
|
#include "boxes/photocropbox.h"
|
||||||
#include "ui/filedialog.h"
|
#include "ui/filedialog.h"
|
||||||
|
#include "ui/widgets/popup_menu.h"
|
||||||
|
#include "ui/widgets/tooltip.h"
|
||||||
#include "window/top_bar_widget.h"
|
#include "window/top_bar_widget.h"
|
||||||
#include "window/chat_background.h"
|
#include "window/chat_background.h"
|
||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
|
@ -931,22 +933,22 @@ void OverviewInner::onUpdateSelected() {
|
||||||
Qt::CursorShape cur = style::cur_default;
|
Qt::CursorShape cur = style::cur_default;
|
||||||
bool lnkChanged = ClickHandler::setActive(lnk, lnkhost);
|
bool lnkChanged = ClickHandler::setActive(lnk, lnkhost);
|
||||||
if (lnkChanged) {
|
if (lnkChanged) {
|
||||||
PopupTooltip::Hide();
|
Ui::Tooltip::Hide();
|
||||||
}
|
}
|
||||||
App::mousedItem(item);
|
App::mousedItem(item);
|
||||||
if (_mousedItem != oldMousedItem) {
|
if (_mousedItem != oldMousedItem) {
|
||||||
PopupTooltip::Hide();
|
Ui::Tooltip::Hide();
|
||||||
if (oldMousedItem) repaintItem(oldMousedItem, oldMousedItemIndex);
|
if (oldMousedItem) repaintItem(oldMousedItem, oldMousedItemIndex);
|
||||||
if (item) repaintItem(item);
|
if (item) repaintItem(item);
|
||||||
}
|
}
|
||||||
if (_cursorState == HistoryInDateCursorState && cursorState != HistoryInDateCursorState) {
|
if (_cursorState == HistoryInDateCursorState && cursorState != HistoryInDateCursorState) {
|
||||||
PopupTooltip::Hide();
|
Ui::Tooltip::Hide();
|
||||||
}
|
}
|
||||||
if (cursorState != _cursorState) {
|
if (cursorState != _cursorState) {
|
||||||
_cursorState = cursorState;
|
_cursorState = cursorState;
|
||||||
}
|
}
|
||||||
if (lnk || cursorState == HistoryInDateCursorState) {
|
if (lnk || cursorState == HistoryInDateCursorState) {
|
||||||
PopupTooltip::Show(1000, this);
|
Ui::Tooltip::Show(1000, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
fixItemIndex(_dragItemIndex, _dragItem);
|
fixItemIndex(_dragItemIndex, _dragItem);
|
||||||
|
@ -1183,7 +1185,7 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
||||||
bool lnkIsAudio = lnkDocument ? (lnkDocument->document()->voice() != nullptr) : false;
|
bool lnkIsAudio = lnkDocument ? (lnkDocument->document()->voice() != nullptr) : false;
|
||||||
bool lnkIsSong = lnkDocument ? (lnkDocument->document()->song() != nullptr) : false;
|
bool lnkIsSong = lnkDocument ? (lnkDocument->document()->song() != nullptr) : false;
|
||||||
if (lnkPhoto || lnkDocument) {
|
if (lnkPhoto || lnkDocument) {
|
||||||
_menu = new PopupMenu();
|
_menu = new Ui::PopupMenu();
|
||||||
if (App::hoveredLinkItem()) {
|
if (App::hoveredLinkItem()) {
|
||||||
_menu->addAction(lang(lng_context_to_msg), this, SLOT(goToMessage()))->setEnabled(true);
|
_menu->addAction(lang(lng_context_to_msg), this, SLOT(goToMessage()))->setEnabled(true);
|
||||||
}
|
}
|
||||||
|
@ -1221,7 +1223,7 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
||||||
repaintItem(App::contextItem());
|
repaintItem(App::contextItem());
|
||||||
if (_selectedMsgId) repaintItem(_selectedMsgId, -1);
|
if (_selectedMsgId) repaintItem(_selectedMsgId, -1);
|
||||||
} else if (!ignoreMousedItem && App::mousedItem() && App::mousedItem()->channelId() == itemChannel(_mousedItem) && App::mousedItem()->id == itemMsgId(_mousedItem)) {
|
} else if (!ignoreMousedItem && App::mousedItem() && App::mousedItem()->channelId() == itemChannel(_mousedItem) && App::mousedItem()->id == itemMsgId(_mousedItem)) {
|
||||||
_menu = new PopupMenu();
|
_menu = new Ui::PopupMenu();
|
||||||
QString linkCopyToClipboardText = _contextMenuLnk ? _contextMenuLnk->copyToClipboardContextItemText() : QString();
|
QString linkCopyToClipboardText = _contextMenuLnk ? _contextMenuLnk->copyToClipboardContextItemText() : QString();
|
||||||
if (!linkCopyToClipboardText.isEmpty()) {
|
if (!linkCopyToClipboardText.isEmpty()) {
|
||||||
_menu->addAction(linkCopyToClipboardText, this, SLOT(copyContextUrl()))->setEnabled(true);
|
_menu->addAction(linkCopyToClipboardText, this, SLOT(copyContextUrl()))->setEnabled(true);
|
||||||
|
|
|
@ -21,7 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "window/section_widget.h"
|
#include "window/section_widget.h"
|
||||||
#include "ui/popupmenu.h"
|
#include "ui/widgets/tooltip.h"
|
||||||
|
|
||||||
namespace Overview {
|
namespace Overview {
|
||||||
namespace Layout {
|
namespace Layout {
|
||||||
|
@ -33,10 +33,11 @@ class Date;
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class PlainShadow;
|
class PlainShadow;
|
||||||
|
class PopupMenu;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
class OverviewWidget;
|
class OverviewWidget;
|
||||||
class OverviewInner : public TWidget, public AbstractTooltipShower, public RPCSender, private base::Subscriber {
|
class OverviewInner : public TWidget, public Ui::AbstractTooltipShower, public RPCSender, private base::Subscriber {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -263,7 +264,7 @@ private:
|
||||||
uint64 _touchTime = 0;
|
uint64 _touchTime = 0;
|
||||||
QTimer _touchScrollTimer;
|
QTimer _touchScrollTimer;
|
||||||
|
|
||||||
PopupMenu *_menu = nullptr;
|
Ui::PopupMenu *_menu = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
class OverviewWidget : public TWidget, public RPCSender {
|
class OverviewWidget : public TWidget, public RPCSender {
|
||||||
|
|
|
@ -28,7 +28,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
#include "localstorage.h"
|
#include "localstorage.h"
|
||||||
#include "ui/popupmenu.h"
|
#include "ui/widgets/popup_menu.h"
|
||||||
|
|
||||||
#include <qpa/qplatformnativeinterface.h>
|
#include <qpa/qplatformnativeinterface.h>
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,9 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "window/main_window.h"
|
#include "window/main_window.h"
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
class PopupMenu;
|
class PopupMenu;
|
||||||
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
|
|
||||||
|
@ -109,7 +111,7 @@ protected:
|
||||||
|
|
||||||
bool posInited = false;
|
bool posInited = false;
|
||||||
QSystemTrayIcon *trayIcon = nullptr;
|
QSystemTrayIcon *trayIcon = nullptr;
|
||||||
PopupMenu *trayIconMenu = nullptr;
|
Ui::PopupMenu *trayIconMenu = nullptr;
|
||||||
QImage icon256, iconbig256;
|
QImage icon256, iconbig256;
|
||||||
QIcon wndIcon;
|
QIcon wndIcon;
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
namespace Profile {
|
namespace Profile {
|
||||||
|
|
||||||
BlockWidget::BlockWidget(QWidget *parent, PeerData *peer, const QString &title) : ScrolledWidget(parent)
|
BlockWidget::BlockWidget(QWidget *parent, PeerData *peer, const QString &title) : TWidget(parent)
|
||||||
, _peer(peer)
|
, _peer(peer)
|
||||||
, _title(title) {
|
, _title(title) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
namespace Profile {
|
namespace Profile {
|
||||||
|
|
||||||
class BlockWidget : public ScrolledWidget, protected base::Subscriber {
|
class BlockWidget : public TWidget, protected base::Subscriber {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -26,7 +26,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
namespace Settings {
|
namespace Settings {
|
||||||
|
|
||||||
BlockWidget::BlockWidget(QWidget *parent, UserData *self, const QString &title) : ScrolledWidget(parent)
|
BlockWidget::BlockWidget(QWidget *parent, UserData *self, const QString &title) : TWidget(parent)
|
||||||
, _self(self)
|
, _self(self)
|
||||||
, _title(title) {
|
, _title(title) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ class WidgetSlideWrap;
|
||||||
|
|
||||||
namespace Settings {
|
namespace Settings {
|
||||||
|
|
||||||
class BlockWidget : public ScrolledWidget, protected base::Subscriber {
|
class BlockWidget : public TWidget, protected base::Subscriber {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -42,19 +42,19 @@ EmojiColorPicker::EmojiColorPicker() : TWidget()
|
||||||
, _a_selected(animation(this, &EmojiColorPicker::step_selected))
|
, _a_selected(animation(this, &EmojiColorPicker::step_selected))
|
||||||
, a_opacity(0)
|
, a_opacity(0)
|
||||||
, _a_appearance(animation(this, &EmojiColorPicker::step_appearance))
|
, _a_appearance(animation(this, &EmojiColorPicker::step_appearance))
|
||||||
, _shadow(st::dropdownDef.shadow) {
|
, _shadow(st::defaultDropdownShadow) {
|
||||||
memset(_variants, 0, sizeof(_variants));
|
memset(_variants, 0, sizeof(_variants));
|
||||||
memset(_hovers, 0, sizeof(_hovers));
|
memset(_hovers, 0, sizeof(_hovers));
|
||||||
|
|
||||||
setMouseTracking(true);
|
setMouseTracking(true);
|
||||||
setFocusPolicy(Qt::NoFocus);
|
setFocusPolicy(Qt::NoFocus);
|
||||||
|
|
||||||
int32 w = st::emojiPanSize.width() * (EmojiColorsCount + 1) + 4 * st::emojiColorsPadding + st::emojiColorsSep + st::dropdownDef.shadow.width() * 2;
|
int32 w = st::emojiPanSize.width() * (EmojiColorsCount + 1) + 4 * st::emojiColorsPadding + st::emojiColorsSep + st::defaultDropdownShadow.width() * 2;
|
||||||
int32 h = 2 * st::emojiColorsPadding + st::emojiPanSize.height() + st::dropdownDef.shadow.height() * 2;
|
int32 h = 2 * st::emojiColorsPadding + st::emojiPanSize.height() + st::defaultDropdownShadow.height() * 2;
|
||||||
resize(w, h);
|
resize(w, h);
|
||||||
|
|
||||||
_hideTimer.setSingleShot(true);
|
_hideTimer.setSingleShot(true);
|
||||||
connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(hideStart()));
|
connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(hideAnimated()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiColorPicker::showEmoji(uint32 code) {
|
void EmojiColorPicker::showEmoji(uint32 code) {
|
||||||
|
@ -72,7 +72,7 @@ void EmojiColorPicker::showEmoji(uint32 code) {
|
||||||
_variants[5] = emojiGet(e, 0xD83CDFFF);
|
_variants[5] = emojiGet(e, 0xD83CDFFF);
|
||||||
|
|
||||||
if (!_cache.isNull()) _cache = QPixmap();
|
if (!_cache.isNull()) _cache = QPixmap();
|
||||||
showStart();
|
showAnimated();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiColorPicker::paintEvent(QPaintEvent *e) {
|
void EmojiColorPicker::paintEvent(QPaintEvent *e) {
|
||||||
|
@ -85,12 +85,12 @@ void EmojiColorPicker::paintEvent(QPaintEvent *e) {
|
||||||
p.setClipRect(e->rect());
|
p.setClipRect(e->rect());
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 w = st::dropdownDef.shadow.width(), h = st::dropdownDef.shadow.height();
|
int32 w = st::defaultDropdownShadow.width(), h = st::defaultDropdownShadow.height();
|
||||||
QRect r = QRect(w, h, width() - 2 * w, height() - 2 * h);
|
QRect r = QRect(w, h, width() - 2 * w, height() - 2 * h);
|
||||||
_shadow.paint(p, r, st::dropdownDef.shadowShift);
|
_shadow.paint(p, r, st::defaultDropdownShadowShift);
|
||||||
|
|
||||||
if (_cache.isNull()) {
|
if (_cache.isNull()) {
|
||||||
p.fillRect(e->rect().intersected(r), st::white->b);
|
p.fillRect(e->rect().intersected(r), st::white);
|
||||||
|
|
||||||
int32 x = w + 2 * st::emojiColorsPadding + st::emojiPanSize.width();
|
int32 x = w + 2 * st::emojiColorsPadding + st::emojiPanSize.width();
|
||||||
if (rtl()) x = width() - x - st::emojiColorsSep;
|
if (rtl()) x = width() - x - st::emojiColorsSep;
|
||||||
|
@ -108,7 +108,7 @@ void EmojiColorPicker::paintEvent(QPaintEvent *e) {
|
||||||
|
|
||||||
void EmojiColorPicker::enterEvent(QEvent *e) {
|
void EmojiColorPicker::enterEvent(QEvent *e) {
|
||||||
_hideTimer.stop();
|
_hideTimer.stop();
|
||||||
if (_hiding) showStart();
|
if (_hiding) showAnimated();
|
||||||
TWidget::enterEvent(e);
|
TWidget::enterEvent(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,7 +135,7 @@ void EmojiColorPicker::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
emit emojiSelected(_variants[_selected]);
|
emit emojiSelected(_variants[_selected]);
|
||||||
}
|
}
|
||||||
_ignoreShow = true;
|
_ignoreShow = true;
|
||||||
hideStart();
|
hideAnimated();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiColorPicker::mouseMoveEvent(QMouseEvent *e) {
|
void EmojiColorPicker::mouseMoveEvent(QMouseEvent *e) {
|
||||||
|
@ -148,7 +148,7 @@ void EmojiColorPicker::step_appearance(float64 ms, bool timer) {
|
||||||
_a_appearance.stop();
|
_a_appearance.stop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
float64 dt = ms / st::dropdownDef.duration;
|
float64 dt = ms / st::defaultDropdownDuration;
|
||||||
if (dt >= 1) {
|
if (dt >= 1) {
|
||||||
a_opacity.finish();
|
a_opacity.finish();
|
||||||
_cache = QPixmap();
|
_cache = QPixmap();
|
||||||
|
@ -178,34 +178,34 @@ void EmojiColorPicker::step_selected(uint64 ms, bool timer) {
|
||||||
_hovers[index] = (i.key() > 0) ? dt : (1 - dt);
|
_hovers[index] = (i.key() > 0) ? dt : (1 - dt);
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
toUpdate += QRect(st::dropdownDef.shadow.width() + st::emojiColorsPadding + index * st::emojiPanSize.width() + (index ? 2 * st::emojiColorsPadding + st::emojiColorsSep : 0), st::dropdownDef.shadow.height() + st::emojiColorsPadding, st::emojiPanSize.width(), st::emojiPanSize.height());
|
toUpdate += QRect(st::defaultDropdownShadow.width() + st::emojiColorsPadding + index * st::emojiPanSize.width() + (index ? 2 * st::emojiColorsPadding + st::emojiColorsSep : 0), st::defaultDropdownShadow.height() + st::emojiColorsPadding, st::emojiPanSize.width(), st::emojiPanSize.height());
|
||||||
}
|
}
|
||||||
if (timer) rtlupdate(toUpdate.boundingRect());
|
if (timer) rtlupdate(toUpdate.boundingRect());
|
||||||
if (_emojiAnimations.isEmpty()) _a_selected.stop();
|
if (_emojiAnimations.isEmpty()) _a_selected.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiColorPicker::hideStart(bool fast) {
|
void EmojiColorPicker::hideFast() {
|
||||||
if (fast) {
|
clearSelection(true);
|
||||||
clearSelection(true);
|
if (_a_appearance.animating()) _a_appearance.stop();
|
||||||
if (_a_appearance.animating()) _a_appearance.stop();
|
if (_a_selected.animating()) _a_selected.stop();
|
||||||
if (_a_selected.animating()) _a_selected.stop();
|
a_opacity = anim::fvalue(0);
|
||||||
a_opacity = anim::fvalue(0);
|
_cache = QPixmap();
|
||||||
_cache = QPixmap();
|
hide();
|
||||||
hide();
|
emit hidden();
|
||||||
emit hidden();
|
|
||||||
} else {
|
|
||||||
if (_cache.isNull()) {
|
|
||||||
int32 w = st::dropdownDef.shadow.width(), h = st::dropdownDef.shadow.height();
|
|
||||||
_cache = myGrab(this, QRect(w, h, width() - 2 * w, height() - 2 * h));
|
|
||||||
clearSelection(true);
|
|
||||||
}
|
|
||||||
_hiding = true;
|
|
||||||
a_opacity.start(0);
|
|
||||||
_a_appearance.start();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiColorPicker::showStart() {
|
void EmojiColorPicker::hideAnimated() {
|
||||||
|
if (_cache.isNull()) {
|
||||||
|
int32 w = st::defaultDropdownShadow.width(), h = st::defaultDropdownShadow.height();
|
||||||
|
_cache = myGrab(this, QRect(w, h, width() - 2 * w, height() - 2 * h));
|
||||||
|
clearSelection(true);
|
||||||
|
}
|
||||||
|
_hiding = true;
|
||||||
|
a_opacity.start(0);
|
||||||
|
_a_appearance.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmojiColorPicker::showAnimated() {
|
||||||
if (_ignoreShow) return;
|
if (_ignoreShow) return;
|
||||||
|
|
||||||
_hiding = false;
|
_hiding = false;
|
||||||
|
@ -217,7 +217,7 @@ void EmojiColorPicker::showStart() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_cache.isNull()) {
|
if (_cache.isNull()) {
|
||||||
int32 w = st::dropdownDef.shadow.width(), h = st::dropdownDef.shadow.height();
|
int32 w = st::defaultDropdownShadow.width(), h = st::defaultDropdownShadow.height();
|
||||||
_cache = myGrab(this, QRect(w, h, width() - 2 * w, height() - 2 * h));
|
_cache = myGrab(this, QRect(w, h, width() - 2 * w, height() - 2 * h));
|
||||||
clearSelection(true);
|
clearSelection(true);
|
||||||
}
|
}
|
||||||
|
@ -241,9 +241,9 @@ void EmojiColorPicker::clearSelection(bool fast) {
|
||||||
void EmojiColorPicker::updateSelected() {
|
void EmojiColorPicker::updateSelected() {
|
||||||
int32 selIndex = -1;
|
int32 selIndex = -1;
|
||||||
QPoint p(mapFromGlobal(_lastMousePos));
|
QPoint p(mapFromGlobal(_lastMousePos));
|
||||||
int32 sx = rtl() ? (width() - p.x()) : p.x(), y = p.y() - st::dropdownDef.shadow.height() - st::emojiColorsPadding;
|
int32 sx = rtl() ? (width() - p.x()) : p.x(), y = p.y() - st::defaultDropdownShadow.height() - st::emojiColorsPadding;
|
||||||
if (y >= 0 && y < st::emojiPanSize.height()) {
|
if (y >= 0 && y < st::emojiPanSize.height()) {
|
||||||
int32 x = sx - st::dropdownDef.shadow.width() - st::emojiColorsPadding;
|
int32 x = sx - st::defaultDropdownShadow.width() - st::emojiColorsPadding;
|
||||||
if (x >= 0 && x < st::emojiPanSize.width()) {
|
if (x >= 0 && x < st::emojiPanSize.width()) {
|
||||||
selIndex = 0;
|
selIndex = 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -279,7 +279,7 @@ void EmojiColorPicker::updateSelected() {
|
||||||
void EmojiColorPicker::drawVariant(Painter &p, int variant) {
|
void EmojiColorPicker::drawVariant(Painter &p, int variant) {
|
||||||
float64 hover = _hovers[variant];
|
float64 hover = _hovers[variant];
|
||||||
|
|
||||||
QPoint w(st::dropdownDef.shadow.width() + st::emojiColorsPadding + variant * st::emojiPanSize.width() + (variant ? 2 * st::emojiColorsPadding + st::emojiColorsSep : 0), st::dropdownDef.shadow.height() + st::emojiColorsPadding);
|
QPoint w(st::defaultDropdownShadow.width() + st::emojiColorsPadding + variant * st::emojiPanSize.width() + (variant ? 2 * st::emojiColorsPadding + st::emojiColorsSep : 0), st::defaultDropdownShadow.height() + st::emojiColorsPadding);
|
||||||
if (hover > 0) {
|
if (hover > 0) {
|
||||||
p.setOpacity(hover);
|
p.setOpacity(hover);
|
||||||
QPoint tl(w);
|
QPoint tl(w);
|
||||||
|
@ -291,7 +291,7 @@ void EmojiColorPicker::drawVariant(Painter &p, int variant) {
|
||||||
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));
|
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() : ScrolledWidget()
|
EmojiPanInner::EmojiPanInner() : TWidget()
|
||||||
, _maxHeight(int(st::emojiPanMaxHeight) - st::rbEmoji.height)
|
, _maxHeight(int(st::emojiPanMaxHeight) - st::rbEmoji.height)
|
||||||
, _a_selected(animation(this, &EmojiPanInner::step_selected)) {
|
, _a_selected(animation(this, &EmojiPanInner::step_selected)) {
|
||||||
resize(st::emojiPanWidth - st::emojiScroll.width, countHeight());
|
resize(st::emojiPanWidth - st::emojiScroll.width, countHeight());
|
||||||
|
@ -404,7 +404,7 @@ void EmojiPanInner::paintEvent(QPaintEvent *e) {
|
||||||
|
|
||||||
bool EmojiPanInner::checkPickerHide() {
|
bool EmojiPanInner::checkPickerHide() {
|
||||||
if (!_picker.isHidden() && _selected == _pickerSel) {
|
if (!_picker.isHidden() && _selected == _pickerSel) {
|
||||||
_picker.hideStart();
|
_picker.hideAnimated();
|
||||||
_pickerSel = -1;
|
_pickerSel = -1;
|
||||||
updateSelected();
|
updateSelected();
|
||||||
return true;
|
return true;
|
||||||
|
@ -446,7 +446,7 @@ void EmojiPanInner::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
int tab = (_pickerSel / MatrixRowShift), sel = _pickerSel % MatrixRowShift;
|
int tab = (_pickerSel / MatrixRowShift), sel = _pickerSel % MatrixRowShift;
|
||||||
if (tab < emojiTabCount && sel < _emojis[tab].size() && _emojis[tab][sel]->color) {
|
if (tab < emojiTabCount && sel < _emojis[tab].size() && _emojis[tab][sel]->color) {
|
||||||
if (cEmojiVariants().constFind(_emojis[tab][sel]->code) != cEmojiVariants().cend()) {
|
if (cEmojiVariants().constFind(_emojis[tab][sel]->code) != cEmojiVariants().cend()) {
|
||||||
_picker.hideStart();
|
_picker.hideAnimated();
|
||||||
_pickerSel = -1;
|
_pickerSel = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -576,7 +576,7 @@ void EmojiPanInner::onColorSelected(EmojiPtr emoji) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
selectEmoji(emoji);
|
selectEmoji(emoji);
|
||||||
_picker.hideStart();
|
_picker.hideAnimated();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiPanInner::mouseMoveEvent(QMouseEvent *e) {
|
void EmojiPanInner::mouseMoveEvent(QMouseEvent *e) {
|
||||||
|
@ -642,7 +642,7 @@ DBIEmojiTab EmojiPanInner::currentTab(int yOffset) const {
|
||||||
|
|
||||||
void EmojiPanInner::hideFinish() {
|
void EmojiPanInner::hideFinish() {
|
||||||
if (!_picker.isHidden()) {
|
if (!_picker.isHidden()) {
|
||||||
_picker.hideStart(true);
|
_picker.hideFast();
|
||||||
_pickerSel = -1;
|
_pickerSel = -1;
|
||||||
clearSelection(true);
|
clearSelection(true);
|
||||||
}
|
}
|
||||||
|
@ -738,9 +738,9 @@ void EmojiPanInner::updateSelected() {
|
||||||
setCursor((newSel >= 0) ? style::cur_pointer : style::cur_default);
|
setCursor((newSel >= 0) ? style::cur_pointer : style::cur_default);
|
||||||
if (newSel >= 0 && !_picker.isHidden()) {
|
if (newSel >= 0 && !_picker.isHidden()) {
|
||||||
if (newSel != _pickerSel) {
|
if (newSel != _pickerSel) {
|
||||||
_picker.hideStart();
|
_picker.hideAnimated();
|
||||||
} else {
|
} else {
|
||||||
_picker.showStart();
|
_picker.showAnimated();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -793,7 +793,7 @@ void EmojiPanInner::showEmojiPack(DBIEmojiTab packIndex) {
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
StickerPanInner::StickerPanInner() : ScrolledWidget()
|
StickerPanInner::StickerPanInner() : TWidget()
|
||||||
, _a_selected(animation(this, &StickerPanInner::step_selected))
|
, _a_selected(animation(this, &StickerPanInner::step_selected))
|
||||||
, _section(cShowingSavedGifs() ? Section::Gifs : Section::Stickers)
|
, _section(cShowingSavedGifs() ? Section::Gifs : Section::Stickers)
|
||||||
, _addText(lang(lng_stickers_featured_add).toUpper())
|
, _addText(lang(lng_stickers_featured_add).toUpper())
|
||||||
|
@ -2550,7 +2550,7 @@ EmojiPan::EmojiPan(QWidget *parent) : TWidget(parent)
|
||||||
, _contentHeightEmoji(_contentHeight - st::rbEmoji.height)
|
, _contentHeightEmoji(_contentHeight - st::rbEmoji.height)
|
||||||
, _contentHeightStickers(_contentHeight - st::rbEmoji.height)
|
, _contentHeightStickers(_contentHeight - st::rbEmoji.height)
|
||||||
, _a_appearance(animation(this, &EmojiPan::step_appearance))
|
, _a_appearance(animation(this, &EmojiPan::step_appearance))
|
||||||
, _shadow(st::dropdownDef.shadow)
|
, _shadow(st::defaultDropdownShadow)
|
||||||
, _recent(this , qsl("emoji_group"), dbietRecent , QString(), true , st::rbEmojiRecent)
|
, _recent(this , qsl("emoji_group"), dbietRecent , QString(), true , st::rbEmojiRecent)
|
||||||
, _people(this , qsl("emoji_group"), dbietPeople , QString(), false, st::rbEmojiPeople)
|
, _people(this , qsl("emoji_group"), dbietPeople , QString(), false, st::rbEmojiPeople)
|
||||||
, _nature(this , qsl("emoji_group"), dbietNature , QString(), false, st::rbEmojiNature)
|
, _nature(this , qsl("emoji_group"), dbietNature , QString(), false, st::rbEmojiNature)
|
||||||
|
@ -2573,24 +2573,24 @@ EmojiPan::EmojiPan(QWidget *parent) : TWidget(parent)
|
||||||
s_scroll.setFocusPolicy(Qt::NoFocus);
|
s_scroll.setFocusPolicy(Qt::NoFocus);
|
||||||
s_scroll.viewport()->setFocusPolicy(Qt::NoFocus);
|
s_scroll.viewport()->setFocusPolicy(Qt::NoFocus);
|
||||||
|
|
||||||
_width = st::dropdownDef.padding.left() + st::emojiPanWidth + st::dropdownDef.padding.right();
|
_width = st::defaultDropdownPadding.left() + st::emojiPanWidth + st::defaultDropdownPadding.right();
|
||||||
_height = st::dropdownDef.padding.top() + _contentHeight + st::dropdownDef.padding.bottom();
|
_height = st::defaultDropdownPadding.top() + _contentHeight + st::defaultDropdownPadding.bottom();
|
||||||
_bottom = 0;
|
_bottom = 0;
|
||||||
resize(_width, _height);
|
resize(_width, _height);
|
||||||
|
|
||||||
e_scroll.resize(st::emojiPanWidth, _contentHeightEmoji);
|
e_scroll.resize(st::emojiPanWidth, _contentHeightEmoji);
|
||||||
s_scroll.resize(st::emojiPanWidth, _contentHeightStickers);
|
s_scroll.resize(st::emojiPanWidth, _contentHeightStickers);
|
||||||
|
|
||||||
e_scroll.move(st::dropdownDef.padding.left(), st::dropdownDef.padding.top());
|
e_scroll.move(st::defaultDropdownPadding.left(), st::defaultDropdownPadding.top());
|
||||||
e_scroll.setWidget(&e_inner);
|
e_scroll.setWidget(&e_inner);
|
||||||
s_scroll.move(st::dropdownDef.padding.left(), st::dropdownDef.padding.top());
|
s_scroll.move(st::defaultDropdownPadding.left(), st::defaultDropdownPadding.top());
|
||||||
s_scroll.setWidget(&s_inner);
|
s_scroll.setWidget(&s_inner);
|
||||||
|
|
||||||
e_inner.moveToLeft(0, 0, e_scroll.width());
|
e_inner.moveToLeft(0, 0, e_scroll.width());
|
||||||
s_inner.moveToLeft(0, 0, s_scroll.width());
|
s_inner.moveToLeft(0, 0, s_scroll.width());
|
||||||
|
|
||||||
int32 left = _iconsLeft = st::dropdownDef.padding.left() + (st::emojiPanWidth - 8 * st::rbEmoji.width) / 2;
|
int32 left = _iconsLeft = st::defaultDropdownPadding.left() + (st::emojiPanWidth - 8 * st::rbEmoji.width) / 2;
|
||||||
int32 top = _iconsTop = st::dropdownDef.padding.top() + _contentHeight - st::rbEmoji.height;
|
int32 top = _iconsTop = st::defaultDropdownPadding.top() + _contentHeight - st::rbEmoji.height;
|
||||||
prepareTab(left, top, _width, _recent);
|
prepareTab(left, top, _width, _recent);
|
||||||
prepareTab(left, top, _width, _people);
|
prepareTab(left, top, _width, _people);
|
||||||
prepareTab(left, top, _width, _nature);
|
prepareTab(left, top, _width, _nature);
|
||||||
|
@ -2603,7 +2603,7 @@ EmojiPan::EmojiPan(QWidget *parent) : TWidget(parent)
|
||||||
updatePanelsPositions(e_panels, 0);
|
updatePanelsPositions(e_panels, 0);
|
||||||
|
|
||||||
_hideTimer.setSingleShot(true);
|
_hideTimer.setSingleShot(true);
|
||||||
connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(hideStart()));
|
connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(hideAnimated()));
|
||||||
|
|
||||||
connect(&e_inner, SIGNAL(scrollToY(int)), &e_scroll, SLOT(scrollToY(int)));
|
connect(&e_inner, SIGNAL(scrollToY(int)), &e_scroll, SLOT(scrollToY(int)));
|
||||||
connect(&e_inner, SIGNAL(disableScroll(bool)), &e_scroll, SLOT(disableScroll(bool)));
|
connect(&e_inner, SIGNAL(disableScroll(bool)), &e_scroll, SLOT(disableScroll(bool)));
|
||||||
|
@ -2666,7 +2666,7 @@ void EmojiPan::updateContentHeight() {
|
||||||
_contentHeightEmoji = he;
|
_contentHeightEmoji = he;
|
||||||
_contentHeightStickers = hs;
|
_contentHeightStickers = hs;
|
||||||
|
|
||||||
_height = st::dropdownDef.padding.top() + _contentHeight + st::dropdownDef.padding.bottom();
|
_height = st::defaultDropdownPadding.top() + _contentHeight + st::defaultDropdownPadding.bottom();
|
||||||
|
|
||||||
resize(_width, _height);
|
resize(_width, _height);
|
||||||
move(x(), _bottom - height());
|
move(x(), _bottom - height());
|
||||||
|
@ -2683,7 +2683,7 @@ void EmojiPan::updateContentHeight() {
|
||||||
s_scroll.resize(st::emojiPanWidth, _contentHeightStickers);
|
s_scroll.resize(st::emojiPanWidth, _contentHeightStickers);
|
||||||
}
|
}
|
||||||
|
|
||||||
_iconsTop = st::dropdownDef.padding.top() + _contentHeight - st::rbEmoji.height;
|
_iconsTop = st::defaultDropdownPadding.top() + _contentHeight - st::rbEmoji.height;
|
||||||
_recent.move(_recent.x(), _iconsTop);
|
_recent.move(_recent.x(), _iconsTop);
|
||||||
_people.move(_people.x(), _iconsTop);
|
_people.move(_people.x(), _iconsTop);
|
||||||
_nature.move(_nature.x(), _iconsTop);
|
_nature.move(_nature.x(), _iconsTop);
|
||||||
|
@ -2742,9 +2742,9 @@ void EmojiPan::paintEvent(QPaintEvent *e) {
|
||||||
p.setOpacity(o = a_opacity.current());
|
p.setOpacity(o = a_opacity.current());
|
||||||
}
|
}
|
||||||
|
|
||||||
QRect r(st::dropdownDef.padding.left(), st::dropdownDef.padding.top(), _width - st::dropdownDef.padding.left() - st::dropdownDef.padding.right(), _height - st::dropdownDef.padding.top() - st::dropdownDef.padding.bottom());
|
QRect r(st::defaultDropdownPadding.left(), st::defaultDropdownPadding.top(), _width - st::defaultDropdownPadding.left() - st::defaultDropdownPadding.right(), _height - st::defaultDropdownPadding.top() - st::defaultDropdownPadding.bottom());
|
||||||
|
|
||||||
_shadow.paint(p, r, st::dropdownDef.shadowShift);
|
_shadow.paint(p, r, st::defaultDropdownShadowShift);
|
||||||
|
|
||||||
if (_toCache.isNull()) {
|
if (_toCache.isNull()) {
|
||||||
if (_cache.isNull()) {
|
if (_cache.isNull()) {
|
||||||
|
@ -2871,7 +2871,7 @@ void EmojiPan::moveBottom(int32 bottom, bool force) {
|
||||||
|
|
||||||
void EmojiPan::enterEvent(QEvent *e) {
|
void EmojiPan::enterEvent(QEvent *e) {
|
||||||
_hideTimer.stop();
|
_hideTimer.stop();
|
||||||
if (_hiding) showStart();
|
if (_hiding) showAnimated();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EmojiPan::preventAutoHide() const {
|
bool EmojiPan::preventAutoHide() const {
|
||||||
|
@ -2881,7 +2881,7 @@ bool EmojiPan::preventAutoHide() const {
|
||||||
void EmojiPan::leaveEvent(QEvent *e) {
|
void EmojiPan::leaveEvent(QEvent *e) {
|
||||||
if (preventAutoHide() || s_inner.inlineResultsShown()) return;
|
if (preventAutoHide() || s_inner.inlineResultsShown()) return;
|
||||||
if (_a_appearance.animating()) {
|
if (_a_appearance.animating()) {
|
||||||
hideStart();
|
hideAnimated();
|
||||||
} else {
|
} else {
|
||||||
_hideTimer.start(300);
|
_hideTimer.start(300);
|
||||||
}
|
}
|
||||||
|
@ -2889,13 +2889,13 @@ void EmojiPan::leaveEvent(QEvent *e) {
|
||||||
|
|
||||||
void EmojiPan::otherEnter() {
|
void EmojiPan::otherEnter() {
|
||||||
_hideTimer.stop();
|
_hideTimer.stop();
|
||||||
showStart();
|
showAnimated();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiPan::otherLeave() {
|
void EmojiPan::otherLeave() {
|
||||||
if (preventAutoHide() || s_inner.inlineResultsShown()) return;
|
if (preventAutoHide() || s_inner.inlineResultsShown()) return;
|
||||||
if (_a_appearance.animating()) {
|
if (_a_appearance.animating()) {
|
||||||
hideStart();
|
hideAnimated();
|
||||||
} else {
|
} else {
|
||||||
_hideTimer.start(0);
|
_hideTimer.start(0);
|
||||||
}
|
}
|
||||||
|
@ -2990,7 +2990,7 @@ bool EmojiPan::event(QEvent *e) {
|
||||||
return TWidget::event(e);
|
return TWidget::event(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiPan::fastHide() {
|
void EmojiPan::hideFast() {
|
||||||
if (_a_appearance.animating()) {
|
if (_a_appearance.animating()) {
|
||||||
_a_appearance.stop();
|
_a_appearance.stop();
|
||||||
}
|
}
|
||||||
|
@ -3107,7 +3107,7 @@ void EmojiPan::updateSelected() {
|
||||||
void EmojiPan::updateIcons() {
|
void EmojiPan::updateIcons() {
|
||||||
if (!_stickersShown || !s_inner.showSectionIcons()) return;
|
if (!_stickersShown || !s_inner.showSectionIcons()) return;
|
||||||
|
|
||||||
QRect r(st::dropdownDef.padding.left(), st::dropdownDef.padding.top(), _width - st::dropdownDef.padding.left() - st::dropdownDef.padding.right(), _height - st::dropdownDef.padding.top() - st::dropdownDef.padding.bottom());
|
QRect r(st::defaultDropdownPadding.left(), st::defaultDropdownPadding.top(), _width - st::defaultDropdownPadding.left() - st::defaultDropdownPadding.right(), _height - st::defaultDropdownPadding.top() - st::defaultDropdownPadding.bottom());
|
||||||
update(r.left(), _iconsTop, r.width(), st::rbEmoji.height);
|
update(r.left(), _iconsTop, r.width(), st::rbEmoji.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3177,7 +3177,7 @@ void EmojiPan::step_appearance(float64 ms, bool timer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
float64 dt = ms / st::dropdownDef.duration;
|
float64 dt = ms / st::defaultDropdownDuration;
|
||||||
if (dt >= 1) {
|
if (dt >= 1) {
|
||||||
_a_appearance.stop();
|
_a_appearance.stop();
|
||||||
a_opacity.finish();
|
a_opacity.finish();
|
||||||
|
@ -3193,10 +3193,10 @@ void EmojiPan::step_appearance(float64 ms, bool timer) {
|
||||||
if (timer) update();
|
if (timer) update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiPan::hideStart() {
|
void EmojiPan::hideAnimated() {
|
||||||
if (preventAutoHide() || s_inner.inlineResultsShown()) return;
|
if (isHidden() || preventAutoHide() || s_inner.inlineResultsShown()) return;
|
||||||
|
|
||||||
hideAnimated();
|
startHideAnimated();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiPan::prepareShowHideCache() {
|
void EmojiPan::prepareShowHideCache() {
|
||||||
|
@ -3204,12 +3204,12 @@ void EmojiPan::prepareShowHideCache() {
|
||||||
QPixmap from = _fromCache, to = _toCache;
|
QPixmap from = _fromCache, to = _toCache;
|
||||||
_fromCache = _toCache = QPixmap();
|
_fromCache = _toCache = QPixmap();
|
||||||
showAll();
|
showAll();
|
||||||
_cache = myGrab(this, rect().marginsRemoved(st::dropdownDef.padding));
|
_cache = myGrab(this, rect().marginsRemoved(st::defaultDropdownPadding));
|
||||||
_fromCache = from; _toCache = to;
|
_fromCache = from; _toCache = to;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiPan::hideAnimated() {
|
void EmojiPan::startHideAnimated() {
|
||||||
if (_hiding) return;
|
if (_hiding) return;
|
||||||
|
|
||||||
prepareShowHideCache();
|
prepareShowHideCache();
|
||||||
|
@ -3247,7 +3247,7 @@ void EmojiPan::hideFinish() {
|
||||||
Notify::clipStopperHidden(ClipStopperSavedGifsPanel);
|
Notify::clipStopperHidden(ClipStopperSavedGifsPanel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiPan::showStart() {
|
void EmojiPan::showAnimated() {
|
||||||
if (!isHidden() && !_hiding) {
|
if (!isHidden() && !_hiding) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3297,7 +3297,7 @@ bool EmojiPan::eventFilter(QObject *obj, QEvent *e) {
|
||||||
} else if (e->type() == QEvent::MouseButtonPress && static_cast<QMouseEvent*>(e)->button() == Qt::LeftButton/* && !dynamic_cast<StickerPan*>(obj)*/) {
|
} else if (e->type() == QEvent::MouseButtonPress && static_cast<QMouseEvent*>(e)->button() == Qt::LeftButton/* && !dynamic_cast<StickerPan*>(obj)*/) {
|
||||||
if (isHidden() || _hiding) {
|
if (isHidden() || _hiding) {
|
||||||
_hideTimer.stop();
|
_hideTimer.stop();
|
||||||
showStart();
|
showAnimated();
|
||||||
} else {
|
} else {
|
||||||
hideAnimated();
|
hideAnimated();
|
||||||
}
|
}
|
||||||
|
@ -3317,7 +3317,7 @@ void EmojiPan::stickersInstalled(uint64 setId) {
|
||||||
showAll();
|
showAll();
|
||||||
s_inner.showStickerSet(setId);
|
s_inner.showStickerSet(setId);
|
||||||
updateContentHeight();
|
updateContentHeight();
|
||||||
showStart();
|
showAnimated();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmojiPan::notify_inlineItemLayoutChanged(const InlineBots::Layout::ItemBase *layout) {
|
void EmojiPan::notify_inlineItemLayoutChanged(const InlineBots::Layout::ItemBase *layout) {
|
||||||
|
@ -3490,7 +3490,7 @@ void EmojiPan::validateSelectedIcon(ValidateIconAnimations animations) {
|
||||||
|
|
||||||
void EmojiPan::onSwitch() {
|
void EmojiPan::onSwitch() {
|
||||||
QPixmap cache = _cache;
|
QPixmap cache = _cache;
|
||||||
_fromCache = myGrab(this, rect().marginsRemoved(st::dropdownDef.padding));
|
_fromCache = myGrab(this, rect().marginsRemoved(st::defaultDropdownPadding));
|
||||||
_stickersShown = !_stickersShown;
|
_stickersShown = !_stickersShown;
|
||||||
if (!_stickersShown) {
|
if (!_stickersShown) {
|
||||||
Notify::clipStopperHidden(ClipStopperSavedGifsPanel);
|
Notify::clipStopperHidden(ClipStopperSavedGifsPanel);
|
||||||
|
@ -3515,7 +3515,7 @@ void EmojiPan::onSwitch() {
|
||||||
|
|
||||||
_cache = QPixmap();
|
_cache = QPixmap();
|
||||||
showAll();
|
showAll();
|
||||||
_toCache = myGrab(this, rect().marginsRemoved(st::dropdownDef.padding));
|
_toCache = myGrab(this, rect().marginsRemoved(st::defaultDropdownPadding));
|
||||||
_cache = cache;
|
_cache = cache;
|
||||||
|
|
||||||
hideAll();
|
hideAll();
|
||||||
|
@ -3804,7 +3804,7 @@ int32 EmojiPan::showInlineRows(bool newResults) {
|
||||||
} else {
|
} else {
|
||||||
_hideTimer.stop();
|
_hideTimer.stop();
|
||||||
if (hidden || _hiding) {
|
if (hidden || _hiding) {
|
||||||
showStart();
|
showAnimated();
|
||||||
} else if (!_stickersShown) {
|
} else if (!_stickersShown) {
|
||||||
onSwitch();
|
onSwitch();
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,21 +67,20 @@ public:
|
||||||
|
|
||||||
void step_appearance(float64 ms, bool timer);
|
void step_appearance(float64 ms, bool timer);
|
||||||
void step_selected(uint64 ms, bool timer);
|
void step_selected(uint64 ms, bool timer);
|
||||||
void showStart();
|
|
||||||
|
|
||||||
void clearSelection(bool fast = false);
|
void clearSelection(bool fast = false);
|
||||||
|
|
||||||
public slots:
|
void hideFast();
|
||||||
|
|
||||||
void hideStart(bool fast = false);
|
public slots:
|
||||||
|
void showAnimated();
|
||||||
|
void hideAnimated();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
void emojiSelected(EmojiPtr emoji);
|
void emojiSelected(EmojiPtr emoji);
|
||||||
void hidden();
|
void hidden();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void drawVariant(Painter &p, int variant);
|
void drawVariant(Painter &p, int variant);
|
||||||
|
|
||||||
void updateSelected();
|
void updateSelected();
|
||||||
|
@ -113,7 +112,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
class EmojiPanel;
|
class EmojiPanel;
|
||||||
class EmojiPanInner : public ScrolledWidget {
|
class EmojiPanInner : public TWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -207,7 +206,7 @@ struct StickerIcon {
|
||||||
int pixh = 0;
|
int pixh = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class StickerPanInner : public ScrolledWidget, private base::Subscriber {
|
class StickerPanInner : public TWidget, private base::Subscriber {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -499,7 +498,7 @@ public:
|
||||||
|
|
||||||
bool event(QEvent *e);
|
bool event(QEvent *e);
|
||||||
|
|
||||||
void fastHide();
|
void hideFast();
|
||||||
bool hiding() const {
|
bool hiding() const {
|
||||||
return _hiding || _hideTimer.isActive();
|
return _hiding || _hideTimer.isActive();
|
||||||
}
|
}
|
||||||
|
@ -517,10 +516,10 @@ public:
|
||||||
bool overlaps(const QRect &globalRect) {
|
bool overlaps(const QRect &globalRect) {
|
||||||
if (isHidden() || !_cache.isNull()) return false;
|
if (isHidden() || !_cache.isNull()) return false;
|
||||||
|
|
||||||
return QRect(st::dropdownDef.padding.left(),
|
return QRect(st::defaultDropdownPadding.left(),
|
||||||
st::dropdownDef.padding.top(),
|
st::defaultDropdownPadding.top(),
|
||||||
_width - st::dropdownDef.padding.left() - st::dropdownDef.padding.right(),
|
_width - st::defaultDropdownPadding.left() - st::defaultDropdownPadding.right(),
|
||||||
_height - st::dropdownDef.padding.top() - st::dropdownDef.padding.bottom()
|
_height - st::defaultDropdownPadding.top() - st::defaultDropdownPadding.bottom()
|
||||||
).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
|
).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -534,7 +533,9 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void hideStart();
|
void showAnimated();
|
||||||
|
void hideAnimated();
|
||||||
|
|
||||||
void refreshStickers();
|
void refreshStickers();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
@ -542,7 +543,6 @@ private slots:
|
||||||
|
|
||||||
void hideFinish();
|
void hideFinish();
|
||||||
|
|
||||||
void showStart();
|
|
||||||
void onWndActiveChanged();
|
void onWndActiveChanged();
|
||||||
|
|
||||||
void onTabChange();
|
void onTabChange();
|
||||||
|
@ -590,7 +590,7 @@ private:
|
||||||
void updateContentHeight();
|
void updateContentHeight();
|
||||||
|
|
||||||
void leaveToChildEvent(QEvent *e, QWidget *child);
|
void leaveToChildEvent(QEvent *e, QWidget *child);
|
||||||
void hideAnimated();
|
void startHideAnimated();
|
||||||
void prepareShowHideCache();
|
void prepareShowHideCache();
|
||||||
|
|
||||||
void updateSelected();
|
void updateSelected();
|
||||||
|
|
|
@ -27,7 +27,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
|
||||||
HistoryDownButton::HistoryDownButton(QWidget *parent) : Button(parent)
|
HistoryDownButton::HistoryDownButton(QWidget *parent) : Button(parent)
|
||||||
, a_arrowOpacity(st::btnAttachEmoji.opacity, st::btnAttachEmoji.opacity)
|
, a_arrowOpacity(st::historyAttachEmoji.opacity, st::historyAttachEmoji.opacity)
|
||||||
, _a_arrowOver(animation(this, &HistoryDownButton::step_arrowOver)) {
|
, _a_arrowOver(animation(this, &HistoryDownButton::step_arrowOver)) {
|
||||||
setCursor(style::cur_pointer);
|
setCursor(style::cur_pointer);
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ void HistoryDownButton::paintEvent(QPaintEvent *e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryDownButton::onStateChanged(int oldState, ButtonStateChangeSource source) {
|
void HistoryDownButton::onStateChanged(int oldState, ButtonStateChangeSource source) {
|
||||||
a_arrowOpacity.start((_state & (StateOver | StateDown)) ? st::btnAttachEmoji.overOpacity : st::btnAttachEmoji.opacity);
|
a_arrowOpacity.start((_state & (StateOver | StateDown)) ? st::historyAttachEmoji.overOpacity : st::historyAttachEmoji.opacity);
|
||||||
|
|
||||||
if (source == ButtonByUser || source == ButtonByPress) {
|
if (source == ButtonByUser || source == ButtonByPress) {
|
||||||
_a_arrowOver.stop();
|
_a_arrowOver.stop();
|
||||||
|
@ -118,7 +118,7 @@ void HistoryDownButton::hideAnimated() {
|
||||||
void HistoryDownButton::toggleAnimated() {
|
void HistoryDownButton::toggleAnimated() {
|
||||||
_shown = !_shown;
|
_shown = !_shown;
|
||||||
float64 from = _shown ? 0. : 1., to = _shown ? 1. : 0.;
|
float64 from = _shown ? 0. : 1., to = _shown ? 1. : 0.;
|
||||||
_a_show.start([this] { update(); }, from, to, st::btnAttachEmoji.duration);
|
_a_show.start([this] { update(); }, from, to, st::historyAttachEmoji.duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryDownButton::finishAnimation() {
|
void HistoryDownButton::finishAnimation() {
|
||||||
|
@ -127,7 +127,7 @@ void HistoryDownButton::finishAnimation() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryDownButton::step_arrowOver(float64 ms, bool timer) {
|
void HistoryDownButton::step_arrowOver(float64 ms, bool timer) {
|
||||||
float64 dt = ms / st::btnAttachEmoji.duration;
|
float64 dt = ms / st::historyAttachEmoji.duration;
|
||||||
if (dt >= 1) {
|
if (dt >= 1) {
|
||||||
_a_arrowOver.stop();
|
_a_arrowOver.stop();
|
||||||
a_arrowOpacity.finish();
|
a_arrowOpacity.finish();
|
||||||
|
@ -137,4 +137,64 @@ void HistoryDownButton::step_arrowOver(float64 ms, bool timer) {
|
||||||
if (timer) update();
|
if (timer) update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EmojiButton::EmojiButton(QWidget *parent, const style::IconButton &st) : Button(parent)
|
||||||
|
, _st(st)
|
||||||
|
, _a_loading(animation(this, &EmojiButton::step_loading)) {
|
||||||
|
resize(_st.width, _st.height);
|
||||||
|
setCursor(style::cur_pointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmojiButton::paintEvent(QPaintEvent *e) {
|
||||||
|
Painter p(this);
|
||||||
|
|
||||||
|
uint64 ms = getms();
|
||||||
|
|
||||||
|
p.fillRect(e->rect(), st::white);
|
||||||
|
|
||||||
|
auto over = _a_over.current(getms(), (_state & StateOver) ? 1. : 0.);
|
||||||
|
auto opacity = over * _st.overOpacity + (1. - over) * _st.opacity;
|
||||||
|
|
||||||
|
auto loading = a_loading.current(ms, _loading ? 1 : 0);
|
||||||
|
p.setOpacity(opacity * (1 - loading));
|
||||||
|
|
||||||
|
_st.icon.paint(p, (_state & StateDown) ? _st.downIconPosition : _st.iconPosition, width());
|
||||||
|
|
||||||
|
p.setOpacity(opacity);
|
||||||
|
p.setPen(QPen(st::historyEmojiCircleFg, st::historyEmojiCircleLine));
|
||||||
|
p.setBrush(Qt::NoBrush);
|
||||||
|
|
||||||
|
p.setRenderHint(QPainter::HighQualityAntialiasing);
|
||||||
|
QRect inner(QPoint((width() - st::historyEmojiCircle.width()) / 2, st::historyEmojiCircleTop), st::historyEmojiCircle);
|
||||||
|
if (loading > 0) {
|
||||||
|
int32 full = 5760;
|
||||||
|
int32 start = qRound(full * float64(ms % uint64(st::historyEmojiCirclePeriod)) / st::historyEmojiCirclePeriod), part = qRound(loading * full / st::historyEmojiCirclePart);
|
||||||
|
p.drawArc(inner, start, full - part);
|
||||||
|
} else {
|
||||||
|
p.drawEllipse(inner);
|
||||||
|
}
|
||||||
|
p.setRenderHint(QPainter::HighQualityAntialiasing, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmojiButton::setLoading(bool loading) {
|
||||||
|
if (_loading != loading) {
|
||||||
|
_loading = loading;
|
||||||
|
auto from = loading ? 0. : 1., to = loading ? 1. : 0.;
|
||||||
|
a_loading.start([this] { update(); }, from, to, st::historyEmojiCircleDuration);
|
||||||
|
if (loading) {
|
||||||
|
_a_loading.start();
|
||||||
|
} else {
|
||||||
|
_a_loading.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmojiButton::onStateChanged(int oldState, ButtonStateChangeSource source) {
|
||||||
|
auto over = (_state & StateOver);
|
||||||
|
if (over != (oldState & StateOver)) {
|
||||||
|
auto from = over ? 0. : 1.;
|
||||||
|
auto to = over ? 1. : 0.;
|
||||||
|
_a_over.start([this] { update(); }, from, to, _st.duration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
|
@ -61,4 +61,31 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class EmojiButton : public Button {
|
||||||
|
public:
|
||||||
|
EmojiButton(QWidget *parent, const style::IconButton &st);
|
||||||
|
|
||||||
|
void setLoading(bool loading);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent *e) override;
|
||||||
|
void onStateChanged(int oldState, ButtonStateChangeSource source) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const style::IconButton &_st;
|
||||||
|
|
||||||
|
FloatAnimation _a_over;
|
||||||
|
|
||||||
|
bool _loading = false;
|
||||||
|
FloatAnimation a_loading;
|
||||||
|
Animation _a_loading;
|
||||||
|
|
||||||
|
void step_loading(uint64 ms, bool timer) {
|
||||||
|
if (timer) {
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
|
@ -261,10 +261,8 @@ void CountrySelectBox::doSetInnerFocus() {
|
||||||
_select->setInnerFocus();
|
_select->setInnerFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
CountrySelectBox::Inner::Inner(QWidget *parent) : ScrolledWidget(parent)
|
CountrySelectBox::Inner::Inner(QWidget *parent) : TWidget(parent)
|
||||||
, _rowHeight(st::countryRowHeight)
|
, _rowHeight(st::countryRowHeight) {
|
||||||
, _sel(0)
|
|
||||||
, _mouseSel(false) {
|
|
||||||
setAttribute(Qt::WA_OpaquePaintEvent);
|
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||||
|
|
||||||
CountriesByISO2::const_iterator l = _countriesByISO2.constFind(lastValidISO);
|
CountriesByISO2::const_iterator l = _countriesByISO2.constFind(lastValidISO);
|
||||||
|
|
|
@ -103,7 +103,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
// This class is hold in header because it requires Qt preprocessing.
|
// This class is hold in header because it requires Qt preprocessing.
|
||||||
class CountrySelectBox::Inner : public ScrolledWidget {
|
class CountrySelectBox::Inner : public TWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -135,11 +135,11 @@ protected:
|
||||||
private:
|
private:
|
||||||
void updateSelectedRow();
|
void updateSelectedRow();
|
||||||
|
|
||||||
int32 _rowHeight;
|
int _rowHeight;
|
||||||
|
|
||||||
int32 _sel;
|
int _sel = 0;
|
||||||
QString _filter;
|
QString _filter;
|
||||||
bool _mouseSel;
|
bool _mouseSel = false;
|
||||||
|
|
||||||
QPoint _lastMousePos;
|
QPoint _lastMousePos;
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "ui/flatbutton.h"
|
#include "ui/flatbutton.h"
|
||||||
|
|
||||||
|
#include "styles/style_history.h"
|
||||||
|
|
||||||
FlatButton::FlatButton(QWidget *parent, const QString &text, const style::flatButton &st) : Button(parent)
|
FlatButton::FlatButton(QWidget *parent, const QString &text, const style::flatButton &st) : Button(parent)
|
||||||
, _text(text)
|
, _text(text)
|
||||||
, _st(st)
|
, _st(st)
|
||||||
|
@ -264,83 +266,6 @@ void IconedButton::paintEvent(QPaintEvent *e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MaskedButton::MaskedButton(QWidget *parent, const style::iconedButton &st, const QString &text) : IconedButton(parent, st, text) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaskedButton::paintEvent(QPaintEvent *e) {
|
|
||||||
Painter p(this);
|
|
||||||
|
|
||||||
p.setOpacity(_opacity);
|
|
||||||
|
|
||||||
p.setOpacity(a_opacity.current() * _opacity);
|
|
||||||
|
|
||||||
if (!_text.isEmpty()) {
|
|
||||||
p.setFont(_st.font->f);
|
|
||||||
p.setRenderHint(QPainter::TextAntialiasing);
|
|
||||||
p.setPen(a_bg.current());
|
|
||||||
const QPoint &t((_state & StateDown) ? _st.downTextPos : _st.textPos);
|
|
||||||
p.drawText(t.x(), t.y() + _st.font->ascent, _text);
|
|
||||||
}
|
|
||||||
|
|
||||||
const style::sprite &i((_state & StateDown) ? _st.downIcon : _st.icon);
|
|
||||||
if (i.pxWidth()) {
|
|
||||||
const QPoint &t((_state & StateDown) ? _st.downIconPos : _st.iconPos);
|
|
||||||
p.fillRect(QRect(t, QSize(i.pxWidth(), i.pxHeight())), a_bg.current());
|
|
||||||
p.drawSprite(t, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EmojiButton::EmojiButton(QWidget *parent, const style::iconedButton &st) : IconedButton(parent, st)
|
|
||||||
, _loading(false)
|
|
||||||
, _a_loading(animation(this, &EmojiButton::step_loading)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmojiButton::paintEvent(QPaintEvent *e) {
|
|
||||||
Painter p(this);
|
|
||||||
|
|
||||||
uint64 ms = getms();
|
|
||||||
float64 loading = a_loading.current(ms, _loading ? 1 : 0);
|
|
||||||
p.setOpacity(_opacity * (1 - loading));
|
|
||||||
|
|
||||||
p.fillRect(e->rect(), a_bg.current());
|
|
||||||
|
|
||||||
p.setOpacity(a_opacity.current() * _opacity * (1 - loading));
|
|
||||||
|
|
||||||
const style::sprite &i((_state & StateDown) ? _st.downIcon : _st.icon);
|
|
||||||
if (!i.isEmpty()) {
|
|
||||||
const QPoint &t((_state & StateDown) ? _st.downIconPos : _st.iconPos);
|
|
||||||
p.drawSprite(t, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
p.setOpacity(a_opacity.current() * _opacity);
|
|
||||||
p.setPen(QPen(st::emojiCircleFg, st::emojiCircleLine));
|
|
||||||
p.setBrush(Qt::NoBrush);
|
|
||||||
|
|
||||||
p.setRenderHint(QPainter::HighQualityAntialiasing);
|
|
||||||
QRect inner(QPoint((width() - st::emojiCircle.width()) / 2, st::emojiCircleTop), st::emojiCircle);
|
|
||||||
if (loading > 0) {
|
|
||||||
int32 full = 5760;
|
|
||||||
int32 start = qRound(full * float64(ms % uint64(st::emojiCirclePeriod)) / st::emojiCirclePeriod), part = qRound(loading * full / st::emojiCirclePart);
|
|
||||||
p.drawArc(inner, start, full - part);
|
|
||||||
} else {
|
|
||||||
p.drawEllipse(inner);
|
|
||||||
}
|
|
||||||
p.setRenderHint(QPainter::HighQualityAntialiasing, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmojiButton::setLoading(bool loading) {
|
|
||||||
if (_loading != loading) {
|
|
||||||
_loading = loading;
|
|
||||||
auto from = loading ? 0. : 1., to = loading ? 1. : 0.;
|
|
||||||
a_loading.start([this] { update(); }, from, to, st::emojiCircleDuration);
|
|
||||||
if (loading) {
|
|
||||||
_a_loading.start();
|
|
||||||
} else {
|
|
||||||
_a_loading.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BoxButton::BoxButton(QWidget *parent, const QString &text, const style::RoundButton &st) : Button(parent)
|
BoxButton::BoxButton(QWidget *parent, const QString &text, const style::RoundButton &st) : Button(parent)
|
||||||
, _text(text.toUpper())
|
, _text(text.toUpper())
|
||||||
, _fullText(text.toUpper())
|
, _fullText(text.toUpper())
|
||||||
|
|
|
@ -28,7 +28,6 @@ class FlatButton : public Button {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
FlatButton(QWidget *parent, const QString &text, const style::flatButton &st);
|
FlatButton(QWidget *parent, const QString &text, const style::flatButton &st);
|
||||||
|
|
||||||
void step_appearance(float64 ms, bool timer);
|
void step_appearance(float64 ms, bool timer);
|
||||||
|
@ -45,11 +44,9 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void onStateChange(int oldState, ButtonStateChangeSource source);
|
void onStateChange(int oldState, ButtonStateChangeSource source);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
QString _text, _textForAutoSize;
|
QString _text, _textForAutoSize;
|
||||||
int32 _textWidth;
|
int32 _textWidth;
|
||||||
|
|
||||||
|
@ -91,7 +88,6 @@ class IconedButton : public Button {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
IconedButton(QWidget *parent, const style::iconedButton &st, const QString &text = QString());
|
IconedButton(QWidget *parent, const style::iconedButton &st, const QString &text = QString());
|
||||||
|
|
||||||
void step_appearance(float64 ms, bool timer);
|
void step_appearance(float64 ms, bool timer);
|
||||||
|
@ -103,11 +99,9 @@ public:
|
||||||
QString getText() const;
|
QString getText() const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
void onStateChange(int oldState, ButtonStateChangeSource source);
|
void onStateChange(int oldState, ButtonStateChangeSource source);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
QString _text;
|
QString _text;
|
||||||
|
|
||||||
style::iconedButton _st;
|
style::iconedButton _st;
|
||||||
|
@ -120,39 +114,6 @@ protected:
|
||||||
float64 _opacity;
|
float64 _opacity;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MaskedButton : public IconedButton {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
MaskedButton(QWidget *parent, const style::iconedButton &st, const QString &text = QString());
|
|
||||||
|
|
||||||
void paintEvent(QPaintEvent *e);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class EmojiButton : public IconedButton {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
EmojiButton(QWidget *parent, const style::iconedButton &st);
|
|
||||||
|
|
||||||
void paintEvent(QPaintEvent *e);
|
|
||||||
void setLoading(bool loading);
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool _loading;
|
|
||||||
FloatAnimation a_loading;
|
|
||||||
Animation _a_loading;
|
|
||||||
|
|
||||||
void step_loading(uint64 ms, bool timer) {
|
|
||||||
if (timer) {
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class BoxButton : public Button {
|
class BoxButton : public Button {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "ui/flatinput.h"
|
#include "ui/flatinput.h"
|
||||||
|
|
||||||
#include "ui/popupmenu.h"
|
#include "ui/widgets/popup_menu.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "countryinput.h"
|
#include "countryinput.h"
|
||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
|
@ -244,7 +244,12 @@ void FlatInput::updatePlaceholderText() {
|
||||||
|
|
||||||
void FlatInput::contextMenuEvent(QContextMenuEvent *e) {
|
void FlatInput::contextMenuEvent(QContextMenuEvent *e) {
|
||||||
if (auto menu = createStandardContextMenu()) {
|
if (auto menu = createStandardContextMenu()) {
|
||||||
(new PopupMenu(menu))->popup(e->globalPos());
|
menu->addSeparator();
|
||||||
|
auto action = menu->addAction(QString("test"));
|
||||||
|
action->setMenu(new QMenu(this));
|
||||||
|
action->menu()->addAction(QString("test123"));
|
||||||
|
action->menu()->addAction(QString("test456"));
|
||||||
|
(new Ui::PopupMenu(menu))->popup(e->globalPos());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1282,7 +1287,7 @@ void InputArea::Inner::paintEvent(QPaintEvent *e) {
|
||||||
|
|
||||||
void InputArea::Inner::contextMenuEvent(QContextMenuEvent *e) {
|
void InputArea::Inner::contextMenuEvent(QContextMenuEvent *e) {
|
||||||
if (auto menu = createStandardContextMenu()) {
|
if (auto menu = createStandardContextMenu()) {
|
||||||
(new PopupMenu(menu))->popup(e->globalPos());
|
(new Ui::PopupMenu(menu))->popup(e->globalPos());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2029,7 +2034,7 @@ void InputField::Inner::paintEvent(QPaintEvent *e) {
|
||||||
|
|
||||||
void InputField::Inner::contextMenuEvent(QContextMenuEvent *e) {
|
void InputField::Inner::contextMenuEvent(QContextMenuEvent *e) {
|
||||||
if (auto menu = createStandardContextMenu()) {
|
if (auto menu = createStandardContextMenu()) {
|
||||||
(new PopupMenu(menu))->popup(e->globalPos());
|
(new Ui::PopupMenu(menu))->popup(e->globalPos());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2237,7 +2242,7 @@ void MaskedInputField::updatePlaceholderText() {
|
||||||
|
|
||||||
void MaskedInputField::contextMenuEvent(QContextMenuEvent *e) {
|
void MaskedInputField::contextMenuEvent(QContextMenuEvent *e) {
|
||||||
if (auto menu = createStandardContextMenu()) {
|
if (auto menu = createStandardContextMenu()) {
|
||||||
(new PopupMenu(menu))->popup(e->globalPos());
|
(new Ui::PopupMenu(menu))->popup(e->globalPos());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "ui/flatlabel.h"
|
#include "ui/flatlabel.h"
|
||||||
|
|
||||||
#include "ui/popupmenu.h"
|
#include "ui/widgets/popup_menu.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "lang.h"
|
#include "lang.h"
|
||||||
|
|
||||||
|
@ -414,7 +414,7 @@ void FlatLabel::showContextMenu(QContextMenuEvent *e, ContextMenuReason reason)
|
||||||
uponSelection = hasSelection;
|
uponSelection = hasSelection;
|
||||||
}
|
}
|
||||||
|
|
||||||
_contextMenu = new PopupMenu();
|
_contextMenu = new Ui::PopupMenu();
|
||||||
|
|
||||||
_contextMenuClickHandler = ClickHandler::getActive();
|
_contextMenuClickHandler = ClickHandler::getActive();
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,9 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
class PopupMenu;
|
class PopupMenu;
|
||||||
|
} // namespace Ui
|
||||||
|
|
||||||
class FlatLabel : public TWidget, public ClickHandlerHost {
|
class FlatLabel : public TWidget, public ClickHandlerHost {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -137,7 +139,7 @@ private:
|
||||||
QPoint _trippleClickPoint;
|
QPoint _trippleClickPoint;
|
||||||
QTimer _trippleClickTimer;
|
QTimer _trippleClickTimer;
|
||||||
|
|
||||||
PopupMenu *_contextMenu = nullptr;
|
Ui::PopupMenu *_contextMenu = nullptr;
|
||||||
ClickHandlerPtr _contextMenuClickHandler;
|
ClickHandlerPtr _contextMenuClickHandler;
|
||||||
QString _contextCopyText;
|
QString _contextCopyText;
|
||||||
ExpandLinksMode _contextExpandLinksMode = ExpandLinksAll;
|
ExpandLinksMode _contextExpandLinksMode = ExpandLinksAll;
|
||||||
|
|
|
@ -21,7 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "flattextarea.h"
|
#include "flattextarea.h"
|
||||||
|
|
||||||
#include "ui/popupmenu.h"
|
#include "ui/widgets/popup_menu.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
|
|
||||||
QByteArray FlatTextarea::serializeTagsList(const TagList &tags) {
|
QByteArray FlatTextarea::serializeTagsList(const TagList &tags) {
|
||||||
|
@ -1421,6 +1421,6 @@ void FlatTextarea::dropEvent(QDropEvent *e) {
|
||||||
|
|
||||||
void FlatTextarea::contextMenuEvent(QContextMenuEvent *e) {
|
void FlatTextarea::contextMenuEvent(QContextMenuEvent *e) {
|
||||||
if (auto menu = createStandardContextMenu()) {
|
if (auto menu = createStandardContextMenu()) {
|
||||||
(new PopupMenu(menu))->popup(e->globalPos());
|
(new Ui::PopupMenu(menu))->popup(e->globalPos());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,678 +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.
|
|
||||||
|
|
||||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
|
||||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|
||||||
*/
|
|
||||||
#include "stdafx.h"
|
|
||||||
|
|
||||||
#include "popupmenu.h"
|
|
||||||
#include "flatbutton.h"
|
|
||||||
#include "pspecific.h"
|
|
||||||
|
|
||||||
#include "application.h"
|
|
||||||
|
|
||||||
#include "lang.h"
|
|
||||||
|
|
||||||
PopupMenu::PopupMenu(const style::PopupMenu &st) : TWidget(nullptr)
|
|
||||||
, _st(st)
|
|
||||||
, _itemHeight(_st.itemPadding.top() + _st.itemFont->height + _st.itemPadding.bottom())
|
|
||||||
, _separatorHeight(_st.separatorPadding.top() + _st.separatorWidth + _st.separatorPadding.bottom())
|
|
||||||
, _shadow(_st.shadow)
|
|
||||||
, a_opacity(1)
|
|
||||||
, _a_hide(animation(this, &PopupMenu::step_hide)) {
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
PopupMenu::PopupMenu(QMenu *menu, const style::PopupMenu &st) : TWidget(nullptr)
|
|
||||||
, _st(st)
|
|
||||||
, _menu(menu)
|
|
||||||
, _itemHeight(_st.itemPadding.top() + _st.itemFont->height + _st.itemPadding.bottom())
|
|
||||||
, _separatorHeight(_st.separatorPadding.top() + _st.separatorWidth + _st.separatorPadding.bottom())
|
|
||||||
, _shadow(_st.shadow)
|
|
||||||
, a_opacity(1)
|
|
||||||
, _a_hide(animation(this, &PopupMenu::step_hide)) {
|
|
||||||
_menu->setParent(this);
|
|
||||||
_menu->hide();
|
|
||||||
|
|
||||||
init();
|
|
||||||
for (auto action : menu->actions()) {
|
|
||||||
addAction(action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupMenu::init() {
|
|
||||||
_padding = _shadow.getDimensions(_st.shadowShift);
|
|
||||||
|
|
||||||
resetActions();
|
|
||||||
|
|
||||||
setWindowFlags(Qt::FramelessWindowHint | Qt::BypassWindowManagerHint | Qt::Popup | Qt::NoDropShadowWindowHint);
|
|
||||||
setMouseTracking(true);
|
|
||||||
|
|
||||||
hide();
|
|
||||||
|
|
||||||
setAttribute(Qt::WA_NoSystemBackground, true);
|
|
||||||
setAttribute(Qt::WA_TranslucentBackground, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
QAction *PopupMenu::addAction(const QString &text, const QObject *receiver, const char* member) {
|
|
||||||
QAction *a = new QAction(text, this);
|
|
||||||
connect(a, SIGNAL(triggered(bool)), receiver, member, Qt::QueuedConnection);
|
|
||||||
return addAction(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
QAction *PopupMenu::addAction(QAction *a) {
|
|
||||||
connect(a, SIGNAL(changed()), this, SLOT(actionChanged()));
|
|
||||||
_actions.push_back(a);
|
|
||||||
if (auto submenu = a->menu()) {
|
|
||||||
_menus.push_back(new PopupMenu(submenu));
|
|
||||||
_menus.back()->deleteOnHide(false);
|
|
||||||
} else {
|
|
||||||
_menus.push_back(nullptr);
|
|
||||||
}
|
|
||||||
_texts.push_back(QString());
|
|
||||||
_shortcutTexts.push_back(QString());
|
|
||||||
int32 w = processAction(a, _actions.size() - 1, width());
|
|
||||||
resize(w, height() + (a->isSeparator() ? _separatorHeight : _itemHeight));
|
|
||||||
update();
|
|
||||||
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
QAction *PopupMenu::addSeparator() {
|
|
||||||
QAction *separator = new QAction(this);
|
|
||||||
separator->setSeparator(true);
|
|
||||||
return addAction(separator);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 PopupMenu::processAction(QAction *a, int32 index, int32 w) {
|
|
||||||
if (a->isSeparator() || a->text().isEmpty()) {
|
|
||||||
_texts[index] = _shortcutTexts[index] = QString();
|
|
||||||
} else {
|
|
||||||
QStringList texts = a->text().split('\t');
|
|
||||||
int32 textw = _st.itemFont->width(texts.at(0));
|
|
||||||
int32 goodw = _padding.left() + _st.itemPadding.left() + textw + _st.itemPadding.right() + _padding.right();
|
|
||||||
if (_menus.at(index)) {
|
|
||||||
goodw += _st.itemPadding.left() + _st.arrow.width();
|
|
||||||
} else if (texts.size() > 1) {
|
|
||||||
goodw += _st.itemPadding.left() + _st.itemFont->width(texts.at(1));
|
|
||||||
}
|
|
||||||
w = snap(goodw, w, int32(_padding.left() + _st.widthMax + _padding.right()));
|
|
||||||
_texts[index] = (w < goodw) ? _st.itemFont->elided(texts.at(0), w - (goodw - textw)) : texts.at(0);
|
|
||||||
_shortcutTexts[index] = texts.size() > 1 ? texts.at(1) : QString();
|
|
||||||
}
|
|
||||||
return w;
|
|
||||||
}
|
|
||||||
|
|
||||||
PopupMenu::Actions &PopupMenu::actions() {
|
|
||||||
return _actions;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupMenu::actionChanged() {
|
|
||||||
int32 w = _padding.left() + _st.widthMin + _padding.right();
|
|
||||||
for (int32 i = 0, l = _actions.size(); i < l; ++i) {
|
|
||||||
w = processAction(_actions.at(i), i, w);
|
|
||||||
}
|
|
||||||
if (w != width()) {
|
|
||||||
resize(w, height());
|
|
||||||
}
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupMenu::resetActions() {
|
|
||||||
clearActions();
|
|
||||||
resize(_padding.left() + _st.widthMin + _padding.right(), _padding.top() + (_st.skip * 2) + _padding.bottom());
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupMenu::clearActions(bool force) {
|
|
||||||
if (_menu && !force) return;
|
|
||||||
|
|
||||||
if (!_menu) {
|
|
||||||
for (int32 i = 0, l = _actions.size(); i < l; ++i) {
|
|
||||||
delete _actions[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_actions.clear();
|
|
||||||
|
|
||||||
for (int32 i = 0, l = _menus.size(); i < l; ++i) {
|
|
||||||
delete _menus[i];
|
|
||||||
}
|
|
||||||
_menus.clear();
|
|
||||||
_childMenuIndex = -1;
|
|
||||||
|
|
||||||
_selected = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupMenu::resizeEvent(QResizeEvent *e) {
|
|
||||||
_inner = QRect(_padding.left(), _padding.top(), width() - _padding.left() - _padding.right(), height() - _padding.top() - _padding.bottom());
|
|
||||||
return TWidget::resizeEvent(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupMenu::paintEvent(QPaintEvent *e) {
|
|
||||||
Painter p(this);
|
|
||||||
|
|
||||||
QRect r(e->rect());
|
|
||||||
p.setClipRect(r);
|
|
||||||
QPainter::CompositionMode m = p.compositionMode();
|
|
||||||
p.setCompositionMode(QPainter::CompositionMode_Source);
|
|
||||||
if (_a_hide.animating()) {
|
|
||||||
p.setOpacity(a_opacity.current());
|
|
||||||
p.drawPixmap(0, 0, _cache);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
p.fillRect(r, st::almostTransparent->b);
|
|
||||||
p.setCompositionMode(m);
|
|
||||||
|
|
||||||
_shadow.paint(p, _inner, _st.shadowShift);
|
|
||||||
|
|
||||||
QRect topskip(_padding.left(), _padding.top(), _inner.width(), _st.skip);
|
|
||||||
QRect bottomskip(_padding.left(), height() - _padding.bottom() - _st.skip, _inner.width(), _st.skip);
|
|
||||||
if (r.intersects(topskip)) p.fillRect(r.intersected(topskip), _st.itemBg->b);
|
|
||||||
if (r.intersects(bottomskip)) p.fillRect(r.intersected(bottomskip), _st.itemBg->b);
|
|
||||||
|
|
||||||
int32 y = _padding.top() + _st.skip;
|
|
||||||
p.translate(_padding.left(), y);
|
|
||||||
p.setFont(_st.itemFont);
|
|
||||||
for (int32 i = 0, l = _actions.size(); i < l; ++i) {
|
|
||||||
if (r.top() + r.height() <= y) break;
|
|
||||||
int32 h = _actions.at(i)->isSeparator() ? _separatorHeight : _itemHeight;
|
|
||||||
y += h;
|
|
||||||
if (r.top() < y) {
|
|
||||||
if (_actions.at(i)->isSeparator()) {
|
|
||||||
p.fillRect(0, 0, _inner.width(), h, _st.itemBg->b);
|
|
||||||
p.fillRect(_st.separatorPadding.left(), _st.separatorPadding.top(), _inner.width() - _st.separatorPadding.left() - _st.separatorPadding.right(), _st.separatorWidth, _st.separatorFg->b);
|
|
||||||
} else {
|
|
||||||
bool enabled = _actions.at(i)->isEnabled(), selected = (i == _selected && enabled);
|
|
||||||
p.fillRect(0, 0, _inner.width(), h, (selected ? _st.itemBgOver : _st.itemBg)->b);
|
|
||||||
p.setPen(selected ? _st.itemFgOver : (enabled ? _st.itemFg : _st.itemFgDisabled));
|
|
||||||
p.drawTextLeft(_st.itemPadding.left(), _st.itemPadding.top(), _inner.width(), _texts.at(i));
|
|
||||||
if (_menus.at(i)) {
|
|
||||||
_st.arrow.paint(p, _inner.width() - _st.itemPadding.right() - _st.arrow.width(), (_itemHeight - _st.arrow.height()) / 2, _inner.width());
|
|
||||||
} else if (!_shortcutTexts.at(i).isEmpty()) {
|
|
||||||
p.setPen(selected ? _st.itemFgShortcutOver : (enabled ? _st.itemFgShortcut : _st.itemFgShortcutDisabled));
|
|
||||||
p.drawTextRight(_st.itemPadding.right(), _st.itemPadding.top(), _inner.width(), _shortcutTexts.at(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p.translate(0, h);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupMenu::updateSelected() {
|
|
||||||
if (!_mouseSelection) return;
|
|
||||||
|
|
||||||
QPoint p(mapFromGlobal(_mouse) - QPoint(_padding.left(), _padding.top() + _st.skip));
|
|
||||||
int32 selected = -1, y = 0;
|
|
||||||
while (y <= p.y() && ++selected < _actions.size()) {
|
|
||||||
y += _actions.at(selected)->isSeparator() ? _separatorHeight : _itemHeight;
|
|
||||||
}
|
|
||||||
setSelected((selected >= 0 && selected < _actions.size() && _actions.at(selected)->isEnabled() && !_actions.at(selected)->isSeparator()) ? selected : -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupMenu::itemPressed(PressSource source) {
|
|
||||||
if (source == PressSourceMouse && !_mouseSelection) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (_selected >= 0 && _selected < _actions.size() && _actions[_selected]->isEnabled()) {
|
|
||||||
if (_menus.at(_selected)) {
|
|
||||||
if (_childMenuIndex == _selected) {
|
|
||||||
_menus.at(_childMenuIndex)->hideMenu(true);
|
|
||||||
} else {
|
|
||||||
popupChildMenu(source);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
hideMenu();
|
|
||||||
_triggering = true;
|
|
||||||
emit _actions[_selected]->trigger();
|
|
||||||
_triggering = false;
|
|
||||||
if (_deleteLater) {
|
|
||||||
_deleteLater = false;
|
|
||||||
deleteLater();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupMenu::popupChildMenu(PressSource source) {
|
|
||||||
if (_childMenuIndex >= 0) {
|
|
||||||
_menus.at(_childMenuIndex)->hideMenu(true);
|
|
||||||
_childMenuIndex = -1;
|
|
||||||
}
|
|
||||||
if (_selected >= 0 && _selected < _menus.size() && _menus.at(_selected)) {
|
|
||||||
QPoint p(_inner.x() + (rtl() ? _padding.right() : _inner.width() - _padding.left()), _inner.y() + _st.skip + itemY(_selected));
|
|
||||||
_childMenuIndex = _selected;
|
|
||||||
_menus.at(_childMenuIndex)->showMenu(geometry().topLeft() + p, this, source);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupMenu::keyPressEvent(QKeyEvent *e) {
|
|
||||||
if (_childMenuIndex >= 0) {
|
|
||||||
return _menus.at(_childMenuIndex)->keyPressEvent(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
|
|
||||||
itemPressed(PressSourceKeyboard);
|
|
||||||
return;
|
|
||||||
} else if (e->key() == Qt::Key_Escape) {
|
|
||||||
hideMenu(_parent ? true : false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (e->key() == (rtl() ? Qt::Key_Left : Qt::Key_Right)) {
|
|
||||||
if (_selected >= 0 && _menus.at(_selected)) {
|
|
||||||
itemPressed(PressSourceKeyboard);
|
|
||||||
return;
|
|
||||||
} else if (_selected < 0 && _parent && !_actions.isEmpty()) {
|
|
||||||
_mouseSelection = false;
|
|
||||||
setSelected(0);
|
|
||||||
}
|
|
||||||
} else if (e->key() == (rtl() ? Qt::Key_Right : Qt::Key_Left)) {
|
|
||||||
if (_parent) {
|
|
||||||
hideMenu(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((e->key() != Qt::Key_Up && e->key() != Qt::Key_Down) || _actions.size() < 1) return;
|
|
||||||
|
|
||||||
int32 delta = (e->key() == Qt::Key_Down ? 1 : -1), start = _selected;
|
|
||||||
if (start < 0 || start >= _actions.size()) {
|
|
||||||
start = (delta > 0) ? (_actions.size() - 1) : 0;
|
|
||||||
}
|
|
||||||
int32 newSelected = start;
|
|
||||||
do {
|
|
||||||
newSelected += delta;
|
|
||||||
if (newSelected < 0) {
|
|
||||||
newSelected += _actions.size();
|
|
||||||
} else if (newSelected >= _actions.size()) {
|
|
||||||
newSelected -= _actions.size();
|
|
||||||
}
|
|
||||||
} while (newSelected != start && (!_actions.at(newSelected)->isEnabled() || _actions.at(newSelected)->isSeparator()));
|
|
||||||
|
|
||||||
if (_actions.at(newSelected)->isEnabled() && !_actions.at(newSelected)->isSeparator()) {
|
|
||||||
_mouseSelection = false;
|
|
||||||
setSelected(newSelected);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupMenu::enterEvent(QEvent *e) {
|
|
||||||
QPoint mouse = QCursor::pos();
|
|
||||||
if (!_inner.marginsRemoved(QMargins(0, _st.skip, 0, _st.skip)).contains(mapFromGlobal(mouse))) {
|
|
||||||
if (_mouseSelection && _childMenuIndex < 0) {
|
|
||||||
_mouseSelection = false;
|
|
||||||
setSelected(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return TWidget::enterEvent(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupMenu::leaveEvent(QEvent *e) {
|
|
||||||
if (_mouseSelection && _childMenuIndex < 0) {
|
|
||||||
_mouseSelection = false;
|
|
||||||
setSelected(-1);
|
|
||||||
}
|
|
||||||
return TWidget::leaveEvent(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupMenu::setSelected(int32 newSelected) {
|
|
||||||
if (newSelected >= _actions.size()) {
|
|
||||||
newSelected = -1;
|
|
||||||
}
|
|
||||||
if (newSelected != _selected) {
|
|
||||||
updateSelectedItem();
|
|
||||||
_selected = newSelected;
|
|
||||||
if (_mouseSelection) {
|
|
||||||
popupChildMenu(PressSourceMouse);
|
|
||||||
}
|
|
||||||
updateSelectedItem();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 PopupMenu::itemY(int32 index) {
|
|
||||||
if (index > _actions.size()) {
|
|
||||||
index = _actions.size();
|
|
||||||
}
|
|
||||||
int32 y = 0;
|
|
||||||
for (int32 i = 0; i < index; ++i) {
|
|
||||||
y += _actions.at(i)->isSeparator() ? _separatorHeight : _itemHeight;
|
|
||||||
}
|
|
||||||
return y;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupMenu::updateSelectedItem() {
|
|
||||||
if (_selected >= 0) {
|
|
||||||
update(_padding.left(), _padding.top() + _st.skip + itemY(_selected), width() - _padding.left() - _padding.right(), _actions.at(_selected)->isSeparator() ? _separatorHeight : _itemHeight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupMenu::mouseMoveEvent(QMouseEvent *e) {
|
|
||||||
if (_inner.marginsRemoved(QMargins(0, _st.skip, 0, _st.skip)).contains(mapFromGlobal(e->globalPos()))) {
|
|
||||||
_mouseSelection = true;
|
|
||||||
_mouse = e->globalPos();
|
|
||||||
updateSelected();
|
|
||||||
} else {
|
|
||||||
if (_mouseSelection && _childMenuIndex < 0) {
|
|
||||||
_mouseSelection = false;
|
|
||||||
setSelected(-1);
|
|
||||||
}
|
|
||||||
if (_parent) {
|
|
||||||
_parent->mouseMoveEvent(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupMenu::mousePressEvent(QMouseEvent *e) {
|
|
||||||
mouseMoveEvent(e);
|
|
||||||
if (_inner.contains(mapFromGlobal(e->globalPos()))) {
|
|
||||||
itemPressed(PressSourceMouse);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (_parent) {
|
|
||||||
_parent->mousePressEvent(e);
|
|
||||||
} else {
|
|
||||||
hideMenu();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupMenu::focusOutEvent(QFocusEvent *e) {
|
|
||||||
hideMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupMenu::hideEvent(QHideEvent *e) {
|
|
||||||
if (_deleteOnHide) {
|
|
||||||
if (_triggering) {
|
|
||||||
_deleteLater = true;
|
|
||||||
} else {
|
|
||||||
deleteLater();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupMenu::hideMenu(bool fast) {
|
|
||||||
if (isHidden()) return;
|
|
||||||
if (_parent && !_a_hide.animating()) {
|
|
||||||
_parent->childHiding(this);
|
|
||||||
}
|
|
||||||
if (fast) {
|
|
||||||
if (_a_hide.animating()) {
|
|
||||||
_a_hide.stop();
|
|
||||||
}
|
|
||||||
a_opacity = anim::fvalue(0, 0);
|
|
||||||
hideFinish();
|
|
||||||
} else {
|
|
||||||
if (!_a_hide.animating()) {
|
|
||||||
_cache = myGrab(this);
|
|
||||||
a_opacity.start(0);
|
|
||||||
_a_hide.start();
|
|
||||||
}
|
|
||||||
if (_parent) {
|
|
||||||
_parent->hideMenu();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (_childMenuIndex >= 0) {
|
|
||||||
_menus.at(_childMenuIndex)->hideMenu(fast);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupMenu::childHiding(PopupMenu *child) {
|
|
||||||
if (_childMenuIndex >= 0 && _menus.at(_childMenuIndex) == child) {
|
|
||||||
_childMenuIndex = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupMenu::hideFinish() {
|
|
||||||
hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupMenu::step_hide(float64 ms, bool timer) {
|
|
||||||
float64 dt = ms / _st.duration;
|
|
||||||
if (dt >= 1) {
|
|
||||||
_a_hide.stop();
|
|
||||||
a_opacity.finish();
|
|
||||||
hideFinish();
|
|
||||||
} else {
|
|
||||||
a_opacity.update(dt, anim::linear);
|
|
||||||
}
|
|
||||||
if (timer) update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupMenu::deleteOnHide(bool del) {
|
|
||||||
_deleteOnHide = del;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupMenu::popup(const QPoint &p) {
|
|
||||||
showMenu(p, 0, PressSourceMouse);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupMenu::showMenu(const QPoint &p, PopupMenu *parent, PressSource source) {
|
|
||||||
_parent = parent;
|
|
||||||
|
|
||||||
QPoint w = p - QPoint(0, _padding.top());
|
|
||||||
QRect r = Sandbox::screenGeometry(p);
|
|
||||||
if (rtl()) {
|
|
||||||
if (w.x() - width() < r.x() - _padding.left()) {
|
|
||||||
if (_parent && w.x() + _parent->width() - _padding.left() - _padding.right() + width() - _padding.right() <= r.x() + r.width()) {
|
|
||||||
w.setX(w.x() + _parent->width() - _padding.left() - _padding.right());
|
|
||||||
} else {
|
|
||||||
w.setX(r.x() - _padding.left());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
w.setX(w.x() - width());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (w.x() + width() - _padding.right() > r.x() + r.width()) {
|
|
||||||
if (_parent && w.x() - _parent->width() + _padding.left() + _padding.right() - width() + _padding.right() >= r.x() - _padding.left()) {
|
|
||||||
w.setX(w.x() + _padding.left() + _padding.right() - _parent->width() - width() + _padding.left() + _padding.right());
|
|
||||||
} else {
|
|
||||||
w.setX(r.x() + r.width() - width() + _padding.right());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (w.y() + height() - _padding.bottom() > r.y() + r.height()) {
|
|
||||||
if (_parent) {
|
|
||||||
w.setY(r.y() + r.height() - height() + _padding.bottom());
|
|
||||||
} else {
|
|
||||||
w.setY(p.y() - height() + _padding.bottom());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (w.y() < r.y()) {
|
|
||||||
w.setY(r.y());
|
|
||||||
}
|
|
||||||
move(w);
|
|
||||||
|
|
||||||
_mouseSelection = (source == PressSourceMouse);
|
|
||||||
setSelected((source == PressSourceMouse || _actions.isEmpty()) ? -1 : 0);
|
|
||||||
psUpdateOverlayed(this);
|
|
||||||
show();
|
|
||||||
psShowOverAll(this);
|
|
||||||
windowHandle()->requestActivate();
|
|
||||||
activateWindow();
|
|
||||||
|
|
||||||
if (_a_hide.animating()) {
|
|
||||||
_a_hide.stop();
|
|
||||||
_cache = QPixmap();
|
|
||||||
}
|
|
||||||
a_opacity = anim::fvalue(1, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
PopupMenu::~PopupMenu() {
|
|
||||||
clearActions(true);
|
|
||||||
|
|
||||||
#if defined Q_OS_LINUX32 || defined Q_OS_LINUX64
|
|
||||||
if (auto w = App::wnd()) {
|
|
||||||
w->onReActivate();
|
|
||||||
QTimer::singleShot(200, w, SLOT(onReActivate()));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
PopupTooltip *PopupTooltipInstance = 0;
|
|
||||||
|
|
||||||
AbstractTooltipShower::~AbstractTooltipShower() {
|
|
||||||
if (PopupTooltipInstance && PopupTooltipInstance->_shower == this) {
|
|
||||||
PopupTooltipInstance->_shower = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PopupTooltip::PopupTooltip() : TWidget(0)
|
|
||||||
, _shower(0)
|
|
||||||
, _st(0) {
|
|
||||||
PopupTooltipInstance = this;
|
|
||||||
|
|
||||||
setWindowFlags(Qt::FramelessWindowHint | Qt::BypassWindowManagerHint | Qt::ToolTip | Qt::NoDropShadowWindowHint);
|
|
||||||
setAttribute(Qt::WA_NoSystemBackground, true);
|
|
||||||
|
|
||||||
_showTimer.setSingleShot(true);
|
|
||||||
connect(&_showTimer, SIGNAL(timeout()), this, SLOT(onShow()));
|
|
||||||
|
|
||||||
connect(App::wnd()->windowHandle(), SIGNAL(activeChanged()), this, SLOT(onWndActiveChanged()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupTooltip::onShow() {
|
|
||||||
if (_shower) {
|
|
||||||
QString text = (App::wnd() && App::wnd()->isActive(false)) ? _shower->tooltipText() : QString();
|
|
||||||
if (text.isEmpty()) {
|
|
||||||
Hide();
|
|
||||||
} else {
|
|
||||||
PopupTooltipInstance->popup(_shower->tooltipPos(), text, _shower->tooltipSt());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupTooltip::onWndActiveChanged() {
|
|
||||||
if (!App::wnd() || !App::wnd()->windowHandle() || !App::wnd()->windowHandle()->isActive()) {
|
|
||||||
PopupTooltip::Hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PopupTooltip::eventFilter(QObject *o, QEvent *e) {
|
|
||||||
if (e->type() == QEvent::Leave) {
|
|
||||||
_hideByLeaveTimer.start(10);
|
|
||||||
} else if (e->type() == QEvent::Enter) {
|
|
||||||
_hideByLeaveTimer.stop();
|
|
||||||
} else if (e->type() == QEvent::MouseMove) {
|
|
||||||
if ((QCursor::pos() - _point).manhattanLength() > QApplication::startDragDistance()) {
|
|
||||||
Hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return TWidget::eventFilter(o, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupTooltip::onHideByLeave() {
|
|
||||||
Hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
PopupTooltip::~PopupTooltip() {
|
|
||||||
if (PopupTooltipInstance == this) {
|
|
||||||
PopupTooltipInstance = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupTooltip::popup(const QPoint &m, const QString &text, const style::Tooltip *st) {
|
|
||||||
if (!_hideByLeaveTimer.isSingleShot()) {
|
|
||||||
_hideByLeaveTimer.setSingleShot(true);
|
|
||||||
connect(&_hideByLeaveTimer, SIGNAL(timeout()), this, SLOT(onHideByLeave()));
|
|
||||||
|
|
||||||
Sandbox::installEventFilter(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
_point = m;
|
|
||||||
_st = st;
|
|
||||||
_text = Text(_st->textFont, text, _textPlainOptions, _st->widthMax, true);
|
|
||||||
|
|
||||||
int32 addw = 2 * st::lineWidth + _st->textPadding.left() + _st->textPadding.right();
|
|
||||||
int32 addh = 2 * st::lineWidth + _st->textPadding.top() + _st->textPadding.bottom();
|
|
||||||
|
|
||||||
// count tooltip size
|
|
||||||
QSize s(addw + _text.maxWidth(), addh + _text.minHeight());
|
|
||||||
if (s.width() > _st->widthMax) {
|
|
||||||
s.setWidth(addw + _text.countWidth(_st->widthMax - addw));
|
|
||||||
s.setHeight(addh + _text.countHeight(s.width() - addw));
|
|
||||||
}
|
|
||||||
int32 maxh = addh + (_st->linesMax * _st->textFont->height);
|
|
||||||
if (s.height() > maxh) {
|
|
||||||
s.setHeight(maxh);
|
|
||||||
}
|
|
||||||
|
|
||||||
// count tooltip position
|
|
||||||
QPoint p(m + _st->shift);
|
|
||||||
if (rtl()) {
|
|
||||||
p.setX(m.x() - s.width() - _st->shift.x());
|
|
||||||
}
|
|
||||||
if (s.width() < 2 * _st->shift.x()) {
|
|
||||||
p.setX(m.x() - (s.width() / 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
// adjust tooltip position
|
|
||||||
QRect r(QApplication::desktop()->screenGeometry(m));
|
|
||||||
if (r.x() + r.width() - _st->skip < p.x() + s.width() && p.x() + s.width() > m.x()) {
|
|
||||||
p.setX(qMax(r.x() + r.width() - int32(_st->skip) - s.width(), m.x() - s.width()));
|
|
||||||
}
|
|
||||||
if (r.x() + _st->skip > p.x() && p.x() < m.x()) {
|
|
||||||
p.setX(qMin(m.x(), r.x() + int32(_st->skip)));
|
|
||||||
}
|
|
||||||
if (r.y() + r.height() - _st->skip < p.y() + s.height()) {
|
|
||||||
p.setY(m.y() - s.height() - _st->skip);
|
|
||||||
}
|
|
||||||
if (r.y() > p.x()) {
|
|
||||||
p.setY(qMin(m.y() + _st->shift.y(), r.y() + r.height() - s.height()));
|
|
||||||
}
|
|
||||||
|
|
||||||
setGeometry(QRect(p, s));
|
|
||||||
|
|
||||||
_hideByLeaveTimer.stop();
|
|
||||||
show();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupTooltip::paintEvent(QPaintEvent *e) {
|
|
||||||
Painter p(this);
|
|
||||||
|
|
||||||
p.fillRect(rect(), _st->textBg);
|
|
||||||
|
|
||||||
p.fillRect(QRect(0, 0, width(), st::lineWidth), _st->textBorder);
|
|
||||||
p.fillRect(QRect(0, height() - st::lineWidth, width(), st::lineWidth), _st->textBorder);
|
|
||||||
p.fillRect(QRect(0, st::lineWidth, st::lineWidth, height() - 2 * st::lineWidth), _st->textBorder);
|
|
||||||
p.fillRect(QRect(width() - st::lineWidth, st::lineWidth, st::lineWidth, height() - 2 * st::lineWidth), _st->textBorder);
|
|
||||||
|
|
||||||
int32 lines = qFloor((height() - 2 * st::lineWidth - _st->textPadding.top() - _st->textPadding.bottom()) / _st->textFont->height);
|
|
||||||
|
|
||||||
p.setPen(_st->textFg);
|
|
||||||
_text.drawElided(p, st::lineWidth + _st->textPadding.left(), st::lineWidth + _st->textPadding.top(), width() - 2 * st::lineWidth - _st->textPadding.left() - _st->textPadding.right(), lines);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupTooltip::hideEvent(QHideEvent *e) {
|
|
||||||
if (PopupTooltipInstance == this) {
|
|
||||||
Hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupTooltip::Show(int32 delay, const AbstractTooltipShower *shower) {
|
|
||||||
if (!PopupTooltipInstance) {
|
|
||||||
new PopupTooltip();
|
|
||||||
}
|
|
||||||
PopupTooltipInstance->_shower = shower;
|
|
||||||
if (delay >= 0) {
|
|
||||||
PopupTooltipInstance->_showTimer.start(delay);
|
|
||||||
} else {
|
|
||||||
PopupTooltipInstance->onShow();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PopupTooltip::Hide() {
|
|
||||||
if (PopupTooltip *instance = PopupTooltipInstance) {
|
|
||||||
PopupTooltipInstance = 0;
|
|
||||||
instance->_showTimer.stop();
|
|
||||||
instance->_hideByLeaveTimer.stop();
|
|
||||||
instance->hide();
|
|
||||||
instance->deleteLater();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,158 +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.
|
|
||||||
|
|
||||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
|
||||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "ui/text/text.h"
|
|
||||||
#include "ui/effects/rect_shadow.h"
|
|
||||||
|
|
||||||
class PopupMenu : public TWidget {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
PopupMenu(const style::PopupMenu &st = st::defaultPopupMenu);
|
|
||||||
PopupMenu(QMenu *menu, const style::PopupMenu &st = st::defaultPopupMenu);
|
|
||||||
QAction *addAction(const QString &text, const QObject *receiver, const char* member);
|
|
||||||
QAction *addAction(QAction *a);
|
|
||||||
QAction *addSeparator();
|
|
||||||
void resetActions();
|
|
||||||
|
|
||||||
typedef QVector<QAction*> Actions;
|
|
||||||
Actions &actions();
|
|
||||||
|
|
||||||
void deleteOnHide(bool del);
|
|
||||||
void popup(const QPoint &p);
|
|
||||||
void hideMenu(bool fast = false);
|
|
||||||
|
|
||||||
~PopupMenu();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
|
||||||
void paintEvent(QPaintEvent *e) override;
|
|
||||||
void keyPressEvent(QKeyEvent *e) override;
|
|
||||||
void mouseMoveEvent(QMouseEvent *e) override;
|
|
||||||
void mousePressEvent(QMouseEvent *e) override;
|
|
||||||
void leaveEvent(QEvent *e) override;
|
|
||||||
void enterEvent(QEvent *e) override;
|
|
||||||
void focusOutEvent(QFocusEvent *e) override;
|
|
||||||
void hideEvent(QHideEvent *e) override;
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void actionChanged();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void updateSelected();
|
|
||||||
|
|
||||||
void childHiding(PopupMenu *child);
|
|
||||||
|
|
||||||
void step_hide(float64 ms, bool timer);
|
|
||||||
|
|
||||||
void init();
|
|
||||||
void hideFinish();
|
|
||||||
|
|
||||||
enum PressSource {
|
|
||||||
PressSourceMouse,
|
|
||||||
PressSourceKeyboard,
|
|
||||||
};
|
|
||||||
|
|
||||||
void clearActions(bool force = false);
|
|
||||||
int32 processAction(QAction *a, int32 index, int32 w);
|
|
||||||
void setSelected(int32 selected);
|
|
||||||
int32 itemY(int32 index);
|
|
||||||
void updateSelectedItem();
|
|
||||||
void itemPressed(PressSource source);
|
|
||||||
void popupChildMenu(PressSource source);
|
|
||||||
void showMenu(const QPoint &p, PopupMenu *parent, PressSource source);;
|
|
||||||
|
|
||||||
const style::PopupMenu &_st;
|
|
||||||
|
|
||||||
typedef QVector<PopupMenu*> PopupMenus;
|
|
||||||
|
|
||||||
QMenu *_menu = nullptr;
|
|
||||||
Actions _actions;
|
|
||||||
PopupMenus _menus;
|
|
||||||
PopupMenu *_parent = nullptr;
|
|
||||||
QStringList _texts, _shortcutTexts;
|
|
||||||
|
|
||||||
int32 _itemHeight, _separatorHeight;
|
|
||||||
QRect _inner;
|
|
||||||
style::margins _padding;
|
|
||||||
|
|
||||||
QPoint _mouse;
|
|
||||||
bool _mouseSelection = false;
|
|
||||||
|
|
||||||
Ui::RectShadow _shadow;
|
|
||||||
int _selected = -1;
|
|
||||||
int _childMenuIndex = -1;
|
|
||||||
|
|
||||||
QPixmap _cache;
|
|
||||||
anim::fvalue a_opacity;
|
|
||||||
Animation _a_hide;
|
|
||||||
|
|
||||||
bool _deleteOnHide = true;
|
|
||||||
bool _triggering = false;
|
|
||||||
bool _deleteLater = false;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class AbstractTooltipShower {
|
|
||||||
public:
|
|
||||||
virtual QString tooltipText() const = 0;
|
|
||||||
virtual QPoint tooltipPos() const = 0;
|
|
||||||
virtual const style::Tooltip *tooltipSt() const {
|
|
||||||
return &st::defaultTooltip;
|
|
||||||
}
|
|
||||||
virtual ~AbstractTooltipShower();
|
|
||||||
};
|
|
||||||
|
|
||||||
class PopupTooltip : public TWidget {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
bool eventFilter(QObject *o, QEvent *e);
|
|
||||||
|
|
||||||
static void Show(int32 delay, const AbstractTooltipShower *shower);
|
|
||||||
static void Hide();
|
|
||||||
|
|
||||||
~PopupTooltip();
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void onShow();
|
|
||||||
void onWndActiveChanged();
|
|
||||||
void onHideByLeave();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void paintEvent(QPaintEvent *e);
|
|
||||||
void hideEvent(QHideEvent *e);
|
|
||||||
|
|
||||||
private:
|
|
||||||
PopupTooltip();
|
|
||||||
|
|
||||||
void popup(const QPoint &p, const QString &text, const style::Tooltip *st);
|
|
||||||
|
|
||||||
friend class AbstractTooltipShower;
|
|
||||||
const AbstractTooltipShower *_shower;
|
|
||||||
QTimer _showTimer;
|
|
||||||
|
|
||||||
Text _text;
|
|
||||||
QPoint _point;
|
|
||||||
|
|
||||||
const style::Tooltip *_st;
|
|
||||||
|
|
||||||
QTimer _hideByLeaveTimer;
|
|
||||||
|
|
||||||
};
|
|
|
@ -273,19 +273,3 @@ public:
|
||||||
}
|
}
|
||||||
void paintEvent(QPaintEvent *e);
|
void paintEvent(QPaintEvent *e);
|
||||||
};
|
};
|
||||||
|
|
||||||
class ScrolledWidget : public TWidget {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
ScrolledWidget(QWidget *parent = nullptr) : TWidget(parent) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Updates the area that is visible inside the scroll container.
|
|
||||||
virtual void setVisibleTopBottom(int visibleTop, int visibleBottom) {
|
|
||||||
}
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void heightUpdated();
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
|
@ -228,6 +228,14 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Updates the area that is visible inside the scroll container.
|
||||||
|
virtual void setVisibleTopBottom(int visibleTop, int visibleBottom) {
|
||||||
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
// Child widget is responsible for emitting this signal.
|
||||||
|
void heightUpdated();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void enterEventHook(QEvent *e) {
|
void enterEventHook(QEvent *e) {
|
||||||
return QWidget::enterEvent(e);
|
return QWidget::enterEvent(e);
|
||||||
|
|
270
Telegram/SourceFiles/ui/widgets/dropdown_menu.cpp
Normal file
|
@ -0,0 +1,270 @@
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "ui/widgets/dropdown_menu.h"
|
||||||
|
|
||||||
|
#include "application.h"
|
||||||
|
#include "lang.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
DropdownMenu::DropdownMenu(QWidget *parent, const style::DropdownMenu &st) : InnerDropdown(parent, st.wrap)
|
||||||
|
, _st(st)
|
||||||
|
, _menu(this, _st.menu) {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not ready with submenus yet.
|
||||||
|
//DropdownMenu::DropdownMenu(QWidget *parent, QMenu *menu, const style::DropdownMenu &st) : InnerDropdown(parent, st.wrap)
|
||||||
|
//, _st(st)
|
||||||
|
//, _menu(this, menu, _st.menu) {
|
||||||
|
// init();
|
||||||
|
//
|
||||||
|
// for (auto action : actions()) {
|
||||||
|
// if (auto submenu = action->menu()) {
|
||||||
|
// auto it = _submenus.insert(action, new DropdownMenu(submenu, st));
|
||||||
|
// it.value()->deleteOnHide(false);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
void DropdownMenu::init() {
|
||||||
|
connect(this, SIGNAL(beforeHidden()), this, SLOT(onHidden()));
|
||||||
|
|
||||||
|
setOwnedWidget(_menu);
|
||||||
|
|
||||||
|
_menu->setResizedCallback([this] { resizeToContent(); });
|
||||||
|
_menu->setActivatedCallback([this](QAction *action, int actionTop, TriggeredSource source) {
|
||||||
|
handleActivated(action, actionTop, source);
|
||||||
|
});
|
||||||
|
_menu->setTriggeredCallback([this](QAction *action, int actionTop, TriggeredSource source) {
|
||||||
|
handleTriggered(action, actionTop, source);
|
||||||
|
});
|
||||||
|
_menu->setKeyPressDelegate([this](int key) { return handleKeyPress(key); });
|
||||||
|
_menu->setMouseMoveDelegate([this](QPoint globalPosition) { handleMouseMove(globalPosition); });
|
||||||
|
_menu->setMousePressDelegate([this](QPoint globalPosition) { handleMousePress(globalPosition); });
|
||||||
|
|
||||||
|
setMouseTracking(true);
|
||||||
|
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
QAction *DropdownMenu::addAction(const QString &text, const QObject *receiver, const char* member, const style::icon *icon) {
|
||||||
|
return _menu->addAction(text, receiver, member, icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
QAction *DropdownMenu::addSeparator() {
|
||||||
|
return _menu->addSeparator();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DropdownMenu::clearActions() {
|
||||||
|
//for (auto submenu : base::take(_submenus)) {
|
||||||
|
// delete submenu;
|
||||||
|
//}
|
||||||
|
return _menu->clearActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
DropdownMenu::Actions &DropdownMenu::actions() {
|
||||||
|
return _menu->actions();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DropdownMenu::handleActivated(QAction *action, int actionTop, TriggeredSource source) {
|
||||||
|
if (source == TriggeredSource::Mouse) {
|
||||||
|
if (!popupSubmenuFromAction(action, actionTop, source)) {
|
||||||
|
if (auto currentSubmenu = base::take(_activeSubmenu)) {
|
||||||
|
currentSubmenu->hideMenu(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DropdownMenu::handleTriggered(QAction *action, int actionTop, TriggeredSource source) {
|
||||||
|
if (!popupSubmenuFromAction(action, actionTop, source)) {
|
||||||
|
hideMenu();
|
||||||
|
_triggering = true;
|
||||||
|
emit action->trigger();
|
||||||
|
_triggering = false;
|
||||||
|
if (_deleteLater) {
|
||||||
|
_deleteLater = false;
|
||||||
|
deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not ready with submenus yet.
|
||||||
|
bool DropdownMenu::popupSubmenuFromAction(QAction *action, int actionTop, TriggeredSource source) {
|
||||||
|
//if (auto submenu = _submenus.value(action)) {
|
||||||
|
// if (_activeSubmenu == submenu) {
|
||||||
|
// submenu->hideMenu(true);
|
||||||
|
// } else {
|
||||||
|
// popupSubmenu(submenu, actionTop, source);
|
||||||
|
// }
|
||||||
|
// return true;
|
||||||
|
//}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//void DropdownMenu::popupSubmenu(SubmenuPointer submenu, int actionTop, TriggeredSource source) {
|
||||||
|
// if (auto currentSubmenu = base::take(_activeSubmenu)) {
|
||||||
|
// currentSubmenu->hideMenu(true);
|
||||||
|
// }
|
||||||
|
// if (submenu) {
|
||||||
|
// auto menuTopLeft = mapFromGlobal(_menu->mapToGlobal(QPoint(0, 0)));
|
||||||
|
// auto menuBottomRight = mapFromGlobal(_menu->mapToGlobal(QPoint(_menu->width(), _menu->height())));
|
||||||
|
// QPoint p(menuTopLeft.x() + (rtl() ? (width() - menuBottomRight.x()) : menuBottomRight.x()), menuTopLeft.y() + actionTop);
|
||||||
|
// _activeSubmenu = submenu;
|
||||||
|
// _activeSubmenu->showMenu(geometry().topLeft() + p, this, source);
|
||||||
|
//
|
||||||
|
// _menu->setChildShown(true);
|
||||||
|
// } else {
|
||||||
|
// _menu->setChildShown(false);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
void DropdownMenu::forwardKeyPress(int key) {
|
||||||
|
if (!handleKeyPress(key)) {
|
||||||
|
_menu->handleKeyPress(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DropdownMenu::handleKeyPress(int key) {
|
||||||
|
if (_activeSubmenu) {
|
||||||
|
_activeSubmenu->handleKeyPress(key);
|
||||||
|
return true;
|
||||||
|
} else if (key == Qt::Key_Escape) {
|
||||||
|
hideMenu(_parent ? true : false);
|
||||||
|
return true;
|
||||||
|
} else if (key == (rtl() ? Qt::Key_Right : Qt::Key_Left)) {
|
||||||
|
if (_parent) {
|
||||||
|
hideMenu(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DropdownMenu::handleMouseMove(QPoint globalPosition) {
|
||||||
|
if (_parent) {
|
||||||
|
_parent->forwardMouseMove(globalPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DropdownMenu::handleMousePress(QPoint globalPosition) {
|
||||||
|
if (_parent) {
|
||||||
|
_parent->forwardMousePress(globalPosition);
|
||||||
|
} else {
|
||||||
|
hideMenu();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DropdownMenu::focusOutEvent(QFocusEvent *e) {
|
||||||
|
hideMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DropdownMenu::hideEvent(QHideEvent *e) {
|
||||||
|
if (_deleteOnHide) {
|
||||||
|
if (_triggering) {
|
||||||
|
_deleteLater = true;
|
||||||
|
} else {
|
||||||
|
deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DropdownMenu::hideMenu(bool fast) {
|
||||||
|
if (isHidden()) return;
|
||||||
|
if (_parent && !isHiding()) {
|
||||||
|
_parent->childHiding(this);
|
||||||
|
}
|
||||||
|
if (fast) {
|
||||||
|
hideFast();
|
||||||
|
} else {
|
||||||
|
hideAnimated();
|
||||||
|
if (_parent) {
|
||||||
|
_parent->hideMenu();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_activeSubmenu) {
|
||||||
|
_activeSubmenu->hideMenu(fast);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DropdownMenu::childHiding(DropdownMenu *child) {
|
||||||
|
if (_activeSubmenu && _activeSubmenu == child) {
|
||||||
|
_activeSubmenu = SubmenuPointer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DropdownMenu::hideFinish() {
|
||||||
|
_menu->clearSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not ready with submenus yet.
|
||||||
|
//void DropdownMenu::deleteOnHide(bool del) {
|
||||||
|
// _deleteOnHide = del;
|
||||||
|
//}
|
||||||
|
|
||||||
|
//void DropdownMenu::popup(const QPoint &p) {
|
||||||
|
// showMenu(p, nullptr, TriggeredSource::Mouse);
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//void DropdownMenu::showMenu(const QPoint &p, DropdownMenu *parent, TriggeredSource source) {
|
||||||
|
// _parent = parent;
|
||||||
|
//
|
||||||
|
// auto menuTopLeft = mapFromGlobal(_menu->mapToGlobal(QPoint(0, 0)));
|
||||||
|
// auto w = p - QPoint(0, menuTopLeft.y());
|
||||||
|
// auto r = Sandbox::screenGeometry(p);
|
||||||
|
// if (rtl()) {
|
||||||
|
// if (w.x() - width() < r.x() - _padding.left()) {
|
||||||
|
// if (_parent && w.x() + _parent->width() - _padding.left() - _padding.right() + width() - _padding.right() <= r.x() + r.width()) {
|
||||||
|
// w.setX(w.x() + _parent->width() - _padding.left() - _padding.right());
|
||||||
|
// } else {
|
||||||
|
// w.setX(r.x() - _padding.left());
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// w.setX(w.x() - width());
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// if (w.x() + width() - _padding.right() > r.x() + r.width()) {
|
||||||
|
// if (_parent && w.x() - _parent->width() + _padding.left() + _padding.right() - width() + _padding.right() >= r.x() - _padding.left()) {
|
||||||
|
// w.setX(w.x() + _padding.left() + _padding.right() - _parent->width() - width() + _padding.left() + _padding.right());
|
||||||
|
// } else {
|
||||||
|
// w.setX(r.x() + r.width() - width() + _padding.right());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if (w.y() + height() - _padding.bottom() > r.y() + r.height()) {
|
||||||
|
// if (_parent) {
|
||||||
|
// w.setY(r.y() + r.height() - height() + _padding.bottom());
|
||||||
|
// } else {
|
||||||
|
// w.setY(p.y() - height() + _padding.bottom());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if (w.y() < r.y()) {
|
||||||
|
// w.setY(r.y());
|
||||||
|
// }
|
||||||
|
// move(w);
|
||||||
|
//
|
||||||
|
// _menu->setShowSource(source);
|
||||||
|
//}
|
||||||
|
|
||||||
|
DropdownMenu::~DropdownMenu() {
|
||||||
|
clearActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Ui
|
110
Telegram/SourceFiles/ui/widgets/dropdown_menu.h
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "styles/style_widgets.h"
|
||||||
|
#include "ui/effects/rect_shadow.h"
|
||||||
|
#include "ui/widgets/inner_dropdown.h"
|
||||||
|
#include "ui/widgets/menu.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
class DropdownMenu : public InnerDropdown {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
DropdownMenu(QWidget *parent, const style::DropdownMenu &st = st::defaultDropdownMenu);
|
||||||
|
|
||||||
|
QAction *addAction(const QString &text, const QObject *receiver, const char* member, const style::icon *icon = nullptr);
|
||||||
|
QAction *addSeparator();
|
||||||
|
void clearActions();
|
||||||
|
|
||||||
|
using Actions = Ui::Menu::Actions;
|
||||||
|
Actions &actions();
|
||||||
|
|
||||||
|
~DropdownMenu();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void focusOutEvent(QFocusEvent *e) override;
|
||||||
|
void hideEvent(QHideEvent *e) override;
|
||||||
|
|
||||||
|
void keyPressEvent(QKeyEvent *e) override {
|
||||||
|
forwardKeyPress(e->key());
|
||||||
|
}
|
||||||
|
void mouseMoveEvent(QMouseEvent *e) override {
|
||||||
|
forwardMouseMove(e->globalPos());
|
||||||
|
}
|
||||||
|
void mousePressEvent(QMouseEvent *e) override {
|
||||||
|
forwardMousePress(e->globalPos());
|
||||||
|
}
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onHidden() {
|
||||||
|
hideFinish();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Not ready with submenus yet.
|
||||||
|
DropdownMenu(QWidget *parent, QMenu *menu, const style::DropdownMenu &st = st::defaultDropdownMenu);
|
||||||
|
void deleteOnHide(bool del);
|
||||||
|
void popup(const QPoint &p);
|
||||||
|
void hideMenu(bool fast = false);
|
||||||
|
|
||||||
|
void childHiding(DropdownMenu *child);
|
||||||
|
|
||||||
|
void init();
|
||||||
|
void hideFinish();
|
||||||
|
|
||||||
|
using TriggeredSource = Ui::Menu::TriggeredSource;
|
||||||
|
void handleActivated(QAction *action, int actionTop, TriggeredSource source);
|
||||||
|
void handleTriggered(QAction *action, int actionTop, TriggeredSource source);
|
||||||
|
void forwardKeyPress(int key);
|
||||||
|
bool handleKeyPress(int key);
|
||||||
|
void forwardMouseMove(QPoint globalPosition) {
|
||||||
|
_menu->handleMouseMove(globalPosition);
|
||||||
|
}
|
||||||
|
void handleMouseMove(QPoint globalPosition);
|
||||||
|
void forwardMousePress(QPoint globalPosition) {
|
||||||
|
_menu->handleMousePress(globalPosition);
|
||||||
|
}
|
||||||
|
void handleMousePress(QPoint globalPosition);
|
||||||
|
|
||||||
|
using SubmenuPointer = QPointer<DropdownMenu>;
|
||||||
|
bool popupSubmenuFromAction(QAction *action, int actionTop, TriggeredSource source);
|
||||||
|
void popupSubmenu(SubmenuPointer submenu, int actionTop, TriggeredSource source);
|
||||||
|
void showMenu(const QPoint &p, DropdownMenu *parent, TriggeredSource source);
|
||||||
|
|
||||||
|
const style::DropdownMenu &_st;
|
||||||
|
|
||||||
|
ChildWidget<Ui::Menu> _menu;
|
||||||
|
|
||||||
|
// Not ready with submenus yet.
|
||||||
|
//using Submenus = QMap<QAction*, SubmenuPointer>;
|
||||||
|
//Submenus _submenus;
|
||||||
|
|
||||||
|
DropdownMenu *_parent = nullptr;
|
||||||
|
|
||||||
|
SubmenuPointer _activeSubmenu;
|
||||||
|
|
||||||
|
bool _deleteOnHide = false;
|
||||||
|
bool _triggering = false;
|
||||||
|
bool _deleteLater = false;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Ui
|
|
@ -19,7 +19,7 @@ Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
*/
|
*/
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "ui/inner_dropdown.h"
|
#include "ui/widgets/inner_dropdown.h"
|
||||||
|
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "ui/scrollarea.h"
|
#include "ui/scrollarea.h"
|
||||||
|
@ -27,12 +27,12 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
|
||||||
InnerDropdown::InnerDropdown(QWidget *parent, const style::InnerDropdown &st, const style::flatScroll &scrollSt) : TWidget(parent)
|
InnerDropdown::InnerDropdown(QWidget *parent, const style::InnerDropdown &st) : TWidget(parent)
|
||||||
, _st(st)
|
, _st(st)
|
||||||
, _shadow(_st.shadow)
|
, _shadow(_st.shadow)
|
||||||
, _scroll(this, scrollSt) {
|
, _scroll(this, _st.scroll) {
|
||||||
_hideTimer.setSingleShot(true);
|
_hideTimer.setSingleShot(true);
|
||||||
connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(onHideStart()));
|
connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(onHideAnimated()));
|
||||||
|
|
||||||
connect(_scroll, SIGNAL(scrolled()), this, SLOT(onScroll()));
|
connect(_scroll, SIGNAL(scrolled()), this, SLOT(onScroll()));
|
||||||
|
|
||||||
|
@ -43,9 +43,9 @@ InnerDropdown::InnerDropdown(QWidget *parent, const style::InnerDropdown &st, co
|
||||||
hide();
|
hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerDropdown::setOwnedWidget(ScrolledWidget *widget) {
|
void InnerDropdown::setOwnedWidget(TWidget *widget) {
|
||||||
auto container = new internal::Container(_scroll, widget, _st);
|
auto container = new Container(_scroll, widget, _st);
|
||||||
connect(container, SIGNAL(heightUpdated()), this, SLOT(onWidgetHeightUpdated()));
|
connect(widget, SIGNAL(heightUpdated()), this, SLOT(onWidgetHeightUpdated()));
|
||||||
_scroll->setOwnedWidget(container);
|
_scroll->setOwnedWidget(container);
|
||||||
container->resizeToWidth(_scroll->width());
|
container->resizeToWidth(_scroll->width());
|
||||||
container->moveToLeft(0, 0);
|
container->moveToLeft(0, 0);
|
||||||
|
@ -55,23 +55,22 @@ void InnerDropdown::setOwnedWidget(ScrolledWidget *widget) {
|
||||||
|
|
||||||
void InnerDropdown::setMaxHeight(int newMaxHeight) {
|
void InnerDropdown::setMaxHeight(int newMaxHeight) {
|
||||||
_maxHeight = newMaxHeight;
|
_maxHeight = newMaxHeight;
|
||||||
updateHeight();
|
resizeToContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerDropdown::onWidgetHeightUpdated() {
|
void InnerDropdown::resizeToContent() {
|
||||||
updateHeight();
|
auto newWidth = _st.padding.left() + _st.scrollMargin.left() + _st.scrollMargin.right() + _st.padding.right();
|
||||||
}
|
auto newHeight = _st.padding.top() + _st.scrollMargin.top() + _st.scrollMargin.bottom() + _st.padding.bottom();
|
||||||
|
if (auto widget = static_cast<Container*>(_scroll->widget())) {
|
||||||
void InnerDropdown::updateHeight() {
|
widget->resizeToContent();
|
||||||
int newHeight = _st.padding.top() + _st.scrollMargin.top() + _st.scrollMargin.bottom() + _st.padding.bottom();
|
newWidth += widget->width();
|
||||||
if (auto widget = static_cast<ScrolledWidget*>(_scroll->widget())) {
|
|
||||||
newHeight += widget->height();
|
newHeight += widget->height();
|
||||||
}
|
}
|
||||||
if (_maxHeight > 0) {
|
if (_maxHeight > 0) {
|
||||||
accumulate_min(newHeight, _maxHeight);
|
accumulate_min(newHeight, _maxHeight);
|
||||||
}
|
}
|
||||||
if (newHeight != height()) {
|
if (newWidth != width() || newHeight != height()) {
|
||||||
resize(width(), newHeight);
|
resize(newWidth, newHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,14 +82,14 @@ void InnerDropdown::onWindowActiveChanged() {
|
||||||
|
|
||||||
void InnerDropdown::resizeEvent(QResizeEvent *e) {
|
void InnerDropdown::resizeEvent(QResizeEvent *e) {
|
||||||
_scroll->setGeometry(rect().marginsRemoved(_st.padding).marginsRemoved(_st.scrollMargin));
|
_scroll->setGeometry(rect().marginsRemoved(_st.padding).marginsRemoved(_st.scrollMargin));
|
||||||
if (auto widget = static_cast<ScrolledWidget*>(_scroll->widget())) {
|
if (auto widget = static_cast<TWidget*>(_scroll->widget())) {
|
||||||
widget->resizeToWidth(_scroll->width());
|
widget->resizeToWidth(_scroll->width());
|
||||||
onScroll();
|
onScroll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerDropdown::onScroll() {
|
void InnerDropdown::onScroll() {
|
||||||
if (auto widget = static_cast<ScrolledWidget*>(_scroll->widget())) {
|
if (auto widget = static_cast<TWidget*>(_scroll->widget())) {
|
||||||
int visibleTop = _scroll->scrollTop();
|
int visibleTop = _scroll->scrollTop();
|
||||||
int visibleBottom = visibleTop + _scroll->height();
|
int visibleBottom = visibleTop + _scroll->height();
|
||||||
widget->setVisibleTopBottom(visibleTop, visibleBottom);
|
widget->setVisibleTopBottom(visibleTop, visibleBottom);
|
||||||
|
@ -103,9 +102,9 @@ void InnerDropdown::paintEvent(QPaintEvent *e) {
|
||||||
if (!_cache.isNull()) {
|
if (!_cache.isNull()) {
|
||||||
bool animating = _a_appearance.animating(getms());
|
bool animating = _a_appearance.animating(getms());
|
||||||
if (animating) {
|
if (animating) {
|
||||||
p.setOpacity(_a_appearance.current(_hiding));
|
p.setOpacity(_a_appearance.current(_hiding ? 0. : 1.));
|
||||||
} else if (_hiding) {
|
} else if (_hiding || isHidden()) {
|
||||||
hidingFinished();
|
hideFinished();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
p.drawPixmap(0, 0, _cache);
|
p.drawPixmap(0, 0, _cache);
|
||||||
|
@ -117,20 +116,19 @@ void InnerDropdown::paintEvent(QPaintEvent *e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw shadow
|
// draw shadow
|
||||||
QRect shadowedRect = rect().marginsRemoved(_st.padding);
|
auto shadowedRect = rect().marginsRemoved(_st.padding);
|
||||||
_shadow.paint(p, shadowedRect, _st.shadowShift);
|
_shadow.paint(p, shadowedRect, _st.shadowShift);
|
||||||
p.fillRect(shadowedRect, st::windowBg);
|
p.fillRect(shadowedRect, st::windowBg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerDropdown::enterEvent(QEvent *e) {
|
void InnerDropdown::enterEvent(QEvent *e) {
|
||||||
_hideTimer.stop();
|
showAnimated();
|
||||||
if (_hiding) showingStarted();
|
|
||||||
return TWidget::enterEvent(e);
|
return TWidget::enterEvent(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerDropdown::leaveEvent(QEvent *e) {
|
void InnerDropdown::leaveEvent(QEvent *e) {
|
||||||
if (_a_appearance.animating(getms())) {
|
if (_a_appearance.animating(getms())) {
|
||||||
onHideStart();
|
hideAnimated();
|
||||||
} else {
|
} else {
|
||||||
_hideTimer.start(300);
|
_hideTimer.start(300);
|
||||||
}
|
}
|
||||||
|
@ -138,25 +136,43 @@ void InnerDropdown::leaveEvent(QEvent *e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerDropdown::otherEnter() {
|
void InnerDropdown::otherEnter() {
|
||||||
_hideTimer.stop();
|
showAnimated();
|
||||||
showingStarted();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerDropdown::otherLeave() {
|
void InnerDropdown::otherLeave() {
|
||||||
if (_a_appearance.animating(getms())) {
|
if (_a_appearance.animating(getms())) {
|
||||||
onHideStart();
|
hideAnimated();
|
||||||
} else {
|
} else {
|
||||||
_hideTimer.start(0);
|
_hideTimer.start(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerDropdown::onHideStart() {
|
void InnerDropdown::showAnimated() {
|
||||||
|
_hideTimer.stop();
|
||||||
|
showStarted();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InnerDropdown::hideAnimated(HideOption option) {
|
||||||
|
if (isHidden()) return;
|
||||||
|
if (option == HideOption::IgnoreShow) {
|
||||||
|
_ignoreShowEvents = true;
|
||||||
|
}
|
||||||
if (_hiding) return;
|
if (_hiding) return;
|
||||||
|
|
||||||
|
_hideTimer.stop();
|
||||||
_hiding = true;
|
_hiding = true;
|
||||||
startAnimation();
|
startAnimation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InnerDropdown::hideFast() {
|
||||||
|
if (isHidden()) return;
|
||||||
|
|
||||||
|
_hideTimer.stop();
|
||||||
|
_hiding = false;
|
||||||
|
_a_appearance.finish();
|
||||||
|
hideFinished();
|
||||||
|
}
|
||||||
|
|
||||||
void InnerDropdown::startAnimation() {
|
void InnerDropdown::startAnimation() {
|
||||||
auto from = _hiding ? 1. : 0.;
|
auto from = _hiding ? 1. : 0.;
|
||||||
auto to = _hiding ? 0. : 1.;
|
auto to = _hiding ? 0. : 1.;
|
||||||
|
@ -168,13 +184,17 @@ void InnerDropdown::startAnimation() {
|
||||||
_a_appearance.start([this] { repaintCallback(); }, from, to, _st.duration);
|
_a_appearance.start([this] { repaintCallback(); }, from, to, _st.duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerDropdown::hidingFinished() {
|
void InnerDropdown::hideFinished() {
|
||||||
hide();
|
_cache = QPixmap();
|
||||||
// showChildren();
|
_ignoreShowEvents = false;
|
||||||
emit hidden();
|
if (!isHidden()) {
|
||||||
|
emit beforeHidden();
|
||||||
|
hide();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerDropdown::showingStarted() {
|
void InnerDropdown::showStarted() {
|
||||||
|
if (_ignoreShowEvents) return;
|
||||||
if (isHidden()) {
|
if (isHidden()) {
|
||||||
show();
|
show();
|
||||||
} else if (!_hiding) {
|
} else if (!_hiding) {
|
||||||
|
@ -188,7 +208,7 @@ void InnerDropdown::repaintCallback() {
|
||||||
update();
|
update();
|
||||||
if (!_a_appearance.animating() && _hiding) {
|
if (!_a_appearance.animating() && _hiding) {
|
||||||
_hiding = false;
|
_hiding = false;
|
||||||
hidingFinished();
|
hideFinished();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,35 +227,45 @@ bool InnerDropdown::eventFilter(QObject *obj, QEvent *e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace internal {
|
int InnerDropdown::resizeGetHeight(int newWidth) {
|
||||||
|
auto newHeight = _st.padding.top() + _st.scrollMargin.top() + _st.scrollMargin.bottom() + _st.padding.bottom();
|
||||||
Container::Container(QWidget *parent, ScrolledWidget *child, const style::InnerDropdown &st) : ScrolledWidget(parent), _st(st) {
|
if (auto widget = static_cast<TWidget*>(_scroll->widget())) {
|
||||||
child->setParent(this);
|
widget->resizeToWidth(newWidth - _st.padding.left() - _st.padding.right() - _st.scrollMargin.left() - _st.scrollMargin.right());
|
||||||
child->moveToLeft(_st.scrollPadding.left(), _st.scrollPadding.top());
|
newHeight += widget->height();
|
||||||
connect(child, SIGNAL(heightUpdated()), this, SLOT(onHeightUpdate()));
|
}
|
||||||
|
if (_maxHeight > 0) {
|
||||||
|
accumulate_min(newHeight, _maxHeight);
|
||||||
|
}
|
||||||
|
return newHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Container::setVisibleTopBottom(int visibleTop, int visibleBottom) {
|
InnerDropdown::Container::Container(QWidget *parent, TWidget *child, const style::InnerDropdown &st) : TWidget(parent), _st(st) {
|
||||||
if (auto child = static_cast<ScrolledWidget*>(children().front())) {
|
child->setParent(this);
|
||||||
|
child->moveToLeft(_st.scrollPadding.left(), _st.scrollPadding.top());
|
||||||
|
}
|
||||||
|
|
||||||
|
void InnerDropdown::Container::setVisibleTopBottom(int visibleTop, int visibleBottom) {
|
||||||
|
if (auto child = static_cast<TWidget*>(children().front())) {
|
||||||
child->setVisibleTopBottom(visibleTop - _st.scrollPadding.top(), visibleBottom - _st.scrollPadding.top());
|
child->setVisibleTopBottom(visibleTop - _st.scrollPadding.top(), visibleBottom - _st.scrollPadding.top());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Container::onHeightUpdate() {
|
void InnerDropdown::Container::resizeToContent() {
|
||||||
int newHeight = _st.scrollPadding.top() + _st.scrollPadding.bottom();
|
auto newWidth = _st.scrollPadding.top() + _st.scrollPadding.bottom();
|
||||||
if (auto child = static_cast<ScrolledWidget*>(children().front())) {
|
auto newHeight = _st.scrollPadding.top() + _st.scrollPadding.bottom();
|
||||||
|
if (auto child = static_cast<TWidget*>(children().front())) {
|
||||||
|
newWidth += child->width();
|
||||||
newHeight += child->height();
|
newHeight += child->height();
|
||||||
}
|
}
|
||||||
if (newHeight != height()) {
|
if (newWidth != width() || newHeight != height()) {
|
||||||
resize(width(), newHeight);
|
resize(newWidth, newHeight);
|
||||||
emit heightUpdated();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int Container::resizeGetHeight(int newWidth) {
|
int InnerDropdown::Container::resizeGetHeight(int newWidth) {
|
||||||
int innerWidth = newWidth - _st.scrollPadding.left() - _st.scrollPadding.right();
|
int innerWidth = newWidth - _st.scrollPadding.left() - _st.scrollPadding.right();
|
||||||
int result = _st.scrollPadding.top() + _st.scrollPadding.bottom();
|
int result = _st.scrollPadding.top() + _st.scrollPadding.bottom();
|
||||||
if (auto child = static_cast<ScrolledWidget*>(children().front())) {
|
if (auto child = static_cast<TWidget*>(children().front())) {
|
||||||
child->resizeToWidth(innerWidth);
|
child->resizeToWidth(innerWidth);
|
||||||
child->moveToLeft(_st.scrollPadding.left(), _st.scrollPadding.top());
|
child->moveToLeft(_st.scrollPadding.left(), _st.scrollPadding.top());
|
||||||
result += child->height();
|
result += child->height();
|
||||||
|
@ -243,5 +273,4 @@ int Container::resizeGetHeight(int newWidth) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace internal
|
|
||||||
} // namespace Ui
|
} // namespace Ui
|
|
@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ui/effects/rect_shadow.h"
|
#include "ui/effects/rect_shadow.h"
|
||||||
|
#include "styles/style_widgets.h"
|
||||||
|
|
||||||
class ScrollArea;
|
class ScrollArea;
|
||||||
|
|
||||||
|
@ -30,9 +31,9 @@ class InnerDropdown : public TWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
InnerDropdown(QWidget *parent, const style::InnerDropdown &st = st::defaultInnerDropdown, const style::flatScroll &scrollSt = st::scrollDef);
|
InnerDropdown(QWidget *parent, const style::InnerDropdown &st = st::defaultInnerDropdown);
|
||||||
|
|
||||||
void setOwnedWidget(ScrolledWidget *widget);
|
void setOwnedWidget(TWidget *widget);
|
||||||
|
|
||||||
bool overlaps(const QRect &globalRect) {
|
bool overlaps(const QRect &globalRect) {
|
||||||
if (isHidden() || _a_appearance.animating()) return false;
|
if (isHidden() || _a_appearance.animating()) return false;
|
||||||
|
@ -41,32 +42,52 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void setMaxHeight(int newMaxHeight);
|
void setMaxHeight(int newMaxHeight);
|
||||||
|
void resizeToContent();
|
||||||
|
|
||||||
void otherEnter();
|
void otherEnter();
|
||||||
void otherLeave();
|
void otherLeave();
|
||||||
|
void showFast();
|
||||||
|
void hideFast();
|
||||||
|
|
||||||
|
bool isHiding() const {
|
||||||
|
return _hiding && _a_appearance.animating();
|
||||||
|
}
|
||||||
|
|
||||||
|
void showAnimated();
|
||||||
|
enum class HideOption {
|
||||||
|
Default,
|
||||||
|
IgnoreShow,
|
||||||
|
};
|
||||||
|
void hideAnimated(HideOption option = HideOption::Default);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void beforeHidden();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
void paintEvent(QPaintEvent *e) override;
|
void paintEvent(QPaintEvent *e) override;
|
||||||
void enterEvent(QEvent *e) override;
|
void enterEvent(QEvent *e) override;
|
||||||
void leaveEvent(QEvent *e) override;
|
void leaveEvent(QEvent *e) override;
|
||||||
|
|
||||||
bool eventFilter(QObject *obj, QEvent *e) override;
|
bool eventFilter(QObject *obj, QEvent *e) override;
|
||||||
|
|
||||||
signals:
|
int resizeGetHeight(int newWidth) override;
|
||||||
void hidden();
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onHideStart();
|
void onHideAnimated() {
|
||||||
|
hideAnimated();
|
||||||
|
}
|
||||||
void onWindowActiveChanged();
|
void onWindowActiveChanged();
|
||||||
void onScroll();
|
void onScroll();
|
||||||
void onWidgetHeightUpdated();
|
void onWidgetHeightUpdated() {
|
||||||
|
resizeToContent();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
class Container;
|
||||||
void repaintCallback();
|
void repaintCallback();
|
||||||
|
|
||||||
void hidingFinished();
|
void hideFinished();
|
||||||
void showingStarted();
|
void showStarted();
|
||||||
|
|
||||||
void startAnimation();
|
void startAnimation();
|
||||||
|
|
||||||
|
@ -80,6 +101,7 @@ private:
|
||||||
FloatAnimation _a_appearance;
|
FloatAnimation _a_appearance;
|
||||||
|
|
||||||
QTimer _hideTimer;
|
QTimer _hideTimer;
|
||||||
|
bool _ignoreShowEvents = false;
|
||||||
|
|
||||||
RectShadow _shadow;
|
RectShadow _shadow;
|
||||||
ChildWidget<ScrollArea> _scroll;
|
ChildWidget<ScrollArea> _scroll;
|
||||||
|
@ -88,17 +110,12 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace internal {
|
class InnerDropdown::Container : public TWidget {
|
||||||
|
|
||||||
class Container : public ScrolledWidget {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Container(QWidget *parent, ScrolledWidget *child, const style::InnerDropdown &st);
|
Container(QWidget *parent, TWidget *child, const style::InnerDropdown &st);
|
||||||
void setVisibleTopBottom(int visibleTop, int visibleBottom) override;
|
void setVisibleTopBottom(int visibleTop, int visibleBottom) override;
|
||||||
|
|
||||||
private slots:
|
void resizeToContent();
|
||||||
void onHeightUpdate();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int resizeGetHeight(int newWidth) override;
|
int resizeGetHeight(int newWidth) override;
|
||||||
|
@ -108,5 +125,4 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace internal
|
|
||||||
} // namespace Ui
|
} // namespace Ui
|
343
Telegram/SourceFiles/ui/widgets/menu.cpp
Normal file
|
@ -0,0 +1,343 @@
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "ui/widgets/menu.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
Menu::Menu(QWidget *parent, const style::Menu &st) : TWidget(parent)
|
||||||
|
, _st(st)
|
||||||
|
, _itemHeight(_st.itemPadding.top() + _st.itemFont->height + _st.itemPadding.bottom())
|
||||||
|
, _separatorHeight(_st.separatorPadding.top() + _st.separatorWidth + _st.separatorPadding.bottom()) {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
Menu::Menu(QWidget *parent, QMenu *menu, const style::Menu &st) : TWidget(parent)
|
||||||
|
, _st(st)
|
||||||
|
, _wappedMenu(menu)
|
||||||
|
, _itemHeight(_st.itemPadding.top() + _st.itemFont->height + _st.itemPadding.bottom())
|
||||||
|
, _separatorHeight(_st.separatorPadding.top() + _st.separatorWidth + _st.separatorPadding.bottom()) {
|
||||||
|
init();
|
||||||
|
|
||||||
|
_wappedMenu->setParent(this);
|
||||||
|
for (auto action : _wappedMenu->actions()) {
|
||||||
|
addAction(action);
|
||||||
|
}
|
||||||
|
_wappedMenu->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Menu::init() {
|
||||||
|
resize(_st.widthMin, _st.skip * 2);
|
||||||
|
|
||||||
|
setMouseTracking(true);
|
||||||
|
|
||||||
|
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
QAction *Menu::addAction(const QString &text, const QObject *receiver, const char* member, const style::icon *icon) {
|
||||||
|
auto action = new QAction(text, this);
|
||||||
|
connect(action, SIGNAL(triggered(bool)), receiver, member, Qt::QueuedConnection);
|
||||||
|
return addAction(action, icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
QAction *Menu::addAction(QAction *action, const style::icon *icon) {
|
||||||
|
connect(action, SIGNAL(changed()), this, SLOT(actionChanged()));
|
||||||
|
_actions.push_back(action);
|
||||||
|
|
||||||
|
ActionData data;
|
||||||
|
data.icon = icon;
|
||||||
|
data.hasSubmenu = (action->menu() != nullptr);
|
||||||
|
_actionsData.push_back(data);
|
||||||
|
|
||||||
|
auto newWidth = qMax(width(), _st.widthMin);
|
||||||
|
newWidth = processAction(action, _actions.size() - 1, newWidth);
|
||||||
|
auto newHeight = height() + (action->isSeparator() ? _separatorHeight : _itemHeight);
|
||||||
|
resize(newWidth, newHeight);
|
||||||
|
if (_resizedCallback) {
|
||||||
|
_resizedCallback();
|
||||||
|
}
|
||||||
|
update();
|
||||||
|
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
QAction *Menu::addSeparator() {
|
||||||
|
auto separator = new QAction(this);
|
||||||
|
separator->setSeparator(true);
|
||||||
|
return addAction(separator);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Menu::clearActions() {
|
||||||
|
_actionsData.clear();
|
||||||
|
for (auto action : base::take(_actions)) {
|
||||||
|
if (action->parent() == this) {
|
||||||
|
delete action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resize(_st.widthMin, _st.skip * 2);
|
||||||
|
if (_resizedCallback) {
|
||||||
|
_resizedCallback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int Menu::processAction(QAction *action, int index, int width) {
|
||||||
|
auto &data = _actionsData[index];
|
||||||
|
if (action->isSeparator() || action->text().isEmpty()) {
|
||||||
|
data.text = data.shortcut = QString();
|
||||||
|
} else {
|
||||||
|
auto actionTextParts = action->text().split('\t');
|
||||||
|
auto actionText = actionTextParts.empty() ? QString() : actionTextParts[0];
|
||||||
|
auto actionShortcut = (actionTextParts.size() > 1) ? actionTextParts[1] : QString();
|
||||||
|
int textw = _st.itemFont->width(actionText);
|
||||||
|
int goodw = _st.itemPadding.left() + textw + _st.itemPadding.right();
|
||||||
|
if (data.hasSubmenu) {
|
||||||
|
goodw += _st.itemPadding.left() + _st.arrow.width();
|
||||||
|
} else if (!actionShortcut.isEmpty()) {
|
||||||
|
goodw += _st.itemPadding.left() + _st.itemFont->width(actionShortcut);
|
||||||
|
}
|
||||||
|
width = snap(goodw, width, _st.widthMax);
|
||||||
|
data.text = (width < goodw) ? _st.itemFont->elided(actionText, width - (goodw - textw)) : actionText;
|
||||||
|
data.shortcut = actionShortcut;
|
||||||
|
}
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Menu::setShowSource(TriggeredSource source) {
|
||||||
|
_mouseSelection = (source == TriggeredSource::Mouse);
|
||||||
|
setSelected((source == TriggeredSource::Mouse || _actions.isEmpty()) ? -1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Menu::Actions &Menu::actions() {
|
||||||
|
return _actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Menu::actionChanged() {
|
||||||
|
int newWidth = _st.widthMin;
|
||||||
|
for (int i = 0, count = _actions.size(); i != count; ++i) {
|
||||||
|
newWidth = processAction(_actions[i], i, newWidth);
|
||||||
|
}
|
||||||
|
if (newWidth != width()) {
|
||||||
|
resize(newWidth, height());
|
||||||
|
if (_resizedCallback) {
|
||||||
|
_resizedCallback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Menu::paintEvent(QPaintEvent *e) {
|
||||||
|
Painter p(this);
|
||||||
|
|
||||||
|
auto clip = e->rect();
|
||||||
|
|
||||||
|
auto topskip = QRect(0, 0, width(), _st.skip);
|
||||||
|
auto bottomskip = QRect(0, height() - _st.skip, width(), _st.skip);
|
||||||
|
if (clip.intersects(topskip)) p.fillRect(clip.intersected(topskip), _st.itemBg);
|
||||||
|
if (clip.intersects(bottomskip)) p.fillRect(clip.intersected(bottomskip), _st.itemBg);
|
||||||
|
|
||||||
|
int top = _st.skip;
|
||||||
|
p.translate(0, top);
|
||||||
|
p.setFont(_st.itemFont);
|
||||||
|
for (int i = 0, count = _actions.size(); i != count; ++i) {
|
||||||
|
if (clip.top() + clip.height() <= top) break;
|
||||||
|
|
||||||
|
auto action = _actions[i];
|
||||||
|
auto &data = _actionsData[i];
|
||||||
|
auto actionHeight = action->isSeparator() ? _separatorHeight : _itemHeight;
|
||||||
|
top += actionHeight;
|
||||||
|
if (clip.top() < top) {
|
||||||
|
if (action->isSeparator()) {
|
||||||
|
p.fillRect(0, 0, width(), actionHeight, _st.itemBg);
|
||||||
|
p.fillRect(_st.separatorPadding.left(), _st.separatorPadding.top(), width() - _st.separatorPadding.left() - _st.separatorPadding.right(), _st.separatorWidth, _st.separatorFg);
|
||||||
|
} else {
|
||||||
|
auto enabled = action->isEnabled(), selected = (i == _selected && enabled);
|
||||||
|
p.fillRect(0, 0, width(), actionHeight, selected ? _st.itemBgOver : _st.itemBg);
|
||||||
|
if (data.icon) {
|
||||||
|
p.setOpacity(selected ? _st.itemIconOverOpacity : _st.itemIconOpacity);
|
||||||
|
data.icon->paint(p, _st.itemIconPosition, width());
|
||||||
|
p.setOpacity(1.);
|
||||||
|
}
|
||||||
|
p.setPen(selected ? _st.itemFgOver : (enabled ? _st.itemFg : _st.itemFgDisabled));
|
||||||
|
p.drawTextLeft(_st.itemPadding.left(), _st.itemPadding.top(), width(), data.text);
|
||||||
|
if (data.hasSubmenu) {
|
||||||
|
_st.arrow.paint(p, width() - _st.itemPadding.right() - _st.arrow.width(), (_itemHeight - _st.arrow.height()) / 2, width());
|
||||||
|
} else if (!data.shortcut.isEmpty()) {
|
||||||
|
p.setPen(selected ? _st.itemFgShortcutOver : (enabled ? _st.itemFgShortcut : _st.itemFgShortcutDisabled));
|
||||||
|
p.drawTextRight(_st.itemPadding.right(), _st.itemPadding.top(), width(), data.shortcut);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.translate(0, actionHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Menu::updateSelected(QPoint globalPosition) {
|
||||||
|
if (!_mouseSelection) return;
|
||||||
|
|
||||||
|
auto p = mapFromGlobal(globalPosition) - QPoint(0, _st.skip);
|
||||||
|
auto selected = -1, top = 0;
|
||||||
|
while (top <= p.y() && ++selected < _actions.size()) {
|
||||||
|
top += _actions[selected]->isSeparator() ? _separatorHeight : _itemHeight;
|
||||||
|
}
|
||||||
|
setSelected((selected >= 0 && selected < _actions.size() && _actions[selected]->isEnabled() && !_actions[selected]->isSeparator()) ? selected : -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Menu::itemPressed(TriggeredSource source) {
|
||||||
|
if (source == TriggeredSource::Mouse && !_mouseSelection) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_selected >= 0 && _selected < _actions.size() && _actions[_selected]->isEnabled()) {
|
||||||
|
if (_triggeredCallback) {
|
||||||
|
auto actionTop = _st.skip + itemTop(_selected);
|
||||||
|
_triggeredCallback(_actions[_selected], actionTop, source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Menu::keyPressEvent(QKeyEvent *e) {
|
||||||
|
auto key = e->key();
|
||||||
|
if (!_keyPressDelegate || !_keyPressDelegate(key)) {
|
||||||
|
handleKeyPress(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Menu::handleKeyPress(int key) {
|
||||||
|
if (key == Qt::Key_Enter || key == Qt::Key_Return) {
|
||||||
|
itemPressed(TriggeredSource::Keyboard);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (key == (rtl() ? Qt::Key_Left : Qt::Key_Right)) {
|
||||||
|
if (_selected >= 0 && _actionsData[_selected].hasSubmenu) {
|
||||||
|
itemPressed(TriggeredSource::Keyboard);
|
||||||
|
return;
|
||||||
|
} else if (_selected < 0 && !_actions.isEmpty()) {
|
||||||
|
_mouseSelection = false;
|
||||||
|
setSelected(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((key != Qt::Key_Up && key != Qt::Key_Down) || _actions.size() < 1) return;
|
||||||
|
|
||||||
|
auto delta = (key == Qt::Key_Down ? 1 : -1), start = _selected;
|
||||||
|
if (start < 0 || start >= _actions.size()) {
|
||||||
|
start = (delta > 0) ? (_actions.size() - 1) : 0;
|
||||||
|
}
|
||||||
|
auto newSelected = start;
|
||||||
|
do {
|
||||||
|
newSelected += delta;
|
||||||
|
if (newSelected < 0) {
|
||||||
|
newSelected += _actions.size();
|
||||||
|
} else if (newSelected >= _actions.size()) {
|
||||||
|
newSelected -= _actions.size();
|
||||||
|
}
|
||||||
|
} while (newSelected != start && (!_actions.at(newSelected)->isEnabled() || _actions.at(newSelected)->isSeparator()));
|
||||||
|
|
||||||
|
if (_actions.at(newSelected)->isEnabled() && !_actions.at(newSelected)->isSeparator()) {
|
||||||
|
_mouseSelection = false;
|
||||||
|
setSelected(newSelected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Menu::clearSelection() {
|
||||||
|
_mouseSelection = false;
|
||||||
|
setSelected(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Menu::clearMouseSelection() {
|
||||||
|
if (_mouseSelection && !_childShown) {
|
||||||
|
clearSelection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Menu::enterEvent(QEvent *e) {
|
||||||
|
QPoint mouse = QCursor::pos();
|
||||||
|
if (!rect().marginsRemoved(QMargins(0, _st.skip, 0, _st.skip)).contains(mapFromGlobal(mouse))) {
|
||||||
|
clearMouseSelection();
|
||||||
|
}
|
||||||
|
return TWidget::enterEvent(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Menu::leaveEvent(QEvent *e) {
|
||||||
|
clearMouseSelection();
|
||||||
|
return TWidget::leaveEvent(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Menu::setSelected(int selected) {
|
||||||
|
if (selected >= _actions.size()) {
|
||||||
|
selected = -1;
|
||||||
|
}
|
||||||
|
if (_selected != selected) {
|
||||||
|
updateSelectedItem();
|
||||||
|
_selected = selected;
|
||||||
|
updateSelectedItem();
|
||||||
|
if (_activatedCallback) {
|
||||||
|
auto actionTop = _st.skip + itemTop(_selected);
|
||||||
|
auto source = _mouseSelection ? TriggeredSource::Mouse : TriggeredSource::Keyboard;
|
||||||
|
_activatedCallback((_selected >= 0) ? _actions[_selected] : nullptr, actionTop, source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int Menu::itemTop(int index) {
|
||||||
|
if (index > _actions.size()) {
|
||||||
|
index = _actions.size();
|
||||||
|
}
|
||||||
|
int top = 0;
|
||||||
|
for (int i = 0; i < index; ++i) {
|
||||||
|
top += _actions.at(i)->isSeparator() ? _separatorHeight : _itemHeight;
|
||||||
|
}
|
||||||
|
return top;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Menu::updateSelectedItem() {
|
||||||
|
if (_selected >= 0) {
|
||||||
|
update(0, _st.skip + itemTop(_selected), width(), _actions.at(_selected)->isSeparator() ? _separatorHeight : _itemHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Menu::mouseMoveEvent(QMouseEvent *e) {
|
||||||
|
handleMouseMove(e->globalPos());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Menu::handleMouseMove(QPoint globalPosition) {
|
||||||
|
auto inner = rect().marginsRemoved(QMargins(0, _st.skip, 0, _st.skip));
|
||||||
|
auto localPosition = mapFromGlobal(globalPosition);
|
||||||
|
if (inner.contains(localPosition)) {
|
||||||
|
_mouseSelection = true;
|
||||||
|
updateSelected(globalPosition);
|
||||||
|
} else {
|
||||||
|
clearMouseSelection();
|
||||||
|
if (_mouseMoveDelegate) {
|
||||||
|
_mouseMoveDelegate(globalPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Menu::mousePressEvent(QMouseEvent *e) {
|
||||||
|
handleMousePress(e->globalPos());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Menu::handleMousePress(QPoint globalPosition) {
|
||||||
|
handleMouseMove(globalPosition);
|
||||||
|
if (rect().contains(mapFromGlobal(globalPosition))) {
|
||||||
|
itemPressed(TriggeredSource::Mouse);
|
||||||
|
} else if (_mousePressDelegate) {
|
||||||
|
_mousePressDelegate(globalPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Ui
|
134
Telegram/SourceFiles/ui/widgets/menu.h
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||||
|
|
||||||
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
It is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
In addition, as a special exception, the copyright holders give permission
|
||||||
|
to link the code of portions of this program with the OpenSSL library.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "styles/style_widgets.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
class Menu : public TWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
Menu(QWidget *parent, const style::Menu &st = st::defaultMenu);
|
||||||
|
Menu(QWidget *parent, QMenu *menu, const style::Menu &st = st::defaultMenu);
|
||||||
|
|
||||||
|
QAction *addAction(const QString &text, const QObject *receiver, const char* member, const style::icon *icon = nullptr);
|
||||||
|
QAction *addSeparator();
|
||||||
|
void clearActions();
|
||||||
|
|
||||||
|
void clearSelection();
|
||||||
|
|
||||||
|
enum class TriggeredSource {
|
||||||
|
Mouse,
|
||||||
|
Keyboard,
|
||||||
|
};
|
||||||
|
void setChildShown(bool shown) {
|
||||||
|
_childShown = shown;
|
||||||
|
}
|
||||||
|
void setShowSource(TriggeredSource source);
|
||||||
|
|
||||||
|
using Actions = QList<QAction*>;
|
||||||
|
Actions &actions();
|
||||||
|
|
||||||
|
void setResizedCallback(base::lambda_unique<void()> callback) {
|
||||||
|
_resizedCallback = std_::move(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setActivatedCallback(base::lambda_unique<void(QAction *action, int actionTop, TriggeredSource source)> callback) {
|
||||||
|
_activatedCallback = std_::move(callback);
|
||||||
|
}
|
||||||
|
void setTriggeredCallback(base::lambda_unique<void(QAction *action, int actionTop, TriggeredSource source)> callback) {
|
||||||
|
_triggeredCallback = std_::move(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setKeyPressDelegate(base::lambda_unique<bool(int key)> delegate) {
|
||||||
|
_keyPressDelegate = std_::move(delegate);
|
||||||
|
}
|
||||||
|
void handleKeyPress(int key);
|
||||||
|
|
||||||
|
void setMouseMoveDelegate(base::lambda_unique<void(QPoint globalPosition)> delegate) {
|
||||||
|
_mouseMoveDelegate = std_::move(delegate);
|
||||||
|
}
|
||||||
|
void handleMouseMove(QPoint globalPosition);
|
||||||
|
|
||||||
|
void setMousePressDelegate(base::lambda_unique<void(QPoint globalPosition)> delegate) {
|
||||||
|
_mousePressDelegate = std_::move(delegate);
|
||||||
|
}
|
||||||
|
void handleMousePress(QPoint globalPosition);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent *e) override;
|
||||||
|
void keyPressEvent(QKeyEvent *e) override;
|
||||||
|
void mouseMoveEvent(QMouseEvent *e) override;
|
||||||
|
void mousePressEvent(QMouseEvent *e) override;
|
||||||
|
void enterEvent(QEvent *e) override;
|
||||||
|
void leaveEvent(QEvent *e) override;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void actionChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateSelected(QPoint globalPosition);
|
||||||
|
void init();
|
||||||
|
|
||||||
|
// Returns the new width.
|
||||||
|
int processAction(QAction *action, int index, int width);
|
||||||
|
QAction *addAction(QAction *a, const style::icon *icon = nullptr);
|
||||||
|
|
||||||
|
void setSelected(int selected);
|
||||||
|
void clearMouseSelection();
|
||||||
|
|
||||||
|
int itemTop(int index);
|
||||||
|
void updateSelectedItem();
|
||||||
|
void itemPressed(TriggeredSource source);
|
||||||
|
|
||||||
|
const style::Menu &_st;
|
||||||
|
|
||||||
|
base::lambda_unique<void()> _resizedCallback;
|
||||||
|
base::lambda_unique<void(QAction *action, int actionTop, TriggeredSource source)> _activatedCallback;
|
||||||
|
base::lambda_unique<void(QAction *action, int actionTop, TriggeredSource source)> _triggeredCallback;
|
||||||
|
base::lambda_unique<bool(int key)> _keyPressDelegate;
|
||||||
|
base::lambda_unique<void(QPoint globalPosition)> _mouseMoveDelegate;
|
||||||
|
base::lambda_unique<void(QPoint globalPosition)> _mousePressDelegate;
|
||||||
|
|
||||||
|
struct ActionData {
|
||||||
|
bool hasSubmenu = false;
|
||||||
|
QString text;
|
||||||
|
QString shortcut;
|
||||||
|
const style::icon *icon = nullptr;
|
||||||
|
};
|
||||||
|
using ActionsData = QList<ActionData>;
|
||||||
|
|
||||||
|
QMenu *_wappedMenu = nullptr;
|
||||||
|
Actions _actions;
|
||||||
|
ActionsData _actionsData;
|
||||||
|
|
||||||
|
int _itemHeight, _separatorHeight;
|
||||||
|
|
||||||
|
bool _mouseSelection = false;
|
||||||
|
|
||||||
|
int _selected = -1;
|
||||||
|
bool _childShown = false;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Ui
|
|
@ -454,7 +454,7 @@ int MultiSelect::resizeGetHeight(int newWidth) {
|
||||||
return newHeight;
|
return newHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
MultiSelect::Inner::Inner(QWidget *parent, const style::MultiSelect &st, const QString &placeholder, ScrollCallback callback) : ScrolledWidget(parent)
|
MultiSelect::Inner::Inner(QWidget *parent, const style::MultiSelect &st, const QString &placeholder, ScrollCallback callback) : TWidget(parent)
|
||||||
, _st(st)
|
, _st(st)
|
||||||
, _scrollCallback(std_::move(callback))
|
, _scrollCallback(std_::move(callback))
|
||||||
, _field(this, _st.field, placeholder)
|
, _field(this, _st.field, placeholder)
|
||||||
|
|
|
@ -71,7 +71,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
// This class is hold in header because it requires Qt preprocessing.
|
// This class is hold in header because it requires Qt preprocessing.
|
||||||
class MultiSelect::Inner : public ScrolledWidget {
|
class MultiSelect::Inner : public TWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
340
Telegram/SourceFiles/ui/widgets/popup_menu.cpp
Normal file
|
@ -0,0 +1,340 @@
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "ui/widgets/popup_menu.h"
|
||||||
|
|
||||||
|
#include "pspecific.h"
|
||||||
|
#include "application.h"
|
||||||
|
#include "lang.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
PopupMenu::PopupMenu(const style::PopupMenu &st) : TWidget(nullptr)
|
||||||
|
, _st(st)
|
||||||
|
, _menu(this, _st.menu)
|
||||||
|
, _shadow(_st.shadow)
|
||||||
|
, a_opacity(1)
|
||||||
|
, _a_hide(animation(this, &PopupMenu::step_hide)) {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
PopupMenu::PopupMenu(QMenu *menu, const style::PopupMenu &st) : TWidget(nullptr)
|
||||||
|
, _st(st)
|
||||||
|
, _menu(this, menu, _st.menu)
|
||||||
|
, _shadow(_st.shadow)
|
||||||
|
, a_opacity(1)
|
||||||
|
, _a_hide(animation(this, &PopupMenu::step_hide)) {
|
||||||
|
init();
|
||||||
|
|
||||||
|
for (auto action : actions()) {
|
||||||
|
if (auto submenu = action->menu()) {
|
||||||
|
auto it = _submenus.insert(action, new PopupMenu(submenu, st));
|
||||||
|
it.value()->deleteOnHide(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopupMenu::init() {
|
||||||
|
_padding = _shadow.getDimensions(_st.shadowShift);
|
||||||
|
|
||||||
|
_menu->setResizedCallback([this] { handleMenuResize(); });
|
||||||
|
_menu->setActivatedCallback([this](QAction *action, int actionTop, TriggeredSource source) {
|
||||||
|
handleActivated(action, actionTop, source);
|
||||||
|
});
|
||||||
|
_menu->setTriggeredCallback([this](QAction *action, int actionTop, TriggeredSource source) {
|
||||||
|
handleTriggered(action, actionTop, source);
|
||||||
|
});
|
||||||
|
_menu->setKeyPressDelegate([this](int key) { return handleKeyPress(key); });
|
||||||
|
_menu->setMouseMoveDelegate([this](QPoint globalPosition) { handleMouseMove(globalPosition); });
|
||||||
|
_menu->setMousePressDelegate([this](QPoint globalPosition) { handleMousePress(globalPosition); });
|
||||||
|
|
||||||
|
_menu->moveToLeft(_padding.left(), _padding.top());
|
||||||
|
handleMenuResize();
|
||||||
|
|
||||||
|
setWindowFlags(Qt::WindowFlags(Qt::FramelessWindowHint) | Qt::BypassWindowManagerHint | Qt::Popup | Qt::NoDropShadowWindowHint);
|
||||||
|
setMouseTracking(true);
|
||||||
|
|
||||||
|
hide();
|
||||||
|
|
||||||
|
setAttribute(Qt::WA_NoSystemBackground, true);
|
||||||
|
setAttribute(Qt::WA_TranslucentBackground, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopupMenu::handleMenuResize() {
|
||||||
|
resize(_padding.left() + _menu->width() + _padding.right(), _padding.top() + _menu->height() + _padding.bottom());
|
||||||
|
_inner = QRect(_padding.left(), _padding.top(), width() - _padding.left() - _padding.right(), height() - _padding.top() - _padding.bottom());
|
||||||
|
}
|
||||||
|
|
||||||
|
QAction *PopupMenu::addAction(const QString &text, const QObject *receiver, const char* member, const style::icon *icon) {
|
||||||
|
return _menu->addAction(text, receiver, member, icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
QAction *PopupMenu::addSeparator() {
|
||||||
|
return _menu->addSeparator();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopupMenu::clearActions() {
|
||||||
|
for (auto submenu : base::take(_submenus)) {
|
||||||
|
delete submenu;
|
||||||
|
}
|
||||||
|
return _menu->clearActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
PopupMenu::Actions &PopupMenu::actions() {
|
||||||
|
return _menu->actions();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopupMenu::paintEvent(QPaintEvent *e) {
|
||||||
|
Painter p(this);
|
||||||
|
|
||||||
|
auto clip = e->rect();
|
||||||
|
p.setClipRect(clip);
|
||||||
|
auto compositionMode = p.compositionMode();
|
||||||
|
p.setCompositionMode(QPainter::CompositionMode_Source);
|
||||||
|
if (_a_hide.animating()) {
|
||||||
|
p.setOpacity(a_opacity.current());
|
||||||
|
p.drawPixmap(0, 0, _cache);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.fillRect(clip, st::almostTransparent);
|
||||||
|
p.setCompositionMode(compositionMode);
|
||||||
|
|
||||||
|
_shadow.paint(p, _inner, _st.shadowShift);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopupMenu::handleActivated(QAction *action, int actionTop, TriggeredSource source) {
|
||||||
|
if (source == TriggeredSource::Mouse) {
|
||||||
|
if (!popupSubmenuFromAction(action, actionTop, source)) {
|
||||||
|
if (auto currentSubmenu = base::take(_activeSubmenu)) {
|
||||||
|
currentSubmenu->hideMenu(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopupMenu::handleTriggered(QAction *action, int actionTop, TriggeredSource source) {
|
||||||
|
if (!popupSubmenuFromAction(action, actionTop, source)) {
|
||||||
|
hideMenu();
|
||||||
|
_triggering = true;
|
||||||
|
emit action->trigger();
|
||||||
|
_triggering = false;
|
||||||
|
if (_deleteLater) {
|
||||||
|
_deleteLater = false;
|
||||||
|
deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PopupMenu::popupSubmenuFromAction(QAction *action, int actionTop, TriggeredSource source) {
|
||||||
|
if (auto submenu = _submenus.value(action)) {
|
||||||
|
if (_activeSubmenu == submenu) {
|
||||||
|
submenu->hideMenu(true);
|
||||||
|
} else {
|
||||||
|
popupSubmenu(submenu, actionTop, source);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopupMenu::popupSubmenu(SubmenuPointer submenu, int actionTop, TriggeredSource source) {
|
||||||
|
if (auto currentSubmenu = base::take(_activeSubmenu)) {
|
||||||
|
currentSubmenu->hideMenu(true);
|
||||||
|
}
|
||||||
|
if (submenu) {
|
||||||
|
QPoint p(_inner.x() + (rtl() ? _padding.right() : _inner.width() - _padding.left()), _inner.y() + actionTop);
|
||||||
|
_activeSubmenu = submenu;
|
||||||
|
_activeSubmenu->showMenu(geometry().topLeft() + p, this, source);
|
||||||
|
|
||||||
|
_menu->setChildShown(true);
|
||||||
|
} else {
|
||||||
|
_menu->setChildShown(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopupMenu::forwardKeyPress(int key) {
|
||||||
|
if (!handleKeyPress(key)) {
|
||||||
|
_menu->handleKeyPress(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PopupMenu::handleKeyPress(int key) {
|
||||||
|
if (_activeSubmenu) {
|
||||||
|
_activeSubmenu->handleKeyPress(key);
|
||||||
|
return true;
|
||||||
|
} else if (key == Qt::Key_Escape) {
|
||||||
|
hideMenu(_parent ? true : false);
|
||||||
|
return true;
|
||||||
|
} else if (key == (rtl() ? Qt::Key_Right : Qt::Key_Left)) {
|
||||||
|
if (_parent) {
|
||||||
|
hideMenu(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopupMenu::handleMouseMove(QPoint globalPosition) {
|
||||||
|
if (_parent) {
|
||||||
|
_parent->forwardMouseMove(globalPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopupMenu::handleMousePress(QPoint globalPosition) {
|
||||||
|
if (_parent) {
|
||||||
|
_parent->forwardMousePress(globalPosition);
|
||||||
|
} else {
|
||||||
|
hideMenu();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopupMenu::focusOutEvent(QFocusEvent *e) {
|
||||||
|
hideMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopupMenu::hideEvent(QHideEvent *e) {
|
||||||
|
if (_deleteOnHide) {
|
||||||
|
if (_triggering) {
|
||||||
|
_deleteLater = true;
|
||||||
|
} else {
|
||||||
|
deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopupMenu::hideMenu(bool fast) {
|
||||||
|
if (isHidden()) return;
|
||||||
|
if (_parent && !_a_hide.animating()) {
|
||||||
|
_parent->childHiding(this);
|
||||||
|
}
|
||||||
|
if (fast) {
|
||||||
|
if (_a_hide.animating()) {
|
||||||
|
_a_hide.stop();
|
||||||
|
}
|
||||||
|
a_opacity = anim::fvalue(0, 0);
|
||||||
|
hideFinish();
|
||||||
|
} else {
|
||||||
|
if (!_a_hide.animating()) {
|
||||||
|
_cache = myGrab(this);
|
||||||
|
a_opacity.start(0);
|
||||||
|
_a_hide.start();
|
||||||
|
}
|
||||||
|
if (_parent) {
|
||||||
|
_parent->hideMenu();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_activeSubmenu) {
|
||||||
|
_activeSubmenu->hideMenu(fast);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopupMenu::childHiding(PopupMenu *child) {
|
||||||
|
if (_activeSubmenu && _activeSubmenu == child) {
|
||||||
|
_activeSubmenu = SubmenuPointer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopupMenu::hideFinish() {
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopupMenu::step_hide(float64 ms, bool timer) {
|
||||||
|
float64 dt = ms / _st.duration;
|
||||||
|
if (dt >= 1) {
|
||||||
|
_a_hide.stop();
|
||||||
|
a_opacity.finish();
|
||||||
|
hideFinish();
|
||||||
|
} else {
|
||||||
|
a_opacity.update(dt, anim::linear);
|
||||||
|
}
|
||||||
|
if (timer) update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopupMenu::deleteOnHide(bool del) {
|
||||||
|
_deleteOnHide = del;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopupMenu::popup(const QPoint &p) {
|
||||||
|
showMenu(p, nullptr, TriggeredSource::Mouse);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopupMenu::showMenu(const QPoint &p, PopupMenu *parent, TriggeredSource source) {
|
||||||
|
_parent = parent;
|
||||||
|
|
||||||
|
QPoint w = p - QPoint(0, _padding.top());
|
||||||
|
QRect r = Sandbox::screenGeometry(p);
|
||||||
|
if (rtl()) {
|
||||||
|
if (w.x() - width() < r.x() - _padding.left()) {
|
||||||
|
if (_parent && w.x() + _parent->width() - _padding.left() - _padding.right() + width() - _padding.right() <= r.x() + r.width()) {
|
||||||
|
w.setX(w.x() + _parent->width() - _padding.left() - _padding.right());
|
||||||
|
} else {
|
||||||
|
w.setX(r.x() - _padding.left());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
w.setX(w.x() - width());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (w.x() + width() - _padding.right() > r.x() + r.width()) {
|
||||||
|
if (_parent && w.x() - _parent->width() + _padding.left() + _padding.right() - width() + _padding.right() >= r.x() - _padding.left()) {
|
||||||
|
w.setX(w.x() + _padding.left() + _padding.right() - _parent->width() - width() + _padding.left() + _padding.right());
|
||||||
|
} else {
|
||||||
|
w.setX(r.x() + r.width() - width() + _padding.right());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (w.y() + height() - _padding.bottom() > r.y() + r.height()) {
|
||||||
|
if (_parent) {
|
||||||
|
w.setY(r.y() + r.height() - height() + _padding.bottom());
|
||||||
|
} else {
|
||||||
|
w.setY(p.y() - height() + _padding.bottom());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (w.y() < r.y()) {
|
||||||
|
w.setY(r.y());
|
||||||
|
}
|
||||||
|
move(w);
|
||||||
|
|
||||||
|
_menu->setShowSource(source);
|
||||||
|
|
||||||
|
psUpdateOverlayed(this);
|
||||||
|
show();
|
||||||
|
psShowOverAll(this);
|
||||||
|
windowHandle()->requestActivate();
|
||||||
|
activateWindow();
|
||||||
|
|
||||||
|
if (_a_hide.animating()) {
|
||||||
|
_a_hide.stop();
|
||||||
|
_cache = QPixmap();
|
||||||
|
}
|
||||||
|
a_opacity = anim::fvalue(1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
PopupMenu::~PopupMenu() {
|
||||||
|
for (auto submenu : base::take(_submenus)) {
|
||||||
|
delete submenu;
|
||||||
|
}
|
||||||
|
#if defined Q_OS_LINUX32 || defined Q_OS_LINUX64
|
||||||
|
if (auto w = App::wnd()) {
|
||||||
|
w->onReActivate();
|
||||||
|
QTimer::singleShot(200, w, SLOT(onReActivate()));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Ui
|
112
Telegram/SourceFiles/ui/widgets/popup_menu.h
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "styles/style_widgets.h"
|
||||||
|
#include "ui/effects/rect_shadow.h"
|
||||||
|
#include "ui/widgets/menu.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
class PopupMenu : public TWidget {
|
||||||
|
public:
|
||||||
|
PopupMenu(const style::PopupMenu &st = st::defaultPopupMenu);
|
||||||
|
PopupMenu(QMenu *menu, const style::PopupMenu &st = st::defaultPopupMenu);
|
||||||
|
|
||||||
|
QAction *addAction(const QString &text, const QObject *receiver, const char* member, const style::icon *icon = nullptr);
|
||||||
|
QAction *addSeparator();
|
||||||
|
void clearActions();
|
||||||
|
|
||||||
|
using Actions = Ui::Menu::Actions;
|
||||||
|
Actions &actions();
|
||||||
|
|
||||||
|
void deleteOnHide(bool del);
|
||||||
|
void popup(const QPoint &p);
|
||||||
|
void hideMenu(bool fast = false);
|
||||||
|
|
||||||
|
~PopupMenu();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent *e) override;
|
||||||
|
void focusOutEvent(QFocusEvent *e) override;
|
||||||
|
void hideEvent(QHideEvent *e) override;
|
||||||
|
|
||||||
|
void keyPressEvent(QKeyEvent *e) override {
|
||||||
|
forwardKeyPress(e->key());
|
||||||
|
}
|
||||||
|
void mouseMoveEvent(QMouseEvent *e) override {
|
||||||
|
forwardMouseMove(e->globalPos());
|
||||||
|
}
|
||||||
|
void mousePressEvent(QMouseEvent *e) override {
|
||||||
|
forwardMousePress(e->globalPos());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void childHiding(PopupMenu *child);
|
||||||
|
|
||||||
|
void step_hide(float64 ms, bool timer);
|
||||||
|
|
||||||
|
void init();
|
||||||
|
void hideFinish();
|
||||||
|
|
||||||
|
using TriggeredSource = Ui::Menu::TriggeredSource;
|
||||||
|
void handleMenuResize();
|
||||||
|
void handleActivated(QAction *action, int actionTop, TriggeredSource source);
|
||||||
|
void handleTriggered(QAction *action, int actionTop, TriggeredSource source);
|
||||||
|
void forwardKeyPress(int key);
|
||||||
|
bool handleKeyPress(int key);
|
||||||
|
void forwardMouseMove(QPoint globalPosition) {
|
||||||
|
_menu->handleMouseMove(globalPosition);
|
||||||
|
}
|
||||||
|
void handleMouseMove(QPoint globalPosition);
|
||||||
|
void forwardMousePress(QPoint globalPosition) {
|
||||||
|
_menu->handleMousePress(globalPosition);
|
||||||
|
}
|
||||||
|
void handleMousePress(QPoint globalPosition);
|
||||||
|
|
||||||
|
using SubmenuPointer = QPointer<PopupMenu>;
|
||||||
|
bool popupSubmenuFromAction(QAction *action, int actionTop, TriggeredSource source);
|
||||||
|
void popupSubmenu(SubmenuPointer submenu, int actionTop, TriggeredSource source);
|
||||||
|
void showMenu(const QPoint &p, PopupMenu *parent, TriggeredSource source);
|
||||||
|
|
||||||
|
const style::PopupMenu &_st;
|
||||||
|
|
||||||
|
ChildWidget<Ui::Menu> _menu;
|
||||||
|
|
||||||
|
using Submenus = QMap<QAction*, SubmenuPointer>;
|
||||||
|
Submenus _submenus;
|
||||||
|
|
||||||
|
PopupMenu *_parent = nullptr;
|
||||||
|
|
||||||
|
QRect _inner;
|
||||||
|
style::margins _padding;
|
||||||
|
|
||||||
|
Ui::RectShadow _shadow;
|
||||||
|
SubmenuPointer _activeSubmenu;
|
||||||
|
|
||||||
|
QPixmap _cache;
|
||||||
|
anim::fvalue a_opacity;
|
||||||
|
Animation _a_hide;
|
||||||
|
|
||||||
|
bool _deleteOnHide = true;
|
||||||
|
bool _triggering = false;
|
||||||
|
bool _deleteLater = false;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Ui
|
185
Telegram/SourceFiles/ui/widgets/tooltip.cpp
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "ui/widgets/tooltip.h"
|
||||||
|
|
||||||
|
#include "application.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
Tooltip *TooltipInstance = nullptr;
|
||||||
|
|
||||||
|
AbstractTooltipShower::~AbstractTooltipShower() {
|
||||||
|
if (TooltipInstance && TooltipInstance->_shower == this) {
|
||||||
|
TooltipInstance->_shower = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Tooltip::Tooltip() : TWidget(nullptr) {
|
||||||
|
TooltipInstance = this;
|
||||||
|
|
||||||
|
setWindowFlags(Qt::WindowFlags(Qt::FramelessWindowHint) | Qt::BypassWindowManagerHint | Qt::ToolTip | Qt::NoDropShadowWindowHint);
|
||||||
|
setAttribute(Qt::WA_NoSystemBackground, true);
|
||||||
|
|
||||||
|
_showTimer.setSingleShot(true);
|
||||||
|
connect(&_showTimer, SIGNAL(timeout()), this, SLOT(onShow()));
|
||||||
|
|
||||||
|
connect(App::wnd()->windowHandle(), SIGNAL(activeChanged()), this, SLOT(onWndActiveChanged()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tooltip::onShow() {
|
||||||
|
if (_shower) {
|
||||||
|
QString text = (App::wnd() && App::wnd()->isActive(false)) ? _shower->tooltipText() : QString();
|
||||||
|
if (text.isEmpty()) {
|
||||||
|
Hide();
|
||||||
|
} else {
|
||||||
|
TooltipInstance->popup(_shower->tooltipPos(), text, _shower->tooltipSt());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tooltip::onWndActiveChanged() {
|
||||||
|
if (!App::wnd() || !App::wnd()->windowHandle() || !App::wnd()->windowHandle()->isActive()) {
|
||||||
|
Tooltip::Hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Tooltip::eventFilter(QObject *o, QEvent *e) {
|
||||||
|
if (e->type() == QEvent::Leave) {
|
||||||
|
_hideByLeaveTimer.start(10);
|
||||||
|
} else if (e->type() == QEvent::Enter) {
|
||||||
|
_hideByLeaveTimer.stop();
|
||||||
|
} else if (e->type() == QEvent::MouseMove) {
|
||||||
|
if ((QCursor::pos() - _point).manhattanLength() > QApplication::startDragDistance()) {
|
||||||
|
Hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TWidget::eventFilter(o, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tooltip::onHideByLeave() {
|
||||||
|
Hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
Tooltip::~Tooltip() {
|
||||||
|
if (TooltipInstance == this) {
|
||||||
|
TooltipInstance = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tooltip::popup(const QPoint &m, const QString &text, const style::Tooltip *st) {
|
||||||
|
if (!_hideByLeaveTimer.isSingleShot()) {
|
||||||
|
_hideByLeaveTimer.setSingleShot(true);
|
||||||
|
connect(&_hideByLeaveTimer, SIGNAL(timeout()), this, SLOT(onHideByLeave()));
|
||||||
|
|
||||||
|
Sandbox::installEventFilter(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
_point = m;
|
||||||
|
_st = st;
|
||||||
|
_text = Text(_st->textFont, text, _textPlainOptions, _st->widthMax, true);
|
||||||
|
|
||||||
|
int32 addw = 2 * st::lineWidth + _st->textPadding.left() + _st->textPadding.right();
|
||||||
|
int32 addh = 2 * st::lineWidth + _st->textPadding.top() + _st->textPadding.bottom();
|
||||||
|
|
||||||
|
// count tooltip size
|
||||||
|
QSize s(addw + _text.maxWidth(), addh + _text.minHeight());
|
||||||
|
if (s.width() > _st->widthMax) {
|
||||||
|
s.setWidth(addw + _text.countWidth(_st->widthMax - addw));
|
||||||
|
s.setHeight(addh + _text.countHeight(s.width() - addw));
|
||||||
|
}
|
||||||
|
int32 maxh = addh + (_st->linesMax * _st->textFont->height);
|
||||||
|
if (s.height() > maxh) {
|
||||||
|
s.setHeight(maxh);
|
||||||
|
}
|
||||||
|
|
||||||
|
// count tooltip position
|
||||||
|
QPoint p(m + _st->shift);
|
||||||
|
if (rtl()) {
|
||||||
|
p.setX(m.x() - s.width() - _st->shift.x());
|
||||||
|
}
|
||||||
|
if (s.width() < 2 * _st->shift.x()) {
|
||||||
|
p.setX(m.x() - (s.width() / 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// adjust tooltip position
|
||||||
|
QRect r(QApplication::desktop()->screenGeometry(m));
|
||||||
|
if (r.x() + r.width() - _st->skip < p.x() + s.width() && p.x() + s.width() > m.x()) {
|
||||||
|
p.setX(qMax(r.x() + r.width() - int32(_st->skip) - s.width(), m.x() - s.width()));
|
||||||
|
}
|
||||||
|
if (r.x() + _st->skip > p.x() && p.x() < m.x()) {
|
||||||
|
p.setX(qMin(m.x(), r.x() + int32(_st->skip)));
|
||||||
|
}
|
||||||
|
if (r.y() + r.height() - _st->skip < p.y() + s.height()) {
|
||||||
|
p.setY(m.y() - s.height() - _st->skip);
|
||||||
|
}
|
||||||
|
if (r.y() > p.x()) {
|
||||||
|
p.setY(qMin(m.y() + _st->shift.y(), r.y() + r.height() - s.height()));
|
||||||
|
}
|
||||||
|
|
||||||
|
setGeometry(QRect(p, s));
|
||||||
|
|
||||||
|
_hideByLeaveTimer.stop();
|
||||||
|
show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tooltip::paintEvent(QPaintEvent *e) {
|
||||||
|
Painter p(this);
|
||||||
|
|
||||||
|
p.fillRect(rect(), _st->textBg);
|
||||||
|
|
||||||
|
p.fillRect(QRect(0, 0, width(), st::lineWidth), _st->textBorder);
|
||||||
|
p.fillRect(QRect(0, height() - st::lineWidth, width(), st::lineWidth), _st->textBorder);
|
||||||
|
p.fillRect(QRect(0, st::lineWidth, st::lineWidth, height() - 2 * st::lineWidth), _st->textBorder);
|
||||||
|
p.fillRect(QRect(width() - st::lineWidth, st::lineWidth, st::lineWidth, height() - 2 * st::lineWidth), _st->textBorder);
|
||||||
|
|
||||||
|
int32 lines = qFloor((height() - 2 * st::lineWidth - _st->textPadding.top() - _st->textPadding.bottom()) / _st->textFont->height);
|
||||||
|
|
||||||
|
p.setPen(_st->textFg);
|
||||||
|
_text.drawElided(p, st::lineWidth + _st->textPadding.left(), st::lineWidth + _st->textPadding.top(), width() - 2 * st::lineWidth - _st->textPadding.left() - _st->textPadding.right(), lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tooltip::hideEvent(QHideEvent *e) {
|
||||||
|
if (TooltipInstance == this) {
|
||||||
|
Hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tooltip::Show(int32 delay, const AbstractTooltipShower *shower) {
|
||||||
|
if (!TooltipInstance) {
|
||||||
|
new Tooltip();
|
||||||
|
}
|
||||||
|
TooltipInstance->_shower = shower;
|
||||||
|
if (delay >= 0) {
|
||||||
|
TooltipInstance->_showTimer.start(delay);
|
||||||
|
} else {
|
||||||
|
TooltipInstance->onShow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tooltip::Hide() {
|
||||||
|
if (auto instance = TooltipInstance) {
|
||||||
|
TooltipInstance = nullptr;
|
||||||
|
instance->_showTimer.stop();
|
||||||
|
instance->_hideByLeaveTimer.stop();
|
||||||
|
instance->hide();
|
||||||
|
instance->deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Ui
|
69
Telegram/SourceFiles/ui/widgets/tooltip.h
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
|
||||||
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||||
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
class AbstractTooltipShower {
|
||||||
|
public:
|
||||||
|
virtual QString tooltipText() const = 0;
|
||||||
|
virtual QPoint tooltipPos() const = 0;
|
||||||
|
virtual const style::Tooltip *tooltipSt() const {
|
||||||
|
return &st::defaultTooltip;
|
||||||
|
}
|
||||||
|
virtual ~AbstractTooltipShower();
|
||||||
|
};
|
||||||
|
|
||||||
|
class Tooltip : public TWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
static void Show(int32 delay, const AbstractTooltipShower *shower);
|
||||||
|
static void Hide();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onShow();
|
||||||
|
void onWndActiveChanged();
|
||||||
|
void onHideByLeave();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent *e) override;
|
||||||
|
void hideEvent(QHideEvent *e) override;
|
||||||
|
|
||||||
|
bool eventFilter(QObject *o, QEvent *e) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Tooltip();
|
||||||
|
~Tooltip();
|
||||||
|
|
||||||
|
void popup(const QPoint &p, const QString &text, const style::Tooltip *st);
|
||||||
|
|
||||||
|
friend class AbstractTooltipShower;
|
||||||
|
const AbstractTooltipShower *_shower = nullptr;
|
||||||
|
QTimer _showTimer;
|
||||||
|
|
||||||
|
Text _text;
|
||||||
|
QPoint _point;
|
||||||
|
|
||||||
|
const style::Tooltip *_st = nullptr;
|
||||||
|
|
||||||
|
QTimer _hideByLeaveTimer;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Ui
|