From 4d4a4e8b55c474ad1a772b64e57ff69ddb1c2f16 Mon Sep 17 00:00:00 2001 From: Fatih Uzunoglu <fuzun54@outlook.com> Date: Mon, 31 Mar 2025 18:27:31 +0300 Subject: [PATCH 1/4] qt: introduce `RadioButtonExt.qml` Based on Qt Quick Basic Style, the difference being mainly custom colorization and sizing. --- modules/gui/qt/Makefile.am | 3 +- modules/gui/qt/meson.build | 1 + modules/gui/qt/widgets/qml/RadioButtonExt.qml | 79 +++++++++++++++++++ 3 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 modules/gui/qt/widgets/qml/RadioButtonExt.qml diff --git a/modules/gui/qt/Makefile.am b/modules/gui/qt/Makefile.am index daabd5e5508e..e442a0309395 100644 --- a/modules/gui/qt/Makefile.am +++ b/modules/gui/qt/Makefile.am @@ -1302,7 +1302,8 @@ libqml_module_widgets_a_QML = \ widgets/qml/RectangularGlow.qml \ widgets/qml/ImageExt.qml \ widgets/qml/ScrollBarExt.qml \ - widgets/qml/FastBlend.qml + widgets/qml/FastBlend.qml \ + widgets/qml/RadioButtonExt.qml if HAVE_QT65 libqml_module_widgets_a_QML += \ widgets/qml/DynamicShadow.qml \ diff --git a/modules/gui/qt/meson.build b/modules/gui/qt/meson.build index 6c6b3dbac48f..fd17c6659911 100644 --- a/modules/gui/qt/meson.build +++ b/modules/gui/qt/meson.build @@ -902,6 +902,7 @@ qml_modules += { 'widgets/qml/ImageExt.qml', 'widgets/qml/ScrollBarExt.qml', 'widgets/qml/FastBlend.qml', + 'widgets/qml/RadioButtonExt.qml', ), } diff --git a/modules/gui/qt/widgets/qml/RadioButtonExt.qml b/modules/gui/qt/widgets/qml/RadioButtonExt.qml new file mode 100644 index 000000000000..d36f1f3aaf42 --- /dev/null +++ b/modules/gui/qt/widgets/qml/RadioButtonExt.qml @@ -0,0 +1,79 @@ +/***************************************************************************** + * Copyright (C) 2025 VLC authors and VideoLAN + * Copyright (C) 2017 The Qt Company Ltd. + * + * 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 +import QtQuick.Templates as T + +import VLC.Style + +// Based on Qt Quick Basic Style: +T.RadioButton { + id: control + + implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, + implicitContentWidth + leftPadding + rightPadding) + implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, + implicitContentHeight + topPadding + bottomPadding, + implicitIndicatorHeight + topPadding + bottomPadding) + + padding: VLCStyle.margin_xxsmall + spacing: VLCStyle.margin_xxsmall + + readonly property ColorContext colorContext: ColorContext { + id: theme + colorSet: ColorContext.ButtonStandard + + focused: control.visualFocus + hovered: control.hovered + enabled: control.enabled + pressed: control.down + } + + // keep in sync with RadioDelegate.qml (shared RadioIndicator.qml was removed for performance reasons) + indicator: Rectangle { + implicitWidth: control.contentItem ? implicitHeight : VLCStyle.dp(28, VLCStyle.scale) + implicitHeight: control.contentItem ? control.contentItem.implicitHeight : VLCStyle.dp(28, VLCStyle.scale) + + x: control.text ? (control.mirrored ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2 + y: control.topPadding + (control.availableHeight - height) / 2 + + radius: width / 2 + color: control.down ? Qt.lighter(theme.accent) : theme.bg.primary + border.width: control.visualFocus ? VLCStyle.dp(2, VLCStyle.scale) : VLCStyle.dp(1, VLCStyle.scale) + border.color: control.visualFocus ? theme.accent : (theme.palette.isDark ? Qt.lighter(theme.separator) : Qt.darker(theme.separator)) + + Rectangle { + x: (parent.width - width) / 2 + y: (parent.height - height) / 2 + width: parent.width * 3 / 4 + height: parent.height * 3 / 4 + radius: width / 2 + color: theme.accent + visible: control.checked + } + } + + contentItem: ListLabel { + leftPadding: control.indicator && !control.mirrored ? control.indicator.width + control.spacing : 0 + rightPadding: control.indicator && control.mirrored ? control.indicator.width + control.spacing : 0 + + text: control.text + color: theme.fg.primary + } +} -- GitLab From 5f38a4c96647df70e1b95f4865f17a6b7c6e10a0 Mon Sep 17 00:00:00 2001 From: Fatih Uzunoglu <fuzun54@outlook.com> Date: Mon, 31 Mar 2025 21:47:41 +0300 Subject: [PATCH 2/4] qml: use radio buttons instead of combo box in `PlaybackSpeed.qml` Having radio buttons requires one click less to adjust the speed from the presets. --- modules/gui/qt/player/qml/PlaybackSpeed.qml | 100 ++++++-------------- 1 file changed, 31 insertions(+), 69 deletions(-) diff --git a/modules/gui/qt/player/qml/PlaybackSpeed.qml b/modules/gui/qt/player/qml/PlaybackSpeed.qml index ff5491a2fb86..6a6513f8e287 100644 --- a/modules/gui/qt/player/qml/PlaybackSpeed.qml +++ b/modules/gui/qt/player/qml/PlaybackSpeed.qml @@ -18,6 +18,7 @@ import QtQuick import QtQuick.Controls +import QtQuick.Templates as T import QtQuick.Layouts @@ -32,16 +33,9 @@ ColumnLayout { property alias slider: slider - // Private + signal radioButtonClicked(T.AbstractButton button) - property var _model: [{ "value": 0.25 }, - { "value": 0.5 }, - { "value": 0.75 }, - { "value": 1, "title": qsTr("Normal") }, - { "value": 1.25 }, - { "value": 1.5 }, - { "value": 1.75 }, - { "value": 2 }] + // Private // NOTE: 0.96 and 1.04 are useful for video enthusiasts. property var _values: [ 0.25, 0.5, 0.75, 0.96, 1.0, 1.04, 1.25, 1.5, 1.75, 2 ] @@ -73,33 +67,11 @@ ColumnLayout { // Function - function _updateComboBox(value) { - // NOTE: We want a rounded 1.xx value. - value = Math.round(value * 100) / 100 - - for (let i = 0; i < _model.length; i++) { - if (Helpers.compareFloat(_model[i].value, value) === false) - continue - - comboBox.currentIndex = i - - _value = value - - return; - } - - comboBox.currentIndex = -1 - - _value = value - } - function _updateValue(value) { _update = false _applySlider(value) - _updateComboBox(value) - _update = true } @@ -138,8 +110,6 @@ ColumnLayout { Player.rate = value - _updateComboBox(value) - _update = true } @@ -232,7 +202,6 @@ ColumnLayout { toolTipFollowsMouse: true Navigation.parentItem: root - Navigation.downItem: comboBox Keys.priority: Keys.AfterItem Keys.onPressed: (event) => Navigation.defaultKeyAction(event) @@ -266,56 +235,49 @@ ColumnLayout { } } - RowLayout { - id: rowB + Widgets.ListLabel { + text: qsTr("Presets:") + color: colorContext.fg.primary + Layout.fillWidth: true + } + GridLayout { Layout.fillWidth: true + Layout.fillHeight: true Layout.topMargin: VLCStyle.margin_xsmall - Navigation.parentItem: root - Navigation.upItem: slider + rows: radioButtonRepeater.count / 2 // two columns + flow: GridLayout.TopToBottom - Widgets.ListLabel { - text: qsTr("Presets") - color: colorContext.fg.primary - Layout.fillWidth: true - } + rowSpacing: VLCStyle.margin_small + columnSpacing: VLCStyle.margin_small - Widgets.ComboBoxExt { - id: comboBox + ButtonGroup { + id: buttonGroup - Layout.preferredWidth: VLCStyle.combobox_width_normal - Layout.preferredHeight: VLCStyle.combobox_height_normal - - model: ListModel {} + onClicked: function(button /* : AbstractButton */) { + Player.rate = button.modelData + root.radioButtonClicked(button) + } + } - // NOTE: We display the 'Normal' string when the Slider is centered. - displayText: (currentIndex === 3) ? currentText - : root._value + Repeater { + id: radioButtonRepeater - Navigation.parentItem: rowB + model: root._values - // NOTE: This makes the navigation possible since 'up' is changing the comboBox value. - Navigation.leftItem: slider + delegate: Widgets.RadioButtonExt { + required property double modelData - Component.onCompleted: { - for (let i = 0; i < _model.length; i++) { - const item = _model[i] + Layout.fillWidth: true - const title = item.title + text: modelData - if (title) - model.append({ "title": title }) - else - model.append({ "title": String(item.value) }) - } - } + checked: Math.abs(Player.rate - modelData) < 0.01 // need some generous epsilon here - onCurrentIndexChanged: { - if (root._update === false || currentIndex === -1) - return + padding: 0 // we use spacing instead of paddings here - root._applySlider(_model[currentIndex].value) + ButtonGroup.group: buttonGroup } } } -- GitLab From d00c68a39cd1197b611214cfa1dc3d735586d9c8 Mon Sep 17 00:00:00 2001 From: Fatih Uzunoglu <fuzun54@outlook.com> Date: Mon, 31 Mar 2025 22:20:29 +0300 Subject: [PATCH 3/4] qml: do not use `Layout.topMargin` when the layout already provides `spacing` --- modules/gui/qt/player/qml/PlaybackSpeed.qml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/gui/qt/player/qml/PlaybackSpeed.qml b/modules/gui/qt/player/qml/PlaybackSpeed.qml index 6a6513f8e287..311426a4ff30 100644 --- a/modules/gui/qt/player/qml/PlaybackSpeed.qml +++ b/modules/gui/qt/player/qml/PlaybackSpeed.qml @@ -61,6 +61,8 @@ ColumnLayout { Layout.fillWidth: true Layout.fillHeight: true + spacing: VLCStyle.margin_normal + // Events Component.onCompleted: _updateValue(Player.rate) @@ -150,7 +152,6 @@ ColumnLayout { id: rowA Layout.fillWidth: true - Layout.topMargin: VLCStyle.margin_xsmall Layout.alignment: Qt.AlignTop @@ -184,7 +185,7 @@ ColumnLayout { id: slider Layout.fillWidth: true - Layout.topMargin: VLCStyle.margin_xsmall + topPadding: 0 // NOTE: These values come from the VLC 3.x implementation. @@ -244,7 +245,6 @@ ColumnLayout { GridLayout { Layout.fillWidth: true Layout.fillHeight: true - Layout.topMargin: VLCStyle.margin_xsmall rows: radioButtonRepeater.count / 2 // two columns flow: GridLayout.TopToBottom -- GitLab From 09d3f9914cd3ab27cbbb0a14a65c21c8d431be76 Mon Sep 17 00:00:00 2001 From: Fatih Uzunoglu <fuzun54@outlook.com> Date: Mon, 31 Mar 2025 21:48:20 +0300 Subject: [PATCH 4/4] qml: close the playback speed popup when a radio button is clicked --- .../qt/player/qml/controlbarcontrols/PlaybackSpeedButton.qml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/gui/qt/player/qml/controlbarcontrols/PlaybackSpeedButton.qml b/modules/gui/qt/player/qml/controlbarcontrols/PlaybackSpeedButton.qml index 7658e5034f81..04c5b858efd9 100644 --- a/modules/gui/qt/player/qml/controlbarcontrols/PlaybackSpeedButton.qml +++ b/modules/gui/qt/player/qml/controlbarcontrols/PlaybackSpeedButton.qml @@ -42,6 +42,10 @@ PopupIconToolButton { // NOTE: Mapping the right direction because the down action triggers the ComboBox. Navigation.rightItem: root + + onRadioButtonClicked: { + root.popup.close() + } } contentItem: Item { -- GitLab