/* SPDX-FileCopyrightText: 2016 Marco Martin SPDX-License-Identifier: LGPL-2.0-or-later */ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Templates as T import QtQuick.Controls as Controls import org.kde.ksvg as KSvg //NOTE: importing PlasmaCore is necessary in order to make KSvg load the current Plasma Theme import org.kde.plasma.core as PlasmaCore import org.kde.kirigami as Kirigami import "private" as Private import "mobiletextselection" as MobileTextSelection /*! \qmltype ComboBox \inqmlmodule org.kde.plasma.components \brief A simple combo box whose visual styling is determined by the active Plasma theme. */ T.ComboBox { id: control property real __indicatorMargin: control.indicator && control.indicator.visible && control.indicator.width > 0 ? control.spacing + indicator.width : 0 implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, implicitContentWidth + leftPadding + rightPadding) implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, implicitContentHeight + topPadding + bottomPadding, implicitIndicatorHeight + topPadding + bottomPadding) baselineOffset: contentItem.y + contentItem.baselineOffset hoverEnabled: true topPadding: surfaceNormal.margins.top leftPadding: surfaceNormal.margins.left + (!control.mirrored ? 0 : __indicatorMargin) rightPadding: surfaceNormal.margins.right + (control.mirrored ? 0 : __indicatorMargin) bottomPadding: surfaceNormal.margins.bottom spacing: Kirigami.Units.smallSpacing delegate: ItemDelegate { required property var model required property int index width: ListView.view.width text: model[control.textRole] highlighted: control.highlightedIndex == index property bool separatorVisible: false } indicator: KSvg.SvgItem { implicitWidth: Kirigami.Units.iconSizes.small implicitHeight: implicitWidth anchors { right: parent.right rightMargin: surfaceNormal.margins.right verticalCenter: parent.verticalCenter } svg: KSvg.Svg { imagePath: "widgets/arrows" colorSet: KSvg.Svg.Button } elementId: "down-arrow" } contentItem: T.TextField { id: textField implicitWidth: Math.ceil(contentWidth) + leftPadding + rightPadding implicitHeight: Math.ceil(contentHeight) + topPadding + bottomPadding padding: 0 text: control.editable ? control.editText : control.displayText // We don't want a disabled text color when the control is not editable Kirigami.Theme.textColor: control.Kirigami.Theme.textColor enabled: control.editable autoScroll: control.editable readOnly: control.down || !control.editable inputMethodHints: control.inputMethodHints validator: control.validator color: Kirigami.Theme.textColor selectionColor: Kirigami.Theme.highlightColor selectedTextColor: Kirigami.Theme.highlightedTextColor selectByMouse: !Kirigami.Settings.tabletMode cursorDelegate: Kirigami.Settings.tabletMode ? mobileCursor : null font: control.font horizontalAlignment: Text.AlignLeft verticalAlignment: Text.AlignVCenter opacity: control.enabled ? 1 : 0.3 onFocusChanged: { if (focus) { MobileTextSelection.MobileTextActionsToolBar.controlRoot = textField; } } onTextChanged: MobileTextSelection.MobileTextActionsToolBar.shouldBeVisible = false; onPressed: event => MobileTextSelection.MobileTextActionsToolBar.shouldBeVisible = true; onPressAndHold: event => { if (!Kirigami.Settings.tabletMode) { return; } forceActiveFocus(); cursorPosition = positionAt(event.x, event.y); selectWord(); } } Component { id: mobileCursor MobileTextSelection.MobileCursor { target: textField } } MobileTextSelection.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: KSvg.FrameSvgItem { id: surfaceNormal anchors.fill: parent imagePath: control.editable ? "widgets/lineedit" : "widgets/button" prefix: control.editable ? "base" : (control.down ? "pressed" : "normal") Private.ButtonShadow { anchors.fill: parent showShadow: !control.editable && !control.down } Private.TextFieldFocus { visible: control.editable z: -1 state: control.activeFocus ? "focus" : (control.enabled && control.hovered ? "hover" : "hidden") anchors.fill: parent } Private.ButtonFocus { anchors.fill: parent showFocus: control.activeFocus && !control.down } Private.ButtonHover { anchors.fill: parent showHover: control.enabled && control.hovered && !control.down } MouseArea { anchors { fill: parent leftMargin: control.leftPadding rightMargin: control.rightPadding } acceptedButtons: Qt.NoButton onWheel: wheel => { if (wheel.pixelDelta.y < 0 || wheel.angleDelta.y < 0) { control.currentIndex = Math.min(control.currentIndex + 1, control.delegateModel.count -1); } else { control.currentIndex = Math.max(control.currentIndex - 1, 0); } control.activated(control.currentIndex); } } } popup: T.Popup { x: control.mirrored ? control.width - width : 0 y: control.height width: Math.max(control.width, 150) implicitHeight: contentItem.implicitHeight topMargin: 6 bottomMargin: 6 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: Application.layoutDirection === Qt.RightToLeft LayoutMirroring.childrenInherit: true T.ScrollBar.vertical: Controls.ScrollBar { } } background: Kirigami.ShadowedRectangle { anchors { fill: parent margins: -1 } radius: 2 Kirigami.Theme.colorSet: Kirigami.Theme.View Kirigami.Theme.inherit: false color: Kirigami.Theme.backgroundColor border { color: Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.3) width: 1 } shadow { size: 4 xOffset: 2 yOffset: 2 color: Qt.rgba(0, 0, 0, 0.3) } } } }