Kirigami2

toolbarlayout.cpp
1/*
2 * SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5 */
6
7#include "toolbarlayout.h"
8
9#include <cmath>
10#include <unordered_map>
11
12#include <QDeadlineTimer>
13#include <QElapsedTimer>
14#include <QQmlComponent>
15#include <QTimer>
16
17#include "loggingcategory.h"
18#include "toolbarlayoutdelegate.h"
19
20ToolBarLayoutAttached::ToolBarLayoutAttached(QObject *parent)
21 : QObject(parent)
22{
23}
24
26{
27 return m_action;
28}
29
30void ToolBarLayoutAttached::setAction(QObject *action)
31{
32 m_action = action;
33}
34
35class ToolBarLayoutPrivate
36{
37 ToolBarLayout *const q;
38
39public:
40 ToolBarLayoutPrivate(ToolBarLayout *qq)
41 : q(qq)
42 {
43 }
44 ~ToolBarLayoutPrivate()
45 {
46 if (moreButtonIncubator) {
47 moreButtonIncubator->clear();
48 delete moreButtonIncubator;
49 }
50 }
51
52 void calculateImplicitSize();
53 void performLayout();
54 QList<ToolBarLayoutDelegate *> createDelegates();
55 ToolBarLayoutDelegate *createDelegate(QObject *action);
56 qreal layoutStart(qreal layoutWidth);
57 void maybeHideDelegate(int index, qreal &currentWidth, qreal totalWidth);
58
59 QList<QObject *> actions;
60 ToolBarLayout::ActionsProperty actionsProperty;
61 QList<QObject *> hiddenActions;
62 QQmlComponent *fullDelegate = nullptr;
63 QQmlComponent *iconDelegate = nullptr;
64 QQmlComponent *separatorDelegate = nullptr;
65 QQmlComponent *moreButton = nullptr;
66 qreal spacing = 0.0;
67 Qt::Alignment alignment = Qt::AlignLeft;
68 qreal visibleActionsWidth = 0.0;
69 qreal visibleWidth = 0.0;
70 Qt::LayoutDirection layoutDirection = Qt::LeftToRight;
72
73 bool completed = false;
74 bool actionsChanged = false;
75 bool implicitSizeValid = false;
76
77 std::unordered_map<QObject *, std::unique_ptr<ToolBarLayoutDelegate>> delegates;
78 QList<ToolBarLayoutDelegate *> sortedDelegates;
79 QQuickItem *moreButtonInstance = nullptr;
80 ToolBarDelegateIncubator *moreButtonIncubator = nullptr;
81 bool shouldShowMoreButton = false;
82 int firstHiddenIndex = -1;
83
84 QList<QObject *> removedActions;
85 QTimer *removalTimer = nullptr;
86
87 QElapsedTimer performanceTimer;
88
89 static void appendAction(ToolBarLayout::ActionsProperty *list, QObject *action);
90 static qsizetype actionCount(ToolBarLayout::ActionsProperty *list);
91 static QObject *action(ToolBarLayout::ActionsProperty *list, qsizetype index);
92 static void clearActions(ToolBarLayout::ActionsProperty *list);
93};
94
95ToolBarLayout::ToolBarLayout(QQuickItem *parent)
96 : QQuickItem(parent)
97 , d(std::make_unique<ToolBarLayoutPrivate>(this))
98{
99 d->actionsProperty = ActionsProperty(this,
100 this,
101 ToolBarLayoutPrivate::appendAction,
102 ToolBarLayoutPrivate::actionCount,
103 ToolBarLayoutPrivate::action,
104 ToolBarLayoutPrivate::clearActions);
105
106 // To prevent multiple assignments to actions from constantly recreating
107 // delegates, we cache the delegates and only remove them once they are no
108 // longer being used. This timer is responsible for triggering that removal.
109 d->removalTimer = new QTimer{this};
110 d->removalTimer->setInterval(1000);
111 d->removalTimer->setSingleShot(true);
112 connect(d->removalTimer, &QTimer::timeout, this, [this]() {
113 for (auto action : std::as_const(d->removedActions)) {
114 if (!d->actions.contains(action)) {
115 d->delegates.erase(action);
116 }
117 }
118 d->removedActions.clear();
119 });
120}
121
122ToolBarLayout::~ToolBarLayout()
123{
124}
125
126ToolBarLayout::ActionsProperty ToolBarLayout::actionsProperty() const
127{
128 return d->actionsProperty;
129}
130
132{
133 if (action == nullptr) {
134 return;
135 }
136 d->actions.append(action);
137 d->actionsChanged = true;
138
139 connect(action, &QObject::destroyed, this, [this](QObject *action) {
140 auto itr = d->delegates.find(action);
141 if (itr != d->delegates.end()) {
142 d->delegates.erase(itr);
143 }
144
145 d->actions.removeOne(action);
146 d->actionsChanged = true;
147
148 relayout();
149 });
150
151 relayout();
152}
153
155{
156 auto itr = d->delegates.find(action);
157 if (itr != d->delegates.end()) {
158 itr->second->hide();
159 }
160
161 d->actions.removeOne(action);
162 d->removedActions.append(action);
163 d->removalTimer->start();
164 d->actionsChanged = true;
165
166 relayout();
167}
168
170{
171 for (auto action : std::as_const(d->actions)) {
172 auto itr = d->delegates.find(action);
173 if (itr != d->delegates.end()) {
174 itr->second->hide();
175 }
176 }
177
178 d->removedActions.append(d->actions);
179 d->actions.clear();
180 d->actionsChanged = true;
181
182 relayout();
183}
184
186{
187 return d->hiddenActions;
188}
189
191{
192 return d->fullDelegate;
193}
194
195void ToolBarLayout::setFullDelegate(QQmlComponent *newFullDelegate)
196{
197 if (newFullDelegate == d->fullDelegate) {
198 return;
199 }
200
201 d->fullDelegate = newFullDelegate;
202 d->delegates.clear();
203 relayout();
204 Q_EMIT fullDelegateChanged();
205}
206
208{
209 return d->iconDelegate;
210}
211
212void ToolBarLayout::setIconDelegate(QQmlComponent *newIconDelegate)
213{
214 if (newIconDelegate == d->iconDelegate) {
215 return;
216 }
217
218 d->iconDelegate = newIconDelegate;
219 d->delegates.clear();
220 relayout();
221 Q_EMIT iconDelegateChanged();
222}
223
225{
226 return d->separatorDelegate;
227}
228
229void ToolBarLayout::setSeparatorDelegate(QQmlComponent *newSeparatorDelegate)
230{
231 if (newSeparatorDelegate == d->separatorDelegate) {
232 return;
233 }
234
235 d->separatorDelegate = newSeparatorDelegate;
236 d->delegates.clear();
237 relayout();
238 Q_EMIT separatorDelegateChanged();
239}
240
242{
243 return d->moreButton;
244}
245
246void ToolBarLayout::setMoreButton(QQmlComponent *newMoreButton)
247{
248 if (newMoreButton == d->moreButton) {
249 return;
250 }
251
252 d->moreButton = newMoreButton;
253 if (d->moreButtonInstance) {
254 d->moreButtonInstance->deleteLater();
255 d->moreButtonInstance = nullptr;
256 }
257 relayout();
258 Q_EMIT moreButtonChanged();
259}
260
261qreal ToolBarLayout::spacing() const
262{
263 return d->spacing;
264}
265
266void ToolBarLayout::setSpacing(qreal newSpacing)
267{
268 if (newSpacing == d->spacing) {
269 return;
270 }
271
272 d->spacing = newSpacing;
273 relayout();
274 Q_EMIT spacingChanged();
275}
276
278{
279 return d->alignment;
280}
281
282void ToolBarLayout::setAlignment(Qt::Alignment newAlignment)
283{
284 if (newAlignment == d->alignment) {
285 return;
286 }
287
288 d->alignment = newAlignment;
289 relayout();
290 Q_EMIT alignmentChanged();
291}
292
293qreal ToolBarLayout::visibleWidth() const
294{
295 return d->visibleWidth;
296}
297
298qreal ToolBarLayout::minimumWidth() const
299{
300 return d->moreButtonInstance ? d->moreButtonInstance->width() : 0;
301}
302
304{
305 return d->layoutDirection;
306}
307
308void ToolBarLayout::setLayoutDirection(Qt::LayoutDirection &newLayoutDirection)
309{
310 if (newLayoutDirection == d->layoutDirection) {
311 return;
312 }
313
314 d->layoutDirection = newLayoutDirection;
315 relayout();
316 Q_EMIT layoutDirectionChanged();
317}
318
320{
321 return d->heightMode;
322}
323
324void ToolBarLayout::setHeightMode(HeightMode newHeightMode)
325{
326 if (newHeightMode == d->heightMode) {
327 return;
328 }
329
330 d->heightMode = newHeightMode;
331 relayout();
332 Q_EMIT heightModeChanged();
333}
334
336{
337 d->implicitSizeValid = false;
338 polish();
339}
340
341void ToolBarLayout::componentComplete()
342{
344 d->completed = true;
345 relayout();
346}
347
348void ToolBarLayout::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
349{
350 if (newGeometry != oldGeometry) {
351 relayout();
352 }
353 QQuickItem::geometryChange(newGeometry, oldGeometry);
354}
355
356void ToolBarLayout::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data)
357{
358 if (change == ItemVisibleHasChanged || change == ItemSceneChange) {
359 relayout();
360 }
361 QQuickItem::itemChange(change, data);
362}
363
364void ToolBarLayout::updatePolish()
365{
366 d->performLayout();
367}
368
369/**
370 * Calculate the implicit size for this layout.
371 *
372 * This is a separate step from performing the actual layout, because of a nasty
373 * little issue with Control, where it will unconditionally set the height of
374 * its contentItem, which means QQuickItem::heightValid() becomes useless. So
375 * instead, we first calculate our implicit size, ignoring any explicitly set
376 * item size. Then we follow that by performing the actual layouting, using the
377 * width and height retrieved from the item, as those will return the explicitly
378 * set width/height if set and the implicit size otherwise. Since control
379 * watches for implicit size changes, we end up with correct behaviour both when
380 * we get an explicit size set and when we're relying on implicit size
381 * calculation.
382 */
383void ToolBarLayoutPrivate::calculateImplicitSize()
384{
385 if (!completed) {
386 return;
387 }
388
389 if (!fullDelegate || !iconDelegate || !separatorDelegate || !moreButton) {
390 qCWarning(KirigamiLayoutsLog) << "ToolBarLayout: Unable to layout, required properties are not set";
391 return;
392 }
393
394 if (actions.isEmpty()) {
395 q->setImplicitSize(0., 0.);
396 return;
397 }
398
399 hiddenActions.clear();
400 firstHiddenIndex = -1;
401
402 sortedDelegates = createDelegates();
403
404 bool ready = std::all_of(delegates.cbegin(), delegates.cend(), [](const std::pair<QObject *const, std::unique_ptr<ToolBarLayoutDelegate>> &entry) {
405 return entry.second->isReady();
406 });
407 if (!ready || !moreButtonInstance) {
408 return;
409 }
410
411 qreal maxHeight = 0.0;
412 qreal maxWidth = 0.0;
413
414 // First, calculate the total width and maximum height of all delegates.
415 // This will be used to determine which actions to show, which ones to
416 // collapse to icon-only etc.
417 for (auto entry : std::as_const(sortedDelegates)) {
418 if (!entry->isActionVisible()) {
419 entry->hide();
420 continue;
421 }
422
423 if (entry->isHidden()) {
424 entry->hide();
425 hiddenActions.append(entry->action());
426 continue;
427 }
428
429 if (entry->isIconOnly()) {
430 entry->showIcon();
431 } else {
432 entry->showFull();
433 }
434
435 maxWidth += entry->width() + spacing;
436 maxHeight = std::max(maxHeight, entry->maxHeight());
437 }
438
439 // The last entry also gets spacing but shouldn't, so remove that.
440 maxWidth -= spacing;
441
442 visibleActionsWidth = 0.0;
443
444 q->setImplicitWidth(maxWidth);
445
446 if (maxWidth > q->width() - (hiddenActions.isEmpty() ? 0.0 : moreButtonInstance->width() + spacing)) {
447 // We have more items than fit into the view, so start hiding some.
448
449 qreal layoutWidth = q->width() - (moreButtonInstance->width() + spacing);
450 if (alignment & Qt::AlignHCenter) {
451 // When centering, we need to reserve space on both sides to make sure
452 // things are properly centered, otherwise we will be to the right of
453 // the center.
454 layoutWidth -= (moreButtonInstance->width() + spacing);
455 }
456
457 for (int i = 0; i < sortedDelegates.size(); ++i) {
458 auto delegate = sortedDelegates.at(i);
459
460 maybeHideDelegate(i, visibleActionsWidth, layoutWidth);
461
462 if (delegate->isVisible()) {
463 visibleActionsWidth += delegate->width() + spacing;
464 }
465 }
466 if (!qFuzzyIsNull(visibleActionsWidth)) {
467 // Like above, remove spacing on the last element that incorrectly gets spacing added.
468 visibleActionsWidth -= spacing;
469 }
470 } else {
471 visibleActionsWidth = maxWidth;
472 }
473
474 if (!hiddenActions.isEmpty()) {
475 maxHeight = std::max(maxHeight, moreButtonInstance->implicitHeight());
476 };
477
478 q->setImplicitHeight(maxHeight);
479
480 Q_EMIT q->hiddenActionsChanged();
481
482 implicitSizeValid = true;
483
484 q->polish();
485}
486
487void ToolBarLayoutPrivate::performLayout()
488{
489 if (!completed || actions.isEmpty()) {
490 return;
491 }
492
493 if (!implicitSizeValid) {
494 calculateImplicitSize();
495 }
496
497 if (sortedDelegates.isEmpty()) {
498 sortedDelegates = createDelegates();
499 }
500
501 bool ready = std::all_of(delegates.cbegin(), delegates.cend(), [](const std::pair<QObject *const, std::unique_ptr<ToolBarLayoutDelegate>> &entry) {
502 return entry.second->isReady();
503 });
504 if (!ready || !moreButtonInstance) {
505 return;
506 }
507
508 qreal width = q->width();
509 qreal height = q->height();
510
511 if (!hiddenActions.isEmpty()) {
512 if (layoutDirection == Qt::LeftToRight) {
513 moreButtonInstance->setX(width - moreButtonInstance->width());
514 } else {
515 moreButtonInstance->setX(0.0);
516 }
517
518 if (heightMode == ToolBarLayout::AlwaysFill) {
519 moreButtonInstance->setHeight(height);
520 } else if (heightMode == ToolBarLayout::ConstrainIfLarger) {
521 if (moreButtonInstance->implicitHeight() > height) {
522 moreButtonInstance->setHeight(height);
523 } else {
524 moreButtonInstance->resetHeight();
525 }
526 } else {
527 moreButtonInstance->resetHeight();
528 }
529
530 moreButtonInstance->setY(qRound((height - moreButtonInstance->height()) / 2.0));
531 shouldShowMoreButton = true;
532 moreButtonInstance->setVisible(true);
533 } else {
534 shouldShowMoreButton = false;
535 moreButtonInstance->setVisible(false);
536 }
537
538 qreal currentX = layoutStart(visibleActionsWidth);
539 for (auto entry : std::as_const(sortedDelegates)) {
540 if (!entry->isVisible()) {
541 continue;
542 }
543
544 if (heightMode == ToolBarLayout::AlwaysFill) {
545 entry->setHeight(height);
546 } else if (heightMode == ToolBarLayout::ConstrainIfLarger) {
547 if (entry->implicitHeight() > height) {
548 entry->setHeight(height);
549 } else {
550 entry->resetHeight();
551 }
552 } else {
553 entry->resetHeight();
554 }
555
556 qreal y = qRound((height - entry->height()) / 2.0);
557
558 if (layoutDirection == Qt::LeftToRight) {
559 entry->setPosition(currentX, y);
560 currentX += entry->width() + spacing;
561 } else {
562 entry->setPosition(currentX - entry->width(), y);
563 currentX -= entry->width() + spacing;
564 }
565
566 entry->show();
567 }
568
569 qreal newVisibleWidth = visibleActionsWidth;
570 if (moreButtonInstance->isVisible()) {
571 newVisibleWidth += moreButtonInstance->width() + (newVisibleWidth > 0.0 ? spacing : 0.0);
572 }
573 if (!qFuzzyCompare(newVisibleWidth, visibleWidth)) {
574 visibleWidth = newVisibleWidth;
575 Q_EMIT q->visibleWidthChanged();
576 }
577
578 if (actionsChanged) {
579 // Due to the way QQmlListProperty works, if we emit changed every time
580 // an action is added/removed, we end up emitting way too often. So
581 // instead only do it after everything else is done.
582 Q_EMIT q->actionsChanged();
583 actionsChanged = false;
584 }
585
586 sortedDelegates.clear();
587}
588
589QList<ToolBarLayoutDelegate *> ToolBarLayoutPrivate::createDelegates()
590{
591 QList<ToolBarLayoutDelegate *> result;
592 for (auto action : std::as_const(actions)) {
593 if (delegates.find(action) != delegates.end()) {
594 result.append(delegates.at(action).get());
595 } else if (action) {
596 auto delegate = std::unique_ptr<ToolBarLayoutDelegate>(createDelegate(action));
597 if (delegate) {
598 result.append(delegate.get());
599 delegates.emplace(action, std::move(delegate));
600 }
601 }
602 }
603
604 if (!moreButtonInstance && !moreButtonIncubator) {
605 moreButtonIncubator = new ToolBarDelegateIncubator(moreButton, qmlContext(moreButton));
606 moreButtonIncubator->setStateCallback([this](QQuickItem *item) {
607 item->setParentItem(q);
608 });
609 moreButtonIncubator->setCompletedCallback([this](ToolBarDelegateIncubator *incubator) {
610 moreButtonInstance = qobject_cast<QQuickItem *>(incubator->object());
611 moreButtonInstance->setVisible(false);
612
613 QObject::connect(moreButtonInstance, &QQuickItem::visibleChanged, q, [this]() {
614 moreButtonInstance->setVisible(shouldShowMoreButton);
615 });
616 QObject::connect(moreButtonInstance, &QQuickItem::widthChanged, q, &ToolBarLayout::minimumWidthChanged);
617 q->relayout();
618 Q_EMIT q->minimumWidthChanged();
619
620 QTimer::singleShot(0, q, [this]() {
621 delete moreButtonIncubator;
622 moreButtonIncubator = nullptr;
623 });
624 });
625 moreButtonIncubator->create();
626 }
627
628 return result;
629}
630
631ToolBarLayoutDelegate *ToolBarLayoutPrivate::createDelegate(QObject *action)
632{
633 QQmlComponent *fullComponent = nullptr;
634 auto displayComponent = action->property("displayComponent");
635 if (displayComponent.isValid()) {
636 fullComponent = displayComponent.value<QQmlComponent *>();
637 }
638
639 if (!fullComponent) {
640 fullComponent = fullDelegate;
641 }
642
643 auto separator = action->property("separator");
644 if (separator.isValid() && separator.toBool()) {
645 fullComponent = separatorDelegate;
646 }
647
648 auto result = new ToolBarLayoutDelegate(q);
649 result->setAction(action);
650 result->createItems(fullComponent, iconDelegate, [this, action](QQuickItem *newItem) {
651 newItem->setParentItem(q);
652 auto attached = static_cast<ToolBarLayoutAttached *>(qmlAttachedPropertiesObject<ToolBarLayout>(newItem, true));
653 attached->setAction(action);
654
655 if (!q->childItems().isEmpty() && q->childItems().first() != newItem) {
656 // Due to asynchronous item creation, we end up creating the last item
657 // first. So move items before previously inserted items to ensure
658 // we have a more sensible tab order.
659 // Note that this will be incorrect if we end up completing in random
660 // order.
661 newItem->stackBefore(q->childItems().first());
662 }
663 });
664
665 return result;
666}
667
668qreal ToolBarLayoutPrivate::layoutStart(qreal layoutWidth)
669{
670 qreal availableWidth = moreButtonInstance->isVisible() ? q->width() - (moreButtonInstance->width() + spacing) : q->width();
671
672 if (alignment & Qt::AlignLeft) {
673 return layoutDirection == Qt::LeftToRight ? 0.0 : q->width();
674 } else if (alignment & Qt::AlignHCenter) {
675 return (q->width() / 2) + (layoutDirection == Qt::LeftToRight ? -layoutWidth / 2.0 : layoutWidth / 2.0);
676 } else if (alignment & Qt::AlignRight) {
677 qreal offset = availableWidth - layoutWidth;
678 return layoutDirection == Qt::LeftToRight ? offset : q->width() - offset;
679 }
680 return 0.0;
681}
682
683void ToolBarLayoutPrivate::maybeHideDelegate(int index, qreal &currentWidth, qreal totalWidth)
684{
685 auto delegate = sortedDelegates.at(index);
686
687 if (!delegate->isVisible()) {
688 // If the delegate isn't visible anyway, do nothing.
689 return;
690 }
691
692 if (currentWidth + delegate->width() < totalWidth && (firstHiddenIndex < 0 || index < firstHiddenIndex)) {
693 // If the delegate is fully visible and we have not already hidden
694 // actions, do nothing.
695 return;
696 }
697
698 if (delegate->isKeepVisible()) {
699 // If the action is marked as KeepVisible, we need to try our best to
700 // keep it in view. If the full size delegate does not fit, we try the
701 // icon-only delegate. If that also does not fit, try and find other
702 // actions to hide. Finally, if that also fails, we will hide the
703 // delegate.
704 if (currentWidth + delegate->iconWidth() > totalWidth) {
705 // First, hide any earlier actions that are not marked as KeepVisible.
706 for (auto currentIndex = index - 1; currentIndex >= 0; --currentIndex) {
707 auto previousDelegate = sortedDelegates.at(currentIndex);
708 if (!previousDelegate->isVisible() || previousDelegate->isKeepVisible()) {
709 continue;
710 }
711
712 auto width = previousDelegate->width();
713 previousDelegate->hide();
714 hiddenActions.append(previousDelegate->action());
715 currentWidth -= (width + spacing);
716
717 if (currentWidth + delegate->fullWidth() <= totalWidth) {
718 delegate->showFull();
719 break;
720 } else if (currentWidth + delegate->iconWidth() <= totalWidth) {
721 delegate->showIcon();
722 break;
723 }
724 }
725
726 if (currentWidth + delegate->width() <= totalWidth) {
727 return;
728 }
729
730 // Hiding normal actions did not help enough, so go through actions
731 // with KeepVisible set and try and collapse them to IconOnly.
732 for (auto currentIndex = index - 1; currentIndex >= 0; --currentIndex) {
733 auto previousDelegate = sortedDelegates.at(currentIndex);
734 if (!previousDelegate->isVisible() || !previousDelegate->isKeepVisible()) {
735 continue;
736 }
737
738 auto extraSpace = previousDelegate->width() - previousDelegate->iconWidth();
739 previousDelegate->showIcon();
740 currentWidth -= extraSpace;
741
742 if (currentWidth + delegate->fullWidth() <= totalWidth) {
743 delegate->showFull();
744 break;
745 } else if (currentWidth + delegate->iconWidth() <= totalWidth) {
746 delegate->showIcon();
747 break;
748 }
749 }
750
751 // If that also did not work, then hide this action after all.
752 if (currentWidth + delegate->width() > totalWidth) {
753 delegate->hide();
754 hiddenActions.append(delegate->action());
755 }
756 } else {
757 delegate->showIcon();
758 }
759 } else {
760 // The action is not marked as KeepVisible and it does not fit within
761 // the current layout, so hide it.
762 delegate->hide();
763 hiddenActions.append(delegate->action());
764
765 // If this is the first item to be hidden, mark it so we know we should
766 // also hide the following items.
767 if (firstHiddenIndex < 0) {
768 firstHiddenIndex = index;
769 }
770 }
771}
772
773void ToolBarLayoutPrivate::appendAction(ToolBarLayout::ActionsProperty *list, QObject *action)
774{
775 auto layout = reinterpret_cast<ToolBarLayout *>(list->data);
776 layout->addAction(action);
777}
778
779qsizetype ToolBarLayoutPrivate::actionCount(ToolBarLayout::ActionsProperty *list)
780{
781 return reinterpret_cast<ToolBarLayout *>(list->data)->d->actions.count();
782}
783
784QObject *ToolBarLayoutPrivate::action(ToolBarLayout::ActionsProperty *list, qsizetype index)
785{
786 return reinterpret_cast<ToolBarLayout *>(list->data)->d->actions.at(index);
787}
788
789void ToolBarLayoutPrivate::clearActions(ToolBarLayout::ActionsProperty *list)
790{
791 reinterpret_cast<ToolBarLayout *>(list->data)->clearActions();
792}
793
794#include "moc_toolbarlayout.cpp"
QObject * action
The action this delegate was created for.
QQmlComponent * iconDelegate
A component that is used to create icon-only delegates from.
Q_SLOT void relayout()
Queue a relayout of this layout.
Qt::Alignment alignment
How to align the delegates within this layout.
QQmlComponent * moreButton
A component that is used to create the "more button" item from.
void removeAction(QObject *action)
Remove an action from the list of actions.
Qt::LayoutDirection layoutDirection
Which direction to layout in.
HeightMode heightMode
How to handle items that do not match the toolbar's height.
void clearActions()
Clear the list of actions.
qreal visibleWidth
The combined width of visible delegates in this layout.
qreal spacing
The amount of spacing between individual delegates.
qreal minimumWidth
The minimum width this layout can have.
QQmlComponent * fullDelegate
A component that is used to create full-size delegates from.
void addAction(QObject *action)
Add an action to the list of actions.
QQmlComponent * separatorDelegate
A component that is used to create separator delegates from.
HeightMode
An enum describing several modes that can be used to deal with items with a height that does not matc...
@ AlwaysFill
Always match the height of the layout. Larger items will be reduced in height, smaller items will be ...
@ ConstrainIfLarger
If the item is larger than the toolbar, reduce its height. Otherwise center it in the toolbar.
QList< QObject * > hiddenActions
A list of actions that do not fit in the current view and are thus hidden.
KIOCORE_EXPORT QStringList list(const QString &fileClass)
void append(QList< T > &&value)
const_reference at(qsizetype i) const const
pointer data()
QObject(QObject *parent)
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void destroyed(QObject *obj)
QObject * object() const const
virtual void componentComplete() override
virtual void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
virtual void itemChange(ItemChange change, const ItemChangeData &value)
void setParentItem(QQuickItem *parent)
void polish()
void stackBefore(const QQuickItem *sibling)
void visibleChanged()
void widthChanged()
typedef Alignment
LayoutDirection
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void setInterval(int msec)
void timeout()
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Apr 11 2025 11:49:27 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.