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;
|
||||
hiding: 0;
|
||||
}
|
||||
defaultDropdownDuration: 150;
|
||||
defaultDropdownPadding: margins(10px, 10px, 10px, 10px);
|
||||
defaultDropdownShadow: icon {{ "dropdown_shadow", windowShadowFg }};
|
||||
defaultPopupMenu: PopupMenu {
|
||||
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;
|
||||
}
|
||||
defaultDropdownShadowShift: 1px;
|
||||
|
||||
defaultTooltip: Tooltip {
|
||||
textBg: #eef2f5;
|
||||
|
@ -1088,54 +1062,6 @@ btnUnblock: flatButton(btnSend) {
|
|||
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 {
|
||||
textColor: black;
|
||||
bgColor: white;
|
||||
|
@ -1158,15 +1084,6 @@ silentToggle: flatCheckbox {
|
|||
|
||||
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;
|
||||
replyColor: #377aae;
|
||||
|
@ -1418,68 +1335,6 @@ connectingBG: #fffe;
|
|||
connectingColor: #777;
|
||||
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);
|
||||
dragSubfont: font(20px semibold);
|
||||
dragColor: #777;
|
||||
|
@ -1720,49 +1575,6 @@ mvControlMargin: 0px;
|
|||
mvControlSize: 90px;
|
||||
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;
|
||||
mvHideDuration: 1000;
|
||||
mvShowDuration: 200;
|
||||
|
@ -1818,23 +1630,6 @@ macAlwaysThisAppTop: 4;
|
|||
macAppHintTop: 8;
|
||||
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);
|
||||
radialLine: 3px;
|
||||
radialDuration: 350;
|
||||
|
|
|
@ -227,59 +227,6 @@ switcher {
|
|||
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 {
|
||||
textBg: 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 "boxes/confirmbox.h"
|
||||
#include "ui/filedialog.h"
|
||||
#include "ui/popupmenu.h"
|
||||
#include "ui/widgets/tooltip.h"
|
||||
#include "langloaderplain.h"
|
||||
#include "localstorage.h"
|
||||
#include "autoupdater.h"
|
||||
|
@ -926,7 +926,7 @@ void AppClass::onAppStateChanged(Qt::ApplicationState state) {
|
|||
_window->updateIsActive((state == Qt::ApplicationActive) ? Global::OnlineFocusTimeout() : Global::OfflineBlurTimeout());
|
||||
}
|
||||
if (state != Qt::ApplicationActive) {
|
||||
PopupTooltip::Hide();
|
||||
Ui::Tooltip::Hide();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -201,7 +201,7 @@ void ScrollableBox::resizeEvent(QResizeEvent *e) {
|
|||
AbstractBox::resizeEvent(e);
|
||||
}
|
||||
|
||||
void ScrollableBox::init(ScrolledWidget *inner, int bottomSkip, int topSkip) {
|
||||
void ScrollableBox::init(TWidget *inner, int bottomSkip, int topSkip) {
|
||||
_bottomSkip = bottomSkip;
|
||||
_topSkip = topSkip;
|
||||
_scroll->setOwnedWidget(inner);
|
||||
|
|
|
@ -105,7 +105,7 @@ public:
|
|||
ScrollableBox(const style::flatScroll &scroll, int w = st::boxWideWidth);
|
||||
|
||||
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 resizeEvent(QResizeEvent *e) override;
|
||||
|
|
|
@ -54,7 +54,7 @@ void BackgroundBox::onBackgroundChosen(int index) {
|
|||
onClose();
|
||||
}
|
||||
|
||||
BackgroundBox::Inner::Inner(QWidget *parent) : ScrolledWidget(parent)
|
||||
BackgroundBox::Inner::Inner(QWidget *parent) : TWidget(parent)
|
||||
, _bgCount(0)
|
||||
, _rows(0)
|
||||
, _over(-1)
|
||||
|
|
|
@ -42,7 +42,7 @@ private:
|
|||
};
|
||||
|
||||
// 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
|
||||
|
||||
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))) {
|
||||
}
|
||||
|
||||
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())
|
||||
, _newItemHeight(creating == CreatingGroupNone ? st::contactsNewItemHeight : 0)
|
||||
, _creating(creating)
|
||||
|
@ -565,7 +565,7 @@ ContactsBox::Inner::Inner(QWidget *parent, CreatingGroupType creating) : Scrolle
|
|||
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())
|
||||
, _channel(channel)
|
||||
, _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())
|
||||
, _chat(chat)
|
||||
, _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())
|
||||
, _bot(bot)
|
||||
, _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.
|
||||
class ContactsBox::Inner : public ScrolledWidget, public RPCSender, private base::Subscriber {
|
||||
class ContactsBox::Inner : public TWidget, public RPCSender, private base::Subscriber {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
|
|
@ -97,7 +97,7 @@ void MembersBox::onAdminAdded() {
|
|||
_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())
|
||||
, _newItemHeight((channel->amCreator() && (channel->membersCount() < (channel->isMegagroup() ? Global::MegagroupSizeMax() : Global::ChatSizeMax()) || (!channel->isMegagroup() && !channel->isPublic()) || filter == MembersFilter::Admins)) ? st::contactsNewItemHeight : 0)
|
||||
, _newItemSel(false)
|
||||
|
|
|
@ -61,7 +61,7 @@ private:
|
|||
};
|
||||
|
||||
// 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
|
||||
|
||||
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)
|
||||
, _current(current)
|
||||
, _terminating(0)
|
||||
|
|
|
@ -72,7 +72,7 @@ private:
|
|||
};
|
||||
|
||||
// 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
|
||||
|
||||
public:
|
||||
|
|
|
@ -289,7 +289,7 @@ void ShareBox::onScroll() {
|
|||
_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))
|
||||
, _chatsIndexed(std_::make_unique<Dialogs::IndexedList>(Dialogs::SortMode::Add)) {
|
||||
_rowsTop = st::shareRowsTop;
|
||||
|
|
|
@ -113,7 +113,7 @@ private:
|
|||
};
|
||||
|
||||
// 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
|
||||
|
||||
public:
|
||||
|
|
|
@ -498,7 +498,7 @@ void StickersBox::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)
|
||||
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
||||
, _a_shifting(animation(this, &Inner::step_shifting))
|
||||
|
@ -511,7 +511,7 @@ StickersBox::Inner::Inner(QWidget *parent, StickersBox::Section section) : Scrol
|
|||
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)
|
||||
, _archivedIds(archivedIds)
|
||||
, _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
|
||||
|
|
|
@ -103,7 +103,7 @@ private:
|
|||
int32 stickerPacksCount(bool includeDisabledOfficial = false);
|
||||
|
||||
// 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
|
||||
|
||||
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) {
|
||||
switch (set.type()) {
|
||||
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.
|
||||
class StickerSetBox::Inner : public ScrolledWidget, public RPCSender, private base::Subscriber {
|
||||
class StickerSetBox::Inner : public TWidget, public RPCSender, private base::Subscriber {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
|
|
@ -27,7 +27,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "core/qthelp_regex.h"
|
||||
#include "core/qthelp_url.h"
|
||||
#include "localstorage.h"
|
||||
#include "ui/popupmenu.h"
|
||||
#include "ui/widgets/tooltip.h"
|
||||
|
||||
QString UrlClickHandler::copyToClipboardContextItemText() const {
|
||||
return lang(isEmail() ? lng_context_copy_email : lng_context_copy_link);
|
||||
|
@ -64,7 +64,7 @@ QString tryConvertUrlToLocal(QString url) {
|
|||
} // namespace
|
||||
|
||||
void UrlClickHandler::doOpen(QString url) {
|
||||
PopupTooltip::Hide();
|
||||
Ui::Tooltip::Hide();
|
||||
|
||||
if (isEmail(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 "styles/style_dialogs.h"
|
||||
#include "ui/buttons/round_button.h"
|
||||
#include "ui/popupmenu.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "data/data_drafts.h"
|
||||
#include "lang.h"
|
||||
#include "application.h"
|
||||
|
@ -639,7 +639,7 @@ void DialogsInner::contextMenuEvent(QContextMenuEvent *e) {
|
|||
if (!history) return;
|
||||
_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(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);
|
||||
|
|
|
@ -30,10 +30,10 @@ class IndexedList;
|
|||
|
||||
namespace Ui {
|
||||
class RoundButton;
|
||||
class PopupMenu;
|
||||
} // namespace Ui
|
||||
|
||||
class MainWidget;
|
||||
class PopupMenu;
|
||||
|
||||
enum DialogsSearchRequestType {
|
||||
DialogsSearchFromStart,
|
||||
|
@ -230,7 +230,7 @@ private:
|
|||
PeerData *_menuPeer = 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 "apiwrap.h"
|
||||
#include "localstorage.h"
|
||||
#include "styles/style_history.h"
|
||||
|
||||
FieldAutocomplete::FieldAutocomplete(QWidget *parent) : TWidget(parent)
|
||||
, _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) {
|
||||
if (mrows.isEmpty() && hrows.isEmpty() && brows.isEmpty() && srows.isEmpty()) {
|
||||
if (!isHidden()) {
|
||||
hideStart();
|
||||
hideAnimated();
|
||||
}
|
||||
_mrows.clear();
|
||||
_hrows.clear();
|
||||
|
@ -354,7 +355,7 @@ void FieldAutocomplete::rowsUpdated(const internal::MentionRows &mrows, const in
|
|||
update();
|
||||
if (hidden) {
|
||||
hide();
|
||||
showStart();
|
||||
showAnimated();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -394,7 +395,7 @@ void FieldAutocomplete::recount(bool resetScroll) {
|
|||
if (resetScroll) _inner->clearSel();
|
||||
}
|
||||
|
||||
void FieldAutocomplete::fastHide() {
|
||||
void FieldAutocomplete::hideFast() {
|
||||
if (_a_appearance.animating()) {
|
||||
_a_appearance.stop();
|
||||
}
|
||||
|
@ -403,18 +404,20 @@ void FieldAutocomplete::fastHide() {
|
|||
hideFinish();
|
||||
}
|
||||
|
||||
void FieldAutocomplete::hideStart() {
|
||||
if (!_hiding) {
|
||||
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::hideAnimated() {
|
||||
if (isHidden() || _hiding) {
|
||||
return;
|
||||
}
|
||||
|
||||
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() {
|
||||
|
@ -424,7 +427,7 @@ void FieldAutocomplete::hideFinish() {
|
|||
_inner->clearSel(true);
|
||||
}
|
||||
|
||||
void FieldAutocomplete::showStart() {
|
||||
void FieldAutocomplete::showAnimated() {
|
||||
if (!isHidden() && a_opacity.current() == 1 && !_hiding) {
|
||||
return;
|
||||
}
|
||||
|
@ -441,7 +444,7 @@ void FieldAutocomplete::showStart() {
|
|||
}
|
||||
|
||||
void FieldAutocomplete::step_appearance(float64 ms, bool timer) {
|
||||
float64 dt = ms / st::dropdownDef.duration;
|
||||
float64 dt = ms / st::defaultDropdownDuration;
|
||||
if (dt >= 1) {
|
||||
_a_appearance.stop();
|
||||
a_opacity.finish();
|
||||
|
@ -544,7 +547,7 @@ void FieldAutocompleteInner::paintEvent(QPaintEvent *e) {
|
|||
int32 atwidth = st::mentionFont->width('@'), hashwidth = st::mentionFont->width('#');
|
||||
int32 mentionleft = 2 * st::mentionPadding.left() + st::mentionPhotoSize;
|
||||
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()) {
|
||||
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()) {
|
||||
p.setPen((selected ? st::mentionFgOverActive : st::mentionFgActive)->p);
|
||||
p.drawText(htagleft, i * st::mentionHeight + st::mentionTop + st::mentionFont->ascent, first);
|
||||
|
|
|
@ -39,8 +39,6 @@ class FieldAutocomplete final : public TWidget {
|
|||
public:
|
||||
FieldAutocomplete(QWidget *parent);
|
||||
|
||||
void fastHide();
|
||||
|
||||
bool clearFilteredBotCommands();
|
||||
void showFiltered(PeerData *peer, QString query, bool addInlineBots);
|
||||
void showStickers(EmojiPtr emoji);
|
||||
|
@ -75,6 +73,8 @@ public:
|
|||
return rect().contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
|
||||
}
|
||||
|
||||
void hideFast();
|
||||
|
||||
~FieldAutocomplete();
|
||||
|
||||
signals:
|
||||
|
@ -86,15 +86,15 @@ signals:
|
|||
void moderateKeyActivate(int key, bool *outHandled) const;
|
||||
|
||||
public slots:
|
||||
void hideStart();
|
||||
void hideFinish();
|
||||
|
||||
void showStart();
|
||||
void showAnimated();
|
||||
void hideAnimated();
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
private:
|
||||
void hideFinish();
|
||||
|
||||
void updateFiltered(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 "dialogs/dialogs.style";
|
||||
using "ui/widgets/widgets.style";
|
||||
|
||||
historyPaddingBottom: 10px;
|
||||
|
||||
|
@ -38,16 +39,16 @@ historyToDownBadgeSize: 22px;
|
|||
historyEmptyDog: icon {{ "history_empty_dog", #ffffff }};
|
||||
historyEmptySize: 128px;
|
||||
|
||||
membersInnerScroll: flatScroll(solidScroll) {
|
||||
deltat: 3px;
|
||||
deltab: 3px;
|
||||
round: 1px;
|
||||
width: 8px;
|
||||
deltax: 3px;
|
||||
}
|
||||
membersInnerWidth: 310px;
|
||||
membersInnerHeightMax: 360px;
|
||||
membersInnerDropdown: InnerDropdown(defaultInnerDropdown) {
|
||||
scroll: flatScroll(solidScroll) {
|
||||
deltat: 3px;
|
||||
deltab: 3px;
|
||||
round: 1px;
|
||||
width: 8px;
|
||||
deltax: 3px;
|
||||
}
|
||||
scrollMargin: margins(0px, 5px, 0px, 5px);
|
||||
scrollPadding: margins(0px, 3px, 8px, 3px);
|
||||
}
|
||||
|
@ -138,3 +139,74 @@ historyPeer8NameFg: #ce671b; // orange
|
|||
historyPeer8UserpicBg: #f7b37c;
|
||||
historyPeer8UserpicFg: #de8d62;
|
||||
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/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 {
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -106,8 +34,6 @@ public:
|
|||
void otherEnter();
|
||||
void otherLeave();
|
||||
|
||||
void fastHide();
|
||||
|
||||
void step_appearance(float64 ms, bool timer);
|
||||
|
||||
bool overlaps(const QRect &globalRect) {
|
||||
|
@ -120,6 +46,8 @@ public:
|
|||
).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
|
||||
}
|
||||
|
||||
void hideFast();
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *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/toast/toast.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 "data/data_drafts.h"
|
||||
#include "history/history_service_layout.h"
|
||||
#include "history/history_media_types.h"
|
||||
#include "history/history_drag_area.h"
|
||||
#include "profile/profile_members_widget.h"
|
||||
#include "core/click_handler_types.h"
|
||||
#include "stickers/emoji_pan.h"
|
||||
#include "lang.h"
|
||||
#include "application.h"
|
||||
#include "dropdown.h"
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
#include "passcodewidget.h"
|
||||
|
@ -52,6 +54,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "window/chat_background.h"
|
||||
#include "observer_peer.h"
|
||||
#include "core/qthelp_regex.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -1154,7 +1157,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
|||
isUponSelected = hasSelected;
|
||||
}
|
||||
|
||||
_menu = new PopupMenu();
|
||||
_menu = new Ui::PopupMenu();
|
||||
|
||||
_contextMenuLnk = ClickHandler::getActive();
|
||||
HistoryItem *item = App::hoveredItem() ? App::hoveredItem() : App::hoveredLinkItem();
|
||||
|
@ -1698,7 +1701,7 @@ void HistoryInner::toggleScrollDateShown() {
|
|||
_scrollDateShown = !_scrollDateShown;
|
||||
auto from = _scrollDateShown ? 0. : 1.;
|
||||
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() {
|
||||
|
@ -1749,7 +1752,7 @@ void HistoryInner::leaveEvent(QEvent *e) {
|
|||
App::hoveredItem(nullptr);
|
||||
}
|
||||
ClickHandler::clearActive();
|
||||
PopupTooltip::Hide();
|
||||
Ui::Tooltip::Hide();
|
||||
if (!ClickHandler::getPressed() && _cursor != style::cur_default) {
|
||||
_cursor = style::cur_default;
|
||||
setCursor(_cursor);
|
||||
|
@ -1970,7 +1973,7 @@ void HistoryInner::onUpdateSelected() {
|
|||
dragState = item->getState(m.x(), m.y(), request);
|
||||
lnkhost = item;
|
||||
if (!dragState.link && m.x() >= st::msgMargin.left() && m.x() < st::msgMargin.left() + st::msgPhotoSize) {
|
||||
if (HistoryMessage *msg = item->toHistoryMessage()) {
|
||||
if (auto msg = item->toHistoryMessage()) {
|
||||
if (msg->hasFromPhoto()) {
|
||||
enumerateUserpics([&dragState, &lnkhost, &point](HistoryMessage *message, int userpicTop) -> bool {
|
||||
// stop enumeration if the userpic is above our point
|
||||
|
@ -1992,10 +1995,10 @@ void HistoryInner::onUpdateSelected() {
|
|||
}
|
||||
bool lnkChanged = ClickHandler::setActive(dragState.link, lnkhost);
|
||||
if (lnkChanged || dragState.cursor != _dragCursorState) {
|
||||
PopupTooltip::Hide();
|
||||
Ui::Tooltip::Hide();
|
||||
}
|
||||
if (dragState.link || dragState.cursor == HistoryInDateCursorState || dragState.cursor == HistoryInForwardedCursorState) {
|
||||
PopupTooltip::Show(1000, this);
|
||||
Ui::Tooltip::Show(1000, this);
|
||||
}
|
||||
|
||||
Qt::CursorShape cur = style::cur_default;
|
||||
|
@ -2611,7 +2614,7 @@ void BotKeyboard::updateStyle(int newWidth) {
|
|||
void BotKeyboard::clearSelection() {
|
||||
if (_impl) {
|
||||
if (ClickHandler::setActive(ClickHandlerPtr(), this)) {
|
||||
PopupTooltip::Hide();
|
||||
Ui::Tooltip::Hide();
|
||||
setCursor(style::cur_default);
|
||||
}
|
||||
}
|
||||
|
@ -2629,7 +2632,7 @@ QString BotKeyboard::tooltipText() const {
|
|||
}
|
||||
|
||||
void BotKeyboard::updateSelected() {
|
||||
PopupTooltip::Show(1000, this);
|
||||
Ui::Tooltip::Show(1000, this);
|
||||
|
||||
if (!_impl) return;
|
||||
|
||||
|
@ -2638,7 +2641,7 @@ void BotKeyboard::updateSelected() {
|
|||
|
||||
auto link = _impl->getState(p.x() - x, p.y() - _st->margin);
|
||||
if (ClickHandler::setActive(link, this)) {
|
||||
PopupTooltip::Hide();
|
||||
Ui::Tooltip::Hide();
|
||||
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) {
|
||||
FlatCheckbox::mouseMoveEvent(e);
|
||||
if (rect().contains(e->pos())) {
|
||||
PopupTooltip::Show(1000, this);
|
||||
Ui::Tooltip::Show(1000, this);
|
||||
} else {
|
||||
PopupTooltip::Hide();
|
||||
Ui::Tooltip::Hide();
|
||||
}
|
||||
}
|
||||
|
||||
void SilentToggle::leaveEvent(QEvent *e) {
|
||||
PopupTooltip::Hide();
|
||||
Ui::Tooltip::Hide();
|
||||
}
|
||||
|
||||
void SilentToggle::mouseReleaseEvent(QMouseEvent *e) {
|
||||
FlatCheckbox::mouseReleaseEvent(e);
|
||||
PopupTooltip::Show(0, this);
|
||||
Ui::Tooltip::Show(0, this);
|
||||
PeerData *p = App::main() ? App::main()->peer() : nullptr;
|
||||
if (p && p->isChannel() && p->notify != UnknownNotifySettings) {
|
||||
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)
|
||||
, _joinChannel(this, lang(lng_channel_join), st::btnSend)
|
||||
, _muteUnmute(this, lang(lng_channel_mute), st::btnSend)
|
||||
, _attachDocument(this, st::btnAttachDocument)
|
||||
, _attachPhoto(this, st::btnAttachPhoto)
|
||||
, _attachEmoji(this, st::btnAttachEmoji)
|
||||
, _kbShow(this, st::btnBotKbShow)
|
||||
, _kbHide(this, st::btnBotKbHide)
|
||||
, _cmdStart(this, st::btnBotCmdStart)
|
||||
, _attachDocument(this, st::historyAttachDocument)
|
||||
, _attachPhoto(this, st::historyAttachPhoto)
|
||||
, _attachEmoji(this, st::historyAttachEmoji)
|
||||
, _botKeyboardShow(this, st::historyBotKeyboardShow)
|
||||
, _botKeyboardHide(this, st::historyBotKeyboardHide)
|
||||
, _botCommandStart(this, st::historyBotCommandStart)
|
||||
, _silent(this)
|
||||
, _field(this, st::taMsgField, lang(lng_message_ph))
|
||||
, _a_record(animation(this, &HistoryWidget::step_record))
|
||||
, _a_recording(animation(this, &HistoryWidget::step_recording))
|
||||
, a_recordCancel(st::recordCancel->c, st::recordCancel->c)
|
||||
, _recordCancelWidth(st::recordFont->width(lang(lng_record_cancel)))
|
||||
, a_recordCancel(st::historyRecordCancel->c, st::historyRecordCancel->c)
|
||||
, _recordCancelWidth(st::historyRecordFont->width(lang(lng_record_cancel)))
|
||||
, _kbScroll(this, st::botKbScroll)
|
||||
, _attachType(this)
|
||||
, _attachType(this, st::historyAttachDropdownMenu)
|
||||
, _emojiPan(this)
|
||||
, _attachDragDocument(this)
|
||||
, _attachDragPhoto(this)
|
||||
|
@ -3028,8 +3031,8 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
|
|||
connect(&_joinChannel, SIGNAL(clicked()), this, SLOT(onJoinChannel()));
|
||||
connect(&_muteUnmute, SIGNAL(clicked()), this, SLOT(onMuteUnmute()));
|
||||
connect(&_silent, SIGNAL(clicked()), this, SLOT(onBroadcastSilentChange()));
|
||||
connect(&_attachDocument, SIGNAL(clicked()), this, SLOT(onDocumentSelect()));
|
||||
connect(&_attachPhoto, SIGNAL(clicked()), this, SLOT(onPhotoSelect()));
|
||||
connect(_attachDocument, SIGNAL(clicked()), this, SLOT(onDocumentSelect()));
|
||||
connect(_attachPhoto, SIGNAL(clicked()), this, SLOT(onPhotoSelect()));
|
||||
connect(&_field, SIGNAL(submitted(bool)), this, SLOT(onSend(bool)));
|
||||
connect(&_field, SIGNAL(cancelled()), this, SLOT(onCancel()));
|
||||
connect(&_field, SIGNAL(tabbed()), this, SLOT(onFieldTabbed()));
|
||||
|
@ -3107,24 +3110,24 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
|
|||
_reportSpamPanel.move(0, 0);
|
||||
_reportSpamPanel.hide();
|
||||
|
||||
_attachDocument.hide();
|
||||
_attachPhoto.hide();
|
||||
_attachEmoji.hide();
|
||||
_kbShow.hide();
|
||||
_kbHide.hide();
|
||||
_attachDocument->hide();
|
||||
_attachPhoto->hide();
|
||||
_attachEmoji->hide();
|
||||
_botKeyboardShow->hide();
|
||||
_botKeyboardHide->hide();
|
||||
_silent.hide();
|
||||
_cmdStart.hide();
|
||||
_botCommandStart->hide();
|
||||
|
||||
_attachDocument.installEventFilter(_attachType);
|
||||
_attachPhoto.installEventFilter(_attachType);
|
||||
_attachEmoji.installEventFilter(_emojiPan);
|
||||
_attachDocument->installEventFilter(_attachType);
|
||||
_attachPhoto->installEventFilter(_attachType);
|
||||
_attachEmoji->installEventFilter(_emojiPan);
|
||||
|
||||
connect(&_kbShow, SIGNAL(clicked()), this, SLOT(onKbToggle()));
|
||||
connect(&_kbHide, SIGNAL(clicked()), this, SLOT(onKbToggle()));
|
||||
connect(&_cmdStart, SIGNAL(clicked()), this, SLOT(onCmdStart()));
|
||||
connect(_botKeyboardShow, SIGNAL(clicked()), this, SLOT(onKbToggle()));
|
||||
connect(_botKeyboardHide, SIGNAL(clicked()), this, SLOT(onKbToggle()));
|
||||
connect(_botCommandStart, SIGNAL(clicked()), this, SLOT(onCmdStart()));
|
||||
|
||||
connect(_attachType->addButton(new IconedButton(this, st::dropdownAttachDocument, lang(lng_attach_file))), SIGNAL(clicked()), this, SLOT(onDocumentSelect()));
|
||||
connect(_attachType->addButton(new IconedButton(this, st::dropdownAttachPhoto, lang(lng_attach_photo))), SIGNAL(clicked()), this, SLOT(onPhotoSelect()));
|
||||
_attachType->addAction(lang(lng_attach_file), this, SLOT(onDocumentSelect()), &st::historyMediaTypeFile);
|
||||
_attachType->addAction(lang(lng_attach_photo), this, SLOT(onPhotoSelect()), &st::historyMediaTypePhoto);
|
||||
_attachType->hide();
|
||||
_emojiPan->hide();
|
||||
_attachDragDocument->hide();
|
||||
|
@ -3221,7 +3224,7 @@ void HistoryWidget::applyInlineBotQuery(UserData *bot, const QString &query) {
|
|||
_emojiPan->queryInlineBot(_inlineBot, _peer, query);
|
||||
}
|
||||
if (!_fieldAutocomplete->isHidden()) {
|
||||
_fieldAutocomplete->hideStart();
|
||||
_fieldAutocomplete->hideAnimated();
|
||||
}
|
||||
} else {
|
||||
clearInlineBot();
|
||||
|
@ -3267,7 +3270,7 @@ void HistoryWidget::onTextChange() {
|
|||
_a_record.stop();
|
||||
_inRecord = _inField = false;
|
||||
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()) {
|
||||
|
@ -3541,7 +3544,7 @@ void HistoryWidget::notify_botCommandsChanged(UserData *user) {
|
|||
}
|
||||
|
||||
void HistoryWidget::notify_inlineBotRequesting(bool requesting) {
|
||||
_attachEmoji.setLoading(requesting);
|
||||
_attachEmoji->setLoading(requesting);
|
||||
}
|
||||
|
||||
void HistoryWidget::notify_replyMarkupUpdated(const HistoryItem *item) {
|
||||
|
@ -4497,14 +4500,14 @@ void HistoryWidget::updateControlsVisibility() {
|
|||
_fieldAutocomplete->hide();
|
||||
_field.hide();
|
||||
_fieldBarCancel.hide();
|
||||
_attachDocument.hide();
|
||||
_attachPhoto.hide();
|
||||
_attachEmoji.hide();
|
||||
_attachDocument->hide();
|
||||
_attachPhoto->hide();
|
||||
_attachEmoji->hide();
|
||||
_silent.hide();
|
||||
_historyToEnd->hide();
|
||||
_kbShow.hide();
|
||||
_kbHide.hide();
|
||||
_cmdStart.hide();
|
||||
_botKeyboardShow->hide();
|
||||
_botKeyboardHide->hide();
|
||||
_botCommandStart->hide();
|
||||
_attachType->hide();
|
||||
_emojiPan->hide();
|
||||
if (_pinnedBar) {
|
||||
|
@ -4556,17 +4559,17 @@ void HistoryWidget::updateControlsVisibility() {
|
|||
_send.hide();
|
||||
if (_inlineBotCancel) _inlineBotCancel->hide();
|
||||
_botStart.hide();
|
||||
_attachDocument.hide();
|
||||
_attachPhoto.hide();
|
||||
_attachDocument->hide();
|
||||
_attachPhoto->hide();
|
||||
_silent.hide();
|
||||
_kbScroll.hide();
|
||||
_fieldBarCancel.hide();
|
||||
_attachDocument.hide();
|
||||
_attachPhoto.hide();
|
||||
_attachEmoji.hide();
|
||||
_kbShow.hide();
|
||||
_kbHide.hide();
|
||||
_cmdStart.hide();
|
||||
_attachDocument->hide();
|
||||
_attachPhoto->hide();
|
||||
_attachEmoji->hide();
|
||||
_botKeyboardShow->hide();
|
||||
_botKeyboardHide->hide();
|
||||
_botCommandStart->hide();
|
||||
_attachType->hide();
|
||||
_emojiPan->hide();
|
||||
if (!_field.isHidden()) {
|
||||
|
@ -4588,12 +4591,12 @@ void HistoryWidget::updateControlsVisibility() {
|
|||
_send.hide();
|
||||
if (_inlineBotCancel) _inlineBotCancel->hide();
|
||||
_field.hide();
|
||||
_attachEmoji.hide();
|
||||
_kbShow.hide();
|
||||
_kbHide.hide();
|
||||
_cmdStart.hide();
|
||||
_attachDocument.hide();
|
||||
_attachPhoto.hide();
|
||||
_attachEmoji->hide();
|
||||
_botKeyboardShow->hide();
|
||||
_botKeyboardHide->hide();
|
||||
_botCommandStart->hide();
|
||||
_attachDocument->hide();
|
||||
_attachPhoto->hide();
|
||||
_silent.hide();
|
||||
_kbScroll.hide();
|
||||
_fieldBarCancel.hide();
|
||||
|
@ -4618,12 +4621,12 @@ void HistoryWidget::updateControlsVisibility() {
|
|||
}
|
||||
if (_recording) {
|
||||
_field.hide();
|
||||
_attachEmoji.hide();
|
||||
_kbShow.hide();
|
||||
_kbHide.hide();
|
||||
_cmdStart.hide();
|
||||
_attachDocument.hide();
|
||||
_attachPhoto.hide();
|
||||
_attachEmoji->hide();
|
||||
_botKeyboardShow->hide();
|
||||
_botKeyboardHide->hide();
|
||||
_botCommandStart->hide();
|
||||
_attachDocument->hide();
|
||||
_attachPhoto->hide();
|
||||
_silent.hide();
|
||||
if (_kbShown) {
|
||||
_kbScroll.show();
|
||||
|
@ -4634,38 +4637,38 @@ void HistoryWidget::updateControlsVisibility() {
|
|||
_field.show();
|
||||
if (_kbShown) {
|
||||
_kbScroll.show();
|
||||
_attachEmoji.hide();
|
||||
_kbHide.show();
|
||||
_kbShow.hide();
|
||||
_cmdStart.hide();
|
||||
_attachEmoji->hide();
|
||||
_botKeyboardHide->show();
|
||||
_botKeyboardShow->hide();
|
||||
_botCommandStart->hide();
|
||||
} else if (_kbReplyTo) {
|
||||
_kbScroll.hide();
|
||||
_attachEmoji.show();
|
||||
_kbHide.hide();
|
||||
_kbShow.hide();
|
||||
_cmdStart.hide();
|
||||
_attachEmoji->show();
|
||||
_botKeyboardHide->hide();
|
||||
_botKeyboardShow->hide();
|
||||
_botCommandStart->hide();
|
||||
} else {
|
||||
_kbScroll.hide();
|
||||
_attachEmoji.show();
|
||||
_kbHide.hide();
|
||||
_attachEmoji->show();
|
||||
_botKeyboardHide->hide();
|
||||
if (_keyboard.hasMarkup()) {
|
||||
_kbShow.show();
|
||||
_cmdStart.hide();
|
||||
_botKeyboardShow->show();
|
||||
_botCommandStart->hide();
|
||||
} else {
|
||||
_kbShow.hide();
|
||||
_botKeyboardShow->hide();
|
||||
if (_cmdStartShown) {
|
||||
_cmdStart.show();
|
||||
_botCommandStart->show();
|
||||
} else {
|
||||
_cmdStart.hide();
|
||||
_botCommandStart->hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cDefaultAttach() == dbidaPhoto) {
|
||||
_attachDocument.hide();
|
||||
_attachPhoto.show();
|
||||
_attachDocument->hide();
|
||||
_attachPhoto->show();
|
||||
} else {
|
||||
_attachDocument.show();
|
||||
_attachPhoto.hide();
|
||||
_attachDocument->show();
|
||||
_attachPhoto->hide();
|
||||
}
|
||||
if (hasSilentToggle()) {
|
||||
_silent.show();
|
||||
|
@ -4692,17 +4695,17 @@ void HistoryWidget::updateControlsVisibility() {
|
|||
_botStart.hide();
|
||||
_joinChannel.hide();
|
||||
_muteUnmute.hide();
|
||||
_attachDocument.hide();
|
||||
_attachPhoto.hide();
|
||||
_attachDocument->hide();
|
||||
_attachPhoto->hide();
|
||||
_silent.hide();
|
||||
_kbScroll.hide();
|
||||
_fieldBarCancel.hide();
|
||||
_attachDocument.hide();
|
||||
_attachPhoto.hide();
|
||||
_attachEmoji.hide();
|
||||
_kbShow.hide();
|
||||
_kbHide.hide();
|
||||
_cmdStart.hide();
|
||||
_attachDocument->hide();
|
||||
_attachPhoto->hide();
|
||||
_attachEmoji->hide();
|
||||
_botKeyboardShow->hide();
|
||||
_botKeyboardHide->hide();
|
||||
_botCommandStart->hide();
|
||||
_attachType->hide();
|
||||
_emojiPan->hide();
|
||||
_kbScroll.hide();
|
||||
|
@ -5219,6 +5222,12 @@ bool HistoryWidget::saveEditMsgFail(History *history, const RPCError &error, mtp
|
|||
return true;
|
||||
}
|
||||
|
||||
void HistoryWidget::hideSelectorControlsAnimated() {
|
||||
_fieldAutocomplete->hideAnimated();
|
||||
_attachType->hideAnimated();
|
||||
_emojiPan->hideAnimated();
|
||||
}
|
||||
|
||||
void HistoryWidget::onSend(bool ctrlShiftEnter, MsgId replyTo) {
|
||||
if (!_history) return;
|
||||
|
||||
|
@ -5244,9 +5253,7 @@ void HistoryWidget::onSend(bool ctrlShiftEnter, MsgId replyTo) {
|
|||
_saveDraftStart = getms();
|
||||
onDraftSave();
|
||||
|
||||
if (!_fieldAutocomplete->isHidden()) _fieldAutocomplete->hideStart();
|
||||
if (!_attachType->isHidden()) _attachType->hideStart();
|
||||
if (!_emojiPan->isHidden()) _emojiPan->hideStart();
|
||||
hideSelectorControlsAnimated();
|
||||
|
||||
if (replyTo < 0) cancelReply(lastKeyboardUsed);
|
||||
if (_previewData && _previewData->pendingTill) previewCancel();
|
||||
|
@ -5448,14 +5455,14 @@ void HistoryWidget::showAnimated(Window::SlideDirection direction, const Window:
|
|||
_kbScroll.hide();
|
||||
_reportSpamPanel.hide();
|
||||
_historyToEnd->hide();
|
||||
_attachDocument.hide();
|
||||
_attachPhoto.hide();
|
||||
_attachEmoji.hide();
|
||||
_attachDocument->hide();
|
||||
_attachPhoto->hide();
|
||||
_attachEmoji->hide();
|
||||
_fieldAutocomplete->hide();
|
||||
_silent.hide();
|
||||
_kbShow.hide();
|
||||
_kbHide.hide();
|
||||
_cmdStart.hide();
|
||||
_botKeyboardShow->hide();
|
||||
_botKeyboardHide->hide();
|
||||
_botCommandStart->hide();
|
||||
_field.hide();
|
||||
_fieldBarCancel.hide();
|
||||
_send.hide();
|
||||
|
@ -5565,16 +5572,16 @@ void HistoryWidget::step_recording(float64 ms, bool timer) {
|
|||
} else {
|
||||
a_recordingLevel.update(dt, anim::linear);
|
||||
}
|
||||
if (timer) update(_attachDocument.geometry());
|
||||
if (timer) update(_attachDocument->geometry());
|
||||
}
|
||||
|
||||
void HistoryWidget::onPhotoSelect() {
|
||||
if (!_history) return;
|
||||
|
||||
_attachDocument.clearState();
|
||||
_attachDocument.hide();
|
||||
_attachPhoto.show();
|
||||
_attachType->fastHide();
|
||||
_attachDocument->clearState();
|
||||
_attachDocument->hide();
|
||||
_attachPhoto->show();
|
||||
_attachType->hideFast();
|
||||
|
||||
if (cDefaultAttach() != dbidaPhoto) {
|
||||
cSetDefaultAttach(dbidaPhoto);
|
||||
|
@ -5599,10 +5606,10 @@ void HistoryWidget::onPhotoSelect() {
|
|||
void HistoryWidget::onDocumentSelect() {
|
||||
if (!_history) return;
|
||||
|
||||
_attachPhoto.clearState();
|
||||
_attachPhoto.hide();
|
||||
_attachDocument.show();
|
||||
_attachType->fastHide();
|
||||
_attachPhoto->clearState();
|
||||
_attachPhoto->hide();
|
||||
_attachDocument->show();
|
||||
_attachType->hideFast();
|
||||
|
||||
if (cDefaultAttach() != dbidaDocument) {
|
||||
cSetDefaultAttach(dbidaDocument);
|
||||
|
@ -5671,7 +5678,7 @@ void HistoryWidget::mouseMoveEvent(QMouseEvent *e) {
|
|||
_inField = inField;
|
||||
a_recordOver.restart();
|
||||
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;
|
||||
}
|
||||
if (inReplyEdit != _inReplyEdit) {
|
||||
|
@ -5722,7 +5729,7 @@ void HistoryWidget::stopRecording(bool send) {
|
|||
|
||||
a_recordDown.start(0);
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -5960,7 +5967,7 @@ void HistoryWidget::updateDragAreas() {
|
|||
case DragStateFiles:
|
||||
_attachDragDocument->otherEnter();
|
||||
_attachDragDocument->setText(lang(lng_drag_files_here), lang(lng_drag_to_send_files));
|
||||
_attachDragPhoto->fastHide();
|
||||
_attachDragPhoto->hideFast();
|
||||
break;
|
||||
case DragStatePhotoFiles:
|
||||
_attachDragDocument->otherEnter();
|
||||
|
@ -5969,7 +5976,7 @@ void HistoryWidget::updateDragAreas() {
|
|||
_attachDragPhoto->setText(lang(lng_drag_photos_here), lang(lng_drag_to_send_quick));
|
||||
break;
|
||||
case DragStateImage:
|
||||
_attachDragDocument->fastHide();
|
||||
_attachDragDocument->hideFast();
|
||||
_attachDragPhoto->otherEnter();
|
||||
_attachDragPhoto->setText(lang(lng_drag_images_here), lang(lng_drag_to_send_quick));
|
||||
break;
|
||||
|
@ -6127,10 +6134,10 @@ void HistoryWidget::onFilesDrop(const QMimeData *data) {
|
|||
void HistoryWidget::onKbToggle(bool manual) {
|
||||
auto fieldEnabled = canWriteMessage();
|
||||
if (_kbShown || _kbReplyTo) {
|
||||
_kbHide.hide();
|
||||
_botKeyboardHide->hide();
|
||||
if (_kbShown) {
|
||||
if (fieldEnabled) {
|
||||
_kbShow.show();
|
||||
_botKeyboardShow->show();
|
||||
}
|
||||
if (manual && _history) {
|
||||
_history->lastKeyboardHiddenId = _keyboard.forMsgId().msg;
|
||||
|
@ -6154,10 +6161,10 @@ void HistoryWidget::onKbToggle(bool manual) {
|
|||
}
|
||||
}
|
||||
} else if (!_keyboard.hasMarkup() && _keyboard.forceReply()) {
|
||||
_kbHide.hide();
|
||||
_kbShow.hide();
|
||||
_botKeyboardHide->hide();
|
||||
_botKeyboardShow->hide();
|
||||
if (fieldEnabled) {
|
||||
_cmdStart.show();
|
||||
_botCommandStart->show();
|
||||
}
|
||||
_kbScroll.hide();
|
||||
_kbShown = false;
|
||||
|
@ -6175,8 +6182,8 @@ void HistoryWidget::onKbToggle(bool manual) {
|
|||
_history->lastKeyboardHiddenId = 0;
|
||||
}
|
||||
} else if (fieldEnabled) {
|
||||
_kbHide.show();
|
||||
_kbShow.hide();
|
||||
_botKeyboardHide->show();
|
||||
_botKeyboardShow->hide();
|
||||
_kbScroll.show();
|
||||
_kbShown = true;
|
||||
|
||||
|
@ -6195,10 +6202,10 @@ void HistoryWidget::onKbToggle(bool manual) {
|
|||
}
|
||||
}
|
||||
resizeEvent(0);
|
||||
if (_kbHide.isHidden() && canWriteMessage()) {
|
||||
_attachEmoji.show();
|
||||
if (_botKeyboardHide->isHidden() && canWriteMessage()) {
|
||||
_attachEmoji->show();
|
||||
} else {
|
||||
_attachEmoji.hide();
|
||||
_attachEmoji->hide();
|
||||
}
|
||||
updateField();
|
||||
}
|
||||
|
@ -6310,13 +6317,13 @@ void HistoryWidget::setMembersShowAreaActive(bool active) {
|
|||
|
||||
void HistoryWidget::onMembersDropdownShow() {
|
||||
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->resize(st::membersInnerWidth, _membersDropdown->height());
|
||||
_membersDropdown->resizeToWidth(st::membersInnerWidth);
|
||||
|
||||
_membersDropdown->setMaxHeight(countMembersDropdownHeightMax());
|
||||
_membersDropdown->moveToLeft(0, 0);
|
||||
connect(_membersDropdown, SIGNAL(hidden()), this, SLOT(onMembersDropdownHidden()));
|
||||
connect(_membersDropdown, SIGNAL(beforeHidden()), this, SLOT(onMembersDropdownHidden()));
|
||||
}
|
||||
_membersDropdown->otherEnter();
|
||||
}
|
||||
|
@ -6436,24 +6443,24 @@ void HistoryWidget::moveFieldControls() {
|
|||
// (_attachDocument|_attachPhoto) _field (_silent|_cmdStart|_kbShow) (_kbHide|_attachEmoji) [_broadcast] _send
|
||||
// (_botStart|_unblock|_joinChannel|_muteUnmute)
|
||||
|
||||
int buttonsBottom = bottom - _attachDocument.height();
|
||||
_attachDocument.move(0, buttonsBottom);
|
||||
_attachPhoto.move(0, buttonsBottom);
|
||||
_field.move(_attachDocument.width(), bottom - _field.height() - st::sendPadding);
|
||||
int buttonsBottom = bottom - _attachDocument->height();
|
||||
_attachDocument->move(0, buttonsBottom);
|
||||
_attachPhoto->move(0, buttonsBottom);
|
||||
_field.move(_attachDocument->width(), bottom - _field.height() - st::sendPadding);
|
||||
_send.move(right - _send.width(), buttonsBottom);
|
||||
if (_inlineBotCancel) _inlineBotCancel->move(_send.pos());
|
||||
right -= _send.width();
|
||||
_attachEmoji.move(right - _attachEmoji.width(), buttonsBottom);
|
||||
_kbHide.move(right - _kbHide.width(), buttonsBottom);
|
||||
right -= _attachEmoji.width();
|
||||
_kbShow.move(right - _kbShow.width(), buttonsBottom);
|
||||
_cmdStart.move(right - _cmdStart.width(), buttonsBottom);
|
||||
_attachEmoji->move(right - _attachEmoji->width(), buttonsBottom);
|
||||
_botKeyboardHide->move(right - _botKeyboardHide->width(), buttonsBottom);
|
||||
right -= _attachEmoji->width();
|
||||
_botKeyboardShow->move(right - _botKeyboardShow->width(), buttonsBottom);
|
||||
_botCommandStart->move(right - _botCommandStart->width(), buttonsBottom);
|
||||
_silent.move(right - _silent.width(), buttonsBottom);
|
||||
|
||||
right = w;
|
||||
_fieldBarCancel.move(right - _fieldBarCancel.width(), _field.y() - st::sendPadding - _fieldBarCancel.height());
|
||||
_attachType->move(0, _attachDocument.y() - _attachType->height());
|
||||
_emojiPan->moveBottom(_attachEmoji.y());
|
||||
_attachType->move(0, _attachDocument->y() - _attachType->height());
|
||||
_emojiPan->moveBottom(_attachEmoji->y());
|
||||
|
||||
_botStart.setGeometry(0, bottom - _botStart.height(), w, _botStart.height());
|
||||
_unblock.setGeometry(0, bottom - _unblock.height(), w, _unblock.height());
|
||||
|
@ -6463,11 +6470,11 @@ void HistoryWidget::moveFieldControls() {
|
|||
|
||||
void HistoryWidget::updateFieldSize() {
|
||||
bool kbShowShown = _history && !_kbShown && _keyboard.hasMarkup();
|
||||
int fieldWidth = width() - _attachDocument.width();
|
||||
int fieldWidth = width() - _attachDocument->width();
|
||||
fieldWidth -= _send.width();
|
||||
fieldWidth -= _attachEmoji.width();
|
||||
if (kbShowShown) fieldWidth -= _kbShow.width();
|
||||
if (_cmdStartShown) fieldWidth -= _cmdStart.width();
|
||||
fieldWidth -= _attachEmoji->width();
|
||||
if (kbShowShown) fieldWidth -= _botKeyboardShow->width();
|
||||
if (_cmdStartShown) fieldWidth -= _botCommandStart->width();
|
||||
if (hasSilentToggle()) fieldWidth -= _silent.width();
|
||||
|
||||
if (_field.width() != fieldWidth) {
|
||||
|
@ -6493,7 +6500,7 @@ void HistoryWidget::inlineBotChanged() {
|
|||
_inlineBotCancel = std_::make_unique<IconedButton>(this, st::inlineBotCancel);
|
||||
connect(_inlineBotCancel.get(), SIGNAL(clicked()), this, SLOT(onInlineBotCancel()));
|
||||
_inlineBotCancel->setGeometry(_send.geometry());
|
||||
_attachEmoji.raise();
|
||||
_attachEmoji->raise();
|
||||
updateFieldSubmitSettings();
|
||||
updateControlsVisibility();
|
||||
} 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());
|
||||
|
||||
_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) {
|
||||
_membersDropdown->setMaxHeight(countMembersDropdownHeightMax());
|
||||
}
|
||||
|
@ -7315,15 +7322,15 @@ void HistoryWidget::updateBotKeyboard(History *h, bool force) {
|
|||
if (!_a_show.animating()) {
|
||||
if (hasMarkup) {
|
||||
_kbScroll.show();
|
||||
_attachEmoji.hide();
|
||||
_kbHide.show();
|
||||
_attachEmoji->hide();
|
||||
_botKeyboardHide->show();
|
||||
} else {
|
||||
_kbScroll.hide();
|
||||
_attachEmoji.show();
|
||||
_kbHide.hide();
|
||||
_attachEmoji->show();
|
||||
_botKeyboardHide->hide();
|
||||
}
|
||||
_kbShow.hide();
|
||||
_cmdStart.hide();
|
||||
_botKeyboardShow->hide();
|
||||
_botCommandStart->hide();
|
||||
}
|
||||
int32 maxh = hasMarkup ? qMin(_keyboard.height(), int(st::maxFieldHeight) - (int(st::maxFieldHeight) / 2)) : 0;
|
||||
_field.setMaxHeight(st::maxFieldHeight - maxh);
|
||||
|
@ -7338,10 +7345,10 @@ void HistoryWidget::updateBotKeyboard(History *h, bool force) {
|
|||
} else {
|
||||
if (!_a_show.animating()) {
|
||||
_kbScroll.hide();
|
||||
_attachEmoji.show();
|
||||
_kbHide.hide();
|
||||
_kbShow.show();
|
||||
_cmdStart.hide();
|
||||
_attachEmoji->show();
|
||||
_botKeyboardHide->hide();
|
||||
_botKeyboardShow->show();
|
||||
_botCommandStart->hide();
|
||||
}
|
||||
_field.setMaxHeight(st::maxFieldHeight);
|
||||
_kbShown = false;
|
||||
|
@ -7354,10 +7361,10 @@ void HistoryWidget::updateBotKeyboard(History *h, bool force) {
|
|||
} else {
|
||||
if (!_scroll.isHidden()) {
|
||||
_kbScroll.hide();
|
||||
_attachEmoji.show();
|
||||
_kbHide.hide();
|
||||
_kbShow.hide();
|
||||
_cmdStart.show();
|
||||
_attachEmoji->show();
|
||||
_botKeyboardHide->hide();
|
||||
_botKeyboardShow->hide();
|
||||
_botCommandStart->show();
|
||||
}
|
||||
_field.setMaxHeight(st::maxFieldHeight);
|
||||
_kbShown = false;
|
||||
|
@ -7543,9 +7550,7 @@ void HistoryWidget::onInlineResultSend(InlineBots::Result *result, UserData *bot
|
|||
Local::writeRecentHashtagsAndBots();
|
||||
}
|
||||
|
||||
if (!_fieldAutocomplete->isHidden()) _fieldAutocomplete->hideStart();
|
||||
if (!_attachType->isHidden()) _attachType->hideStart();
|
||||
if (!_emojiPan->isHidden()) _emojiPan->hideStart();
|
||||
hideSelectorControlsAnimated();
|
||||
|
||||
_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
|
||||
}
|
||||
|
||||
if (!_fieldAutocomplete->isHidden()) _fieldAutocomplete->hideStart();
|
||||
if (!_attachType->isHidden()) _attachType->hideStart();
|
||||
if (!_emojiPan->isHidden()) _emojiPan->hideStart();
|
||||
hideSelectorControlsAnimated();
|
||||
|
||||
_field.setFocus();
|
||||
return true;
|
||||
|
@ -7758,9 +7761,7 @@ void HistoryWidget::sendExistingPhoto(PhotoData *photo, const QString &caption)
|
|||
|
||||
App::historyRegRandom(randomId, newId);
|
||||
|
||||
if (!_fieldAutocomplete->isHidden()) _fieldAutocomplete->hideStart();
|
||||
if (!_attachType->isHidden()) _attachType->hideStart();
|
||||
if (!_emojiPan->isHidden()) _emojiPan->hideStart();
|
||||
hideSelectorControlsAnimated();
|
||||
|
||||
_field.setFocus();
|
||||
}
|
||||
|
@ -8001,7 +8002,7 @@ void HistoryWidget::cancelReplyAfterMediaSend(bool lastKeyboardUsed) {
|
|||
|
||||
int HistoryWidget::countMembersDropdownHeightMax() const {
|
||||
int result = height() - st::membersInnerDropdown.padding.top() - st::membersInnerDropdown.padding.bottom();
|
||||
result -= _attachEmoji.height();
|
||||
result -= _attachEmoji->height();
|
||||
accumulate_min(result, st::membersInnerHeightMax);
|
||||
return result;
|
||||
}
|
||||
|
@ -8221,7 +8222,7 @@ void HistoryWidget::onCancel() {
|
|||
onFieldBarCancel();
|
||||
}
|
||||
} else if (!_fieldAutocomplete->isHidden()) {
|
||||
_fieldAutocomplete->hideStart();
|
||||
_fieldAutocomplete->hideAnimated();
|
||||
} else {
|
||||
App::main()->showBackFromStack();
|
||||
emit cancelled();
|
||||
|
@ -8637,36 +8638,36 @@ void HistoryWidget::paintEditHeader(Painter &p, const QRect &rect, int left, int
|
|||
|
||||
void HistoryWidget::drawRecordButton(Painter &p) {
|
||||
if (a_recordDown.current() < 1) {
|
||||
p.setOpacity(st::btnAttachEmoji.opacity * (1 - a_recordOver.current()) + st::btnAttachEmoji.overOpacity * a_recordOver.current());
|
||||
p.drawSprite(_send.x() + (_send.width() - st::btnRecordAudio.pxWidth()) / 2, _send.y() + (_send.height() - st::btnRecordAudio.pxHeight()) / 2, st::btnRecordAudio);
|
||||
p.setOpacity(st::historyAttachEmoji.opacity * (1 - a_recordOver.current()) + st::historyAttachEmoji.overOpacity * a_recordOver.current());
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
void HistoryWidget::drawRecording(Painter &p) {
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(st::recordSignalColor->b);
|
||||
p.setBrush(st::historyRecordSignalColor);
|
||||
p.setRenderHint(QPainter::HighQualityAntialiasing);
|
||||
float64 delta = qMin(float64(a_recordingLevel.current()) / 0x4000, 1.);
|
||||
int32 d = 2 * qRound(st::recordSignalMin + (delta * (st::recordSignalMax - st::recordSignalMin)));
|
||||
p.drawEllipse(_attachPhoto.x() + (_attachEmoji.width() - d) / 2, _attachPhoto.y() + (_attachPhoto.height() - d) / 2, d, d);
|
||||
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.setRenderHint(QPainter::HighQualityAntialiasing, false);
|
||||
|
||||
QString duration = formatDurationText(_recordingSamples / AudioVoiceMsgFrequency);
|
||||
p.setFont(st::recordFont->f);
|
||||
p.setFont(st::historyRecordFont);
|
||||
|
||||
p.setPen(st::black->p);
|
||||
p.drawText(_attachPhoto.x() + _attachEmoji.width(), _attachPhoto.y() + st::recordTextTop + st::recordFont->ascent, duration);
|
||||
p.setPen(st::black);
|
||||
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();
|
||||
|
||||
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) {
|
||||
|
|
|
@ -22,7 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
|
||||
#include "localimageloader.h"
|
||||
#include "ui/effects/rect_shadow.h"
|
||||
#include "ui/popupmenu.h"
|
||||
#include "ui/widgets/tooltip.h"
|
||||
#include "history/history_common.h"
|
||||
#include "history/field_autocomplete.h"
|
||||
#include "window/section_widget.h"
|
||||
|
@ -36,17 +36,20 @@ class Result;
|
|||
} // namespace InlineBots
|
||||
|
||||
namespace Ui {
|
||||
class HistoryDownButton;
|
||||
class InnerDropdown;
|
||||
class DropdownMenu;
|
||||
class PlainShadow;
|
||||
class PopupMenu;
|
||||
class IconButton;
|
||||
class HistoryDownButton;
|
||||
class EmojiButton;
|
||||
} // namespace Ui
|
||||
|
||||
class Dropdown;
|
||||
class DragArea;
|
||||
class EmojiPan;
|
||||
|
||||
class HistoryWidget;
|
||||
class HistoryInner : public TWidget, public AbstractTooltipShower, private base::Subscriber {
|
||||
class HistoryInner : public TWidget, public Ui::AbstractTooltipShower, private base::Subscriber {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
@ -256,7 +259,7 @@ private:
|
|||
QTimer _touchScrollTimer;
|
||||
|
||||
// context menu
|
||||
PopupMenu *_menu = nullptr;
|
||||
Ui::PopupMenu *_menu = nullptr;
|
||||
|
||||
// save visible area coords for painting / pressing userpics
|
||||
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
|
||||
|
||||
public:
|
||||
|
@ -505,7 +508,7 @@ private:
|
|||
|
||||
};
|
||||
|
||||
class SilentToggle : public FlatCheckbox, public AbstractTooltipShower {
|
||||
class SilentToggle : public FlatCheckbox, public Ui::AbstractTooltipShower {
|
||||
public:
|
||||
|
||||
SilentToggle(QWidget *parent);
|
||||
|
@ -868,6 +871,7 @@ private:
|
|||
|
||||
void cancelReplyAfterMediaSend(bool lastKeyboardUsed);
|
||||
|
||||
void hideSelectorControlsAnimated();
|
||||
int countMembersDropdownHeightMax() const;
|
||||
|
||||
MsgId _replyToId = 0;
|
||||
|
@ -1086,9 +1090,12 @@ private:
|
|||
FlatButton _send, _unblock, _botStart, _joinChannel, _muteUnmute;
|
||||
mtpRequestId _unblockRequest = 0;
|
||||
mtpRequestId _reportSpamRequest = 0;
|
||||
IconedButton _attachDocument, _attachPhoto;
|
||||
EmojiButton _attachEmoji;
|
||||
IconedButton _kbShow, _kbHide, _cmdStart;
|
||||
ChildWidget<Ui::IconButton> _attachDocument;
|
||||
ChildWidget<Ui::IconButton> _attachPhoto;
|
||||
ChildWidget<Ui::EmojiButton> _attachEmoji;
|
||||
ChildWidget<Ui::IconButton> _botKeyboardShow;
|
||||
ChildWidget<Ui::IconButton> _botKeyboardHide;
|
||||
ChildWidget<Ui::IconButton> _botCommandStart;
|
||||
SilentToggle _silent;
|
||||
bool _cmdStartShown = false;
|
||||
MessageField _field;
|
||||
|
@ -1115,7 +1122,7 @@ private:
|
|||
ChildWidget<Ui::InnerDropdown> _membersDropdown = { nullptr };
|
||||
QTimer _membersDropdownShowTimer;
|
||||
|
||||
ChildWidget<Dropdown> _attachType;
|
||||
ChildWidget<Ui::DropdownMenu> _attachType;
|
||||
ChildWidget<EmojiPan> _emojiPan;
|
||||
DragState _attachDrag = DragStateNone;
|
||||
ChildWidget<DragArea> _attachDragDocument, _attachDragPhoto;
|
||||
|
|
|
@ -22,6 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "mainwidget.h"
|
||||
|
||||
#include "styles/style_dialogs.h"
|
||||
#include "styles/style_history.h"
|
||||
#include "ui/buttons/peer_avatar_button.h"
|
||||
#include "ui/buttons/round_button.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/top_bar_widget.h"
|
||||
#include "data/data_drafts.h"
|
||||
#include "dropdown.h"
|
||||
#include "ui/widgets/dropdown_menu.h"
|
||||
#include "observer_peer.h"
|
||||
#include "apiwrap.h"
|
||||
#include "dialogswidget.h"
|
||||
|
@ -75,7 +76,7 @@ MainWidget::MainWidget(MainWindow *window) : TWidget(window)
|
|||
, _topBar(this)
|
||||
, _playerPlaylist(this, Media::Player::Panel::Layout::OnlyPlaylist)
|
||||
, _playerPanel(this, Media::Player::Panel::Layout::Full)
|
||||
, _mediaType(this)
|
||||
, _mediaType(this, st::historyAttachDropdownMenu)
|
||||
, _api(new ApiWrap(this)) {
|
||||
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) {
|
||||
_mediaType->resetButtons();
|
||||
_mediaType->clearActions();
|
||||
for (int32 i = 0; i < OverviewCount; ++i) {
|
||||
if (mask & (1 << i)) {
|
||||
switch (i) {
|
||||
case OverviewPhotos: connect(_mediaType->addButton(new IconedButton(this, st::dropdownMediaPhotos, lang(lng_media_type_photos))), SIGNAL(clicked()), this, SLOT(onPhotosSelect())); break;
|
||||
case OverviewVideos: connect(_mediaType->addButton(new IconedButton(this, st::dropdownMediaVideos, lang(lng_media_type_videos))), SIGNAL(clicked()), this, SLOT(onVideosSelect())); break;
|
||||
case OverviewMusicFiles: connect(_mediaType->addButton(new IconedButton(this, st::dropdownMediaSongs, lang(lng_media_type_songs))), SIGNAL(clicked()), this, SLOT(onSongsSelect())); break;
|
||||
case OverviewFiles: connect(_mediaType->addButton(new IconedButton(this, st::dropdownMediaDocuments, lang(lng_media_type_files))), SIGNAL(clicked()), this, SLOT(onDocumentsSelect())); break;
|
||||
case OverviewVoiceFiles: connect(_mediaType->addButton(new IconedButton(this, st::dropdownMediaAudios, lang(lng_media_type_audios))), SIGNAL(clicked()), this, SLOT(onAudiosSelect())); break;
|
||||
case OverviewLinks: connect(_mediaType->addButton(new IconedButton(this, st::dropdownMediaLinks, lang(lng_media_type_links))), SIGNAL(clicked()), this, SLOT(onLinksSelect())); break;
|
||||
case OverviewPhotos: _mediaType->addAction(lang(lng_media_type_photos), this, SLOT(onPhotosSelect()), &st::historyMediaTypePhoto); break;
|
||||
case OverviewVideos: _mediaType->addAction(lang(lng_media_type_videos), this, SLOT(onVideosSelect()), &st::historyMediaTypeVideo); break;
|
||||
case OverviewMusicFiles: _mediaType->addAction(lang(lng_media_type_songs), this, SLOT(onSongsSelect()), &st::historyMediaTypeSong); break;
|
||||
case OverviewFiles: _mediaType->addAction(lang(lng_media_type_files), this, SLOT(onDocumentsSelect()), &st::historyMediaTypeFile); break;
|
||||
case OverviewVoiceFiles: _mediaType->addAction(lang(lng_media_type_audios), this, SLOT(onAudiosSelect()), &st::historyMediaTypeVoice); 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() {
|
||||
if (_overview) _overview->switchType(OverviewPhotos);
|
||||
_mediaType->hideStart();
|
||||
_mediaType->hideAnimated();
|
||||
}
|
||||
|
||||
void MainWidget::onVideosSelect() {
|
||||
if (_overview) _overview->switchType(OverviewVideos);
|
||||
_mediaType->hideStart();
|
||||
_mediaType->hideAnimated();
|
||||
}
|
||||
|
||||
void MainWidget::onSongsSelect() {
|
||||
if (_overview) _overview->switchType(OverviewMusicFiles);
|
||||
_mediaType->hideStart();
|
||||
_mediaType->hideAnimated();
|
||||
}
|
||||
|
||||
void MainWidget::onDocumentsSelect() {
|
||||
if (_overview) _overview->switchType(OverviewFiles);
|
||||
_mediaType->hideStart();
|
||||
_mediaType->hideAnimated();
|
||||
}
|
||||
|
||||
void MainWidget::onAudiosSelect() {
|
||||
if (_overview) _overview->switchType(OverviewVoiceFiles);
|
||||
_mediaType->hideStart();
|
||||
_mediaType->hideAnimated();
|
||||
}
|
||||
|
||||
void MainWidget::onLinksSelect() {
|
||||
if (_overview) _overview->switchType(OverviewLinks);
|
||||
_mediaType->hideStart();
|
||||
_mediaType->hideAnimated();
|
||||
}
|
||||
|
||||
Window::TopBarWidget *MainWidget::topBar() {
|
||||
|
|
|
@ -39,6 +39,7 @@ class Panel;
|
|||
namespace Ui {
|
||||
class PeerAvatarButton;
|
||||
class PlainShadow;
|
||||
class DropdownMenu;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Window {
|
||||
|
@ -56,7 +57,6 @@ class DialogsWidget;
|
|||
class HistoryWidget;
|
||||
class OverviewWidget;
|
||||
class HistoryHider;
|
||||
class Dropdown;
|
||||
|
||||
enum StackItemType {
|
||||
HistoryStackItem,
|
||||
|
@ -609,7 +609,7 @@ private:
|
|||
int _playerHeight = 0;
|
||||
int _contentScrollAddToY = 0;
|
||||
|
||||
ChildWidget<Dropdown> _mediaType;
|
||||
ChildWidget<Ui::DropdownMenu> _mediaType;
|
||||
int32 _mediaTypeMask = 0;
|
||||
|
||||
int32 updDate = 0;
|
||||
|
|
|
@ -23,7 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
|
||||
#include "dialogs/dialogs_layout.h"
|
||||
#include "styles/style_dialogs.h"
|
||||
#include "ui/popupmenu.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "zip.h"
|
||||
#include "lang.h"
|
||||
#include "shortcuts.h"
|
||||
|
@ -185,7 +185,7 @@ void MainWindow::onWindowActiveChanged() {
|
|||
|
||||
void MainWindow::firstShow() {
|
||||
#ifdef Q_OS_WIN
|
||||
trayIconMenu = new PopupMenu();
|
||||
trayIconMenu = new Ui::PopupMenu();
|
||||
trayIconMenu->deleteOnHide(false);
|
||||
#else // Q_OS_WIN
|
||||
trayIconMenu = new QMenu(this);
|
||||
|
|
|
@ -29,7 +29,7 @@ class Document;
|
|||
namespace Media {
|
||||
namespace Player {
|
||||
|
||||
class ListWidget : public ScrolledWidget, private base::Subscriber {
|
||||
class ListWidget : public TWidget, private base::Subscriber {
|
||||
public:
|
||||
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_instance.h"
|
||||
#include "styles/style_overview.h"
|
||||
#include "styles/style_widgets.h"
|
||||
#include "styles/style_media_player.h"
|
||||
#include "ui/widgets/shadow.h"
|
||||
#include "mainwindow.h"
|
||||
|
@ -34,7 +35,7 @@ namespace Player {
|
|||
|
||||
Panel::Panel(QWidget *parent, Layout layout) : TWidget(parent)
|
||||
, _layout(layout)
|
||||
, _shadow(st::defaultInnerDropdown.shadow)
|
||||
, _shadow(st::defaultDropdownShadow)
|
||||
, _scroll(this, st::mediaPlayerScroll) {
|
||||
_hideTimer.setSingleShot(true);
|
||||
connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(onHideStart()));
|
||||
|
@ -90,7 +91,7 @@ void Panel::updateControlsGeometry() {
|
|||
if (scrollHeight > 0) {
|
||||
_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);
|
||||
onScroll();
|
||||
}
|
||||
|
@ -118,7 +119,7 @@ void Panel::scrollPlaylistToCurrentTrack() {
|
|||
}
|
||||
|
||||
void Panel::onScroll() {
|
||||
if (auto widget = static_cast<ScrolledWidget*>(_scroll->widget())) {
|
||||
if (auto widget = static_cast<TWidget*>(_scroll->widget())) {
|
||||
int visibleTop = _scroll->scrollTop();
|
||||
int visibleBottom = visibleTop + _scroll->height();
|
||||
widget->setVisibleTopBottom(visibleTop, visibleBottom);
|
||||
|
@ -153,7 +154,7 @@ void Panel::paintEvent(QPaintEvent *e) {
|
|||
if (animating) {
|
||||
p.setOpacity(_a_appearance.current(_hiding ? 0. : 1.));
|
||||
} else if (_hiding || isHidden()) {
|
||||
hidingFinished();
|
||||
hideFinished();
|
||||
return;
|
||||
}
|
||||
p.drawPixmap(0, 0, _cache);
|
||||
|
@ -290,7 +291,7 @@ void Panel::onShowStart() {
|
|||
void Panel::hideIgnoringEnterEvents() {
|
||||
_ignoringEnterEvents = true;
|
||||
if (isHidden()) {
|
||||
hidingFinished();
|
||||
hideFinished();
|
||||
} else {
|
||||
onHideStart();
|
||||
}
|
||||
|
@ -317,13 +318,13 @@ void Panel::startAnimation() {
|
|||
void Panel::appearanceCallback() {
|
||||
if (!_a_appearance.animating() && _hiding) {
|
||||
_hiding = false;
|
||||
hidingFinished();
|
||||
hideFinished();
|
||||
} else {
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void Panel::hidingFinished() {
|
||||
void Panel::hideFinished() {
|
||||
hide();
|
||||
_cache = QPixmap();
|
||||
performDestroy();
|
||||
|
|
|
@ -81,7 +81,7 @@ private:
|
|||
|
||||
void updateSize();
|
||||
void appearanceCallback();
|
||||
void hidingFinished();
|
||||
void hideFinished();
|
||||
int contentLeft() const;
|
||||
int contentTop() const;
|
||||
int contentRight() const;
|
||||
|
|
|
@ -56,9 +56,6 @@ public:
|
|||
|
||||
bool overlaps(const QRect &globalRect);
|
||||
|
||||
void otherEnter();
|
||||
void otherLeave();
|
||||
|
||||
QMargins getMargin() const;
|
||||
|
||||
protected:
|
||||
|
@ -75,6 +72,9 @@ private slots:
|
|||
void onWindowActiveChanged();
|
||||
|
||||
private:
|
||||
void otherEnter();
|
||||
void otherLeave();
|
||||
|
||||
void appearanceCallback();
|
||||
void hidingFinished();
|
||||
void startAnimation();
|
||||
|
|
|
@ -110,3 +110,50 @@ mediaviewFileBlue: icon {
|
|||
mediaviewTransparentBg: #ffffff;
|
||||
mediaviewTransparentFg: #cccccc;
|
||||
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 "application.h"
|
||||
#include "ui/filedialog.h"
|
||||
#include "ui/popupmenu.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "media/media_clip_reader.h"
|
||||
#include "media/view/media_clip_controller.h"
|
||||
#include "styles/style_mediaview.h"
|
||||
|
@ -88,7 +88,7 @@ MediaView::MediaView() : TWidget(App::wnd())
|
|||
, _radial(animation(this, &MediaView::step_radial))
|
||||
, _lastAction(-st::mvDeltaFromLastAction, -st::mvDeltaFromLastAction)
|
||||
, _a_state(animation(this, &MediaView::step_state))
|
||||
, _dropdown(this, st::mvDropdown) {
|
||||
, _dropdown(this, st::mediaviewDropdownMenu) {
|
||||
TextCustomTagsMap custom;
|
||||
custom.insert(QChar('c'), qMakePair(textcmdStartLink(1), textcmdStopLink()));
|
||||
_saveMsgText.setRichText(st::medviewSaveMsgFont, lang(lng_mediaview_saved), _textDlgOptions, custom);
|
||||
|
@ -126,32 +126,14 @@ MediaView::MediaView() : TWidget(App::wnd())
|
|||
_touchTimer.setSingleShot(true);
|
||||
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);
|
||||
connect(&_controlsHideTimer, SIGNAL(timeout()), this, SLOT(onHideControls()));
|
||||
|
||||
connect(&_docDownload, SIGNAL(clicked()), this, SLOT(onDownload()));
|
||||
connect(&_docSaveAs, SIGNAL(clicked()), this, SLOT(onSaveAs()));
|
||||
connect(&_docCancel, SIGNAL(clicked()), this, SLOT(onSaveCancel()));
|
||||
|
||||
connect(_dropdown, SIGNAL(beforeHidden()), this, SLOT(onDropdownHidden()));
|
||||
}
|
||||
|
||||
void MediaView::moveToScreen() {
|
||||
|
@ -400,18 +382,31 @@ void MediaView::updateControls() {
|
|||
update();
|
||||
}
|
||||
|
||||
void MediaView::updateDropdown() {
|
||||
_btnSaveCancel->setVisible(_doc && _doc->loading());
|
||||
_btnToMessage->setVisible(_msgid > 0);
|
||||
_btnShowInFolder->setVisible(_doc && !_doc->filepath(DocumentData::FilePathResolveChecked).isEmpty());
|
||||
_btnSaveAs->setVisible(true);
|
||||
_btnCopy->setVisible((_doc && fileShown()) || (_photo && _photo->loaded()));
|
||||
_btnForward->setVisible(_canForward);
|
||||
_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()))));
|
||||
_btnViewAll->setVisible(_history && typeHasMediaOverview(_overview));
|
||||
_btnViewAll->setText(lang(_doc ? lng_mediaview_files_all : lng_mediaview_photos_all));
|
||||
_dropdown.updateButtons();
|
||||
_dropdown.moveToRight(0, height() - _dropdown.height());
|
||||
void MediaView::updateActions() {
|
||||
_actions.clear();
|
||||
|
||||
if (_doc && _doc->loading()) {
|
||||
_actions.push_back({ lang(lng_cancel), SLOT(onSaveCancel()) });
|
||||
}
|
||||
if (_msgid > 0) {
|
||||
_actions.push_back({ lang(lng_context_to_msg), SLOT(onToMessage()) });
|
||||
}
|
||||
if (_doc && !_doc->filepath(DocumentData::FilePathResolveChecked).isEmpty()) {
|
||||
_actions.push_back({ lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_context_show_in_finder : lng_context_show_in_folder), SLOT(onShowInFolder()) });
|
||||
}
|
||||
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) {
|
||||
|
@ -662,7 +657,7 @@ void MediaView::activateControls() {
|
|||
|
||||
void MediaView::onHideControls(bool force) {
|
||||
if (!force) {
|
||||
if (!_dropdown.isHidden()
|
||||
if (!_dropdown->isHidden()
|
||||
|| _menu
|
||||
|| _mousePressed
|
||||
|| (_fullScreenVideo && _clipController && _clipController->geometry().contains(_lastMouseMovePos))) {
|
||||
|
@ -682,7 +677,7 @@ void MediaView::onHideControls(bool force) {
|
|||
if (!_a_state.animating()) _a_state.start();
|
||||
}
|
||||
|
||||
void MediaView::onDropdownHiding() {
|
||||
void MediaView::onDropdownHidden() {
|
||||
setFocus();
|
||||
_ignoringDropdown = true;
|
||||
_lastMouseMovePos = mapFromGlobal(QCursor::pos());
|
||||
|
@ -961,10 +956,7 @@ void MediaView::onOverview() {
|
|||
}
|
||||
|
||||
void MediaView::onCopy() {
|
||||
if (!_dropdown.isHidden()) {
|
||||
_dropdown.ignoreShow();
|
||||
_dropdown.hideStart();
|
||||
}
|
||||
_dropdown->hideAnimated(Ui::DropdownMenu::HideOption::IgnoreShow);
|
||||
if (_doc) {
|
||||
if (!_current.isNull()) {
|
||||
QApplication::clipboard()->setPixmap(_current);
|
||||
|
@ -2395,10 +2387,10 @@ void MediaView::contextMenuEvent(QContextMenuEvent *e) {
|
|||
_menu->deleteLater();
|
||||
_menu = 0;
|
||||
}
|
||||
_menu = new PopupMenu(st::mvPopupMenu);
|
||||
updateDropdown();
|
||||
for (int32 i = 0, l = _btns.size(); i < l; ++i) {
|
||||
if (!_btns.at(i)->isHidden()) _menu->addAction(_btns.at(i)->getText(), _btns.at(i), SIGNAL(clicked()))->setEnabled(true);
|
||||
_menu = new Ui::PopupMenu(st::mediaviewPopupMenu);
|
||||
updateActions();
|
||||
for_const (auto &action, _actions) {
|
||||
_menu->addAction(action.text, this, action.member)->setEnabled(true);
|
||||
}
|
||||
connect(_menu, SIGNAL(destroyed(QObject*)), this, SLOT(onMenuDestroy(QObject*)));
|
||||
_menu->popup(e->globalPos());
|
||||
|
@ -2541,10 +2533,14 @@ void MediaView::receiveMouse() {
|
|||
}
|
||||
|
||||
void MediaView::onDropdown() {
|
||||
updateDropdown();
|
||||
_dropdown.ignoreShow(false);
|
||||
_dropdown.showStart();
|
||||
_dropdown.setFocus();
|
||||
updateActions();
|
||||
_dropdown->clearActions();
|
||||
for_const (auto &action, _actions) {
|
||||
_dropdown->addAction(action.text, this, action.member);
|
||||
}
|
||||
_dropdown->moveToRight(0, height() - _dropdown->height());
|
||||
_dropdown->showAnimated();
|
||||
_dropdown->setFocus();
|
||||
}
|
||||
|
||||
void MediaView::onCheckActive() {
|
||||
|
|
|
@ -20,7 +20,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "dropdown.h"
|
||||
#include "ui/widgets/dropdown_menu.h"
|
||||
#include "ui/effects/radial_animation.h"
|
||||
|
||||
namespace Media {
|
||||
|
@ -29,7 +29,9 @@ class Controller;
|
|||
} // namespace Clip
|
||||
} // namespace Media
|
||||
|
||||
namespace Ui {
|
||||
class PopupMenu;
|
||||
} // namespace Ui
|
||||
|
||||
struct AudioPlaybackState;
|
||||
|
||||
|
@ -60,9 +62,6 @@ public:
|
|||
void mediaOverviewUpdated(PeerData *peer, MediaOverviewType type);
|
||||
void documentUpdated(DocumentData *doc);
|
||||
void changingMsgId(HistoryItem *row, MsgId newId);
|
||||
void updateDocSize();
|
||||
void updateControls();
|
||||
void updateDropdown();
|
||||
|
||||
void showSaveMsgFile();
|
||||
void close();
|
||||
|
@ -81,9 +80,9 @@ public:
|
|||
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
|
||||
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override;
|
||||
|
||||
public slots:
|
||||
private slots:
|
||||
void onHideControls(bool force = false);
|
||||
void onDropdownHiding();
|
||||
void onDropdownHidden();
|
||||
|
||||
void onScreenResized(int screen);
|
||||
|
||||
|
@ -130,6 +129,10 @@ private slots:
|
|||
void onVideoPlayProgress(const AudioMsgId &audioId);
|
||||
|
||||
private:
|
||||
void updateDocSize();
|
||||
void updateControls();
|
||||
void updateActions();
|
||||
|
||||
void displayPhoto(PhotoData *photo, HistoryItem *item);
|
||||
void displayDocument(DocumentData *doc, HistoryItem *item);
|
||||
void displayFinished();
|
||||
|
@ -304,10 +307,14 @@ private:
|
|||
anim::fvalue a_cOpacity;
|
||||
bool _mousePressed = false;
|
||||
|
||||
PopupMenu *_menu = nullptr;
|
||||
Dropdown _dropdown;
|
||||
IconedButton *_btnSaveCancel, *_btnToMessage, *_btnShowInFolder, *_btnSaveAs, *_btnCopy, *_btnForward, *_btnDelete, *_btnViewAll;
|
||||
QList<IconedButton*> _btns;
|
||||
Ui::PopupMenu *_menu = nullptr;
|
||||
ChildWidget<Ui::DropdownMenu> _dropdown;
|
||||
|
||||
struct ActionData {
|
||||
QString text;
|
||||
const char *member;
|
||||
};
|
||||
QList<ActionData> _actions;
|
||||
|
||||
bool _receiveMouse = true;
|
||||
|
||||
|
|
|
@ -25,6 +25,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "boxes/confirmbox.h"
|
||||
#include "boxes/photocropbox.h"
|
||||
#include "ui/filedialog.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/widgets/tooltip.h"
|
||||
#include "window/top_bar_widget.h"
|
||||
#include "window/chat_background.h"
|
||||
#include "lang.h"
|
||||
|
@ -931,22 +933,22 @@ void OverviewInner::onUpdateSelected() {
|
|||
Qt::CursorShape cur = style::cur_default;
|
||||
bool lnkChanged = ClickHandler::setActive(lnk, lnkhost);
|
||||
if (lnkChanged) {
|
||||
PopupTooltip::Hide();
|
||||
Ui::Tooltip::Hide();
|
||||
}
|
||||
App::mousedItem(item);
|
||||
if (_mousedItem != oldMousedItem) {
|
||||
PopupTooltip::Hide();
|
||||
Ui::Tooltip::Hide();
|
||||
if (oldMousedItem) repaintItem(oldMousedItem, oldMousedItemIndex);
|
||||
if (item) repaintItem(item);
|
||||
}
|
||||
if (_cursorState == HistoryInDateCursorState && cursorState != HistoryInDateCursorState) {
|
||||
PopupTooltip::Hide();
|
||||
Ui::Tooltip::Hide();
|
||||
}
|
||||
if (cursorState != _cursorState) {
|
||||
_cursorState = cursorState;
|
||||
}
|
||||
if (lnk || cursorState == HistoryInDateCursorState) {
|
||||
PopupTooltip::Show(1000, this);
|
||||
Ui::Tooltip::Show(1000, this);
|
||||
}
|
||||
|
||||
fixItemIndex(_dragItemIndex, _dragItem);
|
||||
|
@ -1183,7 +1185,7 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
|||
bool lnkIsAudio = lnkDocument ? (lnkDocument->document()->voice() != nullptr) : false;
|
||||
bool lnkIsSong = lnkDocument ? (lnkDocument->document()->song() != nullptr) : false;
|
||||
if (lnkPhoto || lnkDocument) {
|
||||
_menu = new PopupMenu();
|
||||
_menu = new Ui::PopupMenu();
|
||||
if (App::hoveredLinkItem()) {
|
||||
_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());
|
||||
if (_selectedMsgId) repaintItem(_selectedMsgId, -1);
|
||||
} 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();
|
||||
if (!linkCopyToClipboardText.isEmpty()) {
|
||||
_menu->addAction(linkCopyToClipboardText, this, SLOT(copyContextUrl()))->setEnabled(true);
|
||||
|
|
|
@ -21,7 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#pragma once
|
||||
|
||||
#include "window/section_widget.h"
|
||||
#include "ui/popupmenu.h"
|
||||
#include "ui/widgets/tooltip.h"
|
||||
|
||||
namespace Overview {
|
||||
namespace Layout {
|
||||
|
@ -33,10 +33,11 @@ class Date;
|
|||
|
||||
namespace Ui {
|
||||
class PlainShadow;
|
||||
class PopupMenu;
|
||||
} // namespace Ui
|
||||
|
||||
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
|
||||
|
||||
public:
|
||||
|
@ -263,7 +264,7 @@ private:
|
|||
uint64 _touchTime = 0;
|
||||
QTimer _touchScrollTimer;
|
||||
|
||||
PopupMenu *_menu = nullptr;
|
||||
Ui::PopupMenu *_menu = nullptr;
|
||||
};
|
||||
|
||||
class OverviewWidget : public TWidget, public RPCSender {
|
||||
|
|
|
@ -28,7 +28,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "application.h"
|
||||
#include "lang.h"
|
||||
#include "localstorage.h"
|
||||
#include "ui/popupmenu.h"
|
||||
#include "ui/widgets/popup_menu.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 <windows.h>
|
||||
|
||||
namespace Ui {
|
||||
class PopupMenu;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Platform {
|
||||
|
||||
|
@ -109,7 +111,7 @@ protected:
|
|||
|
||||
bool posInited = false;
|
||||
QSystemTrayIcon *trayIcon = nullptr;
|
||||
PopupMenu *trayIconMenu = nullptr;
|
||||
Ui::PopupMenu *trayIconMenu = nullptr;
|
||||
QImage icon256, iconbig256;
|
||||
QIcon wndIcon;
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
|
||||
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)
|
||||
, _title(title) {
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
|
||||
namespace Profile {
|
||||
|
||||
class BlockWidget : public ScrolledWidget, protected base::Subscriber {
|
||||
class BlockWidget : public TWidget, protected base::Subscriber {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
|
|
@ -26,7 +26,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
|
||||
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)
|
||||
, _title(title) {
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ class WidgetSlideWrap;
|
|||
|
||||
namespace Settings {
|
||||
|
||||
class BlockWidget : public ScrolledWidget, protected base::Subscriber {
|
||||
class BlockWidget : public TWidget, protected base::Subscriber {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
|
|
@ -42,19 +42,19 @@ EmojiColorPicker::EmojiColorPicker() : TWidget()
|
|||
, _a_selected(animation(this, &EmojiColorPicker::step_selected))
|
||||
, a_opacity(0)
|
||||
, _a_appearance(animation(this, &EmojiColorPicker::step_appearance))
|
||||
, _shadow(st::dropdownDef.shadow) {
|
||||
, _shadow(st::defaultDropdownShadow) {
|
||||
memset(_variants, 0, sizeof(_variants));
|
||||
memset(_hovers, 0, sizeof(_hovers));
|
||||
|
||||
setMouseTracking(true);
|
||||
setFocusPolicy(Qt::NoFocus);
|
||||
|
||||
int32 w = st::emojiPanSize.width() * (EmojiColorsCount + 1) + 4 * st::emojiColorsPadding + st::emojiColorsSep + st::dropdownDef.shadow.width() * 2;
|
||||
int32 h = 2 * st::emojiColorsPadding + st::emojiPanSize.height() + st::dropdownDef.shadow.height() * 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::defaultDropdownShadow.height() * 2;
|
||||
resize(w, h);
|
||||
|
||||
_hideTimer.setSingleShot(true);
|
||||
connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(hideStart()));
|
||||
connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(hideAnimated()));
|
||||
}
|
||||
|
||||
void EmojiColorPicker::showEmoji(uint32 code) {
|
||||
|
@ -72,7 +72,7 @@ void EmojiColorPicker::showEmoji(uint32 code) {
|
|||
_variants[5] = emojiGet(e, 0xD83CDFFF);
|
||||
|
||||
if (!_cache.isNull()) _cache = QPixmap();
|
||||
showStart();
|
||||
showAnimated();
|
||||
}
|
||||
|
||||
void EmojiColorPicker::paintEvent(QPaintEvent *e) {
|
||||
|
@ -85,12 +85,12 @@ void EmojiColorPicker::paintEvent(QPaintEvent *e) {
|
|||
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);
|
||||
_shadow.paint(p, r, st::dropdownDef.shadowShift);
|
||||
_shadow.paint(p, r, st::defaultDropdownShadowShift);
|
||||
|
||||
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();
|
||||
if (rtl()) x = width() - x - st::emojiColorsSep;
|
||||
|
@ -108,7 +108,7 @@ void EmojiColorPicker::paintEvent(QPaintEvent *e) {
|
|||
|
||||
void EmojiColorPicker::enterEvent(QEvent *e) {
|
||||
_hideTimer.stop();
|
||||
if (_hiding) showStart();
|
||||
if (_hiding) showAnimated();
|
||||
TWidget::enterEvent(e);
|
||||
}
|
||||
|
||||
|
@ -135,7 +135,7 @@ void EmojiColorPicker::mouseReleaseEvent(QMouseEvent *e) {
|
|||
emit emojiSelected(_variants[_selected]);
|
||||
}
|
||||
_ignoreShow = true;
|
||||
hideStart();
|
||||
hideAnimated();
|
||||
}
|
||||
|
||||
void EmojiColorPicker::mouseMoveEvent(QMouseEvent *e) {
|
||||
|
@ -148,7 +148,7 @@ void EmojiColorPicker::step_appearance(float64 ms, bool timer) {
|
|||
_a_appearance.stop();
|
||||
return;
|
||||
}
|
||||
float64 dt = ms / st::dropdownDef.duration;
|
||||
float64 dt = ms / st::defaultDropdownDuration;
|
||||
if (dt >= 1) {
|
||||
a_opacity.finish();
|
||||
_cache = QPixmap();
|
||||
|
@ -178,34 +178,34 @@ void EmojiColorPicker::step_selected(uint64 ms, bool timer) {
|
|||
_hovers[index] = (i.key() > 0) ? dt : (1 - dt);
|
||||
++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 (_emojiAnimations.isEmpty()) _a_selected.stop();
|
||||
}
|
||||
|
||||
void EmojiColorPicker::hideStart(bool fast) {
|
||||
if (fast) {
|
||||
clearSelection(true);
|
||||
if (_a_appearance.animating()) _a_appearance.stop();
|
||||
if (_a_selected.animating()) _a_selected.stop();
|
||||
a_opacity = anim::fvalue(0);
|
||||
_cache = QPixmap();
|
||||
hide();
|
||||
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::hideFast() {
|
||||
clearSelection(true);
|
||||
if (_a_appearance.animating()) _a_appearance.stop();
|
||||
if (_a_selected.animating()) _a_selected.stop();
|
||||
a_opacity = anim::fvalue(0);
|
||||
_cache = QPixmap();
|
||||
hide();
|
||||
emit hidden();
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
_hiding = false;
|
||||
|
@ -217,7 +217,7 @@ void EmojiColorPicker::showStart() {
|
|||
return;
|
||||
}
|
||||
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));
|
||||
clearSelection(true);
|
||||
}
|
||||
|
@ -241,9 +241,9 @@ void EmojiColorPicker::clearSelection(bool fast) {
|
|||
void EmojiColorPicker::updateSelected() {
|
||||
int32 selIndex = -1;
|
||||
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()) {
|
||||
int32 x = sx - st::dropdownDef.shadow.width() - st::emojiColorsPadding;
|
||||
int32 x = sx - st::defaultDropdownShadow.width() - st::emojiColorsPadding;
|
||||
if (x >= 0 && x < st::emojiPanSize.width()) {
|
||||
selIndex = 0;
|
||||
} else {
|
||||
|
@ -279,7 +279,7 @@ void EmojiColorPicker::updateSelected() {
|
|||
void EmojiColorPicker::drawVariant(Painter &p, int 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) {
|
||||
p.setOpacity(hover);
|
||||
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));
|
||||
}
|
||||
|
||||
EmojiPanInner::EmojiPanInner() : ScrolledWidget()
|
||||
EmojiPanInner::EmojiPanInner() : TWidget()
|
||||
, _maxHeight(int(st::emojiPanMaxHeight) - st::rbEmoji.height)
|
||||
, _a_selected(animation(this, &EmojiPanInner::step_selected)) {
|
||||
resize(st::emojiPanWidth - st::emojiScroll.width, countHeight());
|
||||
|
@ -404,7 +404,7 @@ void EmojiPanInner::paintEvent(QPaintEvent *e) {
|
|||
|
||||
bool EmojiPanInner::checkPickerHide() {
|
||||
if (!_picker.isHidden() && _selected == _pickerSel) {
|
||||
_picker.hideStart();
|
||||
_picker.hideAnimated();
|
||||
_pickerSel = -1;
|
||||
updateSelected();
|
||||
return true;
|
||||
|
@ -446,7 +446,7 @@ void EmojiPanInner::mouseReleaseEvent(QMouseEvent *e) {
|
|||
int tab = (_pickerSel / MatrixRowShift), sel = _pickerSel % MatrixRowShift;
|
||||
if (tab < emojiTabCount && sel < _emojis[tab].size() && _emojis[tab][sel]->color) {
|
||||
if (cEmojiVariants().constFind(_emojis[tab][sel]->code) != cEmojiVariants().cend()) {
|
||||
_picker.hideStart();
|
||||
_picker.hideAnimated();
|
||||
_pickerSel = -1;
|
||||
}
|
||||
}
|
||||
|
@ -576,7 +576,7 @@ void EmojiPanInner::onColorSelected(EmojiPtr emoji) {
|
|||
}
|
||||
}
|
||||
selectEmoji(emoji);
|
||||
_picker.hideStart();
|
||||
_picker.hideAnimated();
|
||||
}
|
||||
|
||||
void EmojiPanInner::mouseMoveEvent(QMouseEvent *e) {
|
||||
|
@ -642,7 +642,7 @@ DBIEmojiTab EmojiPanInner::currentTab(int yOffset) const {
|
|||
|
||||
void EmojiPanInner::hideFinish() {
|
||||
if (!_picker.isHidden()) {
|
||||
_picker.hideStart(true);
|
||||
_picker.hideFast();
|
||||
_pickerSel = -1;
|
||||
clearSelection(true);
|
||||
}
|
||||
|
@ -738,9 +738,9 @@ void EmojiPanInner::updateSelected() {
|
|||
setCursor((newSel >= 0) ? style::cur_pointer : style::cur_default);
|
||||
if (newSel >= 0 && !_picker.isHidden()) {
|
||||
if (newSel != _pickerSel) {
|
||||
_picker.hideStart();
|
||||
_picker.hideAnimated();
|
||||
} else {
|
||||
_picker.showStart();
|
||||
_picker.showAnimated();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -793,7 +793,7 @@ void EmojiPanInner::showEmojiPack(DBIEmojiTab packIndex) {
|
|||
update();
|
||||
}
|
||||
|
||||
StickerPanInner::StickerPanInner() : ScrolledWidget()
|
||||
StickerPanInner::StickerPanInner() : TWidget()
|
||||
, _a_selected(animation(this, &StickerPanInner::step_selected))
|
||||
, _section(cShowingSavedGifs() ? Section::Gifs : Section::Stickers)
|
||||
, _addText(lang(lng_stickers_featured_add).toUpper())
|
||||
|
@ -2550,7 +2550,7 @@ EmojiPan::EmojiPan(QWidget *parent) : TWidget(parent)
|
|||
, _contentHeightEmoji(_contentHeight - st::rbEmoji.height)
|
||||
, _contentHeightStickers(_contentHeight - st::rbEmoji.height)
|
||||
, _a_appearance(animation(this, &EmojiPan::step_appearance))
|
||||
, _shadow(st::dropdownDef.shadow)
|
||||
, _shadow(st::defaultDropdownShadow)
|
||||
, _recent(this , qsl("emoji_group"), dbietRecent , QString(), true , st::rbEmojiRecent)
|
||||
, _people(this , qsl("emoji_group"), dbietPeople , QString(), false, st::rbEmojiPeople)
|
||||
, _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.viewport()->setFocusPolicy(Qt::NoFocus);
|
||||
|
||||
_width = st::dropdownDef.padding.left() + st::emojiPanWidth + st::dropdownDef.padding.right();
|
||||
_height = st::dropdownDef.padding.top() + _contentHeight + st::dropdownDef.padding.bottom();
|
||||
_width = st::defaultDropdownPadding.left() + st::emojiPanWidth + st::defaultDropdownPadding.right();
|
||||
_height = st::defaultDropdownPadding.top() + _contentHeight + st::defaultDropdownPadding.bottom();
|
||||
_bottom = 0;
|
||||
resize(_width, _height);
|
||||
|
||||
e_scroll.resize(st::emojiPanWidth, _contentHeightEmoji);
|
||||
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);
|
||||
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);
|
||||
|
||||
e_inner.moveToLeft(0, 0, e_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 top = _iconsTop = st::dropdownDef.padding.top() + _contentHeight - st::rbEmoji.height;
|
||||
int32 left = _iconsLeft = st::defaultDropdownPadding.left() + (st::emojiPanWidth - 8 * st::rbEmoji.width) / 2;
|
||||
int32 top = _iconsTop = st::defaultDropdownPadding.top() + _contentHeight - st::rbEmoji.height;
|
||||
prepareTab(left, top, _width, _recent);
|
||||
prepareTab(left, top, _width, _people);
|
||||
prepareTab(left, top, _width, _nature);
|
||||
|
@ -2603,7 +2603,7 @@ EmojiPan::EmojiPan(QWidget *parent) : TWidget(parent)
|
|||
updatePanelsPositions(e_panels, 0);
|
||||
|
||||
_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(disableScroll(bool)), &e_scroll, SLOT(disableScroll(bool)));
|
||||
|
@ -2666,7 +2666,7 @@ void EmojiPan::updateContentHeight() {
|
|||
_contentHeightEmoji = he;
|
||||
_contentHeightStickers = hs;
|
||||
|
||||
_height = st::dropdownDef.padding.top() + _contentHeight + st::dropdownDef.padding.bottom();
|
||||
_height = st::defaultDropdownPadding.top() + _contentHeight + st::defaultDropdownPadding.bottom();
|
||||
|
||||
resize(_width, _height);
|
||||
move(x(), _bottom - height());
|
||||
|
@ -2683,7 +2683,7 @@ void EmojiPan::updateContentHeight() {
|
|||
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);
|
||||
_people.move(_people.x(), _iconsTop);
|
||||
_nature.move(_nature.x(), _iconsTop);
|
||||
|
@ -2742,9 +2742,9 @@ void EmojiPan::paintEvent(QPaintEvent *e) {
|
|||
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 (_cache.isNull()) {
|
||||
|
@ -2871,7 +2871,7 @@ void EmojiPan::moveBottom(int32 bottom, bool force) {
|
|||
|
||||
void EmojiPan::enterEvent(QEvent *e) {
|
||||
_hideTimer.stop();
|
||||
if (_hiding) showStart();
|
||||
if (_hiding) showAnimated();
|
||||
}
|
||||
|
||||
bool EmojiPan::preventAutoHide() const {
|
||||
|
@ -2881,7 +2881,7 @@ bool EmojiPan::preventAutoHide() const {
|
|||
void EmojiPan::leaveEvent(QEvent *e) {
|
||||
if (preventAutoHide() || s_inner.inlineResultsShown()) return;
|
||||
if (_a_appearance.animating()) {
|
||||
hideStart();
|
||||
hideAnimated();
|
||||
} else {
|
||||
_hideTimer.start(300);
|
||||
}
|
||||
|
@ -2889,13 +2889,13 @@ void EmojiPan::leaveEvent(QEvent *e) {
|
|||
|
||||
void EmojiPan::otherEnter() {
|
||||
_hideTimer.stop();
|
||||
showStart();
|
||||
showAnimated();
|
||||
}
|
||||
|
||||
void EmojiPan::otherLeave() {
|
||||
if (preventAutoHide() || s_inner.inlineResultsShown()) return;
|
||||
if (_a_appearance.animating()) {
|
||||
hideStart();
|
||||
hideAnimated();
|
||||
} else {
|
||||
_hideTimer.start(0);
|
||||
}
|
||||
|
@ -2990,7 +2990,7 @@ bool EmojiPan::event(QEvent *e) {
|
|||
return TWidget::event(e);
|
||||
}
|
||||
|
||||
void EmojiPan::fastHide() {
|
||||
void EmojiPan::hideFast() {
|
||||
if (_a_appearance.animating()) {
|
||||
_a_appearance.stop();
|
||||
}
|
||||
|
@ -3107,7 +3107,7 @@ void EmojiPan::updateSelected() {
|
|||
void EmojiPan::updateIcons() {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -3177,7 +3177,7 @@ void EmojiPan::step_appearance(float64 ms, bool timer) {
|
|||
return;
|
||||
}
|
||||
|
||||
float64 dt = ms / st::dropdownDef.duration;
|
||||
float64 dt = ms / st::defaultDropdownDuration;
|
||||
if (dt >= 1) {
|
||||
_a_appearance.stop();
|
||||
a_opacity.finish();
|
||||
|
@ -3193,10 +3193,10 @@ void EmojiPan::step_appearance(float64 ms, bool timer) {
|
|||
if (timer) update();
|
||||
}
|
||||
|
||||
void EmojiPan::hideStart() {
|
||||
if (preventAutoHide() || s_inner.inlineResultsShown()) return;
|
||||
void EmojiPan::hideAnimated() {
|
||||
if (isHidden() || preventAutoHide() || s_inner.inlineResultsShown()) return;
|
||||
|
||||
hideAnimated();
|
||||
startHideAnimated();
|
||||
}
|
||||
|
||||
void EmojiPan::prepareShowHideCache() {
|
||||
|
@ -3204,12 +3204,12 @@ void EmojiPan::prepareShowHideCache() {
|
|||
QPixmap from = _fromCache, to = _toCache;
|
||||
_fromCache = _toCache = QPixmap();
|
||||
showAll();
|
||||
_cache = myGrab(this, rect().marginsRemoved(st::dropdownDef.padding));
|
||||
_cache = myGrab(this, rect().marginsRemoved(st::defaultDropdownPadding));
|
||||
_fromCache = from; _toCache = to;
|
||||
}
|
||||
}
|
||||
|
||||
void EmojiPan::hideAnimated() {
|
||||
void EmojiPan::startHideAnimated() {
|
||||
if (_hiding) return;
|
||||
|
||||
prepareShowHideCache();
|
||||
|
@ -3247,7 +3247,7 @@ void EmojiPan::hideFinish() {
|
|||
Notify::clipStopperHidden(ClipStopperSavedGifsPanel);
|
||||
}
|
||||
|
||||
void EmojiPan::showStart() {
|
||||
void EmojiPan::showAnimated() {
|
||||
if (!isHidden() && !_hiding) {
|
||||
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)*/) {
|
||||
if (isHidden() || _hiding) {
|
||||
_hideTimer.stop();
|
||||
showStart();
|
||||
showAnimated();
|
||||
} else {
|
||||
hideAnimated();
|
||||
}
|
||||
|
@ -3317,7 +3317,7 @@ void EmojiPan::stickersInstalled(uint64 setId) {
|
|||
showAll();
|
||||
s_inner.showStickerSet(setId);
|
||||
updateContentHeight();
|
||||
showStart();
|
||||
showAnimated();
|
||||
}
|
||||
|
||||
void EmojiPan::notify_inlineItemLayoutChanged(const InlineBots::Layout::ItemBase *layout) {
|
||||
|
@ -3490,7 +3490,7 @@ void EmojiPan::validateSelectedIcon(ValidateIconAnimations animations) {
|
|||
|
||||
void EmojiPan::onSwitch() {
|
||||
QPixmap cache = _cache;
|
||||
_fromCache = myGrab(this, rect().marginsRemoved(st::dropdownDef.padding));
|
||||
_fromCache = myGrab(this, rect().marginsRemoved(st::defaultDropdownPadding));
|
||||
_stickersShown = !_stickersShown;
|
||||
if (!_stickersShown) {
|
||||
Notify::clipStopperHidden(ClipStopperSavedGifsPanel);
|
||||
|
@ -3515,7 +3515,7 @@ void EmojiPan::onSwitch() {
|
|||
|
||||
_cache = QPixmap();
|
||||
showAll();
|
||||
_toCache = myGrab(this, rect().marginsRemoved(st::dropdownDef.padding));
|
||||
_toCache = myGrab(this, rect().marginsRemoved(st::defaultDropdownPadding));
|
||||
_cache = cache;
|
||||
|
||||
hideAll();
|
||||
|
@ -3804,7 +3804,7 @@ int32 EmojiPan::showInlineRows(bool newResults) {
|
|||
} else {
|
||||
_hideTimer.stop();
|
||||
if (hidden || _hiding) {
|
||||
showStart();
|
||||
showAnimated();
|
||||
} else if (!_stickersShown) {
|
||||
onSwitch();
|
||||
}
|
||||
|
|
|
@ -67,21 +67,20 @@ public:
|
|||
|
||||
void step_appearance(float64 ms, bool timer);
|
||||
void step_selected(uint64 ms, bool timer);
|
||||
void showStart();
|
||||
|
||||
void clearSelection(bool fast = false);
|
||||
|
||||
public slots:
|
||||
void hideFast();
|
||||
|
||||
void hideStart(bool fast = false);
|
||||
public slots:
|
||||
void showAnimated();
|
||||
void hideAnimated();
|
||||
|
||||
signals:
|
||||
|
||||
void emojiSelected(EmojiPtr emoji);
|
||||
void hidden();
|
||||
|
||||
private:
|
||||
|
||||
void drawVariant(Painter &p, int variant);
|
||||
|
||||
void updateSelected();
|
||||
|
@ -113,7 +112,7 @@ private:
|
|||
};
|
||||
|
||||
class EmojiPanel;
|
||||
class EmojiPanInner : public ScrolledWidget {
|
||||
class EmojiPanInner : public TWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
@ -207,7 +206,7 @@ struct StickerIcon {
|
|||
int pixh = 0;
|
||||
};
|
||||
|
||||
class StickerPanInner : public ScrolledWidget, private base::Subscriber {
|
||||
class StickerPanInner : public TWidget, private base::Subscriber {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
@ -499,7 +498,7 @@ public:
|
|||
|
||||
bool event(QEvent *e);
|
||||
|
||||
void fastHide();
|
||||
void hideFast();
|
||||
bool hiding() const {
|
||||
return _hiding || _hideTimer.isActive();
|
||||
}
|
||||
|
@ -517,10 +516,10 @@ public:
|
|||
bool overlaps(const QRect &globalRect) {
|
||||
if (isHidden() || !_cache.isNull()) return false;
|
||||
|
||||
return QRect(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()
|
||||
return QRect(st::defaultDropdownPadding.left(),
|
||||
st::defaultDropdownPadding.top(),
|
||||
_width - st::defaultDropdownPadding.left() - st::defaultDropdownPadding.right(),
|
||||
_height - st::defaultDropdownPadding.top() - st::defaultDropdownPadding.bottom()
|
||||
).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size()));
|
||||
}
|
||||
|
||||
|
@ -534,7 +533,9 @@ public:
|
|||
}
|
||||
|
||||
public slots:
|
||||
void hideStart();
|
||||
void showAnimated();
|
||||
void hideAnimated();
|
||||
|
||||
void refreshStickers();
|
||||
|
||||
private slots:
|
||||
|
@ -542,7 +543,6 @@ private slots:
|
|||
|
||||
void hideFinish();
|
||||
|
||||
void showStart();
|
||||
void onWndActiveChanged();
|
||||
|
||||
void onTabChange();
|
||||
|
@ -590,7 +590,7 @@ private:
|
|||
void updateContentHeight();
|
||||
|
||||
void leaveToChildEvent(QEvent *e, QWidget *child);
|
||||
void hideAnimated();
|
||||
void startHideAnimated();
|
||||
void prepareShowHideCache();
|
||||
|
||||
void updateSelected();
|
||||
|
|
|
@ -27,7 +27,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
namespace Ui {
|
||||
|
||||
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)) {
|
||||
setCursor(style::cur_pointer);
|
||||
|
||||
|
@ -83,7 +83,7 @@ void HistoryDownButton::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
|
||||
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) {
|
||||
_a_arrowOver.stop();
|
||||
|
@ -118,7 +118,7 @@ void HistoryDownButton::hideAnimated() {
|
|||
void HistoryDownButton::toggleAnimated() {
|
||||
_shown = !_shown;
|
||||
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() {
|
||||
|
@ -127,7 +127,7 @@ void HistoryDownButton::finishAnimation() {
|
|||
}
|
||||
|
||||
void HistoryDownButton::step_arrowOver(float64 ms, bool timer) {
|
||||
float64 dt = ms / st::btnAttachEmoji.duration;
|
||||
float64 dt = ms / st::historyAttachEmoji.duration;
|
||||
if (dt >= 1) {
|
||||
_a_arrowOver.stop();
|
||||
a_arrowOpacity.finish();
|
||||
|
@ -137,4 +137,64 @@ void HistoryDownButton::step_arrowOver(float64 ms, bool timer) {
|
|||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -261,10 +261,8 @@ void CountrySelectBox::doSetInnerFocus() {
|
|||
_select->setInnerFocus();
|
||||
}
|
||||
|
||||
CountrySelectBox::Inner::Inner(QWidget *parent) : ScrolledWidget(parent)
|
||||
, _rowHeight(st::countryRowHeight)
|
||||
, _sel(0)
|
||||
, _mouseSel(false) {
|
||||
CountrySelectBox::Inner::Inner(QWidget *parent) : TWidget(parent)
|
||||
, _rowHeight(st::countryRowHeight) {
|
||||
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||
|
||||
CountriesByISO2::const_iterator l = _countriesByISO2.constFind(lastValidISO);
|
||||
|
|
|
@ -103,7 +103,7 @@ private:
|
|||
};
|
||||
|
||||
// This class is hold in header because it requires Qt preprocessing.
|
||||
class CountrySelectBox::Inner : public ScrolledWidget {
|
||||
class CountrySelectBox::Inner : public TWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
@ -135,11 +135,11 @@ protected:
|
|||
private:
|
||||
void updateSelectedRow();
|
||||
|
||||
int32 _rowHeight;
|
||||
int _rowHeight;
|
||||
|
||||
int32 _sel;
|
||||
int _sel = 0;
|
||||
QString _filter;
|
||||
bool _mouseSel;
|
||||
bool _mouseSel = false;
|
||||
|
||||
QPoint _lastMousePos;
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "stdafx.h"
|
||||
#include "ui/flatbutton.h"
|
||||
|
||||
#include "styles/style_history.h"
|
||||
|
||||
FlatButton::FlatButton(QWidget *parent, const QString &text, const style::flatButton &st) : Button(parent)
|
||||
, _text(text)
|
||||
, _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)
|
||||
, _text(text.toUpper())
|
||||
, _fullText(text.toUpper())
|
||||
|
|
|
@ -28,7 +28,6 @@ class FlatButton : public Button {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
FlatButton(QWidget *parent, const QString &text, const style::flatButton &st);
|
||||
|
||||
void step_appearance(float64 ms, bool timer);
|
||||
|
@ -45,11 +44,9 @@ public:
|
|||
}
|
||||
|
||||
public slots:
|
||||
|
||||
void onStateChange(int oldState, ButtonStateChangeSource source);
|
||||
|
||||
private:
|
||||
|
||||
QString _text, _textForAutoSize;
|
||||
int32 _textWidth;
|
||||
|
||||
|
@ -91,7 +88,6 @@ class IconedButton : public Button {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
IconedButton(QWidget *parent, const style::iconedButton &st, const QString &text = QString());
|
||||
|
||||
void step_appearance(float64 ms, bool timer);
|
||||
|
@ -103,11 +99,9 @@ public:
|
|||
QString getText() const;
|
||||
|
||||
public slots:
|
||||
|
||||
void onStateChange(int oldState, ButtonStateChangeSource source);
|
||||
|
||||
protected:
|
||||
|
||||
QString _text;
|
||||
|
||||
style::iconedButton _st;
|
||||
|
@ -120,39 +114,6 @@ protected:
|
|||
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 {
|
||||
Q_OBJECT
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "stdafx.h"
|
||||
#include "ui/flatinput.h"
|
||||
|
||||
#include "ui/popupmenu.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "mainwindow.h"
|
||||
#include "countryinput.h"
|
||||
#include "lang.h"
|
||||
|
@ -244,7 +244,12 @@ void FlatInput::updatePlaceholderText() {
|
|||
|
||||
void FlatInput::contextMenuEvent(QContextMenuEvent *e) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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 "ui/flatlabel.h"
|
||||
|
||||
#include "ui/popupmenu.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "mainwindow.h"
|
||||
#include "lang.h"
|
||||
|
||||
|
@ -414,7 +414,7 @@ void FlatLabel::showContextMenu(QContextMenuEvent *e, ContextMenuReason reason)
|
|||
uponSelection = hasSelection;
|
||||
}
|
||||
|
||||
_contextMenu = new PopupMenu();
|
||||
_contextMenu = new Ui::PopupMenu();
|
||||
|
||||
_contextMenuClickHandler = ClickHandler::getActive();
|
||||
|
||||
|
|
|
@ -20,7 +20,9 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
namespace Ui {
|
||||
class PopupMenu;
|
||||
} // namespace Ui
|
||||
|
||||
class FlatLabel : public TWidget, public ClickHandlerHost {
|
||||
Q_OBJECT
|
||||
|
@ -137,7 +139,7 @@ private:
|
|||
QPoint _trippleClickPoint;
|
||||
QTimer _trippleClickTimer;
|
||||
|
||||
PopupMenu *_contextMenu = nullptr;
|
||||
Ui::PopupMenu *_contextMenu = nullptr;
|
||||
ClickHandlerPtr _contextMenuClickHandler;
|
||||
QString _contextCopyText;
|
||||
ExpandLinksMode _contextExpandLinksMode = ExpandLinksAll;
|
||||
|
|
|
@ -21,7 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#include "stdafx.h"
|
||||
#include "flattextarea.h"
|
||||
|
||||
#include "ui/popupmenu.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "mainwindow.h"
|
||||
|
||||
QByteArray FlatTextarea::serializeTagsList(const TagList &tags) {
|
||||
|
@ -1421,6 +1421,6 @@ void FlatTextarea::dropEvent(QDropEvent *e) {
|
|||
|
||||
void FlatTextarea::contextMenuEvent(QContextMenuEvent *e) {
|
||||
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);
|
||||
};
|
||||
|
||||
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:
|
||||
void enterEventHook(QEvent *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
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "ui/inner_dropdown.h"
|
||||
#include "ui/widgets/inner_dropdown.h"
|
||||
|
||||
#include "mainwindow.h"
|
||||
#include "ui/scrollarea.h"
|
||||
|
@ -27,12 +27,12 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
|
||||
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)
|
||||
, _shadow(_st.shadow)
|
||||
, _scroll(this, scrollSt) {
|
||||
, _scroll(this, _st.scroll) {
|
||||
_hideTimer.setSingleShot(true);
|
||||
connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(onHideStart()));
|
||||
connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(onHideAnimated()));
|
||||
|
||||
connect(_scroll, SIGNAL(scrolled()), this, SLOT(onScroll()));
|
||||
|
||||
|
@ -43,9 +43,9 @@ InnerDropdown::InnerDropdown(QWidget *parent, const style::InnerDropdown &st, co
|
|||
hide();
|
||||
}
|
||||
|
||||
void InnerDropdown::setOwnedWidget(ScrolledWidget *widget) {
|
||||
auto container = new internal::Container(_scroll, widget, _st);
|
||||
connect(container, SIGNAL(heightUpdated()), this, SLOT(onWidgetHeightUpdated()));
|
||||
void InnerDropdown::setOwnedWidget(TWidget *widget) {
|
||||
auto container = new Container(_scroll, widget, _st);
|
||||
connect(widget, SIGNAL(heightUpdated()), this, SLOT(onWidgetHeightUpdated()));
|
||||
_scroll->setOwnedWidget(container);
|
||||
container->resizeToWidth(_scroll->width());
|
||||
container->moveToLeft(0, 0);
|
||||
|
@ -55,23 +55,22 @@ void InnerDropdown::setOwnedWidget(ScrolledWidget *widget) {
|
|||
|
||||
void InnerDropdown::setMaxHeight(int newMaxHeight) {
|
||||
_maxHeight = newMaxHeight;
|
||||
updateHeight();
|
||||
resizeToContent();
|
||||
}
|
||||
|
||||
void InnerDropdown::onWidgetHeightUpdated() {
|
||||
updateHeight();
|
||||
}
|
||||
|
||||
void InnerDropdown::updateHeight() {
|
||||
int newHeight = _st.padding.top() + _st.scrollMargin.top() + _st.scrollMargin.bottom() + _st.padding.bottom();
|
||||
if (auto widget = static_cast<ScrolledWidget*>(_scroll->widget())) {
|
||||
void InnerDropdown::resizeToContent() {
|
||||
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())) {
|
||||
widget->resizeToContent();
|
||||
newWidth += widget->width();
|
||||
newHeight += widget->height();
|
||||
}
|
||||
if (_maxHeight > 0) {
|
||||
accumulate_min(newHeight, _maxHeight);
|
||||
}
|
||||
if (newHeight != height()) {
|
||||
resize(width(), newHeight);
|
||||
if (newWidth != width() || newHeight != height()) {
|
||||
resize(newWidth, newHeight);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,14 +82,14 @@ void InnerDropdown::onWindowActiveChanged() {
|
|||
|
||||
void InnerDropdown::resizeEvent(QResizeEvent *e) {
|
||||
_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());
|
||||
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 visibleBottom = visibleTop + _scroll->height();
|
||||
widget->setVisibleTopBottom(visibleTop, visibleBottom);
|
||||
|
@ -103,9 +102,9 @@ void InnerDropdown::paintEvent(QPaintEvent *e) {
|
|||
if (!_cache.isNull()) {
|
||||
bool animating = _a_appearance.animating(getms());
|
||||
if (animating) {
|
||||
p.setOpacity(_a_appearance.current(_hiding));
|
||||
} else if (_hiding) {
|
||||
hidingFinished();
|
||||
p.setOpacity(_a_appearance.current(_hiding ? 0. : 1.));
|
||||
} else if (_hiding || isHidden()) {
|
||||
hideFinished();
|
||||
return;
|
||||
}
|
||||
p.drawPixmap(0, 0, _cache);
|
||||
|
@ -117,20 +116,19 @@ void InnerDropdown::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
|
||||
// draw shadow
|
||||
QRect shadowedRect = rect().marginsRemoved(_st.padding);
|
||||
auto shadowedRect = rect().marginsRemoved(_st.padding);
|
||||
_shadow.paint(p, shadowedRect, _st.shadowShift);
|
||||
p.fillRect(shadowedRect, st::windowBg);
|
||||
}
|
||||
|
||||
void InnerDropdown::enterEvent(QEvent *e) {
|
||||
_hideTimer.stop();
|
||||
if (_hiding) showingStarted();
|
||||
showAnimated();
|
||||
return TWidget::enterEvent(e);
|
||||
}
|
||||
|
||||
void InnerDropdown::leaveEvent(QEvent *e) {
|
||||
if (_a_appearance.animating(getms())) {
|
||||
onHideStart();
|
||||
hideAnimated();
|
||||
} else {
|
||||
_hideTimer.start(300);
|
||||
}
|
||||
|
@ -138,25 +136,43 @@ void InnerDropdown::leaveEvent(QEvent *e) {
|
|||
}
|
||||
|
||||
void InnerDropdown::otherEnter() {
|
||||
_hideTimer.stop();
|
||||
showingStarted();
|
||||
showAnimated();
|
||||
}
|
||||
|
||||
void InnerDropdown::otherLeave() {
|
||||
if (_a_appearance.animating(getms())) {
|
||||
onHideStart();
|
||||
hideAnimated();
|
||||
} else {
|
||||
_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;
|
||||
|
||||
_hideTimer.stop();
|
||||
_hiding = true;
|
||||
startAnimation();
|
||||
}
|
||||
|
||||
void InnerDropdown::hideFast() {
|
||||
if (isHidden()) return;
|
||||
|
||||
_hideTimer.stop();
|
||||
_hiding = false;
|
||||
_a_appearance.finish();
|
||||
hideFinished();
|
||||
}
|
||||
|
||||
void InnerDropdown::startAnimation() {
|
||||
auto from = _hiding ? 1. : 0.;
|
||||
auto to = _hiding ? 0. : 1.;
|
||||
|
@ -168,13 +184,17 @@ void InnerDropdown::startAnimation() {
|
|||
_a_appearance.start([this] { repaintCallback(); }, from, to, _st.duration);
|
||||
}
|
||||
|
||||
void InnerDropdown::hidingFinished() {
|
||||
hide();
|
||||
// showChildren();
|
||||
emit hidden();
|
||||
void InnerDropdown::hideFinished() {
|
||||
_cache = QPixmap();
|
||||
_ignoreShowEvents = false;
|
||||
if (!isHidden()) {
|
||||
emit beforeHidden();
|
||||
hide();
|
||||
}
|
||||
}
|
||||
|
||||
void InnerDropdown::showingStarted() {
|
||||
void InnerDropdown::showStarted() {
|
||||
if (_ignoreShowEvents) return;
|
||||
if (isHidden()) {
|
||||
show();
|
||||
} else if (!_hiding) {
|
||||
|
@ -188,7 +208,7 @@ void InnerDropdown::repaintCallback() {
|
|||
update();
|
||||
if (!_a_appearance.animating() && _hiding) {
|
||||
_hiding = false;
|
||||
hidingFinished();
|
||||
hideFinished();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -207,35 +227,45 @@ bool InnerDropdown::eventFilter(QObject *obj, QEvent *e) {
|
|||
return false;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
Container::Container(QWidget *parent, ScrolledWidget *child, const style::InnerDropdown &st) : ScrolledWidget(parent), _st(st) {
|
||||
child->setParent(this);
|
||||
child->moveToLeft(_st.scrollPadding.left(), _st.scrollPadding.top());
|
||||
connect(child, SIGNAL(heightUpdated()), this, SLOT(onHeightUpdate()));
|
||||
int InnerDropdown::resizeGetHeight(int newWidth) {
|
||||
auto newHeight = _st.padding.top() + _st.scrollMargin.top() + _st.scrollMargin.bottom() + _st.padding.bottom();
|
||||
if (auto widget = static_cast<TWidget*>(_scroll->widget())) {
|
||||
widget->resizeToWidth(newWidth - _st.padding.left() - _st.padding.right() - _st.scrollMargin.left() - _st.scrollMargin.right());
|
||||
newHeight += widget->height();
|
||||
}
|
||||
if (_maxHeight > 0) {
|
||||
accumulate_min(newHeight, _maxHeight);
|
||||
}
|
||||
return newHeight;
|
||||
}
|
||||
|
||||
void Container::setVisibleTopBottom(int visibleTop, int visibleBottom) {
|
||||
if (auto child = static_cast<ScrolledWidget*>(children().front())) {
|
||||
InnerDropdown::Container::Container(QWidget *parent, TWidget *child, const style::InnerDropdown &st) : TWidget(parent), _st(st) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
void Container::onHeightUpdate() {
|
||||
int newHeight = _st.scrollPadding.top() + _st.scrollPadding.bottom();
|
||||
if (auto child = static_cast<ScrolledWidget*>(children().front())) {
|
||||
void InnerDropdown::Container::resizeToContent() {
|
||||
auto newWidth = _st.scrollPadding.top() + _st.scrollPadding.bottom();
|
||||
auto newHeight = _st.scrollPadding.top() + _st.scrollPadding.bottom();
|
||||
if (auto child = static_cast<TWidget*>(children().front())) {
|
||||
newWidth += child->width();
|
||||
newHeight += child->height();
|
||||
}
|
||||
if (newHeight != height()) {
|
||||
resize(width(), newHeight);
|
||||
emit heightUpdated();
|
||||
if (newWidth != width() || newHeight != height()) {
|
||||
resize(newWidth, newHeight);
|
||||
}
|
||||
}
|
||||
|
||||
int Container::resizeGetHeight(int newWidth) {
|
||||
int InnerDropdown::Container::resizeGetHeight(int newWidth) {
|
||||
int innerWidth = newWidth - _st.scrollPadding.left() - _st.scrollPadding.right();
|
||||
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->moveToLeft(_st.scrollPadding.left(), _st.scrollPadding.top());
|
||||
result += child->height();
|
||||
|
@ -243,5 +273,4 @@ int Container::resizeGetHeight(int newWidth) {
|
|||
return result;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Ui
|
|
@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|||
#pragma once
|
||||
|
||||
#include "ui/effects/rect_shadow.h"
|
||||
#include "styles/style_widgets.h"
|
||||
|
||||
class ScrollArea;
|
||||
|
||||
|
@ -30,9 +31,9 @@ class InnerDropdown : public TWidget {
|
|||
Q_OBJECT
|
||||
|
||||
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) {
|
||||
if (isHidden() || _a_appearance.animating()) return false;
|
||||
|
@ -41,32 +42,52 @@ public:
|
|||
}
|
||||
|
||||
void setMaxHeight(int newMaxHeight);
|
||||
void resizeToContent();
|
||||
|
||||
void otherEnter();
|
||||
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:
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void enterEvent(QEvent *e) override;
|
||||
void leaveEvent(QEvent *e) override;
|
||||
|
||||
bool eventFilter(QObject *obj, QEvent *e) override;
|
||||
|
||||
signals:
|
||||
void hidden();
|
||||
int resizeGetHeight(int newWidth) override;
|
||||
|
||||
private slots:
|
||||
void onHideStart();
|
||||
void onHideAnimated() {
|
||||
hideAnimated();
|
||||
}
|
||||
void onWindowActiveChanged();
|
||||
void onScroll();
|
||||
void onWidgetHeightUpdated();
|
||||
void onWidgetHeightUpdated() {
|
||||
resizeToContent();
|
||||
}
|
||||
|
||||
private:
|
||||
class Container;
|
||||
void repaintCallback();
|
||||
|
||||
void hidingFinished();
|
||||
void showingStarted();
|
||||
void hideFinished();
|
||||
void showStarted();
|
||||
|
||||
void startAnimation();
|
||||
|
||||
|
@ -80,6 +101,7 @@ private:
|
|||
FloatAnimation _a_appearance;
|
||||
|
||||
QTimer _hideTimer;
|
||||
bool _ignoreShowEvents = false;
|
||||
|
||||
RectShadow _shadow;
|
||||
ChildWidget<ScrollArea> _scroll;
|
||||
|
@ -88,17 +110,12 @@ private:
|
|||
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
class Container : public ScrolledWidget {
|
||||
Q_OBJECT
|
||||
|
||||
class InnerDropdown::Container : public TWidget {
|
||||
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;
|
||||
|
||||
private slots:
|
||||
void onHeightUpdate();
|
||||
void resizeToContent();
|
||||
|
||||
protected:
|
||||
int resizeGetHeight(int newWidth) override;
|
||||
|
@ -108,5 +125,4 @@ private:
|
|||
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // 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;
|
||||
}
|
||||
|
||||
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)
|
||||
, _scrollCallback(std_::move(callback))
|
||||
, _field(this, _st.field, placeholder)
|
||||
|
|
|
@ -71,7 +71,7 @@ private:
|
|||
};
|
||||
|
||||
// This class is hold in header because it requires Qt preprocessing.
|
||||
class MultiSelect::Inner : public ScrolledWidget {
|
||||
class MultiSelect::Inner : public TWidget {
|
||||
Q_OBJECT
|
||||
|
||||
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
|