1
0
mirror of https://github.com/KDE/latte-dock.git synced 2024-12-26 11:21:40 +03:00
latte-dock/declarativeimports/components/ComboBox.qml
2019-03-31 14:53:12 +03:00

350 lines
12 KiB
QML

/*
* Copyright 2016 Marco Martin <mart@kde.org>
*
* This program 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 2, or
* (at your option) any later version.
*
* This program 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 program; 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.Window 2.2
import QtQuick.Templates 2.2 as T
import QtQuick.Controls 2.2 as Controls
import QtGraphicalEffects 1.0
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.kirigami 2.5 as Kirigami
import "private" as Private
T.ComboBox {
id: control
implicitWidth: Math.max(background ? background.implicitWidth : 0,
contentItem.implicitWidth + leftPadding + rightPadding) + indicator.implicitWidth + rightPadding
implicitHeight: units.gridUnit * 1.6
baselineOffset: contentItem.y + contentItem.baselineOffset
hoverEnabled: true
topPadding: surfaceNormal.margins.top
leftPadding: surfaceNormal.margins.left
rightPadding: surfaceNormal.margins.right + units.gridUnit * 2
bottomPadding: surfaceNormal.margins.bottom
wheelEnabled: false
property bool blankSpaceForEmptyIcons: false
property bool forcePressed: false
property bool popUpAlignRight: true
property int minimumPopUpWidth: 150
property int popUpRelativeX: 0
property string enabledRole
property string iconRole
property string iconToolTipRole
property string iconOnlyWhenHoveredRole
signal iconClicked(int index);
delegate: ItemDelegate {
width: control.popup.width
enabled: control.enabledRole ? (Array.isArray(control.model) ? modelData[control.enabledRole] : model[control.enabledRole]) : true
text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole] : model[control.textRole]) : modelData
icon: control.iconRole ? (Array.isArray(control.model) ? modelData[control.iconRole] : model[control.iconRole]) : ''
iconToolTip: control.iconToolTipRole ? (Array.isArray(control.model) ? modelData[control.iconToolTipRole] : model[control.iconToolTipRole]) : ''
iconOnlyWhenHovered: control.iconOnlyWhenHoveredRole ? (Array.isArray(control.model) ? modelData[control.iconOnlyWhenHoveredRole] : model[control.iconOnlyWhenHoveredRole]) : ''
highlighted: mouseArea.pressed ? listView.currentIndex == index : control.currentIndex == index
blankSpaceForEmptyIcons: control.blankSpaceForEmptyIcons
property bool separatorVisible: false
}
indicator: PlasmaCore.SvgItem {
implicitWidth: units.iconSizes.small
implicitHeight: implicitWidth
anchors {
right: parent.right
rightMargin: surfaceNormal.margins.right
verticalCenter: parent.verticalCenter
}
svg: PlasmaCore.Svg {
imagePath: "widgets/arrows"
colorGroup: PlasmaCore.Theme.ButtonColorGroup
}
elementId: "down-arrow"
}
// contentItem: Label {
// text: control.displayText
// font: control.font
// color: theme.buttonTextColor
// horizontalAlignment: Text.AlignLeft
// verticalAlignment: Text.AlignVCenter
// elide: Text.ElideRight
// }
contentItem: MouseArea {
id: mouseArea
anchors.fill: parent
acceptedButtons: Qt.LeftButton
preventStealing: true
property int indexUnderMouse: -1
onWheel: {
if (!control.wheelEnabled) {
return;
}
if (wheel.pixelDelta.y < 0 || wheel.angleDelta.y < 0) {
control.currentIndex = Math.min(control.currentIndex + 1, delegateModel.count -1);
} else {
control.currentIndex = Math.max(control.currentIndex - 1, 0);
}
control.activated(control.currentIndex);
}
onPressed: {
indexUnderMouse = -1;
listView.currentIndex = control.highlightedIndex
control.down = true;
control.pressed = true;
control.popup.visible = !control.popup.visible;
}
onReleased: {
if (!containsMouse) {
control.down = false;
control.pressed = false;
control.popup.visible = false;
}
if (indexUnderMouse > -1) {
control.currentIndex = indexUnderMouse;
}
}
onCanceled: {
control.down = false;
control.pressed = false;
}
onPositionChanged: {
var pos = listView.mapFromItem(this, mouse.x, mouse.y);
indexUnderMouse = listView.indexAt(pos.x, pos.y);
listView.currentIndex = indexUnderMouse;
control.activated(indexUnderMouse);
}
Connections {
target: popup
onClosed: {
control.down = false;
control.pressed = false;
}
}
T.TextField {
id: textField
padding: 0
anchors {
fill:parent
leftMargin: control.leftPadding
rightMargin: control.rightPadding
topMargin: control.topPadding
bottomMargin: control.bottomPadding
}
text: control.editable ? control.editText : control.displayText
enabled: control.editable
autoScroll: control.editable
readOnly: control.down || !control.hasOwnProperty("editable") || !control.editable
inputMethodHints: control.inputMethodHints
validator: control.validator
// Work around Qt bug where NativeRendering breaks for non-integer scale factors
// https://bugreports.qt.io/browse/QTBUG-67007
renderType: Screen.devicePixelRatio % 1 !== 0 ? Text.QtRendering : Text.NativeRendering
color: theme.buttonTextColor //control.enabled ? theme.textColor : theme.disabledTextColor
selectionColor: Kirigami.Theme.highlightColor
selectedTextColor: Kirigami.Theme.highlightedTextColor
selectByMouse: !Kirigami.Settings.tabletMode
cursorDelegate: Kirigami.Settings.tabletMode ? mobileCursor : undefinedCursor
font: control.font
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
opacity: control.enabled ? 1 : 0.6
onFocusChanged: {
if (focus) {
Private.MobileTextActionsToolBar.controlRoot = textField;
}
}
onPressAndHold: {
if (!Kirigami.Settings.tabletMode) {
return;
}
forceActiveFocus();
cursorPosition = positionAt(event.x, event.y);
selectWord();
}
}
}
Component {
id: mobileCursor
Private.MobileCursor {
target: textField
}
}
Component {
id: undefinedCursor
Item{}
}
Private.MobileCursor {
target: textField
selectionStartHandle: true
property var rect: textField.positionToRectangle(textField.selectionStart)
//FIXME: this magic values seem to be always valid, for every font,every dpi, every scaling
x: rect.x + 5
y: rect.y + 6
}
background: PlasmaCore.FrameSvgItem {
id: surfaceNormal
//retrocompatibility with old controls
implicitWidth: units.gridUnit * 6
anchors.fill: parent
readonly property bool editable: control.hasOwnProperty("editable") && control.editable
imagePath: editable ? "widgets/lineedit" : "widgets/button"
prefix: editable
? "base"
: (control.pressed || control.forcePressed ? "pressed" : "normal")
Private.TextFieldFocus {
visible: parent.editable
z: -1
state: control.activeFocus ? "focus" : (control.hovered ? "hover" : "hidden")
anchors.fill: parent
}
Private.ButtonShadow {
z: -1
visible: !parent.editable
anchors.fill: parent
state: {
if (control.pressed) {
return "hidden"
} else if (control.hovered) {
return "hover"
} else if (control.activeFocus) {
return "focus"
} else {
return "shadow"
}
}
}
MouseArea {
anchors {
fill: parent
leftMargin: control.leftPadding
rightMargin: control.rightPadding
}
acceptedButtons: Qt.NoButton
onWheel: {
if (!control.wheelEnabled) {
return;
}
if (wheel.pixelDelta.y < 0 || wheel.angleDelta.y < 0) {
control.currentIndex = Math.min(control.currentIndex + 1, delegateModel.count -1);
} else {
control.currentIndex = Math.max(control.currentIndex - 1, 0);
}
control.activated(control.currentIndex);
}
}
}
popup: T.Popup {
x: {
if (!control.mirrored) {
if (popUpRelativeX !== 0) {
var adjustedX = exceedsContent && control.popUpAlignRight ? -(width - control.width) : popUpRelativeX;
return adjustedX;
} else {
return 0;
}
} else {
//! mirrored case
if (exceedsContent && control.popUpAlignRight) {
var adjustedX = width - control.width - popUpRelativeX;
return -adjustedX;
} else {
return 0;
}
}
}
y: control.height
width: Math.max(control.width, control.minimumPopUpWidth)
implicitHeight: contentItem.implicitHeight
topMargin: 6
bottomMargin: 6
readonly property bool exceedsContent: control.width < width
/*onVisibleChanged: {
if (visible) {
console.log(" mirrored:" + control.mirrored);
console.log(" exceeds: " + exceedsContent);
console.log(" popupAR: " + control.popUpAlignRight);
console.log(" popupRX: " + popUpRelativeX);
}
}*/
contentItem: ListView {
id: listView
clip: true
implicitHeight: contentHeight
model: control.popup.visible ? control.delegateModel : null
currentIndex: control.highlightedIndex
highlightRangeMode: ListView.ApplyRange
highlightMoveDuration: 0
// HACK: When the ComboBox is not inside a top-level Window, it's Popup does not inherit
// the LayoutMirroring options. This is a workaround to fix this by enforcing
// the LayoutMirroring options properly.
// QTBUG: https://bugreports.qt.io/browse/QTBUG-66446
LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft
LayoutMirroring.childrenInherit: true
T.ScrollBar.vertical: Controls.ScrollBar { }
signal iconClicked(int index);
onIconClicked: control.iconClicked(index);
}
background: Rectangle {
anchors {
fill: parent
margins: -1
}
radius: 2
color: theme.viewBackgroundColor
border.color: Qt.rgba(theme.textColor.r, theme.textColor.g, theme.textColor.b, 0.3)
layer.enabled: true
layer.effect: DropShadow {
transparentBorder: true
radius: 4
samples: 8
horizontalOffset: 2
verticalOffset: 2
color: Qt.rgba(0, 0, 0, 0.3)
}
}
}
}