[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