mirror of
https://github.com/moonlight-stream/moonlight-qt.git
synced 2026-06-17 22:23:31 +00:00
Add custom resolution option
This commit is contained in:
@@ -19,9 +19,7 @@ ComboBox {
|
|||||||
id: textMetrics
|
id: textMetrics
|
||||||
}
|
}
|
||||||
|
|
||||||
// We call this every time the options change (and init)
|
function recalculateWidth() {
|
||||||
// so we can adjust the combo box width here too
|
|
||||||
onActivated: {
|
|
||||||
textMetrics.font = font
|
textMetrics.font = font
|
||||||
popupMetrics.font = popup.font
|
popupMetrics.font = popup.font
|
||||||
textWidth = 0
|
textWidth = 0
|
||||||
@@ -33,6 +31,10 @@ ComboBox {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We call this every time the options change (and init)
|
||||||
|
// so we can adjust the combo box width here too
|
||||||
|
onActivated: recalculateWidth()
|
||||||
|
|
||||||
popup.onAboutToShow: {
|
popup.onAboutToShow: {
|
||||||
// Switch to normal navigation for combo boxes
|
// Switch to normal navigation for combo boxes
|
||||||
SdlGamepadKeyNavigation.setUiNavMode(false)
|
SdlGamepadKeyNavigation.setUiNavMode(false)
|
||||||
|
|||||||
+179
-8
@@ -1,5 +1,6 @@
|
|||||||
import QtQuick 2.9
|
import QtQuick 2.9
|
||||||
import QtQuick.Controls 2.2
|
import QtQuick.Controls 2.2
|
||||||
|
import QtQuick.Layouts 1.2
|
||||||
|
|
||||||
import StreamingPreferences 1.0
|
import StreamingPreferences 1.0
|
||||||
import ComputerManager 1.0
|
import ComputerManager 1.0
|
||||||
@@ -78,6 +79,8 @@ Flickable {
|
|||||||
width: parent.width
|
width: parent.width
|
||||||
|
|
||||||
AutoResizingComboBox {
|
AutoResizingComboBox {
|
||||||
|
property int lastIndexValue
|
||||||
|
|
||||||
// ignore setting the index at first, and actually set it when the component is loaded
|
// ignore setting the index at first, and actually set it when the component is loaded
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
// Add native resolutions for all attached displays
|
// Add native resolutions for all attached displays
|
||||||
@@ -123,7 +126,8 @@ Flickable {
|
|||||||
{
|
{
|
||||||
"text": "Native ("+screenRect.width+"x"+screenRect.height+")",
|
"text": "Native ("+screenRect.width+"x"+screenRect.height+")",
|
||||||
"video_width": ""+screenRect.width,
|
"video_width": ""+screenRect.width,
|
||||||
"video_height": ""+screenRect.height
|
"video_height": ""+screenRect.height,
|
||||||
|
"is_custom": false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -147,19 +151,42 @@ Flickable {
|
|||||||
// and set it to that index.
|
// and set it to that index.
|
||||||
var saved_width = StreamingPreferences.width
|
var saved_width = StreamingPreferences.width
|
||||||
var saved_height = StreamingPreferences.height
|
var saved_height = StreamingPreferences.height
|
||||||
currentIndex = 0
|
var index_set = false
|
||||||
for (var i = 0; i < resolutionListModel.count; i++) {
|
for (var i = 0; i < resolutionListModel.count; i++) {
|
||||||
var el_width = parseInt(resolutionListModel.get(i).video_width);
|
var el_width = parseInt(resolutionListModel.get(i).video_width);
|
||||||
var el_height = parseInt(resolutionListModel.get(i).video_height);
|
var el_height = parseInt(resolutionListModel.get(i).video_height);
|
||||||
|
|
||||||
// Pick the highest value lesser or equal to the saved resolution
|
if (saved_width === el_width && saved_height === el_height) {
|
||||||
if (saved_width * saved_height >= el_width * el_height) {
|
|
||||||
currentIndex = i
|
currentIndex = i
|
||||||
|
index_set = true
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Persist the selected value
|
if (!index_set) {
|
||||||
activated(currentIndex)
|
// We did not find a match. This must be a custom resolution.
|
||||||
|
resolutionListModel.append({
|
||||||
|
"text": "Custom ("+StreamingPreferences.width+"x"+StreamingPreferences.height+")",
|
||||||
|
"video_width": ""+StreamingPreferences.width,
|
||||||
|
"video_height": ""+StreamingPreferences.height,
|
||||||
|
"is_custom": true
|
||||||
|
})
|
||||||
|
currentIndex = resolutionListModel.count - 1
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resolutionListModel.append({
|
||||||
|
"text": "Custom",
|
||||||
|
"video_width": "",
|
||||||
|
"video_height": "",
|
||||||
|
"is_custom": true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since we don't call activate() here, we need to trigger
|
||||||
|
// width calculation manually
|
||||||
|
recalculateWidth()
|
||||||
|
|
||||||
|
lastIndexValue = currentIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
id: resolutionComboBox
|
id: resolutionComboBox
|
||||||
@@ -173,25 +200,29 @@ Flickable {
|
|||||||
text: qsTr("720p")
|
text: qsTr("720p")
|
||||||
video_width: "1280"
|
video_width: "1280"
|
||||||
video_height: "720"
|
video_height: "720"
|
||||||
|
is_custom: false
|
||||||
}
|
}
|
||||||
ListElement {
|
ListElement {
|
||||||
text: qsTr("1080p")
|
text: qsTr("1080p")
|
||||||
video_width: "1920"
|
video_width: "1920"
|
||||||
video_height: "1080"
|
video_height: "1080"
|
||||||
|
is_custom: false
|
||||||
}
|
}
|
||||||
ListElement {
|
ListElement {
|
||||||
text: qsTr("1440p")
|
text: qsTr("1440p")
|
||||||
video_width: "2560"
|
video_width: "2560"
|
||||||
video_height: "1440"
|
video_height: "1440"
|
||||||
|
is_custom: false
|
||||||
}
|
}
|
||||||
ListElement {
|
ListElement {
|
||||||
text: qsTr("4K")
|
text: qsTr("4K")
|
||||||
video_width: "3840"
|
video_width: "3840"
|
||||||
video_height: "2160"
|
video_height: "2160"
|
||||||
|
is_custom: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ::onActivated must be used, as it only listens for when the index is changed by a human
|
|
||||||
onActivated : {
|
function updateBitrateForSelection() {
|
||||||
var selectedWidth = parseInt(resolutionListModel.get(currentIndex).video_width)
|
var selectedWidth = parseInt(resolutionListModel.get(currentIndex).video_width)
|
||||||
var selectedHeight = parseInt(resolutionListModel.get(currentIndex).video_height)
|
var selectedHeight = parseInt(resolutionListModel.get(currentIndex).video_height)
|
||||||
|
|
||||||
@@ -205,6 +236,146 @@ Flickable {
|
|||||||
StreamingPreferences.fps);
|
StreamingPreferences.fps);
|
||||||
slider.value = StreamingPreferences.bitrateKbps
|
slider.value = StreamingPreferences.bitrateKbps
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lastIndexValue = currentIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
// ::onActivated must be used, as it only listens for when the index is changed by a human
|
||||||
|
onActivated : {
|
||||||
|
if (resolutionListModel.get(currentIndex).is_custom) {
|
||||||
|
customResolutionDialog.open()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
updateBitrateForSelection()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NavigableDialog {
|
||||||
|
id: customResolutionDialog
|
||||||
|
standardButtons: Dialog.Ok | Dialog.Cancel
|
||||||
|
onOpened: {
|
||||||
|
// Force keyboard focus on the textbox so keyboard navigation works
|
||||||
|
widthField.forceActiveFocus()
|
||||||
|
|
||||||
|
// standardButton() was added in Qt 5.10, so we must check for it first
|
||||||
|
if (customResolutionDialog.standardButton) {
|
||||||
|
customResolutionDialog.standardButton(Dialog.Ok).enabled = customResolutionDialog.isInputValid()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onClosed: {
|
||||||
|
widthField.clear()
|
||||||
|
heightField.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
onRejected: {
|
||||||
|
resolutionComboBox.currentIndex = resolutionComboBox.lastIndexValue
|
||||||
|
}
|
||||||
|
|
||||||
|
function isInputValid() {
|
||||||
|
// If we have text in either textbox that isn't valid,
|
||||||
|
// reject the input.
|
||||||
|
if ((!widthField.acceptableInput && widthField.text) ||
|
||||||
|
(!heightField.acceptableInput && heightField.text)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// The textboxes need to have text or placeholder text
|
||||||
|
if ((!widthField.text && !widthField.placeholderText) ||
|
||||||
|
(!heightField.text && !heightField.placeholderText)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
onAccepted: {
|
||||||
|
// Reject if there's invalid input
|
||||||
|
if (!isInputValid()) {
|
||||||
|
reject()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var width = widthField.text ? widthField.text : widthField.placeholderText
|
||||||
|
var height = heightField.text ? heightField.text : heightField.placeholderText
|
||||||
|
|
||||||
|
// Find and update the custom entry
|
||||||
|
for (var i = 0; i < resolutionListModel.count; i++) {
|
||||||
|
if (resolutionListModel.get(i).is_custom) {
|
||||||
|
resolutionListModel.setProperty(i, "video_width", width)
|
||||||
|
resolutionListModel.setProperty(i, "video_height", height)
|
||||||
|
resolutionListModel.setProperty(i, "text", "Custom ("+width+"x"+height+")")
|
||||||
|
|
||||||
|
// Now update the bitrate using the custom resolution
|
||||||
|
resolutionComboBox.currentIndex = i
|
||||||
|
resolutionComboBox.updateBitrateForSelection()
|
||||||
|
|
||||||
|
// Update the combobox width too
|
||||||
|
resolutionComboBox.recalculateWidth()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Label {
|
||||||
|
text: qsTr("Custom resolutions are not officially supported by GeForce Experience, so it will not set your host display resolution. You will need to set it manually while in game.") + "\n\n" +
|
||||||
|
qsTr("Resolutions that are not supported by your client or host PC may cause streaming errors.") + "\n"
|
||||||
|
wrapMode: Label.WordWrap
|
||||||
|
Layout.maximumWidth: 300
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: qsTr("Enter a custom resolution:")
|
||||||
|
font.bold: true
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
TextField {
|
||||||
|
id: widthField
|
||||||
|
maximumLength: 5
|
||||||
|
inputMethodHints: Qt.ImhDigitsOnly
|
||||||
|
placeholderText: resolutionListModel.get(resolutionComboBox.currentIndex).video_width
|
||||||
|
validator: IntValidator{bottom:128; top:8192}
|
||||||
|
focus: true
|
||||||
|
|
||||||
|
onTextChanged: {
|
||||||
|
// standardButton() was added in Qt 5.10, so we must check for it first
|
||||||
|
if (customResolutionDialog.standardButton) {
|
||||||
|
customResolutionDialog.standardButton(Dialog.Ok).enabled = customResolutionDialog.isInputValid()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys.onReturnPressed: {
|
||||||
|
customResolutionDialog.accept()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: "x"
|
||||||
|
font.bold: true
|
||||||
|
}
|
||||||
|
|
||||||
|
TextField {
|
||||||
|
id: heightField
|
||||||
|
maximumLength: 5
|
||||||
|
inputMethodHints: Qt.ImhDigitsOnly
|
||||||
|
placeholderText: resolutionListModel.get(resolutionComboBox.currentIndex).video_height
|
||||||
|
validator: IntValidator{bottom:128; top:8192}
|
||||||
|
|
||||||
|
onTextChanged: {
|
||||||
|
// standardButton() was added in Qt 5.10, so we must check for it first
|
||||||
|
if (customResolutionDialog.standardButton) {
|
||||||
|
customResolutionDialog.standardButton(Dialog.Ok).enabled = customResolutionDialog.isInputValid()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys.onReturnPressed: {
|
||||||
|
customResolutionDialog.accept()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -133,8 +133,14 @@ int StreamingPreferences::getDefaultBitrate(int width, int height, int fps)
|
|||||||
// we don't want to bump those 16:10 resolutions up to the
|
// we don't want to bump those 16:10 resolutions up to the
|
||||||
// next 16:9 slot.
|
// next 16:9 slot.
|
||||||
|
|
||||||
|
if (width * height <= 640 * 360) {
|
||||||
|
return static_cast<int>(1000 * (fps / 30.0));
|
||||||
|
}
|
||||||
|
else if (width * height <= 854 * 480) {
|
||||||
|
return static_cast<int>(1500 * (fps / 30.0));
|
||||||
|
}
|
||||||
// This covers 1280x720 and 1280x800 too
|
// This covers 1280x720 and 1280x800 too
|
||||||
if (width * height <= 1366 * 768) {
|
else if (width * height <= 1366 * 768) {
|
||||||
return static_cast<int>(5000 * (fps / 30.0));
|
return static_cast<int>(5000 * (fps / 30.0));
|
||||||
}
|
}
|
||||||
else if (width * height <= 1920 * 1200) {
|
else if (width * height <= 1920 * 1200) {
|
||||||
|
|||||||
Reference in New Issue
Block a user