Libkleo

animatedexpander.cpp
1/*
2 This file is part of libkleopatra
3 SPDX-FileCopyrightText: 2019, 2021 g10 Code GmbH
4 SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
5
6 SPDX-License-Identifier: GPL-2.0-or-later
7*/
8
9#include "animatedexpander_p.h"
10
11#include <QPropertyAnimation>
12
13void AnimatedExpander::setContentLayout(QLayout *contentLayout)
14{
15 delete contentArea.layout();
16 contentArea.setLayout(contentLayout);
17}
18
19bool AnimatedExpander::isExpanded() const
20{
21 return toggleButton.isChecked();
22}
23
24void AnimatedExpander::setExpanded(bool expanded)
25{
26 toggleButton.setChecked(expanded);
27}
28
29AnimatedExpander::AnimatedExpander(const QString &title, const QString &accessibleTitle, QWidget *parent)
30 : QWidget{parent}
31{
32#ifdef Q_OS_WIN
33 // draw dotted focus frame if button has focus; otherwise, draw invisible frame using background color
34 toggleButton.setStyleSheet(
35 QStringLiteral("QToolButton { border: 1px solid palette(window); }"
36 "QToolButton:focus { border: 1px dotted palette(window-text); }"));
37#else
38 // this works with Breeze style because Breeze draws the focus frame when drawing CE_ToolButtonLabel
39 // while the Windows styles (and Qt's common base style) draw the focus frame before drawing CE_ToolButtonLabel
40 toggleButton.setStyleSheet(QStringLiteral("QToolButton { border: none; }"));
41#endif
42 toggleButton.setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
43 toggleButton.setArrowType(Qt::ArrowType::RightArrow);
44 toggleButton.setText(title);
45 if (!accessibleTitle.isEmpty()) {
46 toggleButton.setAccessibleName(accessibleTitle);
47 }
48 toggleButton.setCheckable(true);
49 toggleButton.setChecked(false);
50
51 headerLine.setFrameShape(QFrame::HLine);
52 headerLine.setFrameShadow(QFrame::Sunken);
53 headerLine.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
54
55 contentArea.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
56
57 // start out collapsed
58 contentArea.setMaximumHeight(0);
59 contentArea.setMinimumHeight(0);
60 contentArea.setVisible(false);
61
62 // let the entire widget grow and shrink with its content
63 toggleAnimation.addAnimation(new QPropertyAnimation(this, "minimumHeight"));
64 toggleAnimation.addAnimation(new QPropertyAnimation(this, "maximumHeight"));
65 toggleAnimation.addAnimation(new QPropertyAnimation(&contentArea, "maximumHeight"));
66
67 mainLayout.setVerticalSpacing(0);
68 mainLayout.setContentsMargins(0, 0, 0, 0);
69 int row = 0;
70 mainLayout.addWidget(&toggleButton, row, 0, 1, 1, Qt::AlignLeft);
71 mainLayout.addWidget(&headerLine, row++, 2, 1, 1);
72 mainLayout.addWidget(&contentArea, row, 0, 1, 3);
73 setLayout(&mainLayout);
74 connect(&toggleButton, &QToolButton::toggled, this, [this](const bool checked) {
75 if (checked) {
76 Q_EMIT startExpanding();
77 // make the content visible when expanding starts
78 contentArea.setVisible(true);
79 }
80 // use instant animation if widget isn't visible (e.g. before widget is shown)
81 const int duration = isVisible() ? animationDuration : 0;
82 // update the size of the content area
83 const auto collapsedHeight = sizeHint().height() - contentArea.maximumHeight();
84 const auto contentHeight = contentArea.layout()->sizeHint().height();
85 for (int i = 0; i < toggleAnimation.animationCount() - 1; ++i) {
86 auto expanderAnimation = static_cast<QPropertyAnimation *>(toggleAnimation.animationAt(i));
87 expanderAnimation->setDuration(duration);
88 expanderAnimation->setStartValue(collapsedHeight);
89 expanderAnimation->setEndValue(collapsedHeight + contentHeight);
90 }
91 auto contentAnimation = static_cast<QPropertyAnimation *>(toggleAnimation.animationAt(toggleAnimation.animationCount() - 1));
92 contentAnimation->setDuration(duration);
93 contentAnimation->setStartValue(0);
94 contentAnimation->setEndValue(contentHeight);
95 toggleButton.setArrowType(checked ? Qt::ArrowType::DownArrow : Qt::ArrowType::RightArrow);
96 toggleAnimation.setDirection(checked ? QAbstractAnimation::Forward : QAbstractAnimation::Backward);
97 toggleAnimation.start();
98 });
99 connect(&toggleAnimation, &QAbstractAnimation::finished, this, [this]() {
100 // hide the content area when it is fully collapsed
101 if (!toggleButton.isChecked()) {
102 contentArea.setVisible(false);
103 }
104 });
105}
106
107int AnimatedExpander::contentHeight() const
108{
109 return contentArea.layout()->sizeHint().height();
110}
111
112int AnimatedExpander::contentWidth() const
113{
114 return contentArea.layout()->sizeHint().width();
115}
116
117#include "moc_animatedexpander_p.cpp"
void toggled(bool checked)
bool isEmpty() const const
AlignLeft
ToolButtonTextBesideIcon
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void setDuration(int msecs)
void setStyleSheet(const QString &styleSheet)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Dec 13 2024 11:51:41 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.