4pragma ComponentBehavior: Bound
7import QtQuick.Templates as T
9import "../core/UiMetrics.js" as UiMetrics
10import "../internal/MotionAnimation.js" as MotionAnimation
52 Accessible.role: Accessible.ToolBar
53 Accessible.name: qsTr(
"Search")
90 property string placeholderText: qsTr(
"Search")
100 property
int inputMethodHints: Qt.ImhNone
107 property var validator: null
115 property MD.
AppBarAction searchNavigationAction: defaultSearchAction
121 property color searchContainerColor: MD.Style.surfaceContainerColor
124 property color scrolledSearchContainerColor: MD.Style.surfaceContainerHighestColor
127 property color searchTextColor: MD.Style.onSurfaceColor
130 property color searchContentColor: MD.Style.onSurfaceVariantColor
139 readonly property
bool _centeredText: textAlignment !== 0
142 property var _visibleSearchActions: []
145 property var _searchOverflowActions: []
148 property real _capsuleWidth: 0
151 property var _searchFieldItem: null
154 property var _searchActionRepeater: null
156 collapsedHeight: MD.
Tokens.appBar.smallContainerHeight
157 expandedHeight: collapsedHeight
158 scrollBehavior: MD.BaseAppBar.EnterAlways
159 minimumCenterWidth: MD.
Tokens.appBar.searchContainerHeight + MD.
Tokens.appBar.searchOuterFieldMargin * 2
160 supplementalOverflowActions: _searchOverflowActions
163 function _searchActionWidth(index) {
164 const item = _searchActionRepeater ? _searchActionRepeater.itemAt(index) : null;
165 return item ? item.implicitWidth : MD.
Tokens.appBar.minimumInteractiveSize;
169 function _reflowSearchActions() {
170 const candidates = [];
171 const forcedVisible = [];
174 for (let index = 0; index < searchActions.length; ++index) {
175 const action = searchActions[index];
176 if (!action || !action.visible)
181 width: _searchActionWidth(index)
183 if (action.overflowPolicy === MD.AppBarAction.NeverOverflow) {
184 forcedVisible.push(entry);
185 usedWidth += entry.width;
186 }
else if (action.overflowPolicy !== MD.AppBarAction.AlwaysOverflow) {
187 candidates.push(entry);
191 const leadingWidth = searchNavigationAction && searchNavigationAction.visible ? MD.Tokens.appBar.minimumInteractiveSize + MD.Tokens.appBar.searchContainedLeadingSpace : MD.Tokens.appBar.searchContainedNoActionsLeadingSpace;
192 const fixedWidth = leadingWidth + MD.Tokens.appBar.searchContainedTrailingSpace + MD.Tokens.appBar.titleInset * 2;
193 const budget = Math.max(0, _capsuleWidth - fixedWidth);
195 candidates.sort((left, right) => {
196 if (left.action.priority !== right.action.priority)
197 return right.action.priority - left.action.priority;
198 return left.index - right.index;
201 const selected =
new Set();
202 for (
const entry of forcedVisible)
203 selected.add(entry.action);
204 for (
const entry of candidates) {
205 if (usedWidth + entry.width <= budget) {
206 selected.add(entry.action);
207 usedWidth += entry.width;
213 for (
const action of searchActions) {
214 if (!action || !action.visible)
216 if (action.overflowPolicy === MD.AppBarAction.AlwaysOverflow || (action.overflowPolicy === MD.AppBarAction.AutoOverflow && !selected.has(action))) {
217 overflow.push(action);
219 visible.push(action);
222 _visibleSearchActions = visible;
223 _searchOverflowActions = overflow;
227 function _scheduleSearchReflow() {
228 _reflowSearchActions();
229 Qt.callLater(() => control._reflowSearchActions());
237 function forceSearchFocus() {
239 _searchFieldItem.forceActiveFocus();
247 onSearchActionsChanged: _scheduleSearchReflow()
248 onSearchNavigationActionChanged: _scheduleSearchReflow()
249 on_CapsuleWidthChanged: _scheduleSearchReflow()
252 Qt.callLater(() => control.forceSearchFocus());
255 Component.onCompleted: _scheduleSearchReflow()
258 id: defaultSearchAction
263 onTriggered: control.activated()
266 centerContent: Component {
270 readonly
property real physicalLeadingWidth: control.layoutMirrored ? control.trailingWidth : control.leadingWidth
271 readonly
property real physicalTrailingWidth: control.layoutMirrored ? control.leadingWidth : control.trailingWidth
272 readonly
property real regionLeft: physicalLeadingWidth + MD.Tokens.appBar.searchOuterFieldMargin
273 readonly
property real regionRight: width - physicalTrailingWidth - MD.Tokens.appBar.searchOuterFieldMargin
274 readonly
property real availableWidth: Math.max(0, regionRight - regionLeft)
275 readonly
property real desiredWidth: availableWidth <= MD.Tokens.appBar.searchAdaptiveBreakpoint ? availableWidth : Math.max(MD.Tokens.appBar.searchAdaptiveBreakpoint, availableWidth * MD.Tokens.appBar.searchAdaptiveWidthFraction)
276 readonly
property real capsuleX: Math.max(regionLeft, Math.min((width - desiredWidth) / 2, regionRight - desiredWidth))
280 property:
"_capsuleWidth"
286 objectName:
"searchCapsule"
288 x: searchArea.capsuleX
289 y: (control.collapsedHeight - height) / 2
290 width: Math.max(0, Math.min(searchArea.availableWidth, searchArea.desiredWidth))
291 height: MD.
Tokens.appBar.searchContainerHeight
292 topLeftRadius: UiMetrics.resolveShapeRadius(MD.
Tokens.shape.cornerFull.topLeft,
294 topRightRadius: UiMetrics.resolveShapeRadius(MD.
Tokens.shape.cornerFull.topRight,
296 bottomLeftRadius: UiMetrics.resolveShapeRadius(
297 MD.
Tokens.shape.cornerFull.bottomLeft, width, height)
298 bottomRightRadius: UiMetrics.resolveShapeRadius(
299 MD.
Tokens.shape.cornerFull.bottomRight, width, height)
300 color: control.lifted ? control.scrolledSearchContainerColor : control.searchContainerColor
305 duration: MotionAnimation.expressiveFastEffectsDuration
306 easing.type: Easing.BezierSpline
307 easing.bezierCurve: MotionAnimation.expressiveFastEffectsCurve
313 objectName:
"searchLauncher"
316 text: control.text.length > 0 ? control.text : control.placeholderText
319 focusPolicy: Qt.StrongFocus
322 Accessible.role: Accessible.
Button
323 Accessible.name: text
325 onClicked: control.activated()
326 Keys.onPressed: event => {
327 if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter || event.key === Qt.Key_Space) {
329 event.accepted =
true;
334 MD.AppBarActionDelegate {
335 id: searchNavigationButton
336 objectName:
"searchNavigationActionButton"
338 anchors.left: parent.left
339 anchors.verticalCenter: parent.verticalCenter
340 actionData: control.searchNavigationAction || defaultSearchAction
341 contentColor: control.searchContentColor
342 visible: control.searchNavigationAction !== null && control.searchNavigationAction.visible
343 accessibilityIgnored: control.mode ===
SearchAppBar.Launcher
344 && control.searchNavigationAction === defaultSearchAction
349 id: searchTrailingRow
350 objectName:
"searchTrailingActions"
352 anchors.right: parent.right
353 anchors.verticalCenter: parent.verticalCenter
354 spacing: MD.Tokens.appBar.searchTrailingActionsGap
358 id: searchActionRepeater
359 Component.onCompleted: {
360 control._searchActionRepeater = searchActionRepeater;
361 control._scheduleSearchReflow();
363 Component.onDestruction: {
364 if (control._searchActionRepeater === searchActionRepeater)
365 control._searchActionRepeater = null;
368 model: control.searchActions
370 delegate: MD.AppBarActionDelegate {
371 id: searchActionDelegate
372 required
property var modelData
374 actionData: modelData
375 contentColor: control.searchContentColor
376 visible: control._visibleSearchActions.indexOf(actionData) >= 0
377 onImplicitWidthChanged: control._scheduleSearchReflow()
380 target: searchActionDelegate.modelData
381 function onVisibleChanged() {
382 control._scheduleSearchReflow();
384 function onPriorityChanged() {
385 control._scheduleSearchReflow();
387 function onOverflowPolicyChanged() {
388 control._scheduleSearchReflow();
390 function onPresentationChanged() {
391 control._scheduleSearchReflow();
393 function onTextChanged() {
394 control._scheduleSearchReflow();
401 readonly
property real physicalStartWidth: control.layoutMirrored ? searchTrailingRow.width : searchNavigationButton.width
402 readonly
property real physicalEndWidth: control.layoutMirrored ? searchNavigationButton.width : searchTrailingRow.width
403 readonly
property real textLeft: physicalStartWidth + (searchNavigationButton.visible ? MD.Tokens.appBar.searchContainedLeadingSpace : MD.Tokens.appBar.searchContainedNoActionsLeadingSpace)
404 readonly property real textRight: width - physicalEndWidth - (searchTrailingRow.width > 0 ? MD.
Tokens.appBar.searchContainedTrailingSpace : MD.
Tokens.appBar.searchContainedNoActionsTrailingSpace)
408 objectName:
"searchLauncherLabel"
412 width: Math.max(0, capsule.textRight - capsule.textLeft)
413 height: parent.height
414 text: control.text.length > 0 ? control.text : control.placeholderText
415 typescale: MD.
Tokens.typescale.bodyLarge
416 color: control.searchTextColor
417 opacity: control.text.length > 0 ? 1 : MD.
Tokens.appBar.disabledContentOpacity
418 horizontalAlignment: control._centeredText ? Text.AlignHCenter : control.layoutMirrored ? Text.AlignRight : Text.AlignLeft
419 verticalAlignment: Text.AlignVCenter
421 elide: Text.ElideRight
423 Accessible.ignored: true
428 Component.onCompleted: control._searchFieldItem = searchFieldProxy
429 Component.onDestruction: {
430 if (control._searchFieldItem === searchFieldProxy)
431 control._searchFieldItem = null;
433 objectName:
"searchField"
437 width: Math.max(0, capsule.textRight - capsule.textLeft)
438 height: parent.height
440 placeholderText: control.placeholderText
441 inputMethodHints: control.inputMethodHints
442 validator: control.validator
443 color: control.searchTextColor
444 placeholderTextColor: control.searchContentColor
445 selectionColor: control.MD.Style.primaryColor
446 selectedTextColor: control.MD.Style.onPrimaryColor
447 font.family: control.MD.Style.plainFontFamily
448 font.pixelSize: MD.Tokens.typescale.bodyLarge.fontSize
449 font.weight: MD.Tokens.typescale.bodyLarge.fontWeight
450 font.letterSpacing: MD.Tokens.typescale.bodyLarge.tracking
451 horizontalAlignment: control._centeredText ? Text.AlignHCenter : control.layoutMirrored ? Text.AlignRight : Text.AlignLeft
452 verticalAlignment: Text.AlignVCenter
457 focusPolicy: Qt.StrongFocus
461 Accessible.role: Accessible.EditableText
462 Accessible.name: control.placeholderText
463 Accessible.searchEdit:
true
465 onTextEdited: control.text = text
466 onAccepted: control.accepted()
471 gesturePolicy: TapHandler.ReleaseWithinBounds
472 onTapped: searchFieldProxy.forceActiveFocus()
Describes an action shown by an AppBar or SearchAppBar.
Material Design 3 design tokens.
Tokens(QObject *parent=nullptr)
Displays text using a selectable Material 3 type scale.
A Material 3 Expressive app bar containing an adaptive search field.