vlc | branch: master | Pierre Lamot <[email protected]> | Mon Oct 5 16:05:44 2020 +0200| [8922bbb0e07040c535fca293db5f0e8d9b8ba6bf] | committer: Pierre Lamot
qt: implement mixed qml/native menubar > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=8922bbb0e07040c535fca293db5f0e8d9b8ba6bf --- modules/gui/qt/Makefile.am | 1 + modules/gui/qt/maininterface/mainui.cpp | 1 + modules/gui/qt/menus/qml/Menubar.qml | 117 +++++++++++++++++++++++++ modules/gui/qt/menus/qml_menu_wrapper.cpp | 136 ++++++++++++++++++++++++++++++ modules/gui/qt/menus/qml_menu_wrapper.hpp | 57 ++++++++++++- modules/gui/qt/vlc.qrc | 1 + 6 files changed, 312 insertions(+), 1 deletion(-) diff --git a/modules/gui/qt/Makefile.am b/modules/gui/qt/Makefile.am index e6cab60218..1cf5da7f59 100644 --- a/modules/gui/qt/Makefile.am +++ b/modules/gui/qt/Makefile.am @@ -641,6 +641,7 @@ libqt_plugin_la_QML = \ gui/qt/menus/qml/HelpMenu.qml \ gui/qt/menus/qml/MainDropdownMenu.qml \ gui/qt/menus/qml/MainMenubar.qml \ + gui/qt/menus/qml/Menubar.qml \ gui/qt/menus/qml/MediaMenu.qml \ gui/qt/menus/qml/PlaybackMenu.qml \ gui/qt/menus/qml/PopupMenu.qml \ diff --git a/modules/gui/qt/maininterface/mainui.cpp b/modules/gui/qt/maininterface/mainui.cpp index 500b547585..9b8bc9e93f 100644 --- a/modules/gui/qt/maininterface/mainui.cpp +++ b/modules/gui/qt/maininterface/mainui.cpp @@ -215,6 +215,7 @@ void MainUI::registerQMLTypes() qmlRegisterType<PlayerControlBarModel>( "org.videolan.vlc", 0, 1, "PlayerControlBarModel"); qmlRegisterType<QmlGlobalMenu>( "org.videolan.vlc", 0, 1, "QmlGlobalMenu" ); + qmlRegisterType<QmlMenuBar>( "org.videolan.vlc", 0, 1, "QmlMenuBar" ); qmlRegisterType<NetworkMediaContextMenu>( "org.videolan.vlc", 0, 1, "NetworkMediaContextMenu" ); qmlRegisterType<NetworkDeviceContextMenu>( "org.videolan.vlc", 0, 1, "NetworkDeviceContextMenu" ); qmlRegisterType<PlaylistContextMenu>( "org.videolan.vlc", 0, 1, "PlaylistContextMenu" ); diff --git a/modules/gui/qt/menus/qml/Menubar.qml b/modules/gui/qt/menus/qml/Menubar.qml new file mode 100644 index 0000000000..97ffa4c486 --- /dev/null +++ b/modules/gui/qt/menus/qml/Menubar.qml @@ -0,0 +1,117 @@ +/***************************************************************************** + * Copyright (C) 2020 VLC authors and VideoLAN + * + * This program 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 2 of the License, or + * ( at your option ) any later version. + * + * This program 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ +import QtQuick 2.11 +import QtQuick.Controls 2.4 +import QtQuick.Controls.impl 2.4 +import QtQuick.Templates 2.4 as T +import org.videolan.vlc 0.1 +import QtQuick.Layouts 1.3 + +import "qrc:///style/" + + +Item { + id: root + + implicitHeight: menubarLayout.implicitHeight + implicitWidth: menubarLayout.implicitWidth + + property color textColor: VLCStyle.colors.text + property color bgColor: VLCStyle.colors.bgHover + + Action{ id: mediaMenu; text: i18n.qtr("&Media") ; onTriggered: menubar.popupMediaMenu(source); } + Action{ id: playbackMenu; text: i18n.qtr("&Playback") ; onTriggered: menubar.popupPlaybackMenu(source);} + Action{ id: videoMenu; text: i18n.qtr("&Video") ; onTriggered: menubar.popupVideoMenu(source); } + Action{ id: audioMenu; text: i18n.qtr("&Audio") ; onTriggered: menubar.popupAudioMenu(source); } + Action{ id: subtitleMenu; text: i18n.qtr("&Subtitle") ; onTriggered: menubar.popupSubtitleMenu(source);} + Action{ id: toolMenu; text: i18n.qtr("&Tools") ; onTriggered: menubar.popupToolsMenu(source); } + Action{ id: viewMenu; text: i18n.qtr("V&iew") ; onTriggered: menubar.popupViewMenu(source); } + Action{ id: helpMenu; text: i18n.qtr("&Help") ; onTriggered: menubar.popupHelpMenu(source); } + + property var toolbarModel: [ + mediaMenu, + playbackMenu, + videoMenu, + audioMenu, + subtitleMenu, + toolMenu, + viewMenu, + helpMenu, + ] + + property int _menuIndex: -1 + + function openMenu(obj, cb, index) { + cb.trigger(obj) + root._menuIndex = index + } + + function updateHover(obj, cb, index, hovered ) { + if (hovered && menubar.openMenuOnHover) { + cb.trigger(obj) + root._menuIndex = index + } + } + + QmlMenuBar { + id: menubar + ctx: mainctx + menubar: menubarLayout + + onMenuClosed: _menuIndex = -1 + onNavigateMenu: { + var i = (root._menuIndex + root.toolbarModel.length + direction) % root.toolbarModel.length + root.openMenu(menubarLayout.visibleChildren[i], root.toolbarModel[i], i) + } + + } + + RowLayout { + id: menubarLayout + spacing: 0 + Repeater { + model: root.toolbarModel + + T.Button { + id: control + + text: modelData.text + onClicked: root.openMenu(this, modelData, index) + onHoveredChanged: root.updateHover(this, modelData, index, hovered) + font.pixelSize: VLCStyle.fontSize_normal + + Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft + + implicitWidth: contentItem.implicitWidth + VLCStyle.margin_xsmall * 2 + implicitHeight: contentItem.implicitHeight + VLCStyle.margin_xxxsmall * 2 + + contentItem: IconLabel { + text: control.text + font: control.font + opacity: enabled ? 1.0 : 0.3 + color: root.textColor + } + + background: Rectangle { + color: (control.hovered || index === root._menuIndex) ? root.bgColor + : "transparent" + } + } + } + } +} diff --git a/modules/gui/qt/menus/qml_menu_wrapper.cpp b/modules/gui/qt/menus/qml_menu_wrapper.cpp index 01a85ba730..259b10c877 100644 --- a/modules/gui/qt/menus/qml_menu_wrapper.cpp +++ b/modules/gui/qt/menus/qml_menu_wrapper.cpp @@ -30,6 +30,7 @@ #include "playlist/playlist_controller.hpp" #include "playlist/playlist_model.hpp" #include "dialogs/dialogs_provider.hpp" +#include "maininterface/main_interface.hpp" #include <QSignalMapper> @@ -95,6 +96,141 @@ void QmlGlobalMenu::popup(QPoint pos) m_menu->popup(pos); } +QmlMenuBarMenu::QmlMenuBarMenu(QmlMenuBar* menubar, QWidget* parent) + : QMenu(parent) + , m_menubar(menubar) +{} + +QmlMenuBarMenu::~QmlMenuBarMenu() +{ +} + +void QmlMenuBarMenu::mouseMoveEvent(QMouseEvent* mouseEvent) +{ + QPoint globalPos =m_menubar-> m_menu->mapToGlobal(mouseEvent->pos()); + if (m_menubar->getmenubar()->contains(m_menubar->getmenubar()->mapFromGlobal(globalPos)) + && !m_menubar->m_button->contains(m_menubar->m_button->mapFromGlobal(globalPos))) + { + m_menubar->setopenMenuOnHover(true); + close(); + return; + } + QMenu::mouseMoveEvent(mouseEvent); +} + +void QmlMenuBarMenu::keyPressEvent(QKeyEvent * event) +{ + QMenu::keyPressEvent(event); + if (!event->isAccepted() + && (event->key() == Qt::Key_Left || event->key() == Qt::Key_Right)) + { + event->accept(); + emit m_menubar->navigateMenu(event->key() == Qt::Key_Left ? -1 : 1); + } +} + +void QmlMenuBarMenu::keyReleaseEvent(QKeyEvent * event) +{ + QMenu::keyReleaseEvent(event); +} + +QmlMenuBar::QmlMenuBar(QObject *parent) + : VLCMenuBar(parent) +{ +} + +QmlMenuBar::~QmlMenuBar() +{ + if (m_menu) + delete m_menu; +} + +void QmlMenuBar::popupMenuCommon( QQuickItem* button, std::function<void(QMenu*)> createMenuFunc) +{ + if (!m_ctx || !m_menubar || !button) + return; + + intf_thread_t* p_intf = m_ctx->getIntf(); + if (!p_intf) + return; + + if (m_menu) + delete m_menu; + + m_menu = new QmlMenuBarMenu(this, nullptr); + createMenuFunc(m_menu); + m_button = button; + m_openMenuOnHover = false; + connect(m_menu, &QMenu::aboutToHide, this, &QmlMenuBar::onMenuClosed); + QPointF position = button->mapToGlobal(QPoint(0, button->height())); + m_menu->popup(position.toPoint()); +} + +void QmlMenuBar::popupMediaMenu( QQuickItem* button ) +{ + popupMenuCommon(button, [this](QMenu* menu) { + intf_thread_t* p_intf = m_ctx->getIntf(); + FileMenu( p_intf, menu , p_intf->p_sys->p_mi ); + }); +} + +void QmlMenuBar::popupPlaybackMenu( QQuickItem* button ) +{ + popupMenuCommon(button, [this](QMenu* menu) { + NavigMenu( m_ctx->getIntf(), menu ); + }); +} + +void QmlMenuBar::popupAudioMenu(QQuickItem* button ) +{ + popupMenuCommon(button, [this](QMenu* menu) { + AudioMenu( m_ctx->getIntf(), menu ); + }); +} + +void QmlMenuBar::popupVideoMenu( QQuickItem* button ) +{ + popupMenuCommon(button, [this](QMenu* menu) { + VideoMenu( m_ctx->getIntf(), menu ); + }); +} + +void QmlMenuBar::popupSubtitleMenu( QQuickItem* button ) +{ + popupMenuCommon(button, [this](QMenu* menu) { + SubtitleMenu( m_ctx->getIntf(), menu ); + }); +} + + +void QmlMenuBar::popupToolsMenu( QQuickItem* button ) +{ + popupMenuCommon(button, [this](QMenu* menu) { + ToolsMenu( m_ctx->getIntf(), menu ); + }); +} + +void QmlMenuBar::popupViewMenu( QQuickItem* button ) +{ + popupMenuCommon(button, [this](QMenu* menu) { + intf_thread_t* p_intf = m_ctx->getIntf(); + ViewMenu( p_intf, menu, p_intf->p_sys->p_mi ); + }); +} + +void QmlMenuBar::popupHelpMenu( QQuickItem* button ) +{ + popupMenuCommon(button, [](QMenu* menu) { + HelpMenu(menu); + }); +} + +void QmlMenuBar::onMenuClosed() +{ + if (!m_openMenuOnHover) + emit menuClosed(); +} + BaseMedialibMenu::BaseMedialibMenu(QObject* parent) : QObject(parent) {} diff --git a/modules/gui/qt/menus/qml_menu_wrapper.hpp b/modules/gui/qt/menus/qml_menu_wrapper.hpp index a3031a4a7b..d9a87ddb7a 100644 --- a/modules/gui/qt/menus/qml_menu_wrapper.hpp +++ b/modules/gui/qt/menus/qml_menu_wrapper.hpp @@ -22,7 +22,7 @@ #include <QObject> #include <QPoint> - +#include <QQuickItem> #include "menus.hpp" class MediaLib; @@ -65,6 +65,61 @@ private: QMenu* m_menu = nullptr; }; +//inherit VLCMenuBar so we can access menu creation functions +class QmlMenuBarMenu; +class QmlMenuBar : public VLCMenuBar +{ + Q_OBJECT + SIMPLE_MENU_PROPERTY(QmlMainContext*, ctx, nullptr) + SIMPLE_MENU_PROPERTY(QQuickItem*, menubar, nullptr) + SIMPLE_MENU_PROPERTY(bool, openMenuOnHover, false) + +public: + explicit QmlMenuBar(QObject *parent = nullptr); + ~QmlMenuBar(); + +signals: + //navigate to the left(-1)/right(1) menu + void navigateMenu(int direction); + + void menuClosed(); + +public slots: + void popupMediaMenu( QQuickItem* button); + void popupPlaybackMenu( QQuickItem* button); + void popupAudioMenu( QQuickItem* button ); + void popupVideoMenu( QQuickItem* button ); + void popupSubtitleMenu( QQuickItem* button ); + void popupToolsMenu( QQuickItem* button ); + void popupViewMenu( QQuickItem* button ); + void popupHelpMenu( QQuickItem* button ); + +private slots: + void onMenuClosed(); + +private: + typedef QMenu* (*CreateMenuFunc)(); + void popupMenuCommon( QQuickItem* button, std::function<void(QMenu*)> createMenuFunc); + QMenu* m_menu = nullptr; + QQuickItem* m_button = nullptr; + friend class QmlMenuBarMenu; +}; + +//specialized QMenu for QmlMenuBar +class QmlMenuBarMenu : public QMenu +{ + Q_OBJECT +public: + QmlMenuBarMenu(QmlMenuBar* menubar, QWidget* parent = nullptr); + ~QmlMenuBarMenu(); +protected: + void mouseMoveEvent(QMouseEvent* mouseEvent) override; + void keyPressEvent(QKeyEvent *) override; + void keyReleaseEvent(QKeyEvent *) override; +private: + QmlMenuBar* m_menubar = nullptr; +}; + class BaseMedialibMenu : public QObject { Q_OBJECT diff --git a/modules/gui/qt/vlc.qrc b/modules/gui/qt/vlc.qrc index d9d9c8da66..1fc54805fe 100644 --- a/modules/gui/qt/vlc.qrc +++ b/modules/gui/qt/vlc.qrc @@ -287,6 +287,7 @@ <file alias="MainDropdownMenu.qml">menus/qml/MainDropdownMenu.qml</file> <file alias="MainMenubar.qml">menus/qml/MainMenubar.qml</file> <file alias="MediaMenu.qml">menus/qml/MediaMenu.qml</file> + <file alias="Menubar.qml">menus/qml/Menubar.qml</file> <file alias="PlaybackMenu.qml">menus/qml/PlaybackMenu.qml</file> <file alias="SubtitleMenu.qml">menus/qml/SubtitleMenu.qml</file> <file alias="ToolsMenu.qml">menus/qml/ToolsMenu.qml</file> _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
