blob: 52d3e05effd0612f2b60bb5ebd03644761527cd9 [file] [log] [blame]
Sébastien Blin1f915762020-08-03 13:27:42 -04001/*
2 * Copyright (C) 2019-2020 by Savoir-faire Linux
3 * Author: Yang Wang <yang.wang@savoirfairelinux.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19import QtQuick 2.15
20import QtQuick.Window 2.14
21import QtQuick.Controls 2.15
22import QtQuick.Controls.Universal 2.12
23import QtQuick.Layouts 1.3
24import QtGraphicalEffects 1.14
25import QtQuick.Controls.Styles 1.4
26import net.jami.Models 1.0
ababia284cae2020-08-10 12:33:34 +020027import "../../commoncomponents"
Sébastien Blin1f915762020-08-03 13:27:42 -040028
29Rectangle {
30 id: avSettingPage
31
32 AudioInputDeviceModel{
33 id: audioInputDeviceModel
34 }
35
36 AudioOutputDeviceModel{
37 id: audioOutputDeviceModel
38 }
39
40 AudioManagerListModel{
41 id: audioManagerListModel
42 }
43
44 VideoInputDeviceModel{
45 id: videoInputDeviceModel
46 }
47
48 VideoFormatResolutionModel{
49 id: videoFormatResolutionModel
50 }
51
52 VideoFormatFpsModel{
53 id: videoFormatFpsModel
54 }
55
56 function populateAVSettings(){
57 audioInputDeviceModel.reset()
58 audioOutputDeviceModel.reset()
59
60 inputComboBox.currentIndex = audioInputDeviceModel.getCurrentSettingIndex()
61 outputComboBox.currentIndex = audioOutputDeviceModel.getCurrentSettingIndex()
62 ringtoneDeviceComboBox.currentIndex = audioOutputDeviceModel.getCurrentRingtoneDeviceIndex()
63
64 audioManagerRowLayout.visible = (audioManagerListModel.rowCount() > 0)
65 if(audioManagerListModel.rowCount() > 0){
66 audioManagerComboBox.currentIndex = audioManagerListModel.getCurrentSettingIndex()
67 }
68
69 populateVideoSettings()
70 var encodeAccel = ClientWrapper.avmodel.getHardwareAcceleration()
71 hardwareAccelControl.checked = encodeAccel
72 }
73
74 function populateVideoSettings() {
75 videoInputDeviceModel.reset()
76
77 deviceBox.enabled = (videoInputDeviceModel.deviceCount() > 0)
78 resolutionBox.enabled = (videoInputDeviceModel.deviceCount() > 0)
79 fpsBox.enabled = (videoInputDeviceModel.deviceCount() > 0)
80 labelVideoDevice.enabled = (videoInputDeviceModel.deviceCount() > 0)
81 labelVideoResolution.enabled = (videoInputDeviceModel.deviceCount() > 0)
82 labelVideoFps.enabled = (videoInputDeviceModel.deviceCount() > 0)
83
84 deviceBox.currentIndex = videoInputDeviceModel.getCurrentSettingIndex()
85 slotDeviceBoxCurrentIndexChanged(deviceBox.currentIndex)
86
87 try{
88 startPreviewing(false)
89 } catch (err2){ console.log("Start preview fail when populate video settings, exception: "+ err2.message)}
90
91 }
92
93 function setFormatListForCurrentDevice(){
94 var device = ClientWrapper.avmodel.getCurrentVideoCaptureDevice()
95 if(ClientWrapper.settingsAdaptor.get_DeviceCapabilitiesSize(device) === 0){
96 return
97 }
98
99 try{
100 videoFormatResolutionModel.reset()
101 resolutionBox.currentIndex = videoFormatResolutionModel.getCurrentSettingIndex()
102 slotFormatCurrentIndexChanged(resolutionBox.currentIndex,true)
103 } catch(err){console.warn("Exception: " + err.message)}
104 }
105
106 function startPreviewing(force = false){
107 ClientWrapper.accountAdaptor.startPreviewing(force)
108 previewAvailable = true
109 }
110
111 function stopPreviewing(){
112 ClientWrapper.accountAdaptor.stopPreviewing()
113 }
114
115 function startAudioMeter(async = true){
116 audioInputMeter.start()
117 ClientWrapper.accountAdaptor.startAudioMeter(async)
118 }
119
120 function stopAudioMeter(async = true){
121 audioInputMeter.stop()
122 ClientWrapper.accountAdaptor.stopAudioMeter(async)
123 }
124
125 // slots for av page
126 function slotAudioMeter(id, level){
127 if (id === "audiolayer_id") {
128 audioInputMeter.setLevel(level)
129 }
130 }
131
132 function slotSetHardwareAccel(state){
133 ClientWrapper.accountAdaptor.avModel().setHardwareAcceleration(state)
134 startPreviewing(true)
135 }
136
137 function slotAudioManagerIndexChanged(index){
138 stopAudioMeter(false)
139 var selectedAudioManager = audioManagerListModel.data(audioManagerListModel.index(
140 index, 0), AudioManagerListModel.AudioManagerID)
141 ClientWrapper.avmodel.setAudioManager(selectedAudioManager)
142 startAudioMeter(false)
143 }
144
145 function slotRingtoneDeviceIndexChanged(index){
146 stopAudioMeter(false)
147 var selectedRingtoneDeviceName = audioOutputDeviceModel.data(audioOutputDeviceModel.index(
148 index, 0), AudioOutputDeviceModel.Device_ID)
149 ClientWrapper.avmodel.setRingtoneDevice(selectedRingtoneDeviceName)
150 startAudioMeter(false)
151 }
152
153 function slotAudioOutputIndexChanged(index){
154 stopAudioMeter(false)
155 var selectedOutputDeviceName = audioOutputDeviceModel.data(audioOutputDeviceModel.index(
156 index, 0), AudioOutputDeviceModel.Device_ID)
157 ClientWrapper.avmodel.setOutputDevice(selectedOutputDeviceName)
158 startAudioMeter(false)
159 }
160
161 function slotAudioInputIndexChanged(index){
162 stopAudioMeter(false)
163 var selectedInputDeviceName = audioInputDeviceModel.data(audioInputDeviceModel.index(
164 index, 0), AudioInputDeviceModel.Device_ID)
165
166 ClientWrapper.avmodel.setInputDevice(selectedInputDeviceName)
167 startAudioMeter(false)
168 }
169
170 function slotDeviceBoxCurrentIndexChanged(index){
171 if(videoInputDeviceModel.deviceCount() <= 0){
172 return
173 }
174
175 try{
176 var deviceId = videoInputDeviceModel.data(videoInputDeviceModel.index(
177 index, 0), VideoInputDeviceModel.DeviceId)
178 var deviceName = videoInputDeviceModel.data(videoInputDeviceModel.index(
179 index, 0), VideoInputDeviceModel.DeviceName)
180 if(deviceId.length === 0){
181 console.warn("Couldn't find device: " + deviceName)
182 return
183 }
184
185 ClientWrapper.avmodel.setCurrentVideoCaptureDevice(deviceId)
186 ClientWrapper.avmodel.setDefaultDevice(deviceId)
187 setFormatListForCurrentDevice()
188 startPreviewing(true)
189 } catch(err){console.warn(err.message)}
190 }
191
192 function slotFormatCurrentIndexChanged(index, isResolutionIndex){
193 var resolution
194 var rate
195 if(isResolutionIndex){
196 resolution = videoFormatResolutionModel.data(videoFormatResolutionModel.index(
197 index, 0), VideoFormatResolutionModel.Resolution)
198 videoFormatFpsModel.currentResolution = resolution
199 fpsBox.currentIndex = videoFormatFpsModel.getCurrentSettingIndex()
200 rate = videoFormatFpsModel.data(videoFormatFpsModel.index(
201 fpsBox.currentIndex, 0), VideoFormatFpsModel.FPS)
202 } else {
203 resolution = videoFormatResolutionModel.data(videoFormatResolutionModel.index(
204 resolutionBox.currentIndex, 0), VideoFormatResolutionModel.Resolution)
205 videoFormatFpsModel.currentResolution = resolution
206 rate = videoFormatFpsModel.data(videoFormatFpsModel.index(
207 index, 0), VideoFormatFpsModel.FPS)
208 }
209
210 try{
211 ClientWrapper.settingsAdaptor.set_Video_Settings_Rate_And_Resolution(ClientWrapper.avmodel.getCurrentVideoCaptureDevice(),rate,resolution)
212 } catch(error){console.warn(error.message)}
213 }
214
215 function slotVideoDeviceListChanged(){
216 populateVideoSettings()
217 }
218
219 property bool previewAvailable: false
ababia284cae2020-08-10 12:33:34 +0200220 signal backArrowClicked
Sébastien Blin1f915762020-08-03 13:27:42 -0400221
222 Connections{
223 target: ClientWrapper.avmodel
224
225 function onAudioMeter(id, level){
226 slotAudioMeter(id,level)
227 }
228 }
229
230 Connections{
231 target: ClientWrapper.renderManager
232
233 function onVideoDeviceListChanged(){
234 slotVideoDeviceListChanged()
235 }
236 }
237
238 Layout.fillHeight: true
239 Layout.fillWidth: true
240
241 ScrollView{
242 anchors.fill: parent
243 clip: true
244
245 RowLayout {
246 width: avSettingPage.width
247 height: avSettingPage.height
248
249 spacing: 0
250 Item {
251 Layout.fillHeight: true
252 Layout.maximumWidth: 48
253 Layout.preferredWidth: 48
254 Layout.minimumWidth: 48
255 }
256
257 ColumnLayout {
258 spacing: 7
259
260 Layout.fillHeight: true
261 Layout.maximumWidth: 580
262 Layout.preferredWidth: 580
263 Layout.minimumWidth: 580
264
265 Item {
266 Layout.fillWidth: true
267 Layout.minimumHeight: 10
268 Layout.preferredHeight: 10
269 Layout.maximumHeight: 10
270 }
271
ababia284cae2020-08-10 12:33:34 +0200272 RowLayout {
273
274 Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
275 Layout.leftMargin: 16
Sébastien Blin1f915762020-08-03 13:27:42 -0400276 Layout.fillWidth: true
ababia284cae2020-08-10 12:33:34 +0200277 Layout.maximumHeight: 64
278 Layout.minimumHeight: 64
279 Layout.preferredHeight: 64
Sébastien Blin1f915762020-08-03 13:27:42 -0400280
ababia284cae2020-08-10 12:33:34 +0200281 HoverableButton {
Sébastien Blin1f915762020-08-03 13:27:42 -0400282
ababia284cae2020-08-10 12:33:34 +0200283 Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
284 Layout.preferredWidth: 30
285 Layout.preferredHeight: 30
286
287 radius: 30
288 source: "qrc:/images/icons/ic_arrow_back_24px.svg"
289 backgroundColor: "white"
290 onExitColor: "white"
291
292 visible: mainViewWindow.sidePanelHidden
293
294 onClicked: {
295 backArrowClicked()
296 }
297 }
298
299
300 Label {
301 Layout.fillWidth: true
302 Layout.minimumHeight: 25
303 Layout.preferredHeight: 25
304 Layout.maximumHeight: 25
305
306 text: qsTr("Audio / Video")
307 font.pointSize: 15
308 font.kerning: true
309
310 horizontalAlignment: Text.AlignLeft
311 verticalAlignment: Text.AlignVCenter
312 }
Sébastien Blin1f915762020-08-03 13:27:42 -0400313 }
314
315 Item {
316 Layout.fillWidth: true
317 Layout.minimumHeight: 24
318 Layout.preferredHeight: 24
319 Layout.maximumHeight: 24
320 }
321
322 ColumnLayout {
323 spacing: 0
324 Layout.fillWidth: true
325
326 Label {
327 Layout.fillWidth: true
328 Layout.minimumHeight: 21
329 Layout.preferredHeight: 21
330 Layout.maximumHeight: 21
331
332 text: qsTr("Audio")
333 font.pointSize: 13
334 font.kerning: true
335
336 horizontalAlignment: Text.AlignLeft
337 verticalAlignment: Text.AlignVCenter
338 }
339
340 Item {
341 Layout.fillWidth: true
342 Layout.minimumHeight: 10
343 Layout.preferredHeight: 10
344 Layout.maximumHeight: 10
345 }
346
347 ColumnLayout {
348 spacing: 7
349 Layout.fillWidth: true
350
351 RowLayout {
352 spacing: 7
353 Layout.leftMargin: 20
354 Layout.fillWidth: true
355 Layout.maximumHeight: 30
356
357 Label {
358 Layout.maximumWidth: 77
359 Layout.preferredWidth: 77
360 Layout.minimumWidth: 77
361
362 Layout.minimumHeight: 30
363 Layout.preferredHeight: 30
364 Layout.maximumHeight: 30
365
366 text: qsTr("Microphone")
367 font.pointSize: 11
368 font.kerning: true
369
370 horizontalAlignment: Text.AlignLeft
371 verticalAlignment: Text.AlignVCenter
372 }
373
374 Item {
375 Layout.fillWidth: true
376 Layout.fillHeight: true
377 }
378
379 SettingParaCombobox {
380 id: inputComboBox
381
382 Layout.maximumWidth: 360
383 Layout.preferredWidth: 360
384 Layout.minimumWidth: 360
385
386 Layout.minimumHeight: 30
387 Layout.preferredHeight: 30
388 Layout.maximumHeight: 30
389
390 font.pointSize: 10
391 font.kerning: true
392
393 model: audioInputDeviceModel
394
395 textRole: "ID_UTF8"
396
397 onActivated: {
398 slotAudioInputIndexChanged(index)
399 }
400 }
401 }
402
403 // the audio level meter
404 LevelMeter {
405 id: audioInputMeter
406
407 Layout.leftMargin: 20
408
409 Layout.fillWidth: true
410
411 Layout.minimumHeight: 10
412 Layout.preferredHeight: 10
413 Layout.maximumHeight: 10
414
415 indeterminate: false
416 from: 0
417 to: 100
418 }
419
420 Item {
421 Layout.fillWidth: true
422
423 Layout.minimumHeight: 5
424 Layout.preferredHeight: 5
425 Layout.maximumHeight: 5
426 }
427
428 RowLayout {
429 spacing: 7
430 Layout.leftMargin: 20
431 Layout.fillWidth: true
432 Layout.maximumHeight: 30
433
434 Label {
435 Layout.maximumWidth: 95
436 Layout.preferredWidth: 95
437 Layout.minimumWidth: 95
438
439 Layout.minimumHeight: 30
440 Layout.preferredHeight: 30
441 Layout.maximumHeight: 30
442
443 text: qsTr("Output Device")
444 font.pointSize: 11
445 font.kerning: true
446
447 horizontalAlignment: Text.AlignLeft
448 verticalAlignment: Text.AlignVCenter
449 }
450
451 Item {
452 Layout.fillWidth: true
453 Layout.fillHeight: true
454 }
455
456 SettingParaCombobox {
457 id: outputComboBox
458
459 Layout.maximumWidth: 360
460 Layout.preferredWidth: 360
461 Layout.minimumWidth: 360
462
463 Layout.minimumHeight: 30
464 Layout.preferredHeight: 30
465 Layout.maximumHeight: 30
466
467 font.pointSize: 10
468 font.kerning: true
469
470 model: audioOutputDeviceModel
471
472 textRole: "ID_UTF8"
473
474 onActivated: {
475 slotAudioOutputIndexChanged(index)
476 }
477 }
478 }
479
480 RowLayout {
481 spacing: 7
482 Layout.leftMargin: 20
483 Layout.fillWidth: true
484 Layout.maximumHeight: 30
485
486 Label {
487 Layout.maximumWidth: 77
488 Layout.preferredWidth: 77
489 Layout.minimumWidth: 77
490
491 Layout.minimumHeight: 30
492 Layout.preferredHeight: 30
493 Layout.maximumHeight: 30
494
495 text: qsTr("Ringtone Device")
496 font.pointSize: 11
497 font.kerning: true
498
499 horizontalAlignment: Text.AlignLeft
500 verticalAlignment: Text.AlignVCenter
501 }
502
503 Item {
504 Layout.fillWidth: true
505 Layout.fillHeight: true
506 }
507
508 SettingParaCombobox {
509 id: ringtoneDeviceComboBox
510
511 Layout.maximumWidth: 360
512 Layout.preferredWidth: 360
513 Layout.minimumWidth: 360
514
515 Layout.minimumHeight: 30
516 Layout.preferredHeight: 30
517 Layout.maximumHeight: 30
518
519 font.pointSize: 10
520 font.kerning: true
521
522 model: audioOutputDeviceModel
523
524 textRole: "ID_UTF8"
525
526 onActivated: {
527 slotRingtoneDeviceIndexChanged(index)
528 }
529 }
530 }
531
532 RowLayout {
533 id: audioManagerRowLayout
534
535 spacing: 7
536 Layout.leftMargin: 20
537 Layout.fillWidth: true
538 Layout.maximumHeight: 30
539
540 Label {
541 Layout.maximumWidth: 77
542 Layout.preferredWidth: 77
543 Layout.minimumWidth: 77
544
545 Layout.minimumHeight: 30
546 Layout.preferredHeight: 30
547 Layout.maximumHeight: 30
548
549 text: qsTr("Audio Manager")
550 font.pointSize: 11
551 font.kerning: true
552
553 horizontalAlignment: Text.AlignLeft
554 verticalAlignment: Text.AlignVCenter
555 }
556
557 Item {
558 Layout.fillWidth: true
559 Layout.fillHeight: true
560 }
561
562 SettingParaCombobox {
563 id: audioManagerComboBox
564
565 Layout.maximumWidth: 360
566 Layout.preferredWidth: 360
567 Layout.minimumWidth: 360
568
569 Layout.minimumHeight: 30
570 Layout.preferredHeight: 30
571 Layout.maximumHeight: 30
572
573 font.pointSize: 10
574 font.kerning: true
575
576 model: audioManagerListModel
577
578 textRole: "ID_UTF8"
579
580 onActivated: {
581 slotAudioManagerIndexChanged(index)
582 }
583 }
584 }
585 }
586 }
587
588 Item {
589 Layout.fillWidth: true
590
591 Layout.minimumHeight: 20
592 Layout.preferredHeight: 20
593 Layout.maximumHeight: 20
594 }
595
596 ColumnLayout {
597 spacing: 7
598 Layout.fillWidth: true
599
600 Label {
601 Layout.fillWidth: true
602 Layout.minimumHeight: 30
603 Layout.preferredHeight: 30
604 Layout.maximumHeight: 30
605
606 text: qsTr("Video")
607 font.pointSize: 13
608 font.kerning: true
609
610 horizontalAlignment: Text.AlignLeft
611 verticalAlignment: Text.AlignVCenter
612 }
613
614 Item {
615 Layout.fillWidth: true
616
617 Layout.minimumHeight: 10
618 Layout.preferredHeight: 10
619 Layout.maximumHeight: 10
620 }
621
622 ColumnLayout {
623 spacing: 6
624 RowLayout {
625 spacing: 7
626 Layout.fillWidth: true
627 Layout.leftMargin: 20
628 Layout.maximumHeight: 30
629
630 Label {
631 id: labelVideoDevice
632
633 Layout.maximumWidth: 44
634 Layout.preferredWidth: 44
635 Layout.minimumWidth: 44
636
637 Layout.minimumHeight: 30
638 Layout.preferredHeight: 30
639 Layout.maximumHeight: 30
640
641 text: qsTr("Device")
642 font.pointSize: 11
643 font.kerning: true
644
645 horizontalAlignment: Text.AlignLeft
646 verticalAlignment: Text.AlignVCenter
647 }
648
649 Item {
650 Layout.fillHeight: true
651 Layout.fillWidth: true
652 }
653
654 SettingParaCombobox {
655 id: deviceBox
656
657 Layout.maximumWidth: 360
658 Layout.preferredWidth: 360
659 Layout.minimumWidth: 360
660
661 Layout.minimumHeight: 30
662 Layout.preferredHeight: 30
663 Layout.maximumHeight: 30
664
665 font.pointSize: 10
666 font.kerning: true
667
668 model: videoInputDeviceModel
669
670 textRole: "DeviceName_UTF8"
671
672 onActivated: {
673 slotDeviceBoxCurrentIndexChanged(index)
674 }
675 }
676 }
677
678 RowLayout {
679 spacing: 7
680 Layout.fillWidth: true
681 Layout.leftMargin: 20
682 Layout.maximumHeight: 30
683
684 Label {
685 id: labelVideoResolution
686
687 Layout.maximumWidth: 47
688 Layout.preferredWidth: 47
689 Layout.minimumWidth: 47
690
691 Layout.minimumHeight: 30
692 Layout.preferredHeight: 30
693 Layout.maximumHeight: 30
694
695 text: qsTr("Resolution")
696 font.pointSize: 11
697 font.kerning: true
698
699 horizontalAlignment: Text.AlignLeft
700 verticalAlignment: Text.AlignVCenter
701 }
702
703 Item {
704 Layout.fillHeight: true
705 Layout.fillWidth: true
706 }
707
708 SettingParaCombobox {
709 id: resolutionBox
710
711 Layout.maximumWidth: 360
712 Layout.preferredWidth: 360
713 Layout.minimumWidth: 360
714
715 Layout.minimumHeight: 30
716 Layout.preferredHeight: 30
717 Layout.maximumHeight: 30
718
719 font.pointSize: 10
720 font.kerning: true
721
722 model: videoFormatResolutionModel
723 textRole: "Resolution_UTF8"
724
725 onActivated: {
726 slotFormatCurrentIndexChanged(index,true)
727 }
728 }
729 }
730
731 RowLayout {
732 spacing: 7
733 Layout.fillWidth: true
734 Layout.leftMargin: 20
735 Layout.maximumHeight: 30
736
737 Label {
738 id: labelVideoFps
739
740 Layout.maximumWidth: 47
741 Layout.preferredWidth: 47
742 Layout.minimumWidth: 47
743
744 Layout.minimumHeight: 30
745 Layout.preferredHeight: 30
746 Layout.maximumHeight: 30
747
748 text: qsTr("Fps")
749 font.pointSize: 11
750 font.kerning: true
751
752 horizontalAlignment: Text.AlignLeft
753 verticalAlignment: Text.AlignVCenter
754 }
755
756 Item {
757 Layout.fillHeight: true
758 Layout.fillWidth: true
759 }
760
761 SettingParaCombobox {
762 id: fpsBox
763
764 Layout.maximumWidth: 360
765 Layout.preferredWidth: 360
766 Layout.minimumWidth: 360
767
768 Layout.minimumHeight: 30
769 Layout.preferredHeight: 30
770 Layout.maximumHeight: 30
771
772 font.pointSize: 10
773 font.kerning: true
774
775 model: videoFormatFpsModel
776 textRole: "FPS_ToDisplay_UTF8"
777
778 onActivated: {
779 slotFormatCurrentIndexChanged(index,false)
780 }
781 }
782 }
783 }
784 }
785
786 Item {
787 Layout.fillWidth: true
788 Layout.minimumHeight: 20
789 Layout.preferredHeight: 20
790 Layout.maximumHeight: 20
791 }
792
793 RowLayout{
794 Layout.alignment: Qt.AlignHCenter
795
796 Layout.preferredWidth: 580
797 Layout.minimumWidth: 580
798
799 Layout.minimumHeight: 224
800 Layout.preferredHeight: 224
801 Layout.maximumHeight: 224
802
803 Rectangle {
804 Layout.alignment: Qt.AlignHCenter
805 Layout.fillHeight: true
806 Layout.minimumWidth: 580
807
808 color: "black"
809
810 PreviewRenderer{
811 id: peviewWidget
812
813 visible: previewAvailable
814 height: parent.height
815 width: 224
816 x: (parent.width - width) /2
817 y: 0
818 }
819 }
820 }
821
822 Label {
823 visible: !previewAvailable
824
825 Layout.fillWidth: true
826
827 Layout.minimumHeight: 30
828 Layout.preferredHeight: 30
829 Layout.maximumHeight: 30
830
831 text: qsTr("Preview unavailable")
832 font.pointSize: 10
833 font.kerning: true
834
835 horizontalAlignment: Text.AlignHCenter
836 verticalAlignment: Text.AlignVCenter
837 }
838
839 // Toggle switch to enable hardware acceleration
840 ToggleSwitch {
841 id: hardwareAccelControl
842
843 labelText: "Enable hardware acceleration"
844
845 onSwitchToggled: {
846 slotSetHardwareAccel(checked)
847 }
848 }
849
850 Item {
851 Layout.fillHeight: true
852 Layout.fillWidth: true
853 }
854 }
855
856 Item {
857 Layout.fillHeight: true
858 Layout.fillWidth: true
859 }
860 }
861
862 }
863}