From 83fbedf30cd15c49611ab84ac956ee9e00c49153 Mon Sep 17 00:00:00 2001 From: Daniel F Date: Mon, 5 Oct 2026 22:22:25 +0300 Subject: [PATCH 1/6] GPS filters: auto load companion gps file at filter.isNew --- src/qml/filters/gpsgraphic/ui.qml | 26 +++++++++++++++++++++++++- src/qml/filters/gpstext/ui.qml | 25 +++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/qml/filters/gpsgraphic/ui.qml b/src/qml/filters/gpsgraphic/ui.qml index f368fbe4fc..75be673b8e 100644 --- a/src/qml/filters/gpsgraphic/ui.qml +++ b/src/qml/filters/gpsgraphic/ui.qml @@ -100,6 +100,7 @@ Item { //gps sync data if (gpsFile.exists()) { fileLabel.text = gpsFile.fileName; + fileLabel.color = activePalette.text; fileLabelTip.text = gpsFile.filePath + "\nGPS start time: " + filter.get('gps_start_text') + "\nVideo start time: " + filter.get('video_start_text'); } else { fileLabel.text = qsTr("No File Loaded."); @@ -377,6 +378,7 @@ Item { filter.savePreset(usedParams, "Colors: green middle (5)"); usedParams = reset_all_params(); filter.savePreset(usedParams); + autoGpsFileDetectionTimer.restart(); } //get current timezone //TODO: not sure why this doesn't include daylight saving if active, remove completely? @@ -412,6 +414,29 @@ Item { } } + + //timer to update Ui in case of automatic gps file detection + Timer { + id: autoGpsFileDetectionTimer + property int calls: 0 + interval: 250 + repeat: true + onTriggered: { + var res = filter.get('resource') + if (res) { + autoGpsFileDetectionTimer.stop(); + gpsFile.url = res; + gpsGraphRoot.fileOpened(gpsFile.path); + filter.set('time_offset', filter.get('auto_gps_offset_start')); + setControls(); + } else { + calls += 1; + if (calls > 4) + autoGpsFileDetectionTimer.stop(); + } + } + } + //timer to update UI after gps file is processed; max: 10x250ms Timer { id: gpsFinishParseTimer @@ -420,7 +445,6 @@ Item { interval: 250 repeat: true - triggeredOnStart: false onTriggered: { if (filter.get('gps_start_text') == '') { calls += 1; diff --git a/src/qml/filters/gpstext/ui.qml b/src/qml/filters/gpstext/ui.qml index 510a46d323..3cbe0359a9 100644 --- a/src/qml/filters/gpstext/ui.qml +++ b/src/qml/filters/gpstext/ui.qml @@ -35,6 +35,7 @@ Shotcut.KeyframableFilter { textFilterUi.setControls(); if (gpsFile.exists()) { fileLabel.text = gpsFile.fileName; + fileLabel.color = activePalette.text; fileLabelTip.text = gpsFile.filePath + "\nGPS start time: " + filter.get('gps_start_text') + "\nVideo start time: " + filter.get('video_start_text'); } else { fileLabel.text = qsTr("No File Loaded."); @@ -128,6 +129,7 @@ Shotcut.KeyframableFilter { filter.set(textFilterUi.rectProperty, '10%/10%:80%x80%'); filter.savePreset(presetParams); filter.set(textFilterUi.rectProperty, filter.getRect(textFilterUi.rectProperty)); + autoGpsFileDetectionTimer.restart(); } else { filter.set(textFilterUi.middleValue, filter.getRect(textFilterUi.rectProperty, filter.animateIn + 1)); if (filter.animateIn > 0) @@ -179,6 +181,29 @@ Shotcut.KeyframableFilter { } } + + //timer to update Ui in case of automatic gps file detection + Timer { + id: autoGpsFileDetectionTimer + property int calls: 0 + interval: 250 + repeat: true + onTriggered: { + var res = filter.get('resource') + if (res) { + autoGpsFileDetectionTimer.stop(); + gpsFile.url = res; + gpsGraphRoot.fileOpened(gpsFile.path); + filter.set('time_offset', filter.get('auto_gps_offset_start')); + setControls(); + } else { + calls += 1; + if (calls > 4) + autoGpsFileDetectionTimer.stop(); + } + } + } + //timer to update UI after gps file is processed; max: 10x250ms Timer { id: gpsFinishParseTimer From c299eeb59131151527aab508450e8488984e6b59 Mon Sep 17 00:00:00 2001 From: Daniel F Date: Mon, 5 Oct 2026 22:23:17 +0300 Subject: [PATCH 2/6] GPS text: fix UI refresh of processing start time --- src/qml/filters/gpstext/ui.qml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/qml/filters/gpstext/ui.qml b/src/qml/filters/gpstext/ui.qml index 3cbe0359a9..a438178757 100644 --- a/src/qml/filters/gpstext/ui.qml +++ b/src/qml/filters/gpstext/ui.qml @@ -46,7 +46,13 @@ Shotcut.KeyframableFilter { combo_smoothing.currentIndex = combo_smoothing.get_smooth_index_from_val(filter.get('smoothing_value')); speed_multiplier.value = filter.get('speed_multiplier'); updates_per_second.text = filter.get('updates_per_second'); - gps_processing_start.text = filter.get('gps_processing_start_time'); + if (filter.get('gps_processing_start_time') == 'yyyy-MM-dd hh:mm:ss' && filter.get('gps_start_text') != '') + { + gps_processing_start.text = filter.get('gps_start_text'); + filter.set('gps_processing_start_time', filter.get('gps_start_text')); + } + else + gps_processing_start.text = filter.get('gps_processing_start_time'); } //this function combines the text values from sign combobox * days/hours/mins/sec TextFields into an int From f6806270b1ff44940c3872d876fc61f170a6b6f7 Mon Sep 17 00:00:00 2001 From: Daniel F Date: Tue, 6 Oct 2026 01:25:55 +0300 Subject: [PATCH 3/6] GPS graphic: add 3 buttons for resize fullscreen, bottom right, map ratio --- src/qml/filters/gpsgraphic/ui.qml | 243 ++++++++++++++++++------------ 1 file changed, 145 insertions(+), 98 deletions(-) diff --git a/src/qml/filters/gpsgraphic/ui.qml b/src/qml/filters/gpsgraphic/ui.qml index 75be673b8e..b9cebb96d3 100644 --- a/src/qml/filters/gpsgraphic/ui.qml +++ b/src/qml/filters/gpsgraphic/ui.qml @@ -1550,127 +1550,174 @@ Item { } } - Label { - text: qsTr('Position') + + //special row for size & poz so we center the buttons + ColumnLayout { Layout.alignment: Qt.AlignRight + Label { + text: qsTr('Position') + Layout.alignment: Qt.AlignRight + } + Label { + text: qsTr('Size') + Layout.alignment: Qt.AlignRight + } } + GridLayout { + rows: 2 + columns: 2 - RowLayout { - Shotcut.DoubleSpinBox { - id: rectX + RowLayout { //position + Layout.column: 0 + Layout.row: 0; + Shotcut.DoubleSpinBox { + id: rectX - value: filterRect.x - Layout.minimumWidth: 80 - horizontalAlignment: Qt.AlignRight - decimals: 0 - stepSize: 1 - from: -1e+09 - to: 1e+09 - onValueModified: { - if (_disableUpdate) - return; - setFilter(); + value: filterRect.x + Layout.minimumWidth: 80 + horizontalAlignment: Qt.AlignRight + decimals: 0 + stepSize: 1 + from: -1e+09 + to: 1e+09 + onValueModified: { + if (_disableUpdate) + return; + setFilter(); + } } - } - Label { - text: ',' - Layout.minimumWidth: 20 - horizontalAlignment: Qt.AlignHCenter - } + Label { + text: ',' + Layout.minimumWidth: 20 + horizontalAlignment: Qt.AlignHCenter + } - Shotcut.DoubleSpinBox { - id: rectY + Shotcut.DoubleSpinBox { + id: rectY - value: filterRect.y - Layout.minimumWidth: 80 - horizontalAlignment: Qt.AlignRight - decimals: 0 - stepSize: 1 - from: -1e+09 - to: 1e+09 - onValueModified: { - if (_disableUpdate) - return; - setFilter(); + value: filterRect.y + Layout.minimumWidth: 80 + horizontalAlignment: Qt.AlignRight + decimals: 0 + stepSize: 1 + from: -1e+09 + to: 1e+09 + onValueModified: { + if (_disableUpdate) + return; + setFilter(); + } } } + RowLayout { //size + Layout.column: 0 + Layout.row: 1; + Shotcut.DoubleSpinBox { + id: rectW - Shotcut.UndoButton { - onClicked: { - rectX.value = profile.width * 0.1; - rectY.value = profile.height * 0.1; - setFilter(); + value: filterRect.width + Layout.minimumWidth: 80 + horizontalAlignment: Qt.AlignRight + decimals: 0 + stepSize: 1 + from: -1e+09 + to: 1e+09 + onValueModified: { + if (_disableUpdate) + return; + setFilter(); + } } - } - } - Label { - text: qsTr('Size') - Layout.alignment: Qt.AlignRight - } + Label { + text: 'x' + Layout.minimumWidth: 20 + horizontalAlignment: Qt.AlignHCenter + } - RowLayout { - Shotcut.DoubleSpinBox { - id: rectW + Shotcut.DoubleSpinBox { + id: rectH - value: filterRect.width - Layout.minimumWidth: 80 - horizontalAlignment: Qt.AlignRight - decimals: 0 - stepSize: 1 - from: -1e+09 - to: 1e+09 - onValueModified: { - if (_disableUpdate) - return; - setFilter(); + value: filterRect.height + Layout.minimumWidth: 80 + horizontalAlignment: Qt.AlignRight + decimals: 0 + stepSize: 1 + from: -1e+09 + to: 1e+09 + onValueModified: { + if (_disableUpdate) + return; + setFilter(); + } } } - Label { - text: 'x' - Layout.minimumWidth: 20 - horizontalAlignment: Qt.AlignHCenter - } - - Shotcut.DoubleSpinBox { - id: rectH - - value: filterRect.height - Layout.minimumWidth: 80 - horizontalAlignment: Qt.AlignRight - decimals: 0 - stepSize: 1 - from: -1e+09 - to: 1e+09 - onValueModified: { - if (_disableUpdate) - return; - setFilter(); + //buttons (centered vertically) + RowLayout { + Layout.row: 0 + Layout.column: 1 + Layout.rowSpan: 2 + Layout.alignment: Qt.AlignVCenter + + Shotcut.Button { + icon.name: "view-fullscreen" + implicitWidth: 20 + implicitHeight: 20 + onClicked: { + rectX.value = 0 + profile.width * 0.01; + rectY.value = 0 + profile.height * 0.01; + rectW.value = profile.width * 0.98; + rectH.value = profile.height * 0.98; + setFilter(); + } + Shotcut.HoverTip { + text: qsTr('Reset size and position to almost fullscreen') + } } - } - Shotcut.UndoButton { - onClicked: { - //for map, try to compute height from width using map_aspect_ratio and the crop values - if (combo_data_source.currentIndex === 0) { - var width_p = (spin_right.value - spin_left.value) / 100; - var height_p = (spin_top.value - spin_bot.value) / 100; - rectH.value = 1 * ((rectW.value * height_p) / filter.getDouble('map_original_aspect_ratio')) / width_p; - } else { - rectH.value = rectW.value; + Shotcut.UndoButton { + onClicked: { + rectX.value = profile.width * 0.7; + rectY.value = profile.height * 0.7; + rectW.value = profile.width * 0.25; + rectH.value = profile.height * 0.25; + setFilter(); + } + Shotcut.HoverTip { + text: qsTr('Reset size and position to bottom right side') } - //if it's outside viewport just make it inside, ignore map or crops - if (rectW.value + rectX.value > profile.width) - rectW.value = profile.width - rectX.value; - if (rectH.value + rectY.value > profile.height) - rectH.value = profile.height - rectY.value; - setFilter(); } - Shotcut.HoverTip { - text: qsTr('Sets the height to the correct map aspect ratio or 1:1.') + Shotcut.Button { + icon.name: 'zoom-fit-best' + implicitWidth: 20 + implicitHeight: 20 + onClicked: { + //for map, compute height and width using map_aspect_ratio and the crop values + //only shrink so it doesn't get out of frame + if (combo_data_source.currentIndex === 0) { + var map_ratio = filter.getDouble('map_original_aspect_ratio'); + var width_p = (spin_right.value - spin_left.value) / 100; + var height_p = (spin_top.value - spin_bot.value) / 100; + var new_height = ((rectW.value * height_p) / map_ratio) / width_p; + if (new_height <= rectH.value) { + rectH.value = new_height; + } else { + rectW.value = (rectH.value * width_p * map_ratio) / height_p; + } + } else { + if (rectH.value > rectW.value) + rectH.value = rectW.value; + else + rectW.value = rectH.value; + } + setFilter(); + } + Shotcut.HoverTip { + text: qsTr('Shrink to the correct map aspect ratio (or 1:1)') + } } } } From 202e4854c23c0d18052721b1bd5978020e6d7fcc Mon Sep 17 00:00:00 2001 From: Daniel F Date: Tue, 6 Oct 2026 03:01:56 +0300 Subject: [PATCH 4/6] GPS graphic: auto resize to map_ar on file load; nicer default rect --- src/qml/filters/gpsgraphic/ui.qml | 17 ++++++++++------- src/qml/filters/gpstext/ui.qml | 6 +++--- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/qml/filters/gpsgraphic/ui.qml b/src/qml/filters/gpsgraphic/ui.qml index b9cebb96d3..c028de86d2 100644 --- a/src/qml/filters/gpsgraphic/ui.qml +++ b/src/qml/filters/gpsgraphic/ui.qml @@ -34,7 +34,7 @@ Item { property var default_colors_grade: ["#ff00ff", "#00aaff", "#00e000", "#ffff00", "#ff0000"] property string color_white: "#ffffff" property string default_now_dot: "#00ffffff" - property string default_rect: '10%/10%:30%x30%' + property string default_rect: '75% 75% 20% 20%' property int js_tz_offset: 0 property bool _disableUpdate: true @@ -401,7 +401,7 @@ Item { id: fileDialog title: qsTr("Select GPS File") - nameFilters: ['Supported files (*.gpx *.tcx)', 'GPS Exchange Format (*.gpx)', 'Training Center XML (*.tcx)'] + nameFilters: ['Supported files (*.gpx *.tcx *.txt)', 'GPS Exchange Format (*.gpx)', 'Training Center XML (*.tcx)', 'Text files (*.txt)', 'All files *.*'] onAccepted: { gpsFile.url = fileDialog.selectedFile; gpsGraphRoot.fileOpened(gpsFile.path); @@ -457,6 +457,7 @@ Item { gpsFinishParseTimer.stop(); calls = 0; filter.set('time_offset', filter.get('auto_gps_offset_start')); + button_correct_ar.correct_ar(); setControls(); } } @@ -1679,10 +1680,10 @@ Item { Shotcut.UndoButton { onClicked: { - rectX.value = profile.width * 0.7; - rectY.value = profile.height * 0.7; - rectW.value = profile.width * 0.25; - rectH.value = profile.height * 0.25; + rectX.value = profile.width * 0.75; + rectY.value = profile.height * 0.75; + rectW.value = profile.width * 0.20; + rectH.value = profile.height * 0.20; setFilter(); } Shotcut.HoverTip { @@ -1691,10 +1692,11 @@ Item { } Shotcut.Button { + id: button_correct_ar icon.name: 'zoom-fit-best' implicitWidth: 20 implicitHeight: 20 - onClicked: { + function correct_ar() { //for map, compute height and width using map_aspect_ratio and the crop values //only shrink so it doesn't get out of frame if (combo_data_source.currentIndex === 0) { @@ -1715,6 +1717,7 @@ Item { } setFilter(); } + onClicked: button_correct_ar.correct_ar(); Shotcut.HoverTip { text: qsTr('Shrink to the correct map aspect ratio (or 1:1)') } diff --git a/src/qml/filters/gpstext/ui.qml b/src/qml/filters/gpstext/ui.qml index a438178757..db523b6bd6 100644 --- a/src/qml/filters/gpstext/ui.qml +++ b/src/qml/filters/gpstext/ui.qml @@ -132,7 +132,7 @@ Shotcut.KeyframableFilter { // Add default preset. filter.set(textFilterUi.valignProperty, 'bottom'); filter.set(textFilterUi.halignProperty, 'left'); - filter.set(textFilterUi.rectProperty, '10%/10%:80%x80%'); + filter.set(textFilterUi.rectProperty, '5% 50% 45% 45%'); filter.savePreset(presetParams); filter.set(textFilterUi.rectProperty, filter.getRect(textFilterUi.rectProperty)); autoGpsFileDetectionTimer.restart(); @@ -173,7 +173,7 @@ Shotcut.KeyframableFilter { Shotcut.FileDialog { id: fileDialog - nameFilters: ['Supported files (*.gpx *.tcx)', 'GPS Exchange Format (*.gpx)', 'Training Center XML (*.tcx)'] + nameFilters: ['Supported files (*.gpx *.tcx *.txt)', 'GPS Exchange Format (*.gpx)', 'Training Center XML (*.tcx)', 'Text files (*.txt)', 'All files *.*'] onAccepted: { gpsFile.url = fileDialog.selectedFile; gpsTextRoot.fileOpened(gpsFile.path); @@ -199,7 +199,7 @@ Shotcut.KeyframableFilter { if (res) { autoGpsFileDetectionTimer.stop(); gpsFile.url = res; - gpsGraphRoot.fileOpened(gpsFile.path); + gpsTextRoot.fileOpened(gpsFile.path); filter.set('time_offset', filter.get('auto_gps_offset_start')); setControls(); } else { From dfb1d2531735d00ade64ae298984763fb2222ef2 Mon Sep 17 00:00:00 2001 From: DanielF <3215812+dany123@users.noreply.github.com> Date: Sun, 25 Oct 2026 10:56:18 +0200 Subject: [PATCH 5/6] copilot review fixes --- src/qml/filters/gpsgraphic/ui.qml | 59 +++++++++++++++---------------- src/qml/filters/gpstext/ui.qml | 8 ++--- 2 files changed, 33 insertions(+), 34 deletions(-) diff --git a/src/qml/filters/gpsgraphic/ui.qml b/src/qml/filters/gpsgraphic/ui.qml index c028de86d2..5d6cee5851 100644 --- a/src/qml/filters/gpsgraphic/ui.qml +++ b/src/qml/filters/gpsgraphic/ui.qml @@ -27,9 +27,8 @@ Item { //keep in UI order for sanity! id: gpsGraphRoot - property string rectProperty: "rect" - property rect filterRect: filter.getRect(rectProperty) - property var allParameters: ['time_offset', 'smoothing_value', 'speed_multiplier', 'graph_data_source', 'graph_type', 'trim_start_p', 'trim_end_p', 'crop_mode_h', 'crop_left_p', 'crop_right_p', 'crop_mode_v', 'crop_bot_p', 'crop_top_p', 'color_style', 'color.1', 'color.2', 'color.3', 'color.4', 'color.5', 'color.6', 'color.7', 'color.8', 'color.9', 'color.10', 'show_now_dot', 'now_dot_color', 'show_now_text', 'angle', 'thickness', rectProperty, 'show_grid', 'legend_unit', 'draw_individual_dots', 'bg_img_path', 'bg_scale_w'] + property rect filterRect: filter.getRect("rect") + property var allParameters: ['time_offset', 'smoothing_value', 'speed_multiplier', 'graph_data_source', 'graph_type', 'trim_start_p', 'trim_end_p', 'crop_mode_h', 'crop_left_p', 'crop_right_p', 'crop_mode_v', 'crop_bot_p', 'crop_top_p', 'color_style', 'color.1', 'color.2', 'color.3', 'color.4', 'color.5', 'color.6', 'color.7', 'color.8', 'color.9', 'color.10', 'show_now_dot', 'now_dot_color', 'show_now_text', 'angle', 'thickness', "rect", 'show_grid', 'legend_unit', 'draw_individual_dots', 'bg_img_path', 'bg_scale_w'] property var default_colors: ["#00aaff", "#00e000", "#ffff00", "#ff8c00", "#ff0000"] property var default_colors_grade: ["#ff00ff", "#00aaff", "#00e000", "#ffff00", "#ff0000"] property string color_white: "#ffffff" @@ -49,7 +48,7 @@ Item { //transforms a wheel-up/down event into the correct offset direction function wheel_offset(val) { - var offset = Number(filter.get("time_offset")); + const offset = Number(filter.get("time_offset")); if (offset < 0) val *= -1; if (offset === 0 && val < 0) @@ -81,16 +80,16 @@ Item { //graph rect function setFilter() { _disableUpdate = true; - var x = rectX.value; - var y = rectY.value; - var w = rectW.value; - var h = rectH.value; + const x = rectX.value; + const y = rectY.value; + const w = rectW.value; + const h = rectH.value; if (x !== filterRect.x || y !== filterRect.y || w !== filterRect.width || h !== filterRect.height) { filterRect.x = x; filterRect.y = y; filterRect.width = w; filterRect.height = h; - filter.set(rectProperty, filterRect); + filter.set("rect", filterRect); } _disableUpdate = false; } @@ -220,9 +219,9 @@ Item { used_params.push(filterset_getparams('angle', angle)); if (thick !== undefined) used_params.push(filterset_getparams('thickness', thick)); - - //can't figure out how to properly set rect from preset to update the VUI - //if (rect !== undefined) used_params.push(filterset_getparams(rectProperty, rect)) + //note: we don't generally want to change rect on a preset change + if (rect !== undefined) + used_params.push(filterset_getparams("rect", rect)) if (grid !== undefined) used_params.push(filterset_getparams('show_grid', grid)); if (legendunit !== undefined) @@ -275,14 +274,14 @@ Item { } Component.onCompleted: { filter.blockSignals = true; - var resource = filter.get('resource'); + const resource = filter.get('resource'); gpsFile.url = resource; if (filter.isNew) { var usedParams; - var _ = undefined; //skip params faster + const _ = undefined; //skip params faster //main preset usedParams = set_graph_data_params(0, 0, 0, 100, 0, 0, 100, 0, 0, 100); - usedParams.push(set_graph_style_params(1, 1, 0, 0, 5, default_rect, 0, _, 0)); + usedParams.push(set_graph_style_params(1, 1, 0, 0, 5, _, 0, _, 0)); usedParams.push(set_graph_colors(default_now_dot, default_colors[0], color_white)); filter.savePreset(usedParams, "2D map: full map progress line"); usedParams = set_graph_data_params(0, 1, _, _, 0, 90, 100, 0, 90, 100); @@ -319,10 +318,10 @@ Item { usedParams = set_graph_data_params(0, 1, _, _, 0, 99, 100, 0, 99, 100); usedParams.push(set_graph_style_params(1, 1, 0, 0, 8, _, _, _, 1)); filter.savePreset(usedParams, "Map style: show GPS points as dots @99%"); - usedParams = set_graph_style_params(2, 1, 0, 0, 5, default_rect, 0, _, 0); + usedParams = set_graph_style_params(2, 1, 0, 0, 5, _, 0, _, 0); usedParams.push(set_graph_colors(_, default_colors[0], '#00ffffff')); filter.savePreset(usedParams, "Map style: hide future path"); - usedParams = set_graph_style_params(2, 1, 0, 0, 5, default_rect, 0, _, 0); + usedParams = set_graph_style_params(2, 1, 0, 0, 5, _, 0, _, 0); usedParams.push(set_graph_colors(_, default_colors[0], '#40ffffff')); filter.savePreset(usedParams, "Map style: 25% opacity thin future path"); usedParams = set_graph_data_params(3, 0, 0, 100, 0, 0, 100, 0, 100, 100); @@ -345,19 +344,19 @@ Item { filter.savePreset(usedParams, "Speedometer: min-max km/h"); //basic text only presets usedParams = set_graph_data_params(0, 0, 0, 100, 0, 0, 0, 0, 0, 0); - usedParams.push(set_graph_style_params(_, 0, 1, 0, 5, default_rect, 0, " ", 0)); + usedParams.push(set_graph_style_params(_, 0, 1, 0, 5, _, 0, " ", 0)); filter.savePreset(usedParams, "Text only: GPS coordinates"); usedParams = set_graph_data_params(1, 0, 0, 100, 0, 0, 0, 0, 0, 0); - usedParams.push(set_graph_style_params(_, 0, 1, 0, 5, default_rect, 0, 'm', 0)); + usedParams.push(set_graph_style_params(_, 0, 1, 0, 5, _, 0, 'm', 0)); filter.savePreset(usedParams, "Text only: Altitude"); usedParams = set_graph_data_params(2, 0, 0, 100, 0, 0, 0, 0, 0, 0); - usedParams.push(set_graph_style_params(_, 0, 1, 0, 5, default_rect, 0, 'bpm', 0)); + usedParams.push(set_graph_style_params(_, 0, 1, 0, 5, _, 0, 'bpm', 0)); filter.savePreset(usedParams, "Text only: Heart rate"); usedParams = set_graph_data_params(3, 0, 0, 100, 0, 0, 0, 0, 0, 0); - usedParams.push(set_graph_style_params(_, 0, 1, 0, 5, default_rect, 0, 'km/h', 0)); + usedParams.push(set_graph_style_params(_, 0, 1, 0, 5, _, 0, 'km/h', 0)); filter.savePreset(usedParams, "Text only: Speed"); usedParams = set_graph_data_params(0, 2, _, _, 0, 0, 100, 0, 0, 100); - usedParams.push(set_graph_style_params(0, 0, 1, 0, 5, default_rect, 0, '%', 0)); + usedParams.push(set_graph_style_params(0, 0, 1, 0, 5, _, 0, '%', 0)); usedParams.push(set_graph_colors(_, "#00000000", "#00000000")); filter.savePreset(usedParams, "Text only: Percentage of trimmed track"); //color presets: @@ -401,7 +400,7 @@ Item { id: fileDialog title: qsTr("Select GPS File") - nameFilters: ['Supported files (*.gpx *.tcx *.txt)', 'GPS Exchange Format (*.gpx)', 'Training Center XML (*.tcx)', 'Text files (*.txt)', 'All files *.*'] + nameFilters: ['Supported files (*.gpx *.tcx *.txt)', 'GPS Exchange Format (*.gpx)', 'Training Center XML (*.tcx)', 'Text files (*.txt)', 'All files (*.*)'] onAccepted: { gpsFile.url = fileDialog.selectedFile; gpsGraphRoot.fileOpened(gpsFile.path); @@ -422,7 +421,7 @@ Item { interval: 250 repeat: true onTriggered: { - var res = filter.get('resource') + const res = filter.get('resource') if (res) { autoGpsFileDetectionTimer.stop(); gpsFile.url = res; @@ -518,7 +517,7 @@ Item { filter.resetProperty("legend_unit"); } onPresetSelected: { - filterRect = filter.getRect(rectProperty); + filterRect = filter.getRect("rect"); setControls(); reset_legend_unit(); } @@ -1700,10 +1699,10 @@ Item { //for map, compute height and width using map_aspect_ratio and the crop values //only shrink so it doesn't get out of frame if (combo_data_source.currentIndex === 0) { - var map_ratio = filter.getDouble('map_original_aspect_ratio'); - var width_p = (spin_right.value - spin_left.value) / 100; - var height_p = (spin_top.value - spin_bot.value) / 100; - var new_height = ((rectW.value * height_p) / map_ratio) / width_p; + const map_ratio = filter.getDouble('map_original_aspect_ratio'); + const width_p = (spin_right.value - spin_left.value) / 100; + const height_p = (spin_top.value - spin_bot.value) / 100; + const new_height = ((rectW.value * height_p) / map_ratio) / width_p; if (new_height <= rectH.value) { rectH.value = new_height; } else { @@ -1894,7 +1893,7 @@ Item { Connections { target: filter function onChanged() { - var newValue = filter.getRect(rectProperty); + const newValue = filter.getRect("rect"); if (filterRect !== newValue) { filterRect = newValue; setControls(); diff --git a/src/qml/filters/gpstext/ui.qml b/src/qml/filters/gpstext/ui.qml index db523b6bd6..1421788c70 100644 --- a/src/qml/filters/gpstext/ui.qml +++ b/src/qml/filters/gpstext/ui.qml @@ -64,7 +64,7 @@ Shotcut.KeyframableFilter { //transforms a wheel-up/down event into the correct offset direction function wheel_offset(val) { - var offset = Number(filter.get("time_offset")); + const offset = Number(filter.get("time_offset")); if (offset < 0) val *= -1; if (offset == 0 && val < 0) @@ -173,7 +173,7 @@ Shotcut.KeyframableFilter { Shotcut.FileDialog { id: fileDialog - nameFilters: ['Supported files (*.gpx *.tcx *.txt)', 'GPS Exchange Format (*.gpx)', 'Training Center XML (*.tcx)', 'Text files (*.txt)', 'All files *.*'] + nameFilters: ['Supported files (*.gpx *.tcx *.txt)', 'GPS Exchange Format (*.gpx)', 'Training Center XML (*.tcx)', 'Text files (*.txt)', 'All files (*.*)'] onAccepted: { gpsFile.url = fileDialog.selectedFile; gpsTextRoot.fileOpened(gpsFile.path); @@ -195,7 +195,7 @@ Shotcut.KeyframableFilter { interval: 250 repeat: true onTriggered: { - var res = filter.get('resource') + const res = filter.get('resource') if (res) { autoGpsFileDetectionTimer.stop(); gpsFile.url = res; @@ -646,7 +646,7 @@ Shotcut.KeyframableFilter { implicitWidth: 20 implicitHeight: 20 onClicked: { - var gps_time_now = filter.get('auto_gps_processing_start_now'); + const gps_time_now = filter.get('auto_gps_processing_start_now'); gps_processing_start.text = gps_time_now; filter.set('gps_processing_start_time', gps_time_now); } From 011794815e2283e8d33492ea72c16f1b1f8a8ccb Mon Sep 17 00:00:00 2001 From: DanielF <3215812+dany123@users.noreply.github.com> Date: Sun, 25 Oct 2026 11:44:33 +0200 Subject: [PATCH 6/6] fix aspect ratio math if crop mode not percentage and guard division by 0 --- src/qml/filters/gpsgraphic/ui.qml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/qml/filters/gpsgraphic/ui.qml b/src/qml/filters/gpsgraphic/ui.qml index 5d6cee5851..64f834e2e8 100644 --- a/src/qml/filters/gpsgraphic/ui.qml +++ b/src/qml/filters/gpsgraphic/ui.qml @@ -1699,9 +1699,16 @@ Item { //for map, compute height and width using map_aspect_ratio and the crop values //only shrink so it doesn't get out of frame if (combo_data_source.currentIndex === 0) { + //skip if cropmode is by value as we don't have enough info to correct the ratio + if (combo_cropmode_h.currentIndex !== 0 || combo_cropmode_v.currentIndex !== 0) + return; + const map_ratio = filter.getDouble('map_original_aspect_ratio'); const width_p = (spin_right.value - spin_left.value) / 100; const height_p = (spin_top.value - spin_bot.value) / 100; + if (!isFinite(map_ratio) || !isFinite(width_p) || !isFinite(height_p)) + return; + const new_height = ((rectW.value * height_p) / map_ratio) / width_p; if (new_height <= rectH.value) { rectH.value = new_height;