[vlc-commits] [Git][videolan/vlc][master] 5 commits: qt: expose QmlMenuBar titles and actions through an enum

Steve Lhomme (@robUx4) gitlab at videolan.org
Wed Jan 8 15:15:34 UTC 2025



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
d45a0e88 by Pierre Lamot at 2025-01-08T14:59:13+00:00
qt: expose QmlMenuBar titles and actions through an enum

- - - - -
c6b22799 by Pierre Lamot at 2025-01-08T14:59:13+00:00
qt: allow QmlMenuBar to popup a menu entry with multiple submenus

- - - - -
27af28fc by Pierre Lamot at 2025-01-08T14:59:13+00:00
qml: expand the MenuBar to the available space in the Player

- - - - -
c03e29c5 by Pierre Lamot at 2025-01-08T14:59:13+00:00
qml: allow MenuBar to collapse

This avoids the menubar overlapping the CSD or being inaccessible when the
space is scarce

- - - - -
9d541293 by Pierre Lamot at 2025-01-08T14:59:13+00:00
qml: don't overlap MenuBar with CSD buttons in BannerSources

- - - - -


5 changed files:

- modules/gui/qt/maininterface/qml/BannerSources.qml
- modules/gui/qt/menus/qml/Menubar.qml
- modules/gui/qt/menus/qml_menu_wrapper.cpp
- modules/gui/qt/menus/qml_menu_wrapper.hpp
- modules/gui/qt/player/qml/TopBar.qml


Changes:

=====================================
modules/gui/qt/maininterface/qml/BannerSources.qml
=====================================
@@ -119,7 +119,7 @@ T.ToolBar {
 
                     Menus.Menubar {
                         id: menubar
-                        width: parent.width
+                        width: root._showCSD ? (parent.width - globalToolbarRight.width) : parent.width
                         height: implicitHeight
                         visible: MainCtx.hasToolbarMenu
                         enabled: visible


=====================================
modules/gui/qt/menus/qml/Menubar.qml
=====================================
@@ -23,8 +23,10 @@ import QtQuick.Layouts
 
 import VLC.MainInterface
 import VLC.Style
+import VLC.Widgets as Widgets
 import VLC.Menus
 
+
 Item {
     id: root
 
@@ -38,45 +40,76 @@ Item {
         colorSet: ColorContext.MenuBar
     }
 
-    Action{ id: mediaMenu;    text: qsTr("&Media")    ; onTriggered: (source) => menubar.popupMediaMenu(source);   }
-    Action{ id: playbackMenu; text: qsTr("&Playback") ; onTriggered: (source) => menubar.popupPlaybackMenu(source);}
-    Action{ id: videoMenu;    text: qsTr("&Video")    ; onTriggered: (source) => menubar.popupVideoMenu(source);   }
-    Action{ id: audioMenu;    text: qsTr("&Audio")    ; onTriggered: (source) => menubar.popupAudioMenu(source);   }
-    Action{ id: subtitleMenu; text: qsTr("&Subtitle") ; onTriggered: (source) => menubar.popupSubtitleMenu(source);}
-    Action{ id: toolMenu;     text: qsTr("&Tools")    ; onTriggered: (source) => menubar.popupToolsMenu(source);   }
-    Action{ id: viewMenu;     text: qsTr("V&iew")     ; onTriggered: (source) => menubar.popupViewMenu(source);    }
-    Action{ id: helpMenu;     text: qsTr("&Help")     ; onTriggered: (source) => menubar.popupHelpMenu(source);    }
-
-    property var toolbarModel: [
-        mediaMenu,
-        playbackMenu,
-        videoMenu,
-        audioMenu,
-        subtitleMenu,
-        toolMenu,
-        viewMenu,
-        helpMenu,
+    readonly property var toolbarModel: [
+        QmlMenuBar.MEDIA,
+        QmlMenuBar.PLAYBACK,
+        QmlMenuBar.VIDEO,
+        QmlMenuBar.AUDIO,
+        QmlMenuBar.SUBTITLE,
+        QmlMenuBar.TOOL,
+        QmlMenuBar.VIEW,
+        QmlMenuBar.HELP
     ]
 
     property int _menuIndex: -1
     property int _countHovered: 0
 
+    //will contain the visible action (after _updateContentModel)
+    property var _visibleActionsModel: []
+    //will contain the actions acessible through the '>' menu (after _updateContentModel)
+    property var _extraActionsModel: []
+
+
+    signal _requestMenuPopup(int menuId)
 
     // Accessible
     Accessible.role: Accessible.MenuBar
 
-    function openMenu(obj, cb, index) {
-        cb.trigger(obj)
+    onWidthChanged: _updateContentModel()
+
+    function _openMenu(item, index) {
+        menubar.popupMenuEntry(item, toolbarModel[index])
         root._menuIndex = index
     }
 
-    function updateHover(obj, cb, index, hovered ) {
+    function _updateHover(item, index, hovered ) {
         root._countHovered += hovered ? 1 : -1
 
         if (hovered && menubar.openMenuOnHover) {
-            cb.trigger(obj)
-            root._menuIndex = index
+            _openMenu(item, index)
+        }
+    }
+
+    //set up the model to show as many as possible menu entries
+    //remaining menus are placed in the ">" menu
+    function _updateContentModel() {
+        const visibleActions = []
+        const extraActions = []
+        const extraPadding = VLCStyle.margin_xsmall * 2
+        //keep enough place for the > menu
+        let availableWidth = root.width - _buttonWidth(root._extraActionLabel)
+        let i = 0
+        for (; i < root.toolbarModel.length; ++i) {
+            const textWidth = _buttonWidth(toolbarModel[i])
+            if (textWidth < availableWidth) {
+                visibleActions.push(i)
+            } else {
+                break
+            }
+            availableWidth -= textWidth;
+        }
+        for (; i < toolbarModel.length; ++i) {
+            extraActions.push(i)
         }
+
+        root._visibleActionsModel = visibleActions
+        root._extraActionsModel = extraActions
+    }
+
+    function _buttonWidth(buttonId) {
+        return fontMetrics.advanceWidth(
+                    menubar.menuEntryTitle(buttonId).replace("&", "") //beware of mnemonics
+                ) + (VLCStyle.margin_xsmall * 2)
     }
 
     QmlMenuBar {
@@ -88,51 +121,130 @@ Item {
         onMenuClosed: _menuIndex = -1
         onNavigateMenu: (direction) => {
             const i =  (root._menuIndex + root.toolbarModel.length + direction) % root.toolbarModel.length
-            root.openMenu(menubarLayout.visibleChildren[i], root.toolbarModel[i], i)
+            root._requestMenuPopup(i)
         }
     }
 
-    RowLayout {
+    FontMetrics {
+        id: fontMetrics
+        font.pixelSize: VLCStyle.fontSize_normal
+    }
+
+    Row {
         id: menubarLayout
         spacing: 0
+
         Repeater {
-            model: root.toolbarModel
+            model: root._visibleActionsModel
 
-            T.MenuItem {
-                id: control
+            MenubarButton {
+                id: visibleButton
 
-                text: modelData.text
-                onClicked: root.openMenu(this, modelData, index)
-                onHoveredChanged: root.updateHover(this, modelData, index, hovered)
-                font.pixelSize: VLCStyle.fontSize_normal
+                text: menubar.menuEntryTitle(toolbarModel[modelData])
+                focused: modelData === root._menuIndex
 
-                Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
+                onClicked: root._openMenu(visibleButton, modelData)
+                onHoveredChanged: root._updateHover(visibleButton, modelData, hovered)
 
-                implicitWidth: contentItem.implicitWidth + VLCStyle.margin_xsmall * 2
-                implicitHeight: contentItem.implicitHeight + VLCStyle.margin_xxxsmall * 2
+                Connections {
+                    target: root
+                    function on_RequestMenuPopup(menuId) {
+                        if (menuId === modelData) {
+                            root._openMenu(visibleButton, modelData)
+                        }
+                    }
+                }
+            }
+        }
 
-                Accessible.onPressAction: control.clicked()
+        Repeater {
+            model: root._extraActionsModel
 
-                ColorContext {
-                    id: theme
-                    colorSet: root.colorContext.colorSet
+            Item {
+                id: hiddenButton
 
-                    enabled: control.enabled
-                    focused: index === root._menuIndex
-                    hovered: control.hovered
-                }
+                width: _buttonWidth(toolbarModel[modelData])
+                height: 1 //item with 0 height are discarded
+                anchors.bottom: menubarLayout.bottom
+
+                T.MenuItem {
+                    text: menubar.menuEntryTitle(toolbarModel[modelData])
+
+                    width: 0
+                    height: 0
+
+                    onClicked: root._openMenu(hiddenButton, modelData)
+                    Accessible.onPressAction: root._openMenu(hiddenButton, modelData)
 
-                contentItem: IconLabel {
-                    text: control.text
-                    font: control.font
-                    opacity: enabled ? 1.0 : 0.3
-                    color: theme.fg.primary
+                    contentItem: null
+                    background: null
                 }
 
-                background: Rectangle {
-                    color: theme.bg.primary
+                Connections {
+                    target: root
+                    function on_RequestMenuPopup(menuId) {
+                        if (menuId === modelData) {
+                            root._openMenu(hiddenButton, modelData)
+                        }
+                    }
                 }
             }
         }
     }
+
+    MenubarButton {
+        id: extraActionButton
+
+        anchors.top:  parent.top
+        anchors.right: parent.right
+
+        text: ">"
+
+        Accessible.ignored: true
+
+        visible: _extraActionsModel.length > 0
+        enabled: visible
+
+        onClicked: menubar.popupExtraActionsMenu(extraActionButton, root._extraActionsModel)
+    }
+
+    component MenubarButton: T.MenuItem {
+        id: control
+
+        property bool focused: false
+        property bool textVisible: true
+
+        font.pixelSize: VLCStyle.fontSize_normal
+
+        padding: 0
+
+        implicitWidth: contentItem.implicitWidth + leftPadding + rightPadding
+        implicitHeight: contentItem.implicitHeight + VLCStyle.margin_xxxsmall * 2
+
+        leftPadding: VLCStyle.margin_xsmall
+        rightPadding: VLCStyle.margin_xsmall
+
+        Accessible.onPressAction: control.clicked()
+
+        ColorContext {
+            id: theme
+            colorSet: root.colorContext.colorSet
+
+            enabled: control.enabled
+            focused: control.focused
+            hovered: control.hovered
+        }
+
+        contentItem: IconLabel {
+            text: control.text
+            font: control.font
+            opacity: enabled ? 1.0 : 0.3
+            color: theme.fg.primary
+            visible: control.textVisible
+        }
+
+        background: Rectangle {
+            color: theme.bg.primary
+        }
+    }
 }


=====================================
modules/gui/qt/menus/qml_menu_wrapper.cpp
=====================================
@@ -297,6 +297,31 @@ QmlMenuBar::QmlMenuBar(QObject *parent)
 {
 }
 
+ QString QmlMenuBar::menuEntryTitle(MenuEntry entry)
+{
+    switch (entry)
+    {
+    case MEDIA:
+        return qtr("&Media");
+    case PLAYBACK:
+        return qtr("&Playback");
+    case VIDEO:
+        return qtr("&Video");
+    case AUDIO:
+        return qtr("&Audio");
+    case SUBTITLE:
+        return qtr("&Subtitle");
+    case TOOL:
+        return qtr("&Tools");
+    case VIEW:
+        return qtr("V&iew");
+    case HELP:
+        return qtr("&Help");
+    }
+    vlc_assert_unreachable();
+    return "";
+}
+
 void QmlMenuBar::popupMenuCommon( QQuickItem* button, std::function<void(QMenu*)> createMenuFunc)
 {
     if (!m_ctx || !m_menubar || !button)
@@ -315,6 +340,47 @@ void QmlMenuBar::popupMenuCommon( QQuickItem* button, std::function<void(QMenu*)
     m_menu->popup(position.toPoint());
 }
 
+
+void QmlMenuBar::setupMenuEntry(QMenu* menu, MenuEntry entry)
+{
+    qt_intf_t* p_intf = m_ctx->getIntf();
+    switch (entry) {
+    case MEDIA:
+        FileMenu(p_intf, menu);
+        break;
+    case PLAYBACK:
+        NavigMenu(p_intf, menu);
+        break;
+    case VIDEO:
+        VideoMenu(p_intf, menu);
+        break;
+    case AUDIO:
+        AudioMenu(p_intf, menu);
+        break;
+    case SUBTITLE:
+        SubtitleMenu(p_intf, menu);
+        break;
+    case TOOL:
+        ToolsMenu(p_intf, menu);
+        break;
+    case VIEW:
+        ViewMenu( p_intf, menu, m_playerViewVisible );
+        break;
+    case HELP:
+        HelpMenu( menu );
+        break;
+    default:
+        vlc_assert_unreachable();
+    };
+}
+
+void QmlMenuBar::popupMenuEntry(QQuickItem* button, MenuEntry entry)
+{
+    popupMenuCommon(button, [this, entry](QMenu* menu) {
+        setupMenuEntry(menu, entry);
+    });
+}
+
 void QmlMenuBar::popupMediaMenu( QQuickItem* button )
 {
     popupMenuCommon(button, [this](QMenu* menu) {
@@ -374,6 +440,16 @@ void QmlMenuBar::popupHelpMenu( QQuickItem* button )
     });
 }
 
+void QmlMenuBar::popupExtraActionsMenu( QQuickItem* button, const QList<MenuEntry>& extraActions )
+{
+    popupMenuCommon(button, [this, extraActions](QMenu* menu) {
+        for (auto action: extraActions) {
+            QMenu* subMenu = menu->addMenu(menuEntryTitle(action));
+            setupMenuEntry(subMenu, action);
+        }
+    });
+}
+
 void QmlMenuBar::onMenuClosed()
 {
     if (!m_openMenuOnHover)


=====================================
modules/gui/qt/menus/qml_menu_wrapper.hpp
=====================================
@@ -150,9 +150,25 @@ class QmlMenuBar : public VLCMenuBar
     SIMPLE_MENU_PROPERTY(bool, openMenuOnHover, false)
     SIMPLE_MENU_PROPERTY(bool, playerViewVisible, false)
 
+public:
+    enum MenuEntry {
+        MEDIA,
+        PLAYBACK,
+        VIDEO,
+        AUDIO,
+        SUBTITLE,
+        TOOL,
+        VIEW,
+        HELP
+    };
+    Q_ENUM(MenuEntry);
+
 public:
     explicit QmlMenuBar(QObject *parent = nullptr);
 
+
+    Q_INVOKABLE static QString menuEntryTitle(MenuEntry entry);
+
 signals:
     //navigate to the left(-1)/right(1) menu
     void navigateMenu(int direction);
@@ -160,6 +176,8 @@ signals:
     void menuClosed();
 
 public slots:
+    void popupMenuEntry(QQuickItem* button, MenuEntry entry);
+
     void popupMediaMenu( QQuickItem* button);
     void popupPlaybackMenu( QQuickItem* button);
     void popupAudioMenu( QQuickItem* button );
@@ -168,6 +186,7 @@ public slots:
     void popupToolsMenu( QQuickItem* button );
     void popupViewMenu( QQuickItem* button );
     void popupHelpMenu( QQuickItem* button );
+    void popupExtraActionsMenu( QQuickItem* button, const QList<MenuEntry>& extraActions );
 
 private slots:
     void onMenuClosed();
@@ -175,6 +194,7 @@ private slots:
 private:
     typedef QMenu* (*CreateMenuFunc)();
     void popupMenuCommon( QQuickItem* button, std::function<void(QMenu*)> createMenuFunc);
+    void setupMenuEntry(QMenu* menu, MenuEntry entry);
     std::unique_ptr<QMenu> m_menu;
     QQuickItem* m_button = nullptr;
     friend class QmlMenuBarMenu;


=====================================
modules/gui/qt/player/qml/TopBar.qml
=====================================
@@ -217,8 +217,8 @@ FocusScope{
         anchors.top: parent.top
         anchors.left: parent.left
         anchors.leftMargin: root.sideMargin
+        anchors.right: root.showCSD ? csdDecorations.left : parent.right
 
-        width: implicitWidth
 
         visible: root.showToolbar
         enabled: root.showToolbar



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/a39444d484b07fdd22b4583986fe3097854e3043...9d541293536b3a0fe7385946b1b45b2605808807

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/a39444d484b07fdd22b4583986fe3097854e3043...9d541293536b3a0fe7385946b1b45b2605808807
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list