1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qlineedit.h"
5#include "qlineedit_p.h"
6
7#include "qvariant.h"
8#if QT_CONFIG(itemviews)
9#include "qabstractitemview.h"
10#endif
11#if QT_CONFIG(draganddrop)
12#include "qdrag.h"
13#endif
14#if QT_CONFIG(action)
15# include "qwidgetaction.h"
16#endif
17#include "qclipboard.h"
18#if QT_CONFIG(accessibility)
19#include "qaccessible.h"
20#endif
21#ifndef QT_NO_IM
22#include "qinputmethod.h"
23#include "qlist.h"
24#endif
25#include <qpainter.h>
26#if QT_CONFIG(animation)
27#include <qpropertyanimation.h>
28#endif
29#include <qstylehints.h>
30#include <qvalidator.h>
31
32QT_BEGIN_NAMESPACE
33
34const int QLineEditPrivate::verticalMargin(1);
35const int QLineEditPrivate::horizontalMargin(2);
36
37// Needs to be kept in sync with QLineEdit::paintEvent
38QRect QLineEditPrivate::adjustedControlRect(const QRect &rect) const
39{
40 QRect widgetRect = !rect.isEmpty() ? rect : q_func()->rect();
41 QRect cr = adjustedContentsRect();
42 int cix = cr.x() - hscroll + horizontalMargin;
43 return widgetRect.translated(p: QPoint(cix, vscroll - control->ascent() + q_func()->fontMetrics().ascent()));
44}
45
46int QLineEditPrivate::xToPos(int x, QTextLine::CursorPosition betweenOrOn) const
47{
48 QRect cr = adjustedContentsRect();
49 x-= cr.x() - hscroll + horizontalMargin;
50 return control->xToPos(x, betweenOrOn);
51}
52
53QString QLineEditPrivate::textBeforeCursor(int curPos) const
54{
55 const QString &text = control->text();
56 return text.mid(position: 0, n: curPos);
57}
58
59QString QLineEditPrivate::textAfterCursor(int curPos) const
60{
61 const QString &text = control->text();
62 return text.mid(position: curPos);
63}
64
65bool QLineEditPrivate::inSelection(int x) const
66{
67 x -= adjustedContentsRect().x() - hscroll + horizontalMargin;
68 return control->inSelection(x);
69}
70
71QRect QLineEditPrivate::cursorRect() const
72{
73 return adjustedControlRect(rect: control->cursorRect());
74}
75
76#if QT_CONFIG(completer)
77
78void QLineEditPrivate::_q_completionHighlighted(const QString &newText)
79{
80 Q_Q(QLineEdit);
81 if (control->completer()->completionMode() != QCompleter::InlineCompletion) {
82 q->setText(newText);
83 } else {
84 int c = control->cursor();
85 QString text = control->text();
86 q->setText(QStringView{text}.left(n: c) + QStringView{newText}.mid(pos: c));
87 control->moveCursor(pos: control->end(), mark: false);
88#ifndef Q_OS_ANDROID
89 const bool mark = true;
90#else
91 const bool mark = (imHints & Qt::ImhNoPredictiveText);
92#endif
93 control->moveCursor(pos: c, mark);
94 }
95}
96
97#endif // QT_CONFIG(completer)
98
99void QLineEditPrivate::_q_handleWindowActivate()
100{
101 Q_Q(QLineEdit);
102 if (!q->hasFocus() && control->hasSelectedText())
103 control->deselect();
104}
105
106void QLineEditPrivate::_q_textEdited(const QString &text)
107{
108 Q_Q(QLineEdit);
109 edited = true;
110 emit q->textEdited(text);
111#if QT_CONFIG(completer)
112 if (control->completer()
113 && control->completer()->completionMode() != QCompleter::InlineCompletion)
114 control->complete(key: -1); // update the popup on cut/paste/del
115#endif
116}
117
118void QLineEditPrivate::_q_cursorPositionChanged(int from, int to)
119{
120 Q_Q(QLineEdit);
121 q->update();
122 emit q->cursorPositionChanged(from, to);
123}
124
125#ifdef QT_KEYPAD_NAVIGATION
126void QLineEditPrivate::_q_editFocusChange(bool e)
127{
128 Q_Q(QLineEdit);
129 q->setEditFocus(e);
130}
131#endif
132
133void QLineEditPrivate::_q_selectionChanged()
134{
135 Q_Q(QLineEdit);
136 if (control->preeditAreaText().isEmpty()) {
137 QStyleOptionFrame opt;
138 q->initStyleOption(option: &opt);
139 bool showCursor = control->hasSelectedText() ?
140 q->style()->styleHint(stylehint: QStyle::SH_BlinkCursorWhenTextSelected, opt: &opt, widget: q):
141 q->hasFocus();
142 setCursorVisible(showCursor);
143 }
144
145 emit q->selectionChanged();
146#if QT_CONFIG(accessibility)
147 QAccessibleTextSelectionEvent ev(q, control->selectionStart(), control->selectionEnd());
148 ev.setCursorPosition(control->cursorPosition());
149 QAccessible::updateAccessibility(event: &ev);
150#endif
151}
152
153void QLineEditPrivate::_q_updateNeeded(const QRect &rect)
154{
155 q_func()->update(adjustedControlRect(rect));
156}
157
158void QLineEditPrivate::init(const QString& txt)
159{
160 Q_Q(QLineEdit);
161 control = new QWidgetLineControl(txt);
162 control->setParent(q);
163 control->setFont(q->font());
164 QObject::connect(sender: control, SIGNAL(textChanged(QString)),
165 receiver: q, SIGNAL(textChanged(QString)));
166 QObject::connect(sender: control, SIGNAL(textEdited(QString)),
167 receiver: q, SLOT(_q_textEdited(QString)));
168 QObject::connect(sender: control, SIGNAL(cursorPositionChanged(int,int)),
169 receiver: q, SLOT(_q_cursorPositionChanged(int,int)));
170 QObject::connect(sender: control, SIGNAL(selectionChanged()),
171 receiver: q, SLOT(_q_selectionChanged()));
172 QObject::connect(sender: control, SIGNAL(editingFinished()),
173 receiver: q, SLOT(_q_controlEditingFinished()));
174#ifdef QT_KEYPAD_NAVIGATION
175 QObject::connect(control, SIGNAL(editFocusChange(bool)),
176 q, SLOT(_q_editFocusChange(bool)));
177#endif
178 QObject::connect(sender: control, SIGNAL(cursorPositionChanged(int,int)),
179 receiver: q, SLOT(updateMicroFocus()));
180
181 QObject::connect(sender: control, SIGNAL(textChanged(QString)),
182 receiver: q, SLOT(updateMicroFocus()));
183
184 QObject::connect(sender: control, SIGNAL(updateMicroFocus()),
185 receiver: q, SLOT(updateMicroFocus()));
186
187 // for now, going completely overboard with updates.
188 QObject::connect(sender: control, SIGNAL(selectionChanged()),
189 receiver: q, SLOT(update()));
190
191 QObject::connect(sender: control, SIGNAL(selectionChanged()),
192 receiver: q, SLOT(updateMicroFocus()));
193
194 QObject::connect(sender: control, SIGNAL(displayTextChanged(QString)),
195 receiver: q, SLOT(update()));
196
197 QObject::connect(sender: control, SIGNAL(updateNeeded(QRect)),
198 receiver: q, SLOT(_q_updateNeeded(QRect)));
199 QObject::connect(sender: control, SIGNAL(inputRejected()), receiver: q, SIGNAL(inputRejected()));
200
201 QStyleOptionFrame opt;
202 q->initStyleOption(option: &opt);
203 control->setPasswordCharacter(char16_t(q->style()->styleHint(stylehint: QStyle::SH_LineEdit_PasswordCharacter, opt: &opt, widget: q)));
204 control->setPasswordMaskDelay(q->style()->styleHint(stylehint: QStyle::SH_LineEdit_PasswordMaskDelay, opt: &opt, widget: q));
205#ifndef QT_NO_CURSOR
206 q->setCursor(Qt::IBeamCursor);
207#endif
208 q->setFocusPolicy(Qt::StrongFocus);
209 q->setAttribute(Qt::WA_InputMethodEnabled);
210 // Specifies that this widget can use more, but is able to survive on
211 // less, horizontal space; and is fixed vertically.
212 q->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed, QSizePolicy::LineEdit));
213 q->setBackgroundRole(QPalette::Base);
214 q->setAttribute(Qt::WA_KeyCompression);
215 q->setMouseTracking(true);
216 q->setAcceptDrops(true);
217
218 q->setAttribute(Qt::WA_MacShowFocusRect);
219
220 initMouseYThreshold();
221}
222
223void QLineEditPrivate::initMouseYThreshold()
224{
225 mouseYThreshold = QGuiApplication::styleHints()->mouseQuickSelectionThreshold();
226}
227
228QRect QLineEditPrivate::adjustedContentsRect() const
229{
230 Q_Q(const QLineEdit);
231 QStyleOptionFrame opt;
232 q->initStyleOption(option: &opt);
233 QRect r = q->style()->subElementRect(subElement: QStyle::SE_LineEditContents, option: &opt, widget: q);
234 r = r.marginsRemoved(margins: effectiveTextMargins());
235 return r;
236}
237
238void QLineEditPrivate::setCursorVisible(bool visible)
239{
240 Q_Q(QLineEdit);
241 if ((bool)cursorVisible == visible)
242 return;
243 cursorVisible = visible;
244 if (control->inputMask().isEmpty())
245 q->update(cursorRect());
246 else
247 q->update();
248}
249
250void QLineEditPrivate::setText(const QString& text)
251{
252 edited = true;
253 control->setText(text);
254}
255
256void QLineEditPrivate::updatePasswordEchoEditing(bool editing)
257{
258 Q_Q(QLineEdit);
259 control->updatePasswordEchoEditing(editing);
260 q->setAttribute(Qt::WA_InputMethodEnabled, on: shouldEnableInputMethod());
261}
262
263void QLineEditPrivate::resetInputMethod()
264{
265 Q_Q(QLineEdit);
266 if (q->hasFocus() && qApp) {
267 QGuiApplication::inputMethod()->reset();
268 }
269}
270
271/*!
272 This function is not intended as polymorphic usage. Just a shared code
273 fragment that calls QInputMethod::invokeAction for this
274 class.
275*/
276bool QLineEditPrivate::sendMouseEventToInputContext( QMouseEvent *e )
277{
278#if !defined QT_NO_IM
279 if ( control->composeMode() ) {
280 int tmp_cursor = xToPos(x: e->position().toPoint().x());
281 int mousePos = tmp_cursor - control->cursor();
282 if ( mousePos < 0 || mousePos > control->preeditAreaText().size() )
283 mousePos = -1;
284
285 if (mousePos >= 0) {
286 if (e->type() == QEvent::MouseButtonRelease)
287 QGuiApplication::inputMethod()->invokeAction(a: QInputMethod::Click, cursorPosition: mousePos);
288
289 return true;
290 }
291 }
292#else
293 Q_UNUSED(e);
294#endif
295
296 return false;
297}
298
299#if QT_CONFIG(draganddrop)
300void QLineEditPrivate::drag()
301{
302 Q_Q(QLineEdit);
303 dndTimer.stop();
304 QMimeData *data = new QMimeData;
305 data->setText(control->selectedText());
306 QDrag *drag = new QDrag(q);
307 drag->setMimeData(data);
308 Qt::DropAction action = drag->exec(supportedActions: Qt::CopyAction);
309 if (action == Qt::MoveAction && !control->isReadOnly() && drag->target() != q)
310 control->removeSelection();
311}
312#endif // QT_CONFIG(draganddrop)
313
314
315#if QT_CONFIG(toolbutton)
316QLineEditIconButton::QLineEditIconButton(QWidget *parent)
317 : QToolButton(parent)
318 , m_opacity(0)
319{
320 setFocusPolicy(Qt::NoFocus);
321}
322
323QLineEditPrivate *QLineEditIconButton::lineEditPrivate() const
324{
325 QLineEdit *le = qobject_cast<QLineEdit *>(object: parentWidget());
326 return le ? static_cast<QLineEditPrivate *>(qt_widget_private(widget: le)) : nullptr;
327}
328
329void QLineEditIconButton::paintEvent(QPaintEvent *)
330{
331 QPainter painter(this);
332 QIcon::Mode state = QIcon::Disabled;
333 if (isEnabled())
334 state = isDown() ? QIcon::Active : QIcon::Normal;
335 const QLineEditPrivate *lep = lineEditPrivate();
336 const int iconWidth = lep ? lep->sideWidgetParameters().iconSize : 16;
337 const QSize iconSize(iconWidth, iconWidth);
338 const QPixmap iconPixmap = icon().pixmap(size: iconSize, devicePixelRatio: devicePixelRatio(), mode: state, state: QIcon::Off);
339 QRect pixmapRect = QRect(QPoint(0, 0), iconSize);
340 pixmapRect.moveCenter(p: rect().center());
341 painter.setOpacity(m_opacity);
342 painter.drawPixmap(r: pixmapRect, pm: iconPixmap);
343}
344
345void QLineEditIconButton::actionEvent(QActionEvent *e)
346{
347 switch (e->type()) {
348 case QEvent::ActionChanged: {
349 const auto *action = e->action();
350 if (isVisibleTo(parentWidget()) != action->isVisible()) {
351 setVisible(action->isVisible());
352 if (QLineEditPrivate *lep = lineEditPrivate())
353 lep->positionSideWidgets();
354 }
355 }
356 break;
357 default:
358 break;
359 }
360 QToolButton::actionEvent(e);
361}
362
363void QLineEditIconButton::setOpacity(qreal value)
364{
365 if (!qFuzzyCompare(p1: m_opacity, p2: value)) {
366 m_opacity = value;
367 updateCursor();
368 update();
369 }
370}
371
372#if QT_CONFIG(animation)
373bool QLineEditIconButton::shouldHideWithText() const
374{
375 return m_hideWithText;
376}
377
378void QLineEditIconButton::setHideWithText(bool hide)
379{
380 m_hideWithText = hide;
381}
382
383void QLineEditIconButton::onAnimationFinished()
384{
385 if (shouldHideWithText() && isVisible() && m_fadingOut) {
386 hide();
387 m_fadingOut = false;
388
389 // Invalidate previous geometry to take into account new size of side widgets
390 if (auto le = lineEditPrivate())
391 le->updateGeometry_helper(forceUpdate: true);
392 }
393}
394
395void QLineEditIconButton::animateShow(bool visible)
396{
397 m_fadingOut = !visible;
398
399 if (shouldHideWithText() && !isVisible()) {
400 show();
401
402 // Invalidate previous geometry to take into account new size of side widgets
403 if (auto le = lineEditPrivate())
404 le->updateGeometry_helper(forceUpdate: true);
405 }
406
407 startOpacityAnimation(endValue: visible ? 1.0 : 0.0);
408}
409
410void QLineEditIconButton::startOpacityAnimation(qreal endValue)
411{
412 QPropertyAnimation *animation = new QPropertyAnimation(this, QByteArrayLiteral("opacity"));
413 connect(sender: animation, signal: &QPropertyAnimation::finished, context: this, slot: &QLineEditIconButton::onAnimationFinished);
414
415 animation->setDuration(160);
416 animation->setEndValue(endValue);
417 animation->start(policy: QAbstractAnimation::DeleteWhenStopped);
418}
419#endif
420
421void QLineEditIconButton::updateCursor()
422{
423#ifndef QT_NO_CURSOR
424 setCursor(qFuzzyCompare(p1: m_opacity, p2: qreal(1.0)) || !parentWidget() ? QCursor(Qt::ArrowCursor) : parentWidget()->cursor());
425#endif
426}
427#endif // QT_CONFIG(toolbutton)
428
429#if QT_CONFIG(animation) && QT_CONFIG(toolbutton)
430static void displayWidgets(const QLineEditPrivate::SideWidgetEntryList &widgets, bool display)
431{
432 for (const auto &e : widgets) {
433 if (e.flags & QLineEditPrivate::SideWidgetFadeInWithText)
434 static_cast<QLineEditIconButton *>(e.widget)->animateShow(visible: display);
435 }
436}
437#endif
438
439void QLineEditPrivate::_q_textChanged(const QString &text)
440{
441 if (hasSideWidgets()) {
442 const int newTextSize = text.size();
443 if (!newTextSize || !lastTextSize) {
444 lastTextSize = newTextSize;
445#if QT_CONFIG(animation) && QT_CONFIG(toolbutton)
446 const bool display = newTextSize > 0;
447 displayWidgets(widgets: leadingSideWidgets, display);
448 displayWidgets(widgets: trailingSideWidgets, display);
449#endif
450 }
451 }
452}
453
454void QLineEditPrivate::_q_clearButtonClicked()
455{
456 Q_Q(QLineEdit);
457 if (!q->text().isEmpty()) {
458 q->clear();
459 _q_textEdited(text: QString());
460 }
461}
462
463void QLineEditPrivate::_q_controlEditingFinished()
464{
465 Q_Q(QLineEdit);
466 edited = false;
467 emit q->returnPressed();
468 emit q->editingFinished();
469}
470
471QLineEditPrivate::SideWidgetParameters QLineEditPrivate::sideWidgetParameters() const
472{
473 Q_Q(const QLineEdit);
474 SideWidgetParameters result;
475 result.iconSize = q->style()->pixelMetric(metric: QStyle::PM_LineEditIconSize, option: nullptr, widget: q);
476 result.margin = q->style()->pixelMetric(metric: QStyle::PM_LineEditIconMargin, option: nullptr, widget: q);
477 result.widgetWidth = result.iconSize + 6;
478 result.widgetHeight = result.iconSize + 2;
479 return result;
480}
481
482QIcon QLineEditPrivate::clearButtonIcon() const
483{
484 Q_Q(const QLineEdit);
485 QStyleOptionFrame styleOption;
486 q->initStyleOption(option: &styleOption);
487 return q->style()->standardIcon(standardIcon: QStyle::SP_LineEditClearButton, option: &styleOption, widget: q);
488}
489
490void QLineEditPrivate::setClearButtonEnabled(bool enabled)
491{
492#if QT_CONFIG(action)
493 for (const SideWidgetEntry &e : trailingSideWidgets) {
494 if (e.flags & SideWidgetClearButton) {
495 e.action->setEnabled(enabled);
496 break;
497 }
498 }
499#else
500 Q_UNUSED(enabled);
501#endif
502}
503
504void QLineEditPrivate::positionSideWidgets()
505{
506 Q_Q(QLineEdit);
507 if (hasSideWidgets()) {
508 const QRect contentRect = q->rect();
509 const SideWidgetParameters p = sideWidgetParameters();
510 const int delta = p.margin + p.widgetWidth;
511 QRect widgetGeometry(QPoint(p.margin, (contentRect.height() - p.widgetHeight) / 2),
512 QSize(p.widgetWidth, p.widgetHeight));
513 for (const SideWidgetEntry &e : leftSideWidgetList()) {
514 e.widget->setGeometry(widgetGeometry);
515#if QT_CONFIG(action)
516 if (e.action->isVisible())
517 widgetGeometry.moveLeft(pos: widgetGeometry.left() + delta);
518#else
519 Q_UNUSED(delta);
520#endif
521 }
522 widgetGeometry.moveLeft(pos: contentRect.width() - p.widgetWidth - p.margin);
523 for (const SideWidgetEntry &e : rightSideWidgetList()) {
524 e.widget->setGeometry(widgetGeometry);
525#if QT_CONFIG(action)
526 if (e.action->isVisible())
527 widgetGeometry.moveLeft(pos: widgetGeometry.left() - delta);
528#endif
529 }
530 }
531}
532
533#if QT_CONFIG(action)
534QLineEditPrivate::SideWidgetLocation QLineEditPrivate::findSideWidget(const QAction *a) const
535{
536 int i = 0;
537 for (const auto &e : leadingSideWidgets) {
538 if (a == e.action)
539 return {.position: QLineEdit::LeadingPosition, .index: i};
540 ++i;
541 }
542 i = 0;
543 for (const auto &e : trailingSideWidgets) {
544 if (a == e.action)
545 return {.position: QLineEdit::TrailingPosition, .index: i};
546 ++i;
547 }
548 return {.position: QLineEdit::LeadingPosition, .index: -1};
549}
550
551QWidget *QLineEditPrivate::addAction(QAction *newAction, QAction *before, QLineEdit::ActionPosition position, int flags)
552{
553 Q_Q(QLineEdit);
554 if (!newAction)
555 return nullptr;
556 if (!hasSideWidgets()) { // initial setup.
557 QObject::connect(sender: q, SIGNAL(textChanged(QString)), receiver: q, SLOT(_q_textChanged(QString)));
558 lastTextSize = q->text().size();
559 }
560 QWidget *w = nullptr;
561 // Store flags about QWidgetAction here since removeAction() may be called from ~QAction,
562 // in which a qobject_cast<> no longer works.
563 if (QWidgetAction *widgetAction = qobject_cast<QWidgetAction *>(object: newAction)) {
564 if ((w = widgetAction->requestWidget(parent: q)))
565 flags |= SideWidgetCreatedByWidgetAction;
566 }
567 if (!w) {
568#if QT_CONFIG(toolbutton)
569 QLineEditIconButton *toolButton = new QLineEditIconButton(q);
570 toolButton->setIcon(newAction->icon());
571 toolButton->setOpacity(lastTextSize > 0 || !(flags & SideWidgetFadeInWithText) ? 1 : 0);
572 if (flags & SideWidgetClearButton) {
573 QObject::connect(sender: toolButton, SIGNAL(clicked()), receiver: q, SLOT(_q_clearButtonClicked()));
574
575#if QT_CONFIG(animation)
576 // The clear button is handled only by this widget. The button should be really
577 // shown/hidden in order to calculate size hints correctly.
578 toolButton->setHideWithText(true);
579#endif
580 }
581 toolButton->setDefaultAction(newAction);
582 w = toolButton;
583#else
584 return nullptr;
585#endif
586 }
587
588 // QTBUG-59957: clear button should be the leftmost action.
589 if (!before && !(flags & SideWidgetClearButton) && position == QLineEdit::TrailingPosition) {
590 for (const SideWidgetEntry &e : trailingSideWidgets) {
591 if (e.flags & SideWidgetClearButton) {
592 before = e.action;
593 break;
594 }
595 }
596 }
597
598 // If there is a 'before' action, it takes preference
599
600 // There's a bug in GHS compiler that causes internal error on the following code.
601 // The affected GHS compiler versions are 2016.5.4 and 2017.1. GHS internal reference
602 // to track the progress of this issue is TOOLS-26637.
603 // This temporary workaround allows to compile with GHS toolchain and should be
604 // removed when GHS provides a patch to fix the compiler issue.
605
606#if defined(Q_CC_GHS)
607 const SideWidgetLocation loc = {position, -1};
608 const auto location = before ? findSideWidget(before) : loc;
609#else
610 const auto location = before ? findSideWidget(a: before) : SideWidgetLocation{.position: position, .index: -1};
611#endif
612
613 SideWidgetEntryList &list = location.position == QLineEdit::TrailingPosition ? trailingSideWidgets : leadingSideWidgets;
614 list.insert(position: location.isValid() ? list.begin() + location.index : list.end(),
615 x: SideWidgetEntry(w, newAction, flags));
616 positionSideWidgets();
617 w->show();
618 return w;
619}
620
621void QLineEditPrivate::removeAction(QAction *action)
622{
623 Q_Q(QLineEdit);
624 const auto location = findSideWidget(a: action);
625 if (!location.isValid())
626 return;
627 SideWidgetEntryList &list = location.position == QLineEdit::TrailingPosition ? trailingSideWidgets : leadingSideWidgets;
628 SideWidgetEntry entry = list[location.index];
629 list.erase(position: list.begin() + location.index);
630 if (entry.flags & SideWidgetCreatedByWidgetAction)
631 static_cast<QWidgetAction *>(entry.action)->releaseWidget(widget: entry.widget);
632 else
633 delete entry.widget;
634 positionSideWidgets();
635 if (!hasSideWidgets()) // Last widget, remove connection
636 QObject::disconnect(sender: q, SIGNAL(textChanged(QString)), receiver: q, SLOT(_q_textChanged(QString)));
637 q->update();
638}
639#endif // QT_CONFIG(action)
640
641static int effectiveTextMargin(int defaultMargin, const QLineEditPrivate::SideWidgetEntryList &widgets,
642 const QLineEditPrivate::SideWidgetParameters &parameters)
643{
644 if (widgets.empty())
645 return defaultMargin;
646
647 const auto visibleSideWidgetCount = std::count_if(first: widgets.begin(), last: widgets.end(),
648 pred: [](const QLineEditPrivate::SideWidgetEntry &e) {
649#if QT_CONFIG(toolbutton) && QT_CONFIG(animation)
650 // a button that's fading out doesn't get any space
651 if (auto* iconButton = qobject_cast<QLineEditIconButton*>(object: e.widget))
652 return iconButton->needsSpace();
653
654#endif
655 return e.widget->isVisibleTo(e.widget->parentWidget());
656 });
657
658 return defaultMargin + (parameters.margin + parameters.widgetWidth) * visibleSideWidgetCount;
659}
660
661QMargins QLineEditPrivate::effectiveTextMargins() const
662{
663 return {effectiveTextMargin(defaultMargin: textMargins.left(), widgets: leftSideWidgetList(), parameters: sideWidgetParameters()),
664 textMargins.top(),
665 effectiveTextMargin(defaultMargin: textMargins.right(), widgets: rightSideWidgetList(), parameters: sideWidgetParameters()),
666 textMargins.bottom()};
667}
668
669
670QT_END_NAMESPACE
671
672#include "moc_qlineedit_p.cpp"
673

source code of qtbase/src/widgets/widgets/qlineedit_p.cpp