File indexing completed on 2024-05-05 04:19:13
0001 /* 0002 This file is part of the KDE project 0003 SPDX-FileCopyrightText: 2021 Felix Ernst <fe.a.ernst@gmail.com> 0004 0005 SPDX-License-Identifier: LGPL-2.1-or-later 0006 */ 0007 0008 #include "alignwithsidebarwidgetaction.h" 0009 0010 #include <lib/gwenviewconfig.h> 0011 0012 #include <KLocalizedString> 0013 0014 #include <QApplication> 0015 #include <QEvent> 0016 #include <QStyle> 0017 0018 #include <cmath> 0019 0020 AlignWithSideBarWidgetAction::AlignWithSideBarWidgetAction(QObject *parent) 0021 : QWidgetAction(parent) 0022 { 0023 setText(i18nc("@action:inmenu a spacer that aligns toolbar buttons with the sidebar", "Sidebar Alignment Spacer")); 0024 } 0025 0026 void AlignWithSideBarWidgetAction::setSideBar(QWidget *sideBar) 0027 { 0028 mSideBar = sideBar; 0029 const QList<QWidget *> widgets = createdWidgets(); 0030 for (auto widget : widgets) { 0031 static_cast<AligningSpacer *>(widget)->setSideBar(sideBar); 0032 } 0033 } 0034 0035 QWidget *AlignWithSideBarWidgetAction::createWidget(QWidget *parent) 0036 { 0037 auto aligningSpacer = new AligningSpacer(parent); 0038 aligningSpacer->setSideBar(mSideBar); 0039 return aligningSpacer; 0040 } 0041 0042 AligningSpacer::AligningSpacer(QWidget *parent) 0043 : QWidget{parent} 0044 { 0045 if ((mToolbar = qobject_cast<QToolBar *>(parent))) { 0046 connect(mToolbar, &QToolBar::orientationChanged, this, &AligningSpacer::update); 0047 } 0048 } 0049 0050 void AligningSpacer::setSideBar(QWidget *sideBar) 0051 { 0052 if (mSideBar) { 0053 mSideBar->removeEventFilter(this); 0054 } 0055 mSideBar = sideBar; 0056 if (mSideBar) { 0057 mSideBar->installEventFilter(this); 0058 } 0059 update(); 0060 } 0061 0062 bool AligningSpacer::eventFilter(QObject * /* watched */, QEvent *event) 0063 { 0064 switch (event->type()) { 0065 case QEvent::Show: 0066 case QEvent::Hide: 0067 case QEvent::Resize: 0068 update(); 0069 return false; 0070 default: 0071 return false; 0072 } 0073 } 0074 0075 void AligningSpacer::moveEvent(QMoveEvent * /* moved */) 0076 { 0077 update(); 0078 } 0079 0080 void AligningSpacer::setFollowingSeparatorVisible(bool visible) 0081 { 0082 if (!mToolbar) { 0083 return; 0084 } 0085 if (mToolbar->orientation() == Qt::Vertical) { 0086 visible = true; 0087 } 0088 0089 const QList<QAction *> toolbarActions = mToolbar->actions(); 0090 bool actionForThisSpacerFound = false; // If this is true, the next action in the iteration 0091 // is what we are interested in. 0092 for (auto action : toolbarActions) { 0093 if (actionForThisSpacerFound) { 0094 if (visible && mWasSeparatorRemoved) { 0095 mToolbar->insertSeparator(action); 0096 mWasSeparatorRemoved = false; 0097 } else if (!visible && action->isSeparator()) { 0098 mToolbar->removeAction(action); 0099 mWasSeparatorRemoved = true; 0100 } 0101 return; 0102 } 0103 if (mToolbar->widgetForAction(action) == this) { 0104 actionForThisSpacerFound = true; 0105 } 0106 } 0107 } 0108 0109 void AligningSpacer::update() 0110 { 0111 const bool oldWasSeparatorRemoved = mWasSeparatorRemoved; 0112 if (updateWidth() < 8) { 0113 // Because the spacer is so small the separator should be visible to serve its purpose. 0114 if (mWasSeparatorRemoved) { 0115 setFollowingSeparatorVisible(true); 0116 } 0117 } else if (mSideBar) { 0118 setFollowingSeparatorVisible(mSideBar->isVisible()); 0119 } 0120 0121 if (oldWasSeparatorRemoved != mWasSeparatorRemoved) { // One more updateWidth() is needed. 0122 updateWidth(); 0123 } 0124 } 0125 0126 int AligningSpacer::updateWidth() 0127 { 0128 if (!mSideBar || (mToolbar && mToolbar->orientation() == Qt::Vertical)) { 0129 setFixedWidth(0); 0130 return 0; 0131 } 0132 0133 const auto separatorWidth = static_cast<float>(style()->pixelMetric(QStyle::PM_ToolBarSeparatorExtent, nullptr, this)); 0134 int sideBarWidth = mSideBar->geometry().width(); 0135 if (sideBarWidth <= 0) { 0136 if (!Gwenview::GwenviewConfig::sideBarSplitterSizes().isEmpty()) { 0137 sideBarWidth = Gwenview::GwenviewConfig::sideBarSplitterSizes().constFirst(); 0138 } else { 0139 // We get to this code when gwenview.rc was deleted or when this is the first run. 0140 // There doesn't seem to be an easy way to get the width the sideBar is going 0141 // to have at this point in time so we set it to some value that leads to 0142 // a nice default appearance on the first run. 0143 if (QApplication::layoutDirection() != Qt::RightToLeft) { 0144 sideBarWidth = x() + separatorWidth * 2; // Leads to a nice default spacing. 0145 } else { 0146 sideBarWidth = mToolbar->width() - x() + separatorWidth * 2; 0147 } 0148 mSideBar->resize(sideBarWidth, mSideBar->height()); // Make sure it aligns. 0149 } 0150 } 0151 0152 int newWidth; 0153 if (QApplication::layoutDirection() != Qt::RightToLeft) { 0154 newWidth = sideBarWidth - mapTo(window(), QPoint(0, 0)).x(); 0155 } else { 0156 newWidth = sideBarWidth - window()->width() + mapTo(window(), QPoint(width(), 0)).x(); 0157 } 0158 if (!mWasSeparatorRemoved) { 0159 // Make it so a potentially following separator looks aligned with the sidebar. 0160 newWidth -= std::ceil(separatorWidth * 0.3); 0161 } else { 0162 // Make it so removing the separator doesn't change the toolbutton positions. 0163 newWidth += std::floor(separatorWidth * 0.7); 0164 } 0165 0166 // Make sure nothing weird can happen. 0167 if (newWidth < 0 || newWidth > sideBarWidth) { 0168 newWidth = 0; 0169 } 0170 setFixedWidth(newWidth); 0171 return newWidth; 0172 } 0173 0174 #include "moc_alignwithsidebarwidgetaction.cpp"