Warning, /plasma/qqc2-breeze-style/style/qtquickcontrols/ComboBox.qml is written in an unsupported language. File is not indexed.

0001 /* SPDX-FileCopyrightText: 2017 The Qt Company Ltd.
0002  * SPDX-FileCopyrightText: 2017 Marco Martin <mart@kde.org>
0003  * SPDX-FileCopyrightText: 2020 Noah Davis <noahadvs@gmail.com>
0004  * SPDX-License-Identifier: LicenseRef-KDE-Accepted-LGPL
0005  */
0006 
0007 import QtQuick
0008 import QtQuick.Window
0009 import QtQuick.Templates as T
0010 import QtQuick.Controls as Controls
0011 import org.kde.kirigami as Kirigami
0012 
0013 import org.kde.breeze.impl as Impl
0014 
0015 T.ComboBox {
0016     id: control
0017 
0018     property real __indicatorMargin: control.indicator && control.indicator.visible && control.indicator.width > 0 ? control.spacing + indicator.width + control.spacing : 0
0019     property real __widestImplicitContentWidth: implicitContentWidth
0020     readonly property bool __isContentItemTextInput: contentItem instanceof TextInput
0021 
0022     implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
0023                             __widestImplicitContentWidth + leftPadding + rightPadding)
0024     implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
0025                              implicitContentHeight + topPadding + bottomPadding,
0026                              implicitIndicatorHeight + topPadding + bottomPadding)
0027 
0028     // palette: Kirigami.Theme.palette
0029     Kirigami.Theme.colorSet: control.editable ? Kirigami.Theme.View : Kirigami.Theme.Button
0030     Kirigami.Theme.inherit: false
0031 
0032     spacing: Kirigami.Units.mediumSpacing
0033 
0034     hoverEnabled: Qt.styleHints.useHoverEffects
0035 
0036     leftPadding: horizontalPadding + (!control.mirrored ? 0 : __indicatorMargin)
0037     rightPadding: horizontalPadding + (control.mirrored ? 0 : __indicatorMargin)
0038 
0039     contentItem: Controls.TextField {
0040         id: textField
0041         palette: control.palette
0042         // TextField padding doesn't automatically mirror
0043         leftPadding: control.mirrored ? 0 : Impl.Units.mediumHorizontalPadding
0044         rightPadding: !control.mirrored ? 0 : Impl.Units.mediumHorizontalPadding
0045 
0046         text: control.editable ? control.editText : control.displayText
0047 
0048         enabled: control.editable
0049         autoScroll: control.editable
0050         readOnly: control.down || !control.editable
0051         inputMethodHints: control.inputMethodHints
0052         validator: control.validator
0053 
0054         // Using control.Kirigami.Theme.textColor instead of directly using
0055         // Kirigami.Theme.textColor because the latter always uses the disabled
0056         // palette when textField.enabled == false
0057         color: control.Kirigami.Theme.textColor
0058 
0059         background: null
0060     }
0061 
0062     indicator: Kirigami.Icon {
0063         implicitHeight: Kirigami.Units.iconSizes.sizeForLabels
0064         implicitWidth: implicitHeight
0065         x: control.mirrored ? control.leftPadding : control.leftPadding + control.availableWidth + control.spacing
0066         y: control.topPadding + (control.availableHeight - height) / 2
0067         source: "arrow-down"
0068     }
0069 
0070     background: Impl.ComboBoxBackground {
0071         control: control
0072 
0073         Rectangle {
0074             id: separator
0075             visible: control.editable
0076             width: Impl.Units.smallBorder
0077             anchors {
0078                 right: parent.right
0079                 top: parent.top
0080                 bottom: parent.bottom
0081                 rightMargin: (control.mirrored ? control.leftPadding : control.rightPadding) - width
0082                 topMargin: control.topPadding + (__isContentItemTextInput ? control.contentItem.topPadding : 0)
0083                 bottomMargin: control.bottomPadding + (__isContentItemTextInput ? control.contentItem.bottomPadding : 0)
0084             }
0085 
0086             color: control.down
0087                 || ((control.hovered || control.visualFocus)
0088                     && !(control.contentItem && control.contentItem.hasOwnProperty("hovered") && control.contentItem.hovered))
0089                 ? Kirigami.Theme.focusColor : Impl.Theme.separatorColor()
0090 
0091             Behavior on color {
0092                 enabled: control.down || control.hovered
0093                 ColorAnimation {
0094                     duration: Kirigami.Units.shortDuration
0095                     easing.type: Easing.OutCubic
0096                 }
0097             }
0098         }
0099 
0100         Kirigami.ShadowedRectangle {
0101             id: pressedBg
0102             property real leftRadius: control.mirrored ? radius : 0
0103             property real rightRadius: !control.mirrored ? radius : 0
0104             visible: false
0105 
0106             anchors {
0107                 left: separator.left
0108                 right: parent.right
0109                 top: parent.top
0110                 bottom: parent.bottom
0111             }
0112 
0113             Kirigami.Theme.colorSet: Kirigami.Theme.Button
0114             Kirigami.Theme.inherit: false
0115             color: Kirigami.Theme.alternateBackgroundColor
0116 
0117             radius: parent.radius
0118             corners {
0119                 topLeftRadius: leftRadius
0120                 topRightRadius: rightRadius
0121                 bottomLeftRadius: leftRadius
0122                 bottomRightRadius: rightRadius
0123             }
0124 
0125             border.color: Kirigami.Theme.focusColor
0126             border.width: Impl.Units.smallBorder
0127 
0128             opacity: 0
0129 
0130             states: State {
0131                 name: "pressed"
0132                 when: control.down && control.editable
0133                 PropertyChanges {
0134                     target: pressedBg
0135                     opacity: 1
0136                     visible: true
0137                 }
0138             }
0139             transitions: Transition {
0140                 from: "pressed"
0141                 to: ""
0142                 SequentialAnimation {
0143                     OpacityAnimator {
0144                         duration: Kirigami.Units.shortDuration
0145                         easing.type: Easing.OutCubic
0146                     }
0147                     PropertyAction {
0148                         target: pressedBg
0149                         property: "visible"
0150                         value: false
0151                     }
0152                 }
0153             }
0154         }
0155     }
0156 
0157     delegate: Controls.MenuItem {
0158         implicitWidth: leftPadding + implicitContentWidth + rightPadding
0159         width: parent ? parent.width : implicitWidth
0160         text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole] : model[control.textRole]) : modelData
0161         highlighted: control.highlightedIndex === index
0162         hoverEnabled: control.hoverEnabled
0163         __reserveSpaceForIndicator: false
0164         __reserveSpaceForIcon: false
0165         __reserveSpaceForArrow: false
0166     }
0167 
0168     popup: Controls.Menu {
0169         y: control.height
0170         x: (control.width - width)/2
0171         implicitWidth: contentWidth + leftPadding + rightPadding
0172         width: Math.max(control.width, implicitWidth)
0173         padding: Kirigami.Units.smallSpacing
0174 
0175         delegate: null
0176 
0177         contentItem: ListView {
0178             id: listView
0179             // this causes us to load at least one delegate
0180             // this is essential in guessing the contentHeight
0181             // which is needed to initially resize the popup
0182             //cacheBuffer: 1
0183             implicitHeight: contentHeight
0184             implicitWidth: contentWidth
0185             model: control.delegateModel // Why isn't this in the ComboBox documentation?
0186             currentIndex: control.highlightedIndex
0187             highlightMoveDuration: Kirigami.Units.shortDuration
0188             highlightMoveVelocity: Kirigami.Units.gridUnit * 20
0189             highlight: Impl.ListViewHighlight {
0190                 currentIndex: control.highlightedIndex
0191                 count: control.count
0192                 alwaysCurveCorners: true
0193             }
0194             interactive: Window.window ? contentHeight + control.topPadding + control.bottomPadding > Window.window.height : false
0195             clip: interactive // Only needed when the ListView can be dragged/flicked
0196             keyNavigationWraps: true
0197             ScrollBar.vertical: Controls.ScrollBar {}
0198         }
0199     }
0200 
0201     WheelHandler {
0202         target: control
0203         // FIXME: shouldDec and shouldInc don't work reliably with touchpads when the popup is open.
0204         // Sometimes it's fine, sometimes you need to scroll extra hard to move the highlight.
0205         enabled: control.count > 1 && (popup ? !popup.visible : true)
0206         // Maybe only handle mouse wheels (default) for now. Touchpad scrolling can be too sensitive sometimes.
0207         acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
0208         onWheel: {
0209             // Degrees still change by differences greater than 1 scrollwheel notch (typically 15) if you scroll fast enough.
0210             // That means multiple scroll ticks are registered before the code can run.
0211             // Doesn't seem to impact how the control feels much at least.
0212             let shouldDec = rotation >= 15
0213             let shouldInc = rotation <= -15
0214             let shouldReset = (rotation > 0 && control.currentIndex == 0) || (rotation < 0 && control.currentIndex == control.count-1)
0215             if (shouldDec) {
0216                 control.decrementCurrentIndex(); // This moves the highlight up
0217                 rotation = 0
0218             } else if (shouldInc) {
0219                 control.incrementCurrentIndex(); // This moves the highlight down
0220                 rotation = 0
0221             } else if (shouldReset) {
0222                 rotation = 0
0223             }
0224         }
0225     }
0226 
0227     TextMetrics {
0228         id: textMetrics
0229     }
0230 
0231     // Mimicks WidestTextWhenCompleted from Qt 6.
0232     // Maybe use this if app devs are interested.
0233     // Don't use it for now because lots of GUIs aren't designed for it.
0234     /*
0235     Component.onCompleted: {
0236         // TODO: Remove in Qt 6
0237         if (// Qt 6 does this in QQuickComboBoxPrivate::calculateWidestTextWidth()
0238             __isContentItemTextInput
0239             // Kind of an arbitrary limit, but prevents making lots of calculations with larger models
0240             && control.count <= 20
0241         ) {
0242             let widest = Math.ceil(contentItem.contentWidth)
0243             for (let i = 0; i < count; ++i) {
0244                 textMetrics.text = control.textAt(i)
0245                 widest = Math.max(widest, textMetrics.width)
0246             }
0247             __widestImplicitContentWidth = Math.ceil(widest) + contentItem.leftPadding + contentItem.rightPadding
0248         }
0249     }
0250     */
0251 }