284 lines
8.0 KiB
C++
284 lines
8.0 KiB
C++
/*
|
|
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-2017 John Preston, https://desktop.telegram.org
|
|
*/
|
|
#include "ui/widgets/dropdown_menu.h"
|
|
|
|
#include "application.h"
|
|
#include "lang/lang_keys.h"
|
|
|
|
namespace Ui {
|
|
|
|
DropdownMenu::DropdownMenu(QWidget *parent, const style::DropdownMenu &st) : InnerDropdown(parent, st.wrap)
|
|
, _st(st) {
|
|
_menu = setOwnedWidget(object_ptr<Ui::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 = setOwnedWidget(object_ptr<Ui::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() {
|
|
InnerDropdown::setHiddenCallback([this] { hideFinish(); });
|
|
|
|
_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); });
|
|
_menu->setMouseReleaseDelegate([this](QPoint globalPosition) { handleMouseRelease(globalPosition); });
|
|
|
|
setMouseTracking(true);
|
|
|
|
hide();
|
|
}
|
|
|
|
QAction *DropdownMenu::addAction(const QString &text, const QObject *receiver, const char* member, const style::icon *icon, const style::icon *iconOver) {
|
|
return _menu->addAction(text, receiver, member, icon, iconOver);
|
|
}
|
|
|
|
QAction *DropdownMenu::addAction(const QString &text, base::lambda<void()> callback, const style::icon *icon, const style::icon *iconOver) {
|
|
return _menu->addAction(text, std::move(callback), icon, iconOver);
|
|
}
|
|
|
|
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::handleMouseRelease(QPoint globalPosition) {
|
|
if (_parent) {
|
|
_parent->forwardMouseRelease(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();
|
|
if (_hiddenCallback) {
|
|
_hiddenCallback();
|
|
}
|
|
}
|
|
|
|
// 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
|