mirror of
https://github.com/moonlight-stream/moonlight-qt.git
synced 2025-07-01 15:26:09 +00:00
Replace fixed "unsupported FPS" options with fully custom FPS option
Fixes #1003
This commit is contained in:
parent
41f8fa95fe
commit
9166e70524
@ -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
|
||||
|
@ -23,7 +23,6 @@
|
||||
#define SER_HDR "hdr"
|
||||
#define SER_VIDEODEC "videodec"
|
||||
#define SER_WINDOWMODE "windowmode"
|
||||
#define SER_UNSUPPORTEDFPS "unsupportedfps"
|
||||
#define SER_MDNS "mdns"
|
||||
#define SER_QUITAPPAFTER "quitAppAfter"
|
||||
#define SER_ABSMOUSEMODE "mouseacceleration"
|
||||
@ -88,7 +87,6 @@ void StreamingPreferences::reload()
|
||||
gameOptimizations = settings.value(SER_GAMEOPTS, true).toBool();
|
||||
playAudioOnHost = settings.value(SER_HOSTAUDIO, false).toBool();
|
||||
multiController = settings.value(SER_MULTICONT, true).toBool();
|
||||
unsupportedFps = settings.value(SER_UNSUPPORTEDFPS, false).toBool();
|
||||
enableMdns = settings.value(SER_MDNS, true).toBool();
|
||||
quitAppAfter = settings.value(SER_QUITAPPAFTER, false).toBool();
|
||||
absoluteMouseMode = settings.value(SER_ABSMOUSEMODE, false).toBool();
|
||||
@ -271,7 +269,6 @@ void StreamingPreferences::save()
|
||||
settings.setValue(SER_GAMEOPTS, gameOptimizations);
|
||||
settings.setValue(SER_HOSTAUDIO, playAudioOnHost);
|
||||
settings.setValue(SER_MULTICONT, multiController);
|
||||
settings.setValue(SER_UNSUPPORTEDFPS, unsupportedFps);
|
||||
settings.setValue(SER_MDNS, enableMdns);
|
||||
settings.setValue(SER_QUITAPPAFTER, quitAppAfter);
|
||||
settings.setValue(SER_ABSMOUSEMODE, absoluteMouseMode);
|
||||
|
@ -111,7 +111,6 @@ public:
|
||||
Q_PROPERTY(bool gameOptimizations MEMBER gameOptimizations NOTIFY gameOptimizationsChanged)
|
||||
Q_PROPERTY(bool playAudioOnHost MEMBER playAudioOnHost NOTIFY playAudioOnHostChanged)
|
||||
Q_PROPERTY(bool multiController MEMBER multiController NOTIFY multiControllerChanged)
|
||||
Q_PROPERTY(bool unsupportedFps MEMBER unsupportedFps NOTIFY unsupportedFpsChanged)
|
||||
Q_PROPERTY(bool enableMdns MEMBER enableMdns NOTIFY enableMdnsChanged)
|
||||
Q_PROPERTY(bool quitAppAfter MEMBER quitAppAfter NOTIFY quitAppAfterChanged)
|
||||
Q_PROPERTY(bool absoluteMouseMode MEMBER absoluteMouseMode NOTIFY absoluteMouseModeChanged)
|
||||
@ -148,7 +147,6 @@ public:
|
||||
bool gameOptimizations;
|
||||
bool playAudioOnHost;
|
||||
bool multiController;
|
||||
bool unsupportedFps;
|
||||
bool enableMdns;
|
||||
bool quitAppAfter;
|
||||
bool absoluteMouseMode;
|
||||
|
@ -812,14 +812,6 @@ bool Session::validateLaunch(SDL_Window* testWindow)
|
||||
}
|
||||
}
|
||||
|
||||
if (m_Preferences->unsupportedFps && m_StreamConfig.fps > 60) {
|
||||
emitLaunchWarning(tr("Using unsupported FPS options may cause stuttering or lag."));
|
||||
|
||||
if (m_Preferences->enableVsync) {
|
||||
emitLaunchWarning(tr("V-sync will be disabled when streaming at a higher frame rate than the display."));
|
||||
}
|
||||
}
|
||||
|
||||
if (m_StreamConfig.supportedVideoFormats & VIDEO_FORMAT_MASK_AV1) {
|
||||
if (!(m_Computer->serverCodecModeSupport & SCM_MASK_AV1)) {
|
||||
if (m_Preferences->videoCodecConfig == StreamingPreferences::VCC_FORCE_AV1) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user