diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -239,6 +239,7 @@ qml/ContentView.qml qml/ViewSelector.qml qml/ViewManager.qml + qml/ElisaToolButton.qml qml/MediaPlayListView.qml qml/MediaTrackDelegate.qml diff --git a/src/qml/ElisaMainWindow.qml b/src/qml/ElisaMainWindow.qml --- a/src/qml/ElisaMainWindow.qml +++ b/src/qml/ElisaMainWindow.qml @@ -18,8 +18,7 @@ */ import QtQuick 2.7 -import QtQuick.Controls 2.2 -import QtQuick.Controls 1.4 as Controls1 +import QtQuick.Controls 2.3 import QtQuick.Layouts 1.1 import QtQuick.Window 2.2 import org.kde.elisa 1.0 @@ -46,7 +45,7 @@ property var goBackAction: elisa.action("go_back") property var findAction: elisa.action("edit_find") - Controls1.Action { + Action { shortcut: findAction.shortcut onTriggered: { if ( persistentSettings.expandedFilterView == true) @@ -58,18 +57,11 @@ } } - Controls1.Action { + Action { shortcut: goBackAction.shortcut onTriggered: contentView.goBack() } - Controls1.Action { - id: applicationMenuAction - text: i18nc("open application menu", "Application Menu") - iconName: "application-menu" - onTriggered: applicationMenu.popup() - } - ApplicationMenu { id: applicationMenu } @@ -106,7 +98,12 @@ property bool showPlaylist: true property bool headerBarIsMaximized: false - } + } + + Connections { + target: headerBar.playerControl + onOpenMenu: applicationMenu.popup() + } Connections { target: Qt.application diff --git a/src/qml/ElisaToolButton.qml b/src/qml/ElisaToolButton.qml new file mode 100644 --- /dev/null +++ b/src/qml/ElisaToolButton.qml @@ -0,0 +1,112 @@ +/* + * Copyright 2018 Alexander Stippich + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.7 +import QtQuick.Layouts 1.2 +import QtGraphicalEffects 1.0 +import QtQuick.Controls 2.3 +import org.kde.elisa 1.0 + +ToolButton { + id: elisaToolButton + + Keys.onPressed: { + if (event.key === Qt.Key_Space) { + event.accepted = true + } + } + + Keys.onReleased: { + if (event.key === Qt.Key_Space) { + event.accepted = true + } + } + + onPressed: scale = 0.9 + onReleased: scale = 1 + + contentItem: Image { + anchors.fill: parent + + source: elisaToolButton.action.icon.name != "" ? ('image://icon/' + elisaToolButton.action.icon.name) : Qt.resolvedUrl(elisaToolButton.action.icon.source) + + sourceSize.width: elisaToolButton.width + sourceSize.height: elisaToolButton.height + + fillMode: Image.PreserveAspectFit + opacity: elisaToolButton.action.enabled ? 1 : 0.6 + } + + background: Rectangle { + color: "transparent" + border.width: hoverArea.containsMouse ? 1 : 0 + border.color: myPalette.highlight + } + + MouseArea { + id: hoverArea + anchors.fill: parent + hoverEnabled: true + acceptedButtons: Qt.NoButton + + Loader { + anchors.fill: parent + active: hoverArea && hoverArea.containsMouse + + sourceComponent: ToolTip { + delay: Qt.styleHints.mousePressAndHoldInterval + visible: hoverArea && hoverArea.containsMouse && elisaToolButton.action.text != "" + text: elisaToolButton.action.text + + enter: Transition { + NumberAnimation { + properties: "opacity" + easing.type: Easing.InOutQuad + from: 0.0 + to: 1.0 + duration: 300 + } + } + exit: Transition { + NumberAnimation { + properties: "opacity" + easing.type: Easing.InOutQuad + from: 1.0 + to: 0.0 + duration: 300 + } + } + + background: Rectangle { + color: myPalette.shadow + radius: elisaTheme.tooltipRadius + + layer.enabled: true + layer.effect: DropShadow { + horizontalOffset: elisaTheme.shadowOffset + verticalOffset: elisaTheme.shadowOffset + radius: 8 + samples: 17 + color: myPalette.shadow + } + } + } + } + } +} diff --git a/src/qml/MediaPlayerControl.qml b/src/qml/MediaPlayerControl.qml --- a/src/qml/MediaPlayerControl.qml +++ b/src/qml/MediaPlayerControl.qml @@ -20,11 +20,9 @@ import QtQuick 2.7 import QtQuick.Layouts 1.2 import QtGraphicalEffects 1.0 -import QtQuick.Controls 2.2 +import QtQuick.Controls 2.3 import org.kde.elisa 1.0 -import QtQuick.Controls 1.4 as Controls1 - FocusScope { property double volume property int position @@ -45,6 +43,7 @@ signal playPrevious() signal playNext() signal seek(int position) + signal openMenu() signal maximize() signal minimize() @@ -60,6 +59,65 @@ id: elisaTheme } + Action { + id: applicationMenuAction + text: i18nc("open application menu", "Application Menu") + icon.name: "application-menu" + onTriggered: openMenu() + } + + Action { + id: repeatAction + text: i18nc("toggle repeat mode for playlist", "Toggle Repeat") + icon.name: musicWidget.repeat ? "media-repeat-all" : "media-repeat-none" + onTriggered: musicWidget.repeat = !musicWidget.repeat + } + + Action { + id: shuffleAction + text: i18nc("toggle shuffle mode for playlist", "Toggle Shuffle") + icon.name: musicWidget.shuffle ? "media-playlist-shuffle" : "media-playlist-normal" + onTriggered: musicWidget.shuffle = !musicWidget.shuffle + } + + Action { + id: muteAction + text: i18nc("toggle mute mode for player", "Toggle Mute") + icon.name: musicWidget.muted ? "player-volume-muted" : "player-volume" + onTriggered: musicWidget.muted = !musicWidget.muted + } + + Action { + id: playPauseAction + text: i18nc("toggle play and pause for the audio player", "Toggle Play and Pause") + icon.name: musicWidget.isPlaying? "media-playback-pause" : "media-playback-start" + onTriggered: musicWidget.isPlaying ? musicWidget.pause() : musicWidget.play() + enabled: playEnabled + } + + Action { + id: skipBackwardAction + text: i18nc("skip backward in playlists", "Skip Backward") + icon.name: musicWidget.LayoutMirroring.enabled ? "media-skip-forward" : "media-skip-backward" + onTriggered: musicWidget.playPrevious() + enabled: skipBackwardEnabled + } + + Action { + id: skipForwardAction + text: i18nc("skip forward in playlists", "Skip Forward") + icon.name: musicWidget.LayoutMirroring.enabled ? "media-skip-backward" : "media-skip-forward" + onTriggered: musicWidget.playNext() + enabled: skipForwardEnabled + } + + Action { + id: minimizeMaximizeAction + text: i18nc("skip forward in playlists", "Skip Forward") + icon.name: musicWidget.isMaximized ? "draw-arrow-up" : "draw-arrow-down" + onTriggered: musicWidget.isMaximized = !musicWidget.isMaximized + } + Rectangle { anchors.fill: parent @@ -71,7 +129,10 @@ anchors.fill: parent spacing: 5 - Button { + ElisaToolButton { + id: minimzeMaximizeAction + action: minimizeMaximizeAction + Layout.preferredWidth: elisaTheme.smallControlButtonSize Layout.preferredHeight: elisaTheme.smallControlButtonSize Layout.alignment: Qt.AlignVCenter @@ -81,32 +142,11 @@ Layout.minimumHeight: elisaTheme.smallControlButtonSize Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.mediaPlayerHorizontalMargin : 0 Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.mediaPlayerHorizontalMargin : 0 - - contentItem: Image { - anchors.fill: parent - source: Qt.resolvedUrl(musicWidget.isMaximized ? elisaTheme.minimizeIcon : elisaTheme.maximizeIcon) - - width: elisaTheme.smallControlButtonSize - height: elisaTheme.smallControlButtonSize - - sourceSize.width: elisaTheme.smallControlButtonSize - sourceSize.height: elisaTheme.smallControlButtonSize - - fillMode: Image.PreserveAspectFit - opacity: 1.0 - } - - background: Rectangle { - border.width: 0 - opacity: 0.0 - } - - onClicked: { - musicWidget.isMaximized = !musicWidget.isMaximized - } } - RoundButton { + ElisaToolButton { + id: skipBackwardButton + action: skipBackwardAction focus: skipBackwardEnabled Layout.preferredWidth: elisaTheme.smallControlButtonSize @@ -116,49 +156,11 @@ Layout.maximumHeight: elisaTheme.smallControlButtonSize Layout.minimumWidth: elisaTheme.smallControlButtonSize Layout.minimumHeight: elisaTheme.smallControlButtonSize - Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.mediaPlayerHorizontalMargin : 0 - Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.mediaPlayerHorizontalMargin : 0 - - enabled: skipBackwardEnabled - hoverEnabled: true - - onClicked: { - musicWidget.playPrevious() - } - - contentItem: Image { - anchors.fill: parent - - source: Qt.resolvedUrl(LayoutMirroring.enabled ? elisaTheme.skipForwardIcon : elisaTheme.skipBackwardIcon) - - width: elisaTheme.smallControlButtonSize - height: elisaTheme.smallControlButtonSize - - sourceSize.width: elisaTheme.smallControlButtonSize - sourceSize.height: elisaTheme.smallControlButtonSize - - fillMode: Image.PreserveAspectFit - - opacity: skipBackwardEnabled ? 1.0 : 0.6 - } - - background: Rectangle { - color: "transparent" - - border.color: (parent.hovered || parent.activeFocus) ? myPalette.highlight : "transparent" - border.width: 1 - - radius: elisaTheme.smallControlButtonSize - - Behavior on border.color { - ColorAnimation { - duration: 300 - } - } - } } - RoundButton { + ElisaToolButton { + id: playPauseButton + action: playPauseAction focus: playEnabled Layout.preferredWidth: elisaTheme.smallControlButtonSize @@ -168,56 +170,11 @@ Layout.maximumHeight: elisaTheme.smallControlButtonSize Layout.minimumWidth: elisaTheme.smallControlButtonSize Layout.minimumHeight: elisaTheme.smallControlButtonSize - - enabled: playEnabled - hoverEnabled: true - - onClicked: { - if (musicWidget.isPlaying) { - musicWidget.pause() - } else { - musicWidget.play() - } - } - - contentItem: Image { - anchors.fill: parent - - source: { - if (musicWidget.isPlaying) - Qt.resolvedUrl(elisaTheme.pauseIcon) - else - Qt.resolvedUrl(elisaTheme.playIcon) - } - - width: elisaTheme.smallControlButtonSize - height: elisaTheme.smallControlButtonSize - - sourceSize.width: elisaTheme.smallControlButtonSize - sourceSize.height: elisaTheme.smallControlButtonSize - - fillMode: Image.PreserveAspectFit - mirror: LayoutMirroring.enabled - opacity: playEnabled ? 1.0 : 0.6 - } - - background: Rectangle { - color: "transparent" - - border.color: (parent.hovered || parent.activeFocus) ? myPalette.highlight : "transparent" - border.width: 1 - - radius: elisaTheme.smallControlButtonSize - - Behavior on border.color { - ColorAnimation { - duration: 300 - } - } - } } - RoundButton { + ElisaToolButton { + id: skipForwardButton + action: skipForwardAction focus: skipForwardEnabled Layout.preferredWidth: elisaTheme.smallControlButtonSize @@ -227,44 +184,6 @@ Layout.maximumHeight: elisaTheme.smallControlButtonSize Layout.minimumWidth: elisaTheme.smallControlButtonSize Layout.minimumHeight: elisaTheme.smallControlButtonSize - - enabled: skipForwardEnabled - hoverEnabled: true - - onClicked: { - musicWidget.playNext() - } - - contentItem: Image { - anchors.fill: parent - - source: Qt.resolvedUrl(LayoutMirroring.enabled ? elisaTheme.skipBackwardIcon : elisaTheme.skipForwardIcon) - - width: elisaTheme.smallControlButtonSize - height: elisaTheme.smallControlButtonSize - - sourceSize.width: elisaTheme.smallControlButtonSize - sourceSize.height: elisaTheme.smallControlButtonSize - - fillMode: Image.PreserveAspectFit - - opacity: skipForwardEnabled ? 1.0 : 0.6 - } - - background: Rectangle { - color: "transparent" - - border.color: (parent.hovered || parent.activeFocus) ? myPalette.highlight : "transparent" - border.width: 1 - - radius: elisaTheme.smallControlButtonSize - - Behavior on border.color { - ColorAnimation { - duration: 300 - } - } - } } TextMetrics { @@ -382,34 +301,9 @@ } } - Image { - id: volumeIcon - - source: if (musicWidget.muted) - Qt.resolvedUrl(elisaTheme.playerVolumeMutedIcon) - else - Qt.resolvedUrl(elisaTheme.playerVolumeIcon) - - Layout.preferredWidth: elisaTheme.smallControlButtonSize - Layout.preferredHeight: elisaTheme.smallControlButtonSize - Layout.alignment: Qt.AlignVCenter - Layout.maximumWidth: elisaTheme.smallControlButtonSize - Layout.maximumHeight: elisaTheme.smallControlButtonSize - Layout.minimumWidth: elisaTheme.smallControlButtonSize - Layout.minimumHeight: elisaTheme.smallControlButtonSize - Layout.rightMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 - Layout.leftMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 - - sourceSize.width: elisaTheme.smallControlButtonSize - sourceSize.height: elisaTheme.smallControlButtonSize - - fillMode: Image.PreserveAspectFit - - visible: false - } - - - RoundButton { + ElisaToolButton { + id: muteButton + action: muteAction focus: true Layout.preferredWidth: elisaTheme.smallControlButtonSize @@ -419,42 +313,6 @@ Layout.maximumHeight: elisaTheme.smallControlButtonSize Layout.minimumWidth: elisaTheme.smallControlButtonSize Layout.minimumHeight: elisaTheme.smallControlButtonSize - - hoverEnabled: true - - onClicked: musicWidget.muted = !musicWidget.muted - - contentItem: Image { - anchors.fill: parent - - source: if (musicWidget.muted) - Qt.resolvedUrl(elisaTheme.playerVolumeMutedIcon) - else - Qt.resolvedUrl(elisaTheme.playerVolumeIcon) - - width: elisaTheme.smallControlButtonSize - height: elisaTheme.smallControlButtonSize - - sourceSize.width: elisaTheme.smallControlButtonSize - sourceSize.height: elisaTheme.smallControlButtonSize - - fillMode: Image.PreserveAspectFit - } - - background: Rectangle { - color: "transparent" - - border.color: (parent.hovered || parent.activeFocus) ? myPalette.highlight : "transparent" - border.width: 1 - - radius: elisaTheme.smallControlButtonSize - - Behavior on border.color { - ColorAnimation { - duration: 300 - } - } - } } Slider { @@ -510,8 +368,9 @@ } } - RoundButton { + ElisaToolButton { focus: true + action: shuffleAction id: shuffleButton Layout.preferredWidth: elisaTheme.smallControlButtonSize @@ -521,32 +380,11 @@ Layout.maximumHeight: elisaTheme.smallControlButtonSize Layout.minimumWidth: elisaTheme.smallControlButtonSize Layout.minimumHeight: elisaTheme.smallControlButtonSize + } - hoverEnabled: true - onClicked: musicWidget.shuffle = !musicWidget.shuffle - - contentItem: Image { - anchors.fill: parent - - source: musicWidget.shuffle ? Qt.resolvedUrl(elisaTheme.shuffleIcon) : Qt.resolvedUrl(elisaTheme.noShuffleIcon) - - width: elisaTheme.smallControlButtonSize - height: elisaTheme.smallControlButtonSize - - sourceSize.width: elisaTheme.smallControlButtonSize - sourceSize.height: elisaTheme.smallControlButtonSize - - fillMode: Image.PreserveAspectFit - } - - background: Rectangle { - color: "transparent" - } - } - - - RoundButton { + ElisaToolButton { focus: true + action: repeatAction id: repeatButton Layout.preferredWidth: elisaTheme.smallControlButtonSize @@ -556,33 +394,12 @@ Layout.maximumHeight: elisaTheme.smallControlButtonSize Layout.minimumWidth: elisaTheme.smallControlButtonSize Layout.minimumHeight: elisaTheme.smallControlButtonSize - - hoverEnabled: true - onClicked: musicWidget.repeat = !musicWidget.repeat - - contentItem: Image { - anchors.fill: parent - - source: musicWidget.repeat ? Qt.resolvedUrl(elisaTheme.repeatIcon) : Qt.resolvedUrl(elisaTheme.noRepeatIcon) - - width: elisaTheme.smallControlButtonSize - height: elisaTheme.smallControlButtonSize - - sourceSize.width: elisaTheme.smallControlButtonSize - sourceSize.height: elisaTheme.smallControlButtonSize - - fillMode: Image.PreserveAspectFit - } - - background: Rectangle { - color: "transparent" - } - } - Controls1.ToolButton { + ElisaToolButton { id: menuButton action: applicationMenuAction + focus: true Layout.preferredWidth: elisaTheme.smallControlButtonSize Layout.preferredHeight: elisaTheme.smallControlButtonSize diff --git a/src/qml/Theme.qml b/src/qml/Theme.qml --- a/src/qml/Theme.qml +++ b/src/qml/Theme.qml @@ -35,24 +35,12 @@ property string tracksIcon: 'image://icon/view-media-track' property string genresIcon: 'image://icon/view-media-genre' property string clearIcon: 'image://icon/edit-clear' - property string skipBackwardIcon: 'image://icon/media-skip-backward' - property string pauseIcon: 'image://icon/media-playback-pause' - property string playIcon: 'image://icon/media-playback-start' - property string skipForwardIcon: 'image://icon/media-skip-forward' property string pausedIndicatorIcon: 'image://icon/media-playback-paused' property string playingIndicatorIcon: 'image://icon/media-playback-playing' - property string playerVolumeMutedIcon: 'image://icon/player-volume-muted' - property string playerVolumeIcon: 'image://icon/player-volume' property string ratingIcon: 'image://icon/rating' property string ratingUnratedIcon: 'image://icon/rating-unrated' property string errorIcon: 'image://icon/error' - property string repeatIcon: 'image://icon/media-repeat-all' - property string shuffleIcon: 'image://icon/media-playlist-shuffle' - property string noRepeatIcon: 'image://icon/media-repeat-none' - property string noShuffleIcon: 'image://icon/media-playlist-normal' property string folderIcon: 'image://icon/document-open-folder' - property string maximizeIcon: 'image://icon/draw-arrow-down' - property string minimizeIcon: 'image://icon/draw-arrow-up' property int layoutHorizontalMargin: dp(8) property int layoutVerticalMargin: dp(6) diff --git a/src/resources.qrc b/src/resources.qrc --- a/src/resources.qrc +++ b/src/resources.qrc @@ -31,6 +31,7 @@ qtquickcontrols2.conf background.png qml/ViewManager.qml + qml/ElisaToolButton.qml windows/WindowsTheme.qml diff --git a/src/windows/WindowsTheme.qml b/src/windows/WindowsTheme.qml --- a/src/windows/WindowsTheme.qml +++ b/src/windows/WindowsTheme.qml @@ -35,24 +35,12 @@ property string tracksIcon: 'image://icon/view-media-track' property string genresIcon: 'image://icon/view-media-genre' property string clearIcon: 'image://icon/edit-clear' - property string skipBackwardIcon: 'image://icon/media-skip-backward' - property string pauseIcon: 'image://icon/media-playback-pause' - property string playIcon: 'image://icon/media-playback-start' - property string skipForwardIcon: 'image://icon/media-skip-forward' property string pausedIndicatorIcon: 'image://icon/media-playback-paused' property string playingIndicatorIcon: 'image://icon/media-playback-playing' - property string playerVolumeMutedIcon: 'image://icon/player-volume-muted' - property string playerVolumeIcon: 'image://icon/player-volume' property string ratingIcon: 'image://icon/rating' property string ratingUnratedIcon: 'image://icon/rating-unrated' property string errorIcon: 'image://icon/error' - property string repeatIcon: 'image://icon/media-repeat-all' - property string shuffleIcon: 'image://icon/media-playlist-shuffle' - property string noRepeatIcon: 'image://icon/media-repeat-none' - property string noShuffleIcon: 'image://icon/media-playlist-normal' property string folderIcon: 'image://icon/document-open-folder' - property string maximizeIcon: 'image://icon/draw-arrow-down' - property string minimizeIcon: 'image://icon/draw-arrow-up' property int layoutHorizontalMargin: dp(8) property int layoutVerticalMargin: dp(6)