Replace fixed "unsupported FPS" options with fully custom FPS option

Fixes #1003
This commit is contained in:
Cameron Gutman 2023-09-02 15:53:30 -05:00
commit 9166e70524
4 changed files with 152 additions and 70 deletions

View file

@ -388,12 +388,124 @@ Flickable {
}
AutoResizingComboBox {
function addRefreshRateOrdered(fpsListModel, refreshRate, description) {
property int lastIndexValue
function updateBitrateForSelection() {
// Only modify the bitrate if the values actually changed
var selectedFps = parseInt(model.get(fpsComboBox.currentIndex).video_fps)
if (StreamingPreferences.fps !== selectedFps) {
StreamingPreferences.fps = selectedFps
StreamingPreferences.bitrateKbps = StreamingPreferences.getDefaultBitrate(StreamingPreferences.width,
StreamingPreferences.height,
StreamingPreferences.fps);
slider.value = StreamingPreferences.bitrateKbps
}
lastIndexValue = currentIndex
}
NavigableDialog {
function isInputValid() {
// If we have text that isn't valid, reject the input.
if (!fpsField.acceptableInput && fpsField.text) {
return false
}
// The textbox needs to have text or placeholder text
if (!fpsField.text && !fpsField.placeholderText) {
return false
}
return true
}
id: customFpsDialog
standardButtons: Dialog.Ok | Dialog.Cancel
onOpened: {
// Force keyboard focus on the textbox so keyboard navigation works
fpsField.forceActiveFocus()
// standardButton() was added in Qt 5.10, so we must check for it first
if (customFpsDialog.standardButton) {
customFpsDialog.standardButton(Dialog.Ok).enabled = customFpsDialog.isInputValid()
}
}
onClosed: {
fpsField.clear()
}
onRejected: {
fpsComboBox.currentIndex = fpsComboBox.lastIndexValue
}
onAccepted: {
// Reject if there's invalid input
if (!isInputValid()) {
reject()
return
}
var fps = fpsField.text ? fpsField.text : fpsField.placeholderText
// Find and update the custom entry
for (var i = 0; i < fpsListModel.count; i++) {
if (fpsListModel.get(i).is_custom) {
fpsListModel.setProperty(i, "video_fps", fps)
fpsListModel.setProperty(i, "text", qsTr("Custom (%1 FPS)").arg(fps))
// Now update the bitrate using the custom resolution
fpsComboBox.currentIndex = i
fpsComboBox.updateBitrateForSelection()
// Update the combobox width too
fpsComboBox.recalculateWidth()
break
}
}
}
ColumnLayout {
Label {
text: qsTr("Enter a custom frame rate:")
font.bold: true
}
RowLayout {
TextField {
id: fpsField
maximumLength: 4
inputMethodHints: Qt.ImhDigitsOnly
placeholderText: fpsListModel.get(fpsComboBox.currentIndex).video_fps
validator: IntValidator{bottom:1; top:9999}
focus: true
onTextChanged: {
// standardButton() was added in Qt 5.10, so we must check for it first
if (customFpsDialog.standardButton) {
customFpsDialog.standardButton(Dialog.Ok).enabled = customFpsDialog.isInputValid()
}
}
Keys.onReturnPressed: {
customFpsDialog.accept()
}
Keys.onEnterPressed: {
customFpsDialog.accept()
}
}
}
}
}
function addRefreshRateOrdered(fpsListModel, refreshRate, description, custom) {
var indexToAdd = 0
for (var j = 0; j < fpsListModel.count; j++) {
var existing_fps = parseInt(fpsListModel.get(j).video_fps);
if (refreshRate === existing_fps) {
if (refreshRate === existing_fps || (custom && fpsListModel.get(j).is_custom)) {
// Duplicate entry, skip
indexToAdd = -1
break
@ -404,25 +516,25 @@ Flickable {
}
}
// Insert this display's resolution if it's not a duplicate
// Insert this frame rate if it's not a duplicate
if (indexToAdd >= 0) {
// Custom values always go at the end of the list
if (custom) {
indexToAdd = fpsListModel.count
}
fpsListModel.insert(indexToAdd,
{
"text": description,
"video_fps": ""+refreshRate
"text": description,
"video_fps": ""+refreshRate,
"is_custom": custom
})
}
return indexToAdd
}
function createModel() {
var fpsListModel = Qt.createQmlObject('import QtQuick 2.0; ListModel {}', parent, '')
// Default entries
fpsListModel.append({"text": qsTr("%1 FPS").arg("30"), "video_fps": "30"})
fpsListModel.append({"text": qsTr("%1 FPS").arg("60"), "video_fps": "60"})
function reinitialize() {
// Add native refresh rate for all attached displays
var done = false
for (var displayIndex = 0; !done; displayIndex++) {
@ -433,21 +545,9 @@ Flickable {
break
}
addRefreshRateOrdered(fpsListModel, refreshRate, qsTr("%1 FPS").arg(refreshRate))
addRefreshRateOrdered(fpsListModel, refreshRate, qsTr("%1 FPS").arg(refreshRate), false)
}
// Add unsupported FPS values
if (StreamingPreferences.unsupportedFps) {
addRefreshRateOrdered(fpsListModel, 90, qsTr("%1 FPS (Unsupported)").arg(90))
addRefreshRateOrdered(fpsListModel, 120, qsTr("%1 FPS (Unsupported)").arg(120))
}
return fpsListModel
}
function reinitialize() {
model = createModel()
var saved_fps = StreamingPreferences.fps
currentIndex = -1
for (var i = 0; i < model.count; i++) {
@ -462,11 +562,15 @@ Flickable {
// If we didn't find one, add a custom frame rate for the current value
if (currentIndex === -1) {
currentIndex = addRefreshRateOrdered(model, saved_fps, qsTr("%1 FPS (Custom)").arg(saved_fps))
currentIndex = addRefreshRateOrdered(model, saved_fps, qsTr("Custom (%1 FPS)").arg(saved_fps), true)
}
else {
addRefreshRateOrdered(model, "", qsTr("Custom"), true)
}
// Persist the selected value
activated(currentIndex)
recalculateWidth()
lastIndexValue = currentIndex
}
// ignore setting the index at first, and actually set it when the component is loaded
@ -475,21 +579,31 @@ Flickable {
languageChanged.connect(reinitialize)
}
model: ListModel {
id: fpsListModel
// Other elements may be added at runtime
ListElement {
text: qsTr("30 FPS")
video_fps: "30"
is_custom: false
}
ListElement {
text: qsTr("60 FPS")
video_fps: "60"
is_custom: false
}
}
id: fpsComboBox
maximumWidth: parent.width / 2
textRole: "text"
// ::onActivated must be used, as it only listens for when the index is changed by a human
onActivated : {
var selectedFps = parseInt(model.get(currentIndex).video_fps)
// Only modify the bitrate if the values actually changed
if (StreamingPreferences.fps !== selectedFps) {
StreamingPreferences.fps = selectedFps
StreamingPreferences.bitrateKbps = StreamingPreferences.getDefaultBitrate(StreamingPreferences.width,
StreamingPreferences.height,
StreamingPreferences.fps);
slider.value = StreamingPreferences.bitrateKbps
if (model.get(currentIndex).is_custom) {
customFpsDialog.open()
}
else {
updateBitrateForSelection()
}
}
}
@ -1445,25 +1559,6 @@ Flickable {
qsTr("HDR streaming is not supported on this PC.")
}
CheckBox {
id: unlockUnsupportedFps
width: parent.width
text: qsTr("Unlock unsupported FPS options")
font.pointSize: 12
checked: StreamingPreferences.unsupportedFps
onCheckedChanged: {
// This is called on init, so only do the work if we've
// actually changed the value.
if (StreamingPreferences.unsupportedFps != checked) {
StreamingPreferences.unsupportedFps = checked
// The selectable FPS values depend on whether
// this option is enabled or not
fpsComboBox.reinitialize()
}
}
}
CheckBox {
id: enableMdns
width: parent.width