diff --git a/applet/contents/ui/DeviceListItem.qml b/applet/contents/ui/DeviceListItem.qml --- a/applet/contents/ui/DeviceListItem.qml +++ b/applet/contents/ui/DeviceListItem.qml @@ -27,17 +27,5 @@ property bool onlyOne: false draggable: false - label: { - if (!currentPort) { - return Description - } else { - if (onlyOne) { - return currentPort.description - } else { - return i18nc("label of device items", "%1 (%2)", currentPort.description, Description) - } - } - } - labelOpacity: onlyOne ? 1 : 0.6 - icon: Icon.formFactorIcon(FormFactor) || IconName + label: currentPort ? currentPort.description : Description } diff --git a/applet/contents/ui/ListItemBase.qml b/applet/contents/ui/ListItemBase.qml --- a/applet/contents/ui/ListItemBase.qml +++ b/applet/contents/ui/ListItemBase.qml @@ -36,8 +36,7 @@ PlasmaComponents.ListItem { id: item - property alias label: textLabel.text - property alias labelOpacity: textLabel.opacity + property alias label: defaultButton.text property alias draggable: dragArea.enabled property alias icon: clientIcon.source property alias iconUsesPlasmaTheme: clientIcon.usesPlasmaTheme @@ -66,6 +65,7 @@ Layout.preferredHeight: column.height * 0.75 Layout.preferredWidth: Layout.preferredHeight source: "unknown" + visible: type === "sink-input" || type === "source-input" onSourceChanged: { if (!valid && source != "unknown") { @@ -107,61 +107,37 @@ ColumnLayout { id: column - spacing: 1 + spacing: 0 RowLayout { - Layout.fillWidth: true - PlasmaExtras.Heading { - id: textLabel - Layout.fillWidth: true - height: undefined - level: 5 - opacity: 0.6 - wrapMode: Text.NoWrap - elide: Text.ElideRight - visible: !portbox.visible + PlasmaComponents3.RadioButton { + id: defaultButton + Layout.leftMargin: units.smallSpacing * 0.75 + spacing: units.smallSpacing * 1.5 + checked: PulseObject.default + visible: (type == "sink" && sinkView.model.count > 1) || (type == "source" && sourceView.model.count > 1) + onClicked: PulseObject.default = true; } - PlasmaComponents3.ComboBox { - id: portbox - visible: portbox.count > 1 - Layout.minimumWidth: units.gridUnit * 10 - model: { - var items = []; - for (var i = 0; i < PulseObject.ports.length; ++i) { - var port = PulseObject.ports[i]; - if (port.availability != Port.Unavailable) { - items.push(port.description); - } - } - return items - } - currentIndex: ActivePortIndex - onActivated: ActivePortIndex = index + Label { + id: solotextLabel + text: defaultButton.text + visible: !defaultButton.visible + wrapMode: Text.NoWrap + elide: Text.ElideRight } Item { - visible: portbox.visible Layout.fillWidth: true } - PlasmaComponents3.ToolButton { - id: defaultButton - text: i18n("Default Device") - icon.name: PulseObject.default ? "starred-symbolic" : "non-starred-symbolic" - checkable: true - checked: PulseObject.default - visible: (type == "sink" && sinkView.model.count > 1) || (type == "source" && sourceView.model.count > 1) - onClicked: PulseObject.default = true; - } - SmallToolButton { id: contextMenuButton icon: "application-menu" checkable: true onClicked: contextMenu.show() - tooltip: i18n("Show additional options for %1", textLabel.text) + tooltip: i18n("Show additional options for %1", defaultButton.text) } } @@ -171,8 +147,7 @@ icon: Icon.name(Volume, Muted, isPlayback ? "audio-volume" : "microphone-sensitivity") onClicked: Muted = !Muted checked: Muted - tooltip: i18n("Mute %1", textLabel.text) - + tooltip: i18n("Mute %1", defaultButton.text) } PlasmaComponents.Slider { @@ -195,7 +170,7 @@ enabled: VolumeWritable opacity: Muted ? 0.5 : 1 - Accessible.name: i18nc("Accessibility data on volume slider", "Adjust volume for %1", textLabel.text) + Accessible.name: i18nc("Accessibility data on volume slider", "Adjust volume for %1", defaultButton.text) Component.onCompleted: { ignoreValueChange = false; @@ -338,6 +313,46 @@ contextMenu.addMenuItem(menuItem); } + // Ports + // By choice only shown when there are at least two available ports. + if (PulseObject.ports && PulseObject.ports.length > 1) { + contextMenu.addMenuItem(newSeperator()); + + var menuItem = newMenuItem(); + menuItem.text = i18nc("Heading for a list of ports of a device (for example built-in laptop speakers or a plug for headphones)", "Ports"); + menuItem.section = true; + contextMenu.addMenuItem(menuItem); + menuItem.visible = false; + + var menuItemsPorts = []; + var availablePorts = 0; + for (var i = 0; i < PulseObject.ports.length; i++) { + var port = PulseObject.ports[i]; + if (port.availability != Port.Unavailable) { + menuItemsPorts[availablePorts] = newMenuItem(); + menuItemsPorts[availablePorts].text = port.description; + menuItemsPorts[availablePorts].checkable = true; + menuItemsPorts[availablePorts].checked = i === PulseObject.activePortIndex; + var setActivePort = function(portIndex) { + return function() { + PulseObject.activePortIndex = portIndex; + }; + }; + menuItemsPorts[availablePorts].clicked.connect(setActivePort(i)); + contextMenu.addMenuItem(menuItemsPorts[availablePorts]); + menuItemsPorts[availablePorts].visible = false; + availablePorts++; + } + } + + if (1 < availablePorts){ + menuItem.visible = true; + for (var i = 0; i < availablePorts; i++) { + menuItemsPorts[i].visible = true; + } + } + } + // Choose output / input device // By choice only shown when there are at least two options if ((type == "sink-input" && sinkView.model.count > 1) || (type == "source-input" && sourceView.model.count > 1)) { diff --git a/applet/contents/ui/StreamListItem.qml b/applet/contents/ui/StreamListItem.qml --- a/applet/contents/ui/StreamListItem.qml +++ b/applet/contents/ui/StreamListItem.qml @@ -27,18 +27,7 @@ ListItemBase { property bool onlyOne: false - label: { - if (! Client) { - return Name - } else { - if (onlyOne) { - return Client.name - } else { - return i18nc("label of stream items", "%1 (%2)", Client.name, Name) - } - } - } - labelOpacity: onlyOne ? 1 : 0.6 + label: Client ? Client.name : Name icon: IconName iconUsesPlasmaTheme: false } diff --git a/applet/contents/ui/main.qml b/applet/contents/ui/main.qml --- a/applet/contents/ui/main.qml +++ b/applet/contents/ui/main.qml @@ -23,6 +23,7 @@ import org.kde.plasma.core 2.1 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents +import org.kde.plasma.components 3.0 as PlasmaComponents3 import org.kde.plasma.extras 2.0 as PlasmaExtras import org.kde.plasma.plasmoid 2.0 @@ -63,7 +64,16 @@ return i18n("Volume at %1%", volumePercent(sink.volume)); } } - Plasmoid.toolTipSubText: paSinkModel.preferredSink && !isDummyOutput(paSinkModel.preferredSink) ? paSinkModel.preferredSink.description : "" + Plasmoid.toolTipSubText: { + if (paSinkModel.preferredSink && !isDummyOutput(paSinkModel.preferredSink)) { + var port = paSinkModel.preferredSink.ports[paSinkModel.preferredSink.activePortIndex]; + if (port) { + return port.description + } + return paSinkModel.preferredSink.name + } + return "" + } function isDummyOutput(output) { return output && output.name === dummyOutputName; @@ -298,8 +308,13 @@ id: feedback } + PlasmaCore.Svg { + id: lineSvg + imagePath: "widgets/line" + } + Plasmoid.fullRepresentation: ColumnLayout { - spacing: units.smallSpacing + spacing: units.smallSpacing * 0.75 Layout.minimumHeight: main.Layout.minimumHeight Layout.minimumWidth: main.Layout.minimumWidth @@ -343,16 +358,6 @@ text: i18n("Applications") } } - - PlasmaComponents.ToolButton { - Layout.alignment: Qt.AlignBottom - tooltip: plasmoid.action("configure").text - iconName: "configure" - Accessible.name: tooltip - onClicked: { - plasmoid.action("configure").trigger(); - } - } } PlasmaExtras.ScrollArea { @@ -373,17 +378,13 @@ ColumnLayout { id: streamsView + spacing: 0 visible: tabBar.currentTab == streamsTab readonly property bool simpleMode: (sinkInputView.count >= 1 && sourceOutputView.count == 0) || (sinkInputView.count == 0 && sourceOutputView.count >= 1) property int maximumWidth: scrollView.viewport.width width: maximumWidth Layout.maximumWidth: maximumWidth - Header { - Layout.fillWidth: true - visible: sinkInputView.count > 0 && !streamsView.simpleMode - text: i18n("Playback Streams") - } ListView { id: sinkInputView @@ -403,11 +404,16 @@ } } - Header { - Layout.fillWidth: true - visible: sourceOutputView.count > 0 && !streamsView.simpleMode - text: i18n("Recording Streams") + PlasmaCore.SvgItem { + elementId: "horizontal-line" + Layout.preferredWidth: scrollView.viewport.width - units.smallSpacing * 4 + Layout.preferredHeight: naturalSize.height + Layout.leftMargin: units.smallSpacing * 2 + Layout.rightMargin: units.smallSpacing * 2 + svg: lineSvg + visible: sinkInputView.model.count > 0 && sourceOutputView.model.count > 0 } + ListView { id: sourceOutputView @@ -435,19 +441,15 @@ property int maximumWidth: scrollView.viewport.width width: maximumWidth Layout.maximumWidth: maximumWidth + spacing: 0 - Header { - id: sinkViewHeader - Layout.fillWidth: true - visible: sinkView.count > 0 && !devicesView.simpleMode - text: i18n("Playback Devices") - } ListView { id: sinkView Layout.fillWidth: true Layout.minimumHeight: contentHeight Layout.maximumHeight: contentHeight + spacing: 0 model: PlasmaCore.SortFilterModel { sortRole: "SortByDefault" @@ -471,12 +473,15 @@ } } - Header { - id: sourceViewHeader - Layout.fillWidth: true - visible: sourceView.count > 0 && !devicesView.simpleMode - text: i18n("Recording Devices") + PlasmaCore.SvgItem { + elementId: "horizontal-line" + Layout.preferredWidth: scrollView.viewport.width - units.smallSpacing * 4 + Layout.leftMargin: units.smallSpacing * 2 + Layout.rightMargin: Layout.leftMargin + svg: lineSvg + visible: sinkView.model.count > 0 && sourceView.model.count > 0 && (sinkView.model.count > 1 || sourceView.model.count > 1) } + ListView { id: sourceView @@ -522,6 +527,31 @@ } } } + + PlasmaCore.SvgItem { + elementId: "horizontal-line" + Layout.fillWidth: true + Layout.topMargin: 0 - units.smallSpacing / 4 + Layout.leftMargin: 0 - units.smallSpacing * 1.5 + Layout.rightMargin: Layout.leftMargin + svg: lineSvg + } + + RowLayout { + + Item { + Layout.fillWidth: true + } + + PlasmaComponents.ToolButton { + tooltip: plasmoid.action("configure").text + iconName: "configure" + Accessible.name: tooltip + onClicked: { + plasmoid.action("configure").trigger(); + } + } + } } Component.onCompleted: {