[vlc-commits] [Git][videolan/vlc][master] 20 commits: qml: consider safe area also in insets in side navigation delegate
Steve Lhomme (@robUx4)
gitlab at videolan.org
Fri Aug 21 10:27:11 UTC 2026
Steve Lhomme pushed to branch master at VideoLAN / VLC
Commits:
eb77f989 by Fatih Uzunoglu at 2026-08-21T10:17:20+00:00
qml: consider safe area also in insets in side navigation delegate
Not doing so causes the current indicator to be placed outside the
safe area.
- - - - -
618b516b by Fatih Uzunoglu at 2026-08-21T10:17:20+00:00
qml: use always off policy if scroll bar is not shown in `SideNavigationPane`
This prevents swallowing mouse events in the scroll bar area.
- - - - -
08df2f7f by Fatih Uzunoglu at 2026-08-21T10:17:20+00:00
qml: respect property `showText` in `SideNavigationDelegate`
- - - - -
bb604321 by Fatih Uzunoglu at 2026-08-21T10:17:20+00:00
qml: pass the item in `itemClicked()` signal in `SideNavigationPane`
- - - - -
8cd23e5a by Fatih Uzunoglu at 2026-08-21T10:17:20+00:00
qml: add property `delegateShowText` in `SideNavigationPane`
- - - - -
11ab537e by Fatih Uzunoglu at 2026-08-21T10:17:20+00:00
qml: make delegate checked if text is not shown when not expanded in `SideNavigationPane`
- - - - -
48506729 by Fatih Uzunoglu at 2026-08-21T10:17:20+00:00
qml: add missing required properties in delegate of `SideNavigationPane`
- - - - -
0d0f8a24 by Fatih Uzunoglu at 2026-08-21T10:17:20+00:00
qml: hide delegate if show text is false and there is no icon in `SideNavigationPane`
- - - - -
ad094a50 by Fatih Uzunoglu at 2026-08-21T10:17:20+00:00
qt: introduce role `icon_svg` in `NavigationModel`
- - - - -
927a99fc by Fatih Uzunoglu at 2026-08-21T10:17:20+00:00
qt: introduce role `children` in `NavigationModel`
- - - - -
371e922a by Fatih Uzunoglu at 2026-08-21T10:17:20+00:00
qt: introduce `NavigationBarContextMenu`
- - - - -
0e0cc07e by Fatih Uzunoglu at 2026-08-21T10:17:20+00:00
qt: register `NavigationBarContextMenu`
- - - - -
9d438b48 by Fatih Uzunoglu at 2026-08-21T10:17:20+00:00
qml: introduce property `VLCStyle::isScreenReallySmall`
- - - - -
eff3a05d by Fatih Uzunoglu at 2026-08-21T10:17:20+00:00
qml: expose the model in `SideNavigationPane`
- - - - -
c7c10c98 by Fatih Uzunoglu at 2026-08-21T10:17:20+00:00
qml: expose the navigation pane toggle button in `LocalTopbar`
- - - - -
14cbd562 by Fatih Uzunoglu at 2026-08-21T10:17:20+00:00
qml: do not fully collapse the side navigation bar unless the window is really small
Instead, collapse to show the delegate icon. If the
delegate is hidden due to missing icon, context menu
opens for sub-items.
This is inspired from Fluent UI.
- - - - -
fd089a41 by Fatih Uzunoglu at 2026-08-21T10:17:20+00:00
qml: make side navigation pane overlay the main view with small screen
This aligns the behavior with the playlist pane.
- - - - -
42ceb7b4 by Fatih Uzunoglu at 2026-08-21T10:17:20+00:00
qml: dissect required property `model` in delegate in `SideNavigationPane`
This enables more native code generation through `qmlcachegen`.
- - - - -
03fedded by Fatih Uzunoglu at 2026-08-21T10:17:20+00:00
qml: animate delegate height also depending on visibility change in `SideNavigationPane`
- - - - -
8c2b88db by Fatih Uzunoglu at 2026-08-21T10:17:20+00:00
qml: consider the display margin in small screen overlay in `MainDisplay`
- - - - -
10 changed files:
- modules/gui/qt/maininterface/mainui.cpp
- modules/gui/qt/maininterface/navigationmodel.cpp
- modules/gui/qt/maininterface/navigationmodel.hpp
- modules/gui/qt/maininterface/qml/LocalTopbar.qml
- modules/gui/qt/maininterface/qml/MainDisplay.qml
- modules/gui/qt/maininterface/qml/SideNavigationDelegate.qml
- modules/gui/qt/maininterface/qml/SideNavigationPane.qml
- modules/gui/qt/menus/qml_menu_wrapper.cpp
- modules/gui/qt/menus/qml_menu_wrapper.hpp
- modules/gui/qt/style/VLCStyle.qml
Changes:
=====================================
modules/gui/qt/maininterface/mainui.cpp
=====================================
@@ -250,6 +250,7 @@ void MainUI::registerQMLTypes()
#endif
qmlRegisterTypesAndRevisions<NavigationModel>( uri, versionMajor);
+ qmlRegisterTypesAndRevisions<NavigationBarContextMenu>( uri, versionMajor );
// Foreign types:
qmlRegisterTypesAndRevisions<vlc::QAbstractProxyModelForeign>(uri, versionMajor);
=====================================
modules/gui/qt/maininterface/navigationmodel.cpp
=====================================
@@ -23,15 +23,17 @@
//hierachical model entry
struct ModelEntry
{
- ModelEntry( QString name, QString uri, QString icon = "")
+ ModelEntry( QString name, QString uri, QString icon = {}, QString iconSvg = {})
: name(name)
, urinode(uri)
, icon(icon)
+ , icon_svg(iconSvg)
{}
- QString name;
- QString urinode;
- QString icon;
+ const QString name;
+ const QString urinode;
+ const QString icon;
+ const QString icon_svg;
std::vector<ModelEntry> children;
size_t visibleChildren = 0;
int expandedIndex = -1;
@@ -211,6 +213,14 @@ struct ModelEntry
return children[*it].getIcon(it + 1, end);
}
+ QString getIconSvg(const PathIterator& it, const PathIterator& end) const
+ {
+ if (it == end)
+ return icon_svg;
+ else
+ return children[*it].getIconSvg(it + 1, end);
+ }
+
int getIndex(const PathIterator& it, const PathIterator& end) const
{
if (it == end)
@@ -219,6 +229,14 @@ struct ModelEntry
return *it + (getIndex(it + 1, end));
}
+ const ModelEntry* getModelEntry(const PathIterator& it, const PathIterator& end) const
+ {
+ if (it == end)
+ return this;
+ else
+ return &children[*it];
+ }
+
template<typename OutIterator>
void getUri(
PathIterator it, const PathIterator& end,
@@ -247,16 +265,16 @@ public:
void initilializeModel()
{
- m_model.children.emplace_back(qtr("Home"), "home", VLCIcons::home);
+ m_model.children.emplace_back(qtr("Home"), "home", VLCIcons::home, QStringLiteral(":/icons/ic_fluent_home.svg"));
if (m_hasMedialib)
{
- ModelEntry videoEntry{ qtr("Video"), "video", VLCIcons::topbar_video };
+ ModelEntry videoEntry{ qtr("Video"), "video", VLCIcons::topbar_video, QStringLiteral(":/icons/ic_fluent_filmstrip.svg") };
videoEntry.children.emplace_back(qtr("All"), "all");
videoEntry.children.emplace_back(qtr("Playlists"), "playlists");
m_model.children.push_back(std::move(videoEntry));
- ModelEntry musicEntry{ qtr("Music"), "music", VLCIcons::topbar_music };
+ ModelEntry musicEntry{ qtr("Music"), "music", VLCIcons::topbar_music, QStringLiteral(":/icons/ic_fluent_music_note_2.svg") };
musicEntry.children.emplace_back(qtr("Artists"), "artists");
musicEntry.children.emplace_back(qtr("Albums"), "albums");
musicEntry.children.emplace_back(qtr("Tracks"), "tracks");
@@ -265,9 +283,9 @@ public:
m_model.children.push_back(std::move(musicEntry));
}
- m_model.children.emplace_back(qtr("Browse"), "network", VLCIcons::topbar_network);
+ m_model.children.emplace_back(qtr("Browse"), "network", VLCIcons::topbar_network, QStringLiteral(":/icons/ic_fluent_wifi_1.svg"));
- ModelEntry discoverEntry{ qtr("Discover"), "discover", VLCIcons::topbar_discover };
+ ModelEntry discoverEntry{ qtr("Discover"), "discover", VLCIcons::topbar_discover, QStringLiteral(":/icons/ic_fluent_globe.svg") };
discoverEntry.children.emplace_back(qtr("Services"), "services");
discoverEntry.children.emplace_back(qtr("URL"), "url");
@@ -311,6 +329,14 @@ public:
//itemIndex doesn't change
auto itemIndex = q->index(newExpandedIndex);
q->dataChanged(itemIndex, itemIndex, {NavigationModel::EXPANDED});
+
+ // TODO: Use more specific range:
+ for (int i = 0; i < q->rowCount(); ++i)
+ {
+ const auto modelIndex = q->index(i, 0);
+ q->dataChanged(modelIndex, modelIndex, {NavigationModel::CHILDREN});
+ }
+
return true;
}
else
@@ -359,6 +385,13 @@ public:
auto itemIndex = q->index(itemIndexRow);
q->dataChanged(itemIndex, itemIndex, {NavigationModel::EXPANDED});
+
+ // TODO: Use more specific range:
+ for (int i = 0; i < q->rowCount(); ++i)
+ {
+ const auto modelIndex = q->index(i, 0);
+ q->dataChanged(modelIndex, modelIndex, {NavigationModel::CHILDREN});
+ }
}
return true;
@@ -390,9 +423,12 @@ QHash<int,QByteArray> NavigationModel::roleNames() const
{TITLE, QByteArrayLiteral("title") },
{URI, QByteArrayLiteral("uri") },
{DEPTH, QByteArrayLiteral("depth") },
- {ICON, QByteArrayLiteral("icon") },
+ // TODO: Use "icon" instead, when minimum Qt increases:
+ {ICON, QByteArrayLiteral("icon_alias") },
+ {ICON_SVG, QByteArrayLiteral("icon_svg")},
{EXPANDABLE, QByteArrayLiteral("expandable") },
{EXPANDED, QByteArrayLiteral("expanded") },
+ {CHILDREN, QByteArrayLiteral("children") }
};
}
@@ -424,10 +460,34 @@ QVariant NavigationModel::data(const QModelIndex &index, int role) const
return d->m_model.getDepth(path.cbegin(), path.cend()) - 1;
case ICON:
return d->m_model.getIcon(path.cbegin(), path.cend());
+ case ICON_SVG:
+ return d->m_model.getIconSvg(path.cbegin(), path.cend());
case EXPANDABLE:
return d->m_model.isExpandable(path.cbegin(), path.cend());
case EXPANDED:
return d->m_model.isExpanded(path.cbegin(), path.cend());
+ case CHILDREN:
+ {
+ const ModelEntry* modelEntry = d->m_model.getModelEntry(path.cbegin(), path.cend());
+ assert(modelEntry);
+
+ const auto& children = modelEntry->children;
+
+ QList<NavigationModelItem> list;
+ list.reserve(children.size());
+ for (const auto& child : children)
+ {
+ QStringList outlist;
+ d->m_model.getUri(path.cbegin(), path.cend(), std::back_inserter(outlist));
+ //don't advertise our root note
+ outlist.pop_front();
+ outlist.push_back(child.urinode);
+
+ list.emplace_back(child.name, child.icon, child.icon_svg, outlist);
+ }
+
+ return QVariant::fromValue(list);
+ }
default:
break;
}
=====================================
modules/gui/qt/maininterface/navigationmodel.hpp
=====================================
@@ -23,6 +23,40 @@
#include <QQmlEngine>
#include <QAbstractListModel>
+class NavigationModelItem
+{
+ Q_GADGET
+
+ Q_PROPERTY(QString name READ name CONSTANT FINAL)
+ Q_PROPERTY(QString icon READ icon CONSTANT FINAL)
+ Q_PROPERTY(QString icon_svg READ icon_svg CONSTANT FINAL)
+ Q_PROPERTY(QStringList uri READ uri CONSTANT FINAL)
+
+ QML_VALUE_TYPE(navigationModelItem)
+
+public:
+ NavigationModelItem() = default;
+
+ NavigationModelItem(const QString& name,
+ const QString& icon,
+ const QString& icon_svg,
+ const QStringList& uri)
+ : m_name(name)
+ , m_icon(icon)
+ , m_icon_svg(icon_svg)
+ , m_uri(uri)
+ { }
+
+ QString name() const { return m_name; }
+ QString icon() const { return m_icon; }
+ QString icon_svg() const { return m_icon_svg; }
+ QStringList uri() const { return m_uri; }
+
+private:
+ QString m_name, m_icon, m_icon_svg;
+ QStringList m_uri;
+};
+
class NavigationModelPrivate;
class NavigationModel : public QAbstractListModel, public QQmlParserStatus
{
@@ -38,8 +72,10 @@ public:
URI,
DEPTH,
ICON,
+ ICON_SVG,
EXPANDABLE,
EXPANDED,
+ CHILDREN
};
Q_ENUM(Roles)
=====================================
modules/gui/qt/maininterface/qml/LocalTopbar.qml
=====================================
@@ -51,6 +51,8 @@ T.ToolBar {
property alias navigationVisible: navigationVisibilty.checked
property alias playqueueVisible: playlistBtn.checked
+ property alias navigationButton: navigationVisibilty
+
signal toggleNavigationVisibility()
signal togglePlayqueueVisibility()
=====================================
modules/gui/qt/maininterface/qml/MainDisplay.qml
=====================================
@@ -447,12 +447,18 @@ FocusScope {
focus: true
anchors.fill: parent
- anchors.leftMargin: sidebar.width
+ anchors.leftMargin: (sidebar.visible && (VLCStyle.isScreenSmall ? (sidebar.state === "") : true)) ? sidebar.width : 0.0
anchors.rightMargin: (playlistLoader.shown && !VLCStyle.isScreenSmall)
? playlistLoader.width
: 0
anchors.bottomMargin: g_mainDisplay.displayMargin
+ // Prevent animating x on collapse with overlayed side navigation bar:
+ Binding on anchors.leftMargin {
+ when: (VLCStyle.isScreenSmall && sidebar.state === "" && sidebarTransition.running)
+ value: 0.0
+ }
+
pageModel: g_mainDisplay.pageModel
leftPadding: sidebar.visible ? 0 : VLCStyle.applicationHorizontalMargin
@@ -519,11 +525,18 @@ FocusScope {
}
Rectangle {
+ id: smallScreenOverlay
+
// overlay for smallscreens
z: 2
- anchors.fill: parent
- visible: VLCStyle.isScreenSmall && (playlistLoader.shown || (pannelVisiblity.showNavigation && sidebar.visible))
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+
+ height: parent.height - g_mainDisplay.displayMargin
+
+ visible: VLCStyle.isScreenSmall && (playlistLoader.shown || (sidebar.visible && (sidebar.state === "expanded")))
color: "black"
opacity: 0.4
@@ -549,9 +562,13 @@ FocusScope {
left: parent.left
}
- width: 0
+ width: VLCStyle.isScreenReallySmall ? 0.0 : collapsedWidth
- visible: false
+ property real collapsedWidth: VLCStyle.icon_normal + VLCStyle.margin_small + VLCStyle.margin_xsmall + VLCStyle.applicationHorizontalMargin
+
+ delegateShowText: (state === "expanded")
+
+ visible: (width > 0.0)
height: parent.height - g_mainDisplay.displayMargin
@@ -559,14 +576,44 @@ FocusScope {
topPadding: 0
leftPadding: 0
- rightPadding: sidebarResizeHandle.visualBorder.width
+ rightPadding: sidebarResizeHandle.visible ? sidebarResizeHandle.visualBorder.width : 0.0
bottomPadding: VLCStyle.applicationVerticalMargin + VLCStyle.margin_small
safeAreaLeftMargin: VLCStyle.applicationHorizontalMargin
- useAcrylic: !VLCStyle.isScreenSmall
+ useAcrylic: (VLCStyle.isScreenSmall ? (sidebar.state === "") : true) // See `694d51a7` for the reasoning.
+
+ NavigationBarContextMenu {
+ id: navigationBarContextMenu
+
+ ctx: MainCtx
+
+ model: sidebar.model
+
+ onPageRequested: (uri) => {
+ if (stackView.isDefaulLoadedForPath([...uri]) ||
+ History.exactMatch(History.viewPath, uri)) {
+ stackView.positionContentAtBeginning()
+ return
+ }
+
+ History.push(uri)
+ }
+ }
+
+ onItemClicked: (modelUri, item) => {
+ console.assert(modelUri)
+
+ console.assert(item)
+ if ((sidebar.state !== 'expanded') && item.expandable) {
+ // TODO: Investigate opening the menu on hover, if
+ // we switch to `Popup.Item` type of menus.
+ const mappedPos = mapToGlobal(item.x + item.width, item.y)
+ navigationBarContextMenu.popup(item.index, mappedPos, !item.hovered)
+
+ return
+ }
- onItemClicked: (modelUri) => {
if (stackView.isDefaulLoadedForPath([...modelUri]) ||
!!modelUri.length && History.exactMatch(History.viewPath, modelUri)) {
stackView.positionContentAtBeginning()
@@ -600,7 +647,6 @@ FocusScope {
PropertyChanges {
target: sidebar
width: sidebar.implicitWidth
- visible: true
}
}
@@ -611,14 +657,10 @@ FocusScope {
from: ""; to: "expanded";
reversible: true
- SequentialAnimation {
- PropertyAction { property: "visible" }
-
- NumberAnimation {
- property: "width"
- duration: VLCStyle.duration_short
- easing.type: Easing.InOutSine
- }
+ NumberAnimation {
+ property: "width"
+ duration: VLCStyle.duration_short
+ easing.type: Easing.InOutSine
}
}
@@ -631,6 +673,7 @@ FocusScope {
panelObject: MainCtx.navigationPanel
atRight: true
+ resizeHandle.visible: (sidebar.state === "expanded") && !VLCStyle.isScreenSmall
visualBorder.visible: !topLeftCornerBackground.visible
minimumWidth: sidebar.minimumWidth
@@ -782,7 +825,7 @@ FocusScope {
} else {
if (UpdateModel.updateStatus === _updateStatusOnDismissal)
return false // already dismissed with the same status
-
+
switch (UpdateModel.updateStatus) {
case UpdateModel.Unchecked:
case UpdateModel.Checking:
@@ -834,7 +877,7 @@ FocusScope {
Navigation.downItem: miniPlayer
Navigation.navigable: (active && height > 0.0)
- onLoaded: {
+ onLoaded: {
item.background.visible = Qt.binding(function() { return !stackViewParent.layer.enabled })
item.leftPadding = Qt.binding(function() { return VLCStyle.margin_large + VLCStyle.applicationHorizontalMargin })
@@ -1045,6 +1088,7 @@ FocusScope {
property alias atRight: resizeHandle.atRight
property alias visualBorder: visualBorder
+ property alias resizeHandle: resizeHandle
property alias minimumWidth: resizeHandle.minimumWidth
property alias maximumWidth: resizeHandle.maximumWidth
=====================================
modules/gui/qt/maininterface/qml/SideNavigationDelegate.qml
=====================================
@@ -46,11 +46,17 @@ T.ItemDelegate {
padding: VLCStyle.margin_xxsmall
- leftInset: VLCStyle.margin_xxsmall
- rightInset: VLCStyle.margin_xxsmall
+ leftInset: implicitLeftInset
+ rightInset: implicitRightInset
- topInset: VLCStyle.margin_xxxsmall
- bottomInset: VLCStyle.margin_xxxsmall
+ topInset: implicitTopInset
+ bottomInset: implicitBottomInset
+
+ property real implicitLeftInset: VLCStyle.margin_xxsmall
+ property real implicitRightInset: VLCStyle.margin_xxsmall
+
+ property real implicitTopInset: VLCStyle.margin_xxxsmall
+ property real implicitBottomInset: VLCStyle.margin_xxxsmall
// Accessible
@@ -150,6 +156,8 @@ T.ItemDelegate {
elide: Text.ElideRight
+ visible: control.showText
+
font.pixelSize: VLCStyle.fontSize_normal
font.weight: control.checked ? Font.DemiBold : Font.Normal
=====================================
modules/gui/qt/maininterface/qml/SideNavigationPane.qml
=====================================
@@ -30,7 +30,7 @@ import VLC.Util
T.Pane {
id: root
- signal itemClicked(uri : var)
+ signal itemClicked(uri : var, item : Item)
//safe area margins for delegate content,
//so the background of the delegates fills the available space
@@ -38,7 +38,11 @@ T.Pane {
property int safeAreaLeftMargin: 0
property int safeAreaRightMargin: 0
- property bool useAcrylic: false
+ property bool useAcrylic: true
+
+ property bool delegateShowText: true
+
+ property alias model: navigationModel
readonly property int minimumWidth: VLCStyle.expandNavigationPaneWidth + safeAreaLeftMargin + safeAreaRightMargin
@@ -109,6 +113,13 @@ T.Pane {
model: navigationModel
+ Binding {
+ target: listView.T.ScrollBar.vertical
+ property: "policy"
+ when: listView.T.ScrollBar.vertical?.size > (1.0 - Number.EPSILON)
+ value: T.ScrollBar.AlwaysOff
+ }
+
colorContext.colorSet: ColorContext.Window
fadingEdge.backgroundColor: (root.background && (root.background.color.a >= 1.0)) ? root.background.color
@@ -152,22 +163,46 @@ T.Pane {
width: ListView.view.contentWidth
height: preferredHeight
- property real preferredHeight: VLCStyle.buttonHeightNavigationPane
+ property real preferredHeight: shouldShow ? VLCStyle.buttonHeightNavigationPane : 0.0
leftPadding: root.safeAreaLeftMargin + VLCStyle.margin_xsmall
rightPadding: root.safeAreaRightMargin
- iconTxt: model.icon
- text: model.title
+ leftInset: root.safeAreaLeftMargin + implicitLeftInset
+ rightInset: root.safeAreaRightMargin + implicitRightInset
+
+ iconTxt: icon_alias
+ text: title
+
+ showText: root.delegateShowText
+
+ required property string title
+ required property var uri
+ required property int depth
+ // TODO: Qt 6.2 has property `icon` marked final, so we can't override it:
+ required property string icon_alias
+ required property bool expandable
+ required property bool expanded
+
+ required property int index
+
+ visible: (height > 0.0)
+
+ property bool shouldShow: showText || (iconTxt.length > 0)
+
+ onShouldShowChanged: {
+ if (listView.readyForAnimations)
+ heightBehavior.enabled = true // At this point, it can keep being enabled for good.
+ }
Binding on highlighted {
- when: !!model.uri && History.match(History.viewPath, model.uri)
+ when: !!uri && History.match(History.viewPath, uri)
value: true
}
- checked: !model.expanded && highlighted
+ checked: (!showText || !expanded) && highlighted
onClicked: {
- itemClicked(model.uri)
+ itemClicked(uri, this)
listView.currentIndex = index
listView.forceActiveFocus(focusReason)
}
@@ -189,7 +224,7 @@ T.Pane {
}
ListView.onAdd: {
- if (listView.readyForAnimations) {
+ if (listView.readyForAnimations && delegate.showText) {
heightBehavior.enabled = false
delegate.height = 0.0
heightBehavior.enabled = true
@@ -228,11 +263,16 @@ T.Pane {
leftPadding: root.safeAreaLeftMargin + VLCStyle.margin_xsmall
rightPadding: root.safeAreaRightMargin
+ leftInset: root.safeAreaLeftMargin + implicitLeftInset
+ rightInset: root.safeAreaRightMargin + implicitRightInset
+
iconTxt: VLCIcons.settings
text: qsTr("Preferences")
checked: DialogsProvider.prefsDialogVisible
+ showText: root.delegateShowText
+
onClicked: DialogsProvider.prefsDialog()
//SideNavigationDelegate is an ItemDelegate and has NoFocus by default
=====================================
modules/gui/qt/menus/qml_menu_wrapper.cpp
=====================================
@@ -28,6 +28,7 @@
#include "playlist/playlist_model.hpp"
#include "dialogs/dialogs_provider.hpp"
#include "util/colorizedsvgicon.hpp"
+#include "maininterface/navigationmodel.hpp"
// Qt includes
#include <QPainter>
@@ -1245,3 +1246,122 @@ void PlaylistContextMenu::popup(int selectedIndex, QPoint pos )
m_menu->popup(pos);
}
+
+NavigationBarContextMenu::NavigationBarContextMenu(QObject *parent)
+ : BasicMenuContainer(parent)
+{
+
+}
+
+void NavigationBarContextMenu::popup(int index, const QPoint& pos, bool setFirstActionAsActive)
+{
+ assert(m_ctx);
+ assert(m_model);
+
+ QMenu *menu = newMenu();
+ assert(menu);
+
+ const auto modelIndex = m_model->index(index, 0);
+ assert(modelIndex.isValid());
+
+ const auto children = m_model->data(modelIndex, NavigationModel::CHILDREN).value<QList<NavigationModelItem>>();
+
+ if (children.count() <= 0)
+ {
+ emit pageRequested(m_model->data(modelIndex, NavigationModel::URI).toStringList());
+ return;
+ }
+
+ populateMenuForChildren(menu, children, setFirstActionAsActive);
+
+ menu->popup(pos);
+}
+
+void NavigationBarContextMenu::popup(const QPoint &pos, bool setFirstActionAsActive)
+{
+ assert(m_ctx);
+ assert(m_model);
+
+ QMenu *menu = newMenu();
+ assert(menu);
+
+ bool activeActionSet = !setFirstActionAsActive;
+ bool menuAdded = false;
+
+ for (int i = 0; i < m_model->rowCount(); ++i)
+ {
+ const auto modelIndex = m_model->index(i, 0);
+ assert(modelIndex.isValid());
+
+ const auto menuTitle = m_model->data(modelIndex, NavigationModel::TITLE).toString();
+ const auto menuUri = m_model->data(modelIndex, NavigationModel::URI).toStringList();
+ const auto menuIcon = m_model->data(modelIndex, NavigationModel::ICON_SVG).toString();
+ const auto menuExpandable = m_model->data(modelIndex, NavigationModel::EXPANDABLE).toBool();
+ const auto menuChildren = m_model->data(modelIndex, NavigationModel::CHILDREN).value<QList<NavigationModelItem>>();
+ const auto menuDepth = m_model->data(modelIndex, NavigationModel::DEPTH).toInt();
+
+ // We currently do not care about deeper levels:
+ if (menuDepth != 0)
+ continue;
+
+ if (menuExpandable && menuChildren.size() > 0)
+ {
+ const auto subMenu = menu->addMenu(menuTitle);
+
+ if (menuIcon.length() > 0)
+ subMenu->setIcon(ColorizedSvgIcon::colorizedIconForWidget(menuIcon, subMenu));
+
+ populateMenuForChildren(subMenu, menuChildren, setFirstActionAsActive);
+
+ menuAdded = true;
+ }
+ else
+ {
+ const auto action = menu->addAction(menuTitle, [this, menuUri]() {
+ emit pageRequested(menuUri);
+ });
+
+ if (menuIcon.length() > 0)
+ action->setIcon(ColorizedSvgIcon::colorizedIconForWidget(menuIcon, qobject_cast<QWidget*>(menu)));
+
+ if (!activeActionSet && !menuAdded)
+ {
+ menu->setActiveAction(action);
+ activeActionSet = true;
+ }
+ }
+ }
+
+ menu->popup(pos);
+}
+
+void NavigationBarContextMenu::populateMenuForChildren(QMenu *menu, const QList<NavigationModelItem> &children, bool setFirstActionAsActive)
+{
+ assert(m_ctx);
+ assert(m_model);
+ assert(menu);
+
+ bool activeActionSet = !setFirstActionAsActive;
+
+ for (const auto& child : children)
+ {
+ const auto childTitle = child.name();
+ assert(childTitle.length() > 0);
+ const auto childUri = child.uri();
+ assert(childUri.length() > 0);
+ const auto childIcon = child.icon_svg();
+
+ const auto action = menu->addAction(childTitle, [this, uri = childUri]() {
+ emit pageRequested(uri);
+ });
+
+ if (childIcon.length() > 0)
+ action->setIcon(ColorizedSvgIcon::colorizedIconForWidget(childIcon, qobject_cast<QWidget*>(menu)));
+
+ if (!activeActionSet)
+ {
+ menu->setActiveAction(action);
+ activeActionSet = true;
+ }
+ }
+}
=====================================
modules/gui/qt/menus/qml_menu_wrapper.hpp
=====================================
@@ -483,6 +483,28 @@ private:
std::unique_ptr<QMenu> m_menu;
};
+class NavigationBarContextMenu : public BasicMenuContainer
+{
+ Q_OBJECT
+
+ SIMPLE_MENU_PROPERTY(QAbstractItemModel*, model, nullptr)
+
+ QML_ELEMENT
+
+public:
+ explicit NavigationBarContextMenu(QObject *parent = nullptr);
+
+public slots:
+ void popup(int index, const QPoint& pos, bool setFirstActionAsActive = false);
+ void popup(const QPoint& pos, bool setFirstActionAsActive = false);
+
+signals:
+ void pageRequested(const QStringList& uri);
+
+private:
+ void populateMenuForChildren(QMenu *menu, const QList<class NavigationModelItem>& children, bool setFirstActionAsActive = false);
+};
+
#undef SIMPLE_MENU_PROPERTY
#endif // QMLMENUWRAPPER_HPP
=====================================
modules/gui/qt/style/VLCStyle.qml
=====================================
@@ -256,6 +256,7 @@ QtObject {
readonly property int mediumWidth: MainCtx.dp(1000, scale)
readonly property bool isScreenSmall: appWidth <= smallWidth
+ readonly property bool isScreenReallySmall: appWidth <= MainCtx.dp(380, scale)
//global application margin "safe area"
readonly property int applicationHorizontalMargin: MainCtx.safeArea * appWidth / 100
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/f8d7ef84e037c9741e9878a114fd004da6a6dd2a...8c2b88db9ac5157d11ca4d3592c3efec715c7623
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/f8d7ef84e037c9741e9878a114fd004da6a6dd2a...8c2b88db9ac5157d11ca4d3592c3efec715c7623
You're receiving this email because of your account on code.videolan.org. Manage all notifications: https://code.videolan.org/-/profile/notifications | Help: https://code.videolan.org/help
More information about the vlc-commits
mailing list