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 <QQmlComponent>
14#include <QTimer>
15
16#include "loggingcategory.h"
17#include "toolbarlayoutdelegate.h"
18
19ToolBarLayoutAttached::ToolBarLayoutAttached(QObject *parent)
20 : QObject(parent)
21{
22}
23
25{
26 return m_action;
27}
28
29void ToolBarLayoutAttached::setAction(QObject *action)
30{
31 m_action = action;
32}
33
34class ToolBarLayoutPrivate
35{
36 ToolBarLayout *const q;
37
38public:
39 ToolBarLayoutPrivate(ToolBarLayout *qq)
40 : q(qq)
41 {
42 }
43 ~ToolBarLayoutPrivate()
44 {
45 if (moreButtonIncubator) {
46 moreButtonIncubator->clear();
47 delete moreButtonIncubator;
48 }
49 }
50
51 void calculateImplicitSize();
52 void performLayout();
53 QList<ToolBarLayoutDelegate *> createDelegates();
54 ToolBarLayoutDelegate *createDelegate(QObject *action);
55 qreal layoutStart(qreal layoutWidth);
56 void maybeHideDelegate(int index, qreal &currentWidth, qreal totalWidth);
57
58 QList<QObject *> actions;
59 ToolBarLayout::ActionsProperty actionsProperty;
60 QList<QObject *> hiddenActions;
61 QQmlComponent *fullDelegate = nullptr;
62 QQmlComponent *iconDelegate = nullptr;
63 QQmlComponent *separatorDelegate = nullptr;
64 QQmlComponent *moreButton = nullptr;
65 qreal spacing = 0.0;
66 Qt::Alignment alignment = Qt::AlignLeft;
67 qreal visibleActionsWidth = 0.0;
68 qreal visibleWidth = 0.0;
69 Qt::LayoutDirection layoutDirection = Qt::LeftToRight;
71
72 bool completed = false;
73 bool actionsChanged = false;
74 bool implicitSizeValid = false;
75
76 std::unordered_map<QObject *, std::unique_ptr<ToolBarLayoutDelegate>> delegates;
77 QList<ToolBarLayoutDelegate *> sortedDelegates;
78 QQuickItem *moreButtonInstance = nullptr;
79 ToolBarDelegateIncubator *moreButtonIncubator = nullptr;
80 bool shouldShowMoreButton = false;
81 int firstHiddenIndex = -1;
82
83 QList<QObject *> removedActions;
84 QTimer *removalTimer = nullptr;
85
86 QElapsedTimer performanceTimer;
87
88 static void appendAction(ToolBarLayout::ActionsProperty *list, QObject *action);
89 static qsizetype actionCount(ToolBarLayout::ActionsProperty *list);
90 static QObject *action(ToolBarLayout::ActionsProperty *list, qsizetype index);
91 static void clearActions(ToolBarLayout::ActionsProperty *list);
92};
93
94ToolBarLayout::ToolBarLayout(QQuickItem *parent)
95 : QQuickItem(parent)
96 , d(std::make_unique<ToolBarLayoutPrivate>(this))
97{
98 d->actionsProperty = ActionsProperty(this,
99 this,
100 ToolBarLayoutPrivate::appendAction,
101 ToolBarLayoutPrivate::actionCount,
102 ToolBarLayoutPrivate::action,
103 ToolBarLayoutPrivate::clearActions);
104
105 // To prevent multiple assignments to actions from constantly recreating
106 // delegates, we cache the delegates and only remove them once they are no
107 // longer being used. This timer is responsible for triggering that removal.
108 d->removalTimer = new QTimer{this};
109 d->removalTimer->setInterval(1000);
110 d->removalTimer->setSingleShot(true);
111 connect(d->removalTimer, &QTimer::timeout, this, [this]() {
112 for (auto action : std::as_const(d->removedActions)) {
113 if (!d->actions.contains(action)) {
114 d->delegates.erase(action);
115 }
116 }
117 d->removedActions.clear();
118 });
119}
120
121ToolBarLayout::~ToolBarLayout()
122{
123}
124
125ToolBarLayout::ActionsProperty ToolBarLayout::actionsProperty() const
126{
127 return d->actionsProperty;
128}
129
131{
132 if (action == nullptr) {
133 return;
134 }
135 d->actions.append(action);
136 d->actionsChanged = true;
137
138 connect(action, &QObject::destroyed, this, [this](QObject *action) {
139 auto itr = d->delegates.find(action);
140 if (itr != d->delegates.end()) {
141 d->delegates.erase(itr);
142 }
143
144 d->actions.removeOne(action);
145 d->actionsChanged = true;
146
147 relayout();
148 });
149
150 relayout();
151}
152
154{
155 auto itr = d->delegates.find(action);
156 if (itr != d->delegates.end()) {
157 itr->second->hide();
158 }
159
160 d->actions.removeOne(action);
161 d->removedActions.append(action);
162 d->removalTimer->start();
163 d->actionsChanged = true;
164
165 relayout();
166}
167
169{
170 for (auto action : std::as_const(d->actions)) {
171 auto itr = d->delegates.find(action);
172 if (itr != d->delegates.end()) {
173 itr->second->hide();
174 }
175 }
176
177 d->removedActions.append(d->actions);
178 d->actions.clear();
179 d->actionsChanged = true;
180
181 relayout();
182}
183
185{
186 return d->hiddenActions;
187}
188
190{
191 return d->fullDelegate;
192}
193
194void ToolBarLayout::setFullDelegate(QQmlComponent *newFullDelegate)
195{
196 if (newFullDelegate == d->fullDelegate) {
197 return;
198 }
199
200 d->fullDelegate = newFullDelegate;
201 d->delegates.clear();
202 relayout();
203 Q_EMIT fullDelegateChanged();
204}
205
207{
208 return d->iconDelegate;
209}
210
211void ToolBarLayout::setIconDelegate(QQmlComponent *newIconDelegate)
212{
213 if (newIconDelegate == d->iconDelegate) {
214 return;
215 }
216
217 d->iconDelegate = newIconDelegate;
218 d->delegates.clear();
219 relayout();
220 Q_EMIT iconDelegateChanged();
221}
222
224{
225 return d->separatorDelegate;
226}
227
228void ToolBarLayout::setSeparatorDelegate(QQmlComponent *newSeparatorDelegate)
229{
230 if (newSeparatorDelegate == d->separatorDelegate) {
231 return;
232 }
233
234 d->separatorDelegate = newSeparatorDelegate;
235 d->delegates.clear();
236 relayout();
237 Q_EMIT separatorDelegateChanged();
238}
239
241{
242 return d->moreButton;
243}
244
245void ToolBarLayout::setMoreButton(QQmlComponent *newMoreButton)
246{
247 if (newMoreButton == d->moreButton) {
248 return;
249 }
250
251 d->moreButton = newMoreButton;
252 if (d->moreButtonInstance) {
253 d->moreButtonInstance->deleteLater();
254 d->moreButtonInstance = nullptr;
255 }
256 relayout();
257 Q_EMIT moreButtonChanged();
258}
259
260qreal ToolBarLayout::spacing() const
261{
262 return d->spacing;
263}
264
265void ToolBarLayout::setSpacing(qreal newSpacing)
266{
267 if (newSpacing == d->spacing) {
268 return;
269 }
270
271 d->spacing = newSpacing;
272 relayout();
273 Q_EMIT spacingChanged();
274}
275
277{
278 return d->alignment;
279}
280
281void ToolBarLayout::setAlignment(Qt::Alignment newAlignment)
282{
283 if (newAlignment == d->alignment) {
284 return;
285 }
286
287 d->alignment = newAlignment;
288 relayout();
289 Q_EMIT alignmentChanged();
290}
291
292qreal ToolBarLayout::visibleWidth() const
293{
294 return d->visibleWidth;
295}
296
297qreal ToolBarLayout::minimumWidth() const
298{
299 return d->moreButtonInstance ? d->moreButtonInstance->width() : 0;
300}
301
303{
304 return d->layoutDirection;
305}
306
307void ToolBarLayout::setLayoutDirection(Qt::LayoutDirection &newLayoutDirection)
308{
309 if (newLayoutDirection == d->layoutDirection) {
310 return;
311 }
312
313 d->layoutDirection = newLayoutDirection;
314 relayout();
315 Q_EMIT layoutDirectionChanged();
316}
317
319{
320 return d->heightMode;
321}
322
323void ToolBarLayout::setHeightMode(HeightMode newHeightMode)
324{
325 if (newHeightMode == d->heightMode) {
326 return;
327 }
328
329 d->heightMode = newHeightMode;
330 relayout();
331 Q_EMIT heightModeChanged();
332}
333
335{
336 d->implicitSizeValid = false;
337 polish();
338}
339
340void ToolBarLayout::componentComplete()
341{
343 d->completed = true;
344 relayout();
345}
346
347void ToolBarLayout::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
348{
349 if (newGeometry != oldGeometry) {
350 if (newGeometry.size() != QSizeF{implicitWidth(), implicitHeight()}) {
351 relayout();
352 } else {
353 polish();
354 }
355 }
356 QQuickItem::geometryChange(newGeometry, oldGeometry);
357}
358
359void ToolBarLayout::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data)
360{
361 if (change == ItemVisibleHasChanged || change == ItemSceneChange) {
362 relayout();
363 }
364 QQuickItem::itemChange(change, data);
365}
366
367void ToolBarLayout::updatePolish()
368{
369 d->performLayout();
370}
371
372/**
373 * Calculate the implicit size for this layout.
374 *
375 * This is a separate step from performing the actual layout, because of a nasty
376 * little issue with Control, where it will unconditionally set the height of
377 * its contentItem, which means QQuickItem::heightValid() becomes useless. So
378 * instead, we first calculate our implicit size, ignoring any explicitly set
379 * item size. Then we follow that by performing the actual layouting, using the
380 * width and height retrieved from the item, as those will return the explicitly
381 * set width/height if set and the implicit size otherwise. Since control
382 * watches for implicit size changes, we end up with correct behaviour both when
383 * we get an explicit size set and when we're relying on implicit size
384 * calculation.
385 */
386void ToolBarLayoutPrivate::calculateImplicitSize()
387{
388 if (!completed) {
389 return;
390 }
391
392 if (!fullDelegate || !iconDelegate || !separatorDelegate || !moreButton) {
393 qCWarning(KirigamiLayoutsLog) << "ToolBarLayout: Unable to layout, required properties are not set";
394 return;
395 }
396
397 if (actions.isEmpty()) {
398 q->setImplicitSize(0., 0.);
399 return;
400 }
401
402 hiddenActions.clear();
403 firstHiddenIndex = -1;
404
405 sortedDelegates = createDelegates();
406
407 bool ready = std::all_of(delegates.cbegin(), delegates.cend(), [](const std::pair<QObject *const, std::unique_ptr<ToolBarLayoutDelegate>> &entry) {
408 return entry.second->isReady();
409 });
410 if (!ready || !moreButtonInstance) {
411 return;
412 }
413
414 qreal maxHeight = 0.0;
415 qreal maxWidth = 0.0;
416
417 // First, calculate the total width and maximum height of all delegates.
418 // This will be used to determine which actions to show, which ones to
419 // collapse to icon-only etc.
420 for (auto entry : std::as_const(sortedDelegates)) {
421 if (!entry->isActionVisible()) {
422 entry->hide();
423 continue;
424 }
425
426 if (entry->isHidden()) {
427 entry->hide();
428 hiddenActions.append(entry->action());
429 continue;
430 }
431
432 if (entry->isIconOnly()) {
433 entry->showIcon();
434 } else {
435 entry->showFull();
436 }
437
438 maxWidth += entry->width() + spacing;
439 maxHeight = std::max(maxHeight, entry->maxHeight());
440 }
441
442 // The last entry also gets spacing but shouldn't, so remove that.
443 maxWidth -= spacing;
444
445 visibleActionsWidth = 0.0;
446
447 if (maxWidth > q->width() - (hiddenActions.isEmpty() ? 0.0 : moreButtonInstance->width() + spacing)) {
448 // We have more items than fit into the view, so start hiding some.
449
450 qreal layoutWidth = q->width() - (moreButtonInstance->width() + spacing);
451 if (alignment & Qt::AlignHCenter) {
452 // When centering, we need to reserve space on both sides to make sure
453 // things are properly centered, otherwise we will be to the right of
454 // the center.
455 layoutWidth -= (moreButtonInstance->width() + spacing);
456 }
457
458 for (int i = 0; i < sortedDelegates.size(); ++i) {
459 auto delegate = sortedDelegates.at(i);
460
461 maybeHideDelegate(i, visibleActionsWidth, layoutWidth);
462
463 if (delegate->isVisible()) {
464 visibleActionsWidth += delegate->width() + spacing;
465 }
466 }
467 if (!qFuzzyIsNull(visibleActionsWidth)) {
468 // Like above, remove spacing on the last element that incorrectly gets spacing added.
469 visibleActionsWidth -= spacing;
470 }
471 } else {
472 visibleActionsWidth = maxWidth;
473 }
474
475 if (!hiddenActions.isEmpty()) {
476 maxHeight = std::max(maxHeight, moreButtonInstance->implicitHeight());
477 };
478
479 q->setImplicitSize(maxWidth, maxHeight);
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{
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"
Attached property for ToolBarLayout delegates.
QObject * action
The action this delegate was created for.
An item that creates delegates for actions and lays them out in a row.
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.
QML_ELEMENTQQmlListProperty< QObject > actions
The actions this layout should create delegates for.
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
void clear()
pointer data()
T & first()
bool isEmpty() const const
qsizetype size() const const
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void destroyed(QObject *obj)
QVariant property(const char *name) const const
QObject * object() const const
QList< QQuickItem * > childItems() 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 setVisible(bool)
void setX(qreal)
void setY(qreal)
QSizeF size() const const
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-2024 The KDE developers.
Generated on Fri Oct 11 2024 12:13:25 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.