You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
latte-dock/declarativeimports/components/ComboBox.qml

455 lines
16 KiB
QML

/*
SPDX-FileCopyrightText: 2016 Marco Martin <mart@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
import QtQuick 2.7
import QtQuick.Window 2.2
import QtQuick.Templates 2.2 as T
import QtQuick.Controls 2.2 as Controls
import QtQuick.Layouts 1.3
import QtGraphicalEffects 1.0
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.kirigami 2.2 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 hideDisplayText: false
property bool hideSelectedItemIcon: false
property bool blankSpaceForEmptyIcons: false
property bool forcePressed: false
property bool popUpAlignRight: true
property bool buttonIsTransparent: false
property int minimumPopUpWidth: 150
property int popUpRelativeX: 0
property int popUpTextHorizontalAlignment: Text.AlignLeft
property string enabledRole
property string iconRole
property string iconToolTipRole
property string iconOnlyWhenHoveredRole
property string isSeparatorRole
property string toolTipRole
signal iconClicked(int index);
delegate: ItemDelegate {
width: control.popup.width
enabled: !isSeparator && (control.enabledRole.length>0 ? (isArray ? modelData[control.enabledRole] : model[control.enabledRole]) : true)
text: control.textRole.length>0 ? (isArray ? modelData[control.textRole] : model[control.textRole]) : modelData
icon: control.iconRole.length>0 ? (isArray ? modelData[control.iconRole] : model[control.iconRole]) : ''
iconToolTip: control.iconToolTipRole.length>0 ? (isArray ? modelData[control.iconToolTipRole] : model[control.iconToolTipRole]) : ''
iconOnlyWhenHovered: control.iconOnlyWhenHoveredRole.length>0 ? (isArray ? modelData[control.iconOnlyWhenHoveredRole] : model[control.iconOnlyWhenHoveredRole]) : ''
isSeparator: control.isSeparatorRole.length>0 ? (isArray ? modelData[control.isSeparatorRole] : model[control.isSeparatorRole]) : false
toolTip: control.toolTipRole.length>0 ? (isArray ? modelData[control.toolTipRole] : model[control.toolTipRole]) : ''
highlighted: mouseArea.pressed ? listView.currentIndex == index : control.currentIndex == index
blankSpaceForEmptyIcons: control.blankSpaceForEmptyIcons
textHorizontalAlignment: popUpTextHorizontalAlignment
readonly property bool isArray: Array.isArray(control.model)
property bool separatorVisible: false
PlasmaComponents.Button {
id: tooltipBtn
anchors.fill: parent
opacity: 0
tooltip: parent.toolTip
visible: tooltip !== ''
onPressedChanged: {
if (!pressed) {
control.currentIndex = index;
control.down = false;
control.pressed = false;
control.popup.visible = false;
}
}
}
}
indicator: PlasmaCore.SvgItem {
implicitWidth: units.iconSizes.small
implicitHeight: implicitWidth
anchors {
right: parent.right
rightMargin: control.buttonIsTransparent ? 0 : 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: onGenericPressed()
onReleased: onGenericReleased()
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;
}
}
function onGenericPressed() {
indexUnderMouse = -1;
listView.currentIndex = control.highlightedIndex;
control.down = true;
control.pressed = true;
control.popup.visible = !control.popup.visible;
}
function onGenericReleased() {
if (!containsMouse && !hiddenTooltipButton.hovered) {
control.down = false;
control.pressed = false;
control.popup.visible = false;
}
if (indexUnderMouse > -1) {
control.currentIndex = indexUnderMouse;
}
}
PlasmaComponents.Button {
id: hiddenTooltipButton
anchors.fill: parent
opacity: 0
visible: control && control.currentIndex>=0 && control.toolTipRole.length>0
tooltip: {
if (!visible) {
return "";
}
if (Array.isArray(control.model)) {
return control.model[control.currentIndex][control.toolTipRole];
} else {
return control.model.get(control.currentIndex)[control.toolTipRole];
}
}
onPressedChanged: {
if (pressed) {
mouseArea.onGenericPressed();
} else {
mouseArea.onGenericReleased();
}
}
}
RowLayout {
anchors.fill: parent
spacing: 0
anchors {
leftMargin: !control.mirrored ? 1 : 0
rightMargin: control.mirrored ? 1 : 0
}
PlasmaCore.IconItem {
id: selectedIcon
implicitWidth: textLabel.height
implicitHeight: textLabel.height
colorGroup: PlasmaCore.Theme.ButtonColorGroup
source: {
if (control
&& control.currentIndex>=0
&& control.iconRole.length>0) {
if (Array.isArray(control.model)) {
return control.model[control.currentIndex][control.iconRole];
} else {
return control.model.get(control.currentIndex)[control.iconRole];
}
}
return "";
}
visible: source !== '' && !control.hideSelectedItemIcon
}
Label {
id: textLabel
Layout.fillWidth: true
Layout.fillHeight: true
Layout.leftMargin: !selectedIcon.visible && !control.mirrored ? units.smallSpacing : 0
Layout.rightMargin: !selectedIcon.visible && control.mirrored ? units.smallSpacing : 0
text: control.displayText
font: control.font
color: control.pressed ? theme.highlightedTextColor : theme.buttonTextColor
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
opacity: control.enabled ? 1 : 0.6
visible: !control.hideDisplayText
}
/* T.TextField {
id: textField
padding: 0
Layout.fillWidth: true
Layout.fillHeight: true
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();
}
}*/
}
}
6 years ago
/* Component {
id: mobileCursor
Private.MobileCursor {
target: textField
}
6 years ago
}*/
Component {
id: undefinedCursor
Item{}
}
6 years ago
/* 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
6 years ago
}*/
background: PlasmaCore.FrameSvgItem {
id: surfaceNormal
//retrocompatibility with old controls
implicitWidth: units.gridUnit * 6
width: parent.width
height: parent.height
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.rightMargin: control.buttonIsTransparent ? -margins.right : 0
readonly property bool editable: control.hasOwnProperty("editable") && control.editable
imagePath: editable ? "widgets/lineedit" : "widgets/button"
prefix: editable
? "base"
: (control.pressed || control.forcePressed ? "pressed" : "normal")
opacity: control.buttonIsTransparent && prefix !== "pressed" && textFieldPrivate.state !== "hover" && !control.popup.visible ? 0 : 1
Private.TextFieldFocus {
id: textFieldPrivate
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)
}
}
}
}