/* 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() { InnerDropdown::setHiddenCallback([this] { hideFinish(); }); 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); }); _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 &&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