1/* Webcamoid, webcam capture application.
2 * Copyright (C) 2016  Gonzalo Exequiel Pedone
3 *
4 * Webcamoid is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * Webcamoid is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Webcamoid. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Web-Site: http://webcamoid.github.io/
18 */
19
20import QtQuick 2.7
21import QtQuick.Controls 2.0
22import QtQuick.Layouts 1.3
23import AkQmlControls 1.0
24
25Rectangle {
26    id: recAudioConfig
27    color: Qt.rgba(0, 0, 0, 0)
28    clip: true
29    width: 200
30    height: 400
31
32    function updateInputs(inputs)
33    {
34        lsvInputs.model.clear();
35
36        for (var input in inputs) {
37            if (inputs[input] === ":dummyin:")
38                continue;
39
40            lsvInputs.model.append({
41                input: inputs[input],
42                description: AudioLayer.description(inputs[input])
43            })
44        }
45
46        if (AudioLayer.audioInput.indexOf(":dummyin:") >= 0) {
47            lsvInputs.currentIndex = -1
48            noInput.selected = true
49        } else
50            lsvInputs.currentIndex = inputs.indexOf(AudioLayer.audioInput[0]) - 1
51    }
52
53    function updateOutputs(outputs)
54    {
55        lsvOutputs.model.clear();
56
57        for (var output in outputs) {
58            if (outputs[output] === ":dummyout:")
59                continue;
60
61            lsvOutputs.model.append({
62                output: outputs[output],
63                description: AudioLayer.description(outputs[output])})
64        }
65
66        if (AudioLayer.audioOutput === ":dummyout:") {
67            lsvOutputs.currentIndex = -1
68            noOutput.selected = true
69        } else
70            lsvOutputs.currentIndex = outputs.indexOf(AudioLayer.audioOutput)
71    }
72
73    Component.onCompleted: {
74        updateInputs(AudioLayer.inputs)
75        updateOutputs(AudioLayer.outputs)
76    }
77
78    Connections {
79        target: AudioLayer
80
81        onInputsChanged: updateInputs(inputs)
82        onOutputsChanged: updateOutputs(outputs)
83        onAudioInputChanged: {
84            lsvInputs.lock = true
85
86            if (audioInput.length > 0)
87                lsvInputs.currentIndex = AudioLayer.inputs.indexOf(audioInput[0]) - 1
88
89            lsvInputs.lock = false
90        }
91        onAudioOutputChanged: {
92            lsvOutputs.lock = true
93
94            if (AudioLayer.audioOutput === ":dummyout:") {
95                lsvOutputs.currentIndex = -1
96                noOutput.selected = true
97            } else
98                lsvOutputs.currentIndex = AudioLayer.outputs.indexOf(audioOutput)
99
100            lsvOutputs.lock = false
101        }
102
103        onInputDescriptionChanged: {
104            lsvInputs.lock = true
105            updateInputs(AudioLayer.inputs)
106            lsvInputs.lock = false
107        }
108    }
109
110    RowLayout {
111        id: rlyDevices
112        anchors.left: parent.left
113        anchors.right: parent.right
114
115        AkToolButton {
116            id: btnOutputs
117            label: qsTr("Outputs")
118            checked: true
119            Layout.fillWidth: true
120            ToolTip.visible: hovered
121            ToolTip.text: qsTr("Select the output device for audio playing")
122            checkable: true
123            iconRc: "image://icons/webcamoid-headphones"
124
125            onCheckedChanged: {
126                if (checked) {
127                    btnInputs.checked = false
128                    recAudioConfig.state = ""
129                }
130            }
131        }
132        AkToolButton {
133            id: btnInputs
134            label: qsTr("Inputs")
135            Layout.fillWidth: true
136            ToolTip.visible: hovered
137            ToolTip.text: qsTr("Select the device for audio capturing")
138            checkable: true
139            iconRc: "image://icons/webcamoid-mic"
140
141            onCheckedChanged: {
142                if (checked) {
143                    btnOutputs.checked = false
144                    recAudioConfig.state = "showInputs"
145                }
146            }
147        }
148    }
149
150    // Output devices
151
152    Rectangle {
153        id: noOutput
154        height: 32
155        anchors.top: rlyDevices.bottom
156        anchors.right: parent.right
157        anchors.left: parent.left
158
159        property bool selected: false
160
161        property color gradUp: selected?
162                                   Qt.rgba(0.75, 0, 0, 1):
163                                   Qt.rgba(0.25, 0, 0, 1)
164        property color gradLow: selected?
165                                    Qt.rgba(1, 0, 0, 1):
166                                    Qt.rgba(0.5, 0, 0, 1)
167
168        onSelectedChanged: {
169            gradUp = selected?
170                        Qt.rgba(0.75, 0, 0, 1):
171                        Qt.rgba(0.25, 0, 0, 1)
172            gradLow = selected?
173                        Qt.rgba(1, 0, 0, 1):
174                        Qt.rgba(0.5, 0, 0, 1)
175        }
176
177        gradient: Gradient {
178            GradientStop {
179                position: 0
180                color: noOutput.gradUp
181            }
182
183            GradientStop {
184                position: 1
185                color: noOutput.gradLow
186            }
187        }
188
189        Label {
190            id: txtNoOutputButton
191            anchors.verticalCenter: parent.verticalCenter
192            anchors.horizontalCenter: parent.horizontalCenter
193            text: qsTr("Silence")
194            color: noOutput.selected? Qt.rgba(1, 1, 1, 1): Qt.rgba(0.75, 0.75, 0.75, 1)
195        }
196
197        MouseArea {
198            id: msaNoOutputButton
199            hoverEnabled: true
200            cursorShape: Qt.PointingHandCursor
201            anchors.fill: parent
202
203            onEntered: {
204                txtNoOutputButton.font.bold = true
205                noOutput.gradUp = noOutput.selected?
206                                            Qt.rgba(1, 0.25, 0.25, 1):
207                                            Qt.rgba(0.5, 0.25, 0.25, 1)
208                noOutput.gradLow = noOutput.selected?
209                                            Qt.rgba(1, 0.25, 0.25, 1):
210                                            Qt.rgba(0.75, 0.25, 0.25, 1)
211            }
212            onExited: {
213                txtNoOutputButton.font.bold = false
214                txtNoOutputButton.scale = 1
215                noOutput.gradUp = noOutput.selected?
216                                            Qt.rgba(0.75, 0, 0, 1):
217                                            Qt.rgba(0.25, 0, 0, 1)
218                noOutput.gradLow = noOutput.selected?
219                                            Qt.rgba(1, 0, 0, 1):
220                                            Qt.rgba(0.5, 0, 0, 1)
221            }
222            onPressed: txtNoOutputButton.scale = 0.75
223            onReleased: txtNoOutputButton.scale = 1
224            onClicked: {
225                AudioLayer.audioOutput = ":dummyout:"
226                lsvOutputs.currentIndex = -1
227                noOutput.selected = true
228            }
229        }
230    }
231    OptionList {
232        id: lsvOutputs
233        anchors.left: parent.left
234        anchors.right: parent.right
235        anchors.top: noOutput.bottom
236        anchors.bottom: parent.bottom
237        textRole: "description"
238
239        property bool lock: false
240
241        onCurrentIndexChanged: {
242            if (lock)
243                return;
244
245            var option = model.get(currentIndex)
246            AudioLayer.audioOutput = option? option.output: ":dummyout:"
247            noOutput.selected = false
248        }
249    }
250
251    // Input devices
252
253    Rectangle {
254        id: noInput
255        height: 0
256        anchors.top: rlyDevices.bottom
257        anchors.right: parent.right
258        anchors.left: parent.left
259        visible: false
260
261        property bool selected: false
262
263        property color gradUp: selected?
264                                   Qt.rgba(0.75, 0, 0, 1):
265                                   Qt.rgba(0.25, 0, 0, 1)
266        property color gradLow: selected?
267                                    Qt.rgba(1, 0, 0, 1):
268                                    Qt.rgba(0.5, 0, 0, 1)
269
270        onSelectedChanged: {
271            gradUp = selected?
272                        Qt.rgba(0.75, 0, 0, 1):
273                        Qt.rgba(0.25, 0, 0, 1)
274            gradLow = selected?
275                        Qt.rgba(1, 0, 0, 1):
276                        Qt.rgba(0.5, 0, 0, 1)
277        }
278
279        gradient: Gradient {
280            GradientStop {
281                position: 0
282                color: noInput.gradUp
283            }
284
285            GradientStop {
286                position: 1
287                color: noInput.gradLow
288            }
289        }
290
291        Label {
292            id: txtNoInputButton
293            anchors.verticalCenter: parent.verticalCenter
294            anchors.horizontalCenter: parent.horizontalCenter
295            text: qsTr("Silence")
296            color: noInput.selected? Qt.rgba(1, 1, 1, 1): Qt.rgba(0.75, 0.75, 0.75, 1)
297        }
298
299        MouseArea {
300            id: msaNoInputButton
301            hoverEnabled: true
302            cursorShape: Qt.PointingHandCursor
303            anchors.fill: parent
304
305            onEntered: {
306                txtNoInputButton.font.bold = true
307                noInput.gradUp = noInput.selected?
308                                            Qt.rgba(1, 0.25, 0.25, 1):
309                                            Qt.rgba(0.5, 0.25, 0.25, 1)
310                noInput.gradLow = noInput.selected?
311                                            Qt.rgba(1, 0.25, 0.25, 1):
312                                            Qt.rgba(0.75, 0.25, 0.25, 1)
313            }
314            onExited: {
315                txtNoInputButton.font.bold = false
316                txtNoInputButton.scale = 1
317                noInput.gradUp = noInput.selected?
318                                            Qt.rgba(0.75, 0, 0, 1):
319                                            Qt.rgba(0.25, 0, 0, 1)
320                noInput.gradLow = noInput.selected?
321                                            Qt.rgba(1, 0, 0, 1):
322                                            Qt.rgba(0.5, 0, 0, 1)
323            }
324            onPressed: txtNoInputButton.scale = 0.75
325            onReleased: txtNoInputButton.scale = 1
326            onClicked: {
327                AudioLayer.audioInput = [":dummyin:"]
328                lsvInputs.currentIndex = -1
329                noInput.selected = true
330            }
331        }
332    }
333    OptionList {
334        id: lsvInputs
335        anchors.left: parent.left
336        anchors.right: parent.right
337        anchors.top: noInput.bottom
338        anchors.bottom: parent.bottom
339        textRole: "description"
340        visible: false
341
342        property bool lock: false
343
344        onCurrentIndexChanged: {
345            if (lock)
346                return;
347
348            var option = model.get(currentIndex)
349            AudioLayer.audioInput = option? [option.input]: [":dummyin:"]
350            noInput.selected = false
351        }
352    }
353
354    states: [
355        State {
356            name: "showInputs"
357
358            PropertyChanges {
359                target: noOutput
360                height: 0
361                visible: false
362            }
363            PropertyChanges {
364                target: lsvOutputs
365                visible: false
366            }
367            PropertyChanges {
368                target: noInput
369                height: 32
370                visible: true
371            }
372            PropertyChanges {
373                target: lsvInputs
374                visible: true
375            }
376        }
377    ]
378}
379