Files
o3de/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/SegmentBar.cpp
T
2021-04-23 09:43:40 -07:00

389 lines
11 KiB
C++

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "SegmentBar.h"
#include <AzQtComponents/Components/Style.h>
#include <QIcon>
#include <QBoxLayout>
#include <QButtonGroup>
#include <QPushButton>
#include <QApplication>
namespace AzQtComponents
{
bool layoutDirectionIsLeftToRight(QWidget* widget)
{
const Qt::LayoutDirection direction = widget->layoutDirection();
return direction == Qt::LayoutDirectionAuto
? (widget->parentWidget()
? layoutDirectionIsLeftToRight(widget->parentWidget())
: QApplication::isLeftToRight())
: direction == Qt::LeftToRight;
}
QBoxLayout::Direction boxLayoutDirection(Qt::Orientation orientation, QWidget* widget)
{
const bool leftToRight = layoutDirectionIsLeftToRight(widget);
if (orientation == Qt::Horizontal)
{
return leftToRight ? QBoxLayout::LeftToRight : QBoxLayout::RightToLeft;
}
return leftToRight ? QBoxLayout::TopToBottom : QBoxLayout::BottomToTop;
}
SegmentBar::SegmentBar(Qt::Orientation orientation, QWidget* parent)
: QFrame(parent)
{
initialize(orientation);
}
SegmentBar::SegmentBar(QWidget* parent)
: QFrame(parent)
{
initialize(Qt::Horizontal);
}
Qt::Orientation SegmentBar::orientation() const
{
switch (m_buttonsLayout->direction())
{
case QBoxLayout::LeftToRight:
case QBoxLayout::RightToLeft:
return Qt::Horizontal;
case QBoxLayout::TopToBottom:
case QBoxLayout::BottomToTop:
default:
return Qt::Vertical;
}
}
void SegmentBar::setOrientation(Qt::Orientation orientation)
{
m_buttonsLayout->setDirection(boxLayoutDirection(orientation, this));
if (orientation == Qt::Horizontal)
{
m_alignmentLayout->itemAt(0)->setAlignment(Qt::AlignCenter);
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
}
else
{
m_alignmentLayout->itemAt(0)->setAlignment(Qt::AlignTop);
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
}
}
int SegmentBar::addTab(const QString& text)
{
return insertTab(-1, QIcon(), text);
}
int SegmentBar::addTab(const QIcon& icon, const QString& text)
{
return insertTab(-1, icon, text);
}
int SegmentBar::insertTab(int index, const QString& text)
{
return insertTab(index, QIcon(), text);
}
int SegmentBar::insertTab(int index, const QIcon& icon, const QString& text)
{
const int i = qBound(index < 0 ? count() : 0, index, count());
QAbstractButton* btn = createButton(icon, text);
m_buttons->addButton(btn);
m_buttonsLayout->insertWidget(i, btn);
updateTabs();
if (currentIndex() == -1)
{
btn->setChecked(true);
}
return i;
}
void SegmentBar::removeTab(int index)
{
if (QAbstractButton* btn = button(index))
{
const int curIndex = currentIndex();
const bool isCurrent = index == curIndex;
m_buttonsLayout->removeWidget(btn);
m_buttons->removeButton(btn);
updateTabs();
if (isCurrent)
{
setCurrentIndex(count() > 0 ? qBound(0, index -1, count() -1) : -1);
}
else if (curIndex > index)
{
setCurrentIndex(curIndex -1);
}
}
}
void SegmentBar::moveTab(int from, int to)
{
if (from < 0 || from >= count() || to < 0 || to >= count() || from == to)
{
return;
}
const bool isCurrent = from == currentIndex();
m_buttonsLayout->insertItem(to, m_buttonsLayout->takeAt(from));
updateTabs();
if (isCurrent)
{
emit currentChanged(to);
}
}
bool SegmentBar::isTabEnabled(int index) const
{
const QAbstractButton* btn = button(index);
return btn ? btn->isEnabled() : false;
}
void SegmentBar::setTabEnabled(int index, bool enabled)
{
if (QAbstractButton* btn = button(index))
{
btn->setEnabled(enabled);
}
}
QString SegmentBar::tabText(int index) const
{
const QAbstractButton* btn = button(index);
return btn ? btn->text() : QString();
}
void SegmentBar::setTabText(int index, const QString& text)
{
if (QAbstractButton* btn = button(index))
{
btn->setText(text);
updateTabs();
}
}
QColor SegmentBar::tabTextColor(int index) const
{
const QAbstractButton* btn = button(index);
return btn ? btn->palette().brush(QPalette::Active, QPalette::Text).color() : QColor();
}
void SegmentBar::setTabTextColor(int index, const QColor& color)
{
if (QAbstractButton* btn = button(index))
{
QPalette pal = btn->palette();
pal.setBrush(QPalette::Active, QPalette::Text, color);
btn->setPalette(pal);
}
}
QIcon SegmentBar::tabIcon(int index) const
{
const QAbstractButton* btn = button(index);
return btn ? btn->icon() : QIcon();
}
void SegmentBar::setTabIcon(int index, const QIcon& icon)
{
if (QAbstractButton* btn = button(index))
{
btn->setIcon(icon);
updateTabs();
}
}
#ifndef QT_NO_TOOLTIP
void SegmentBar::setTabToolTip(int index, const QString& tip)
{
if (QAbstractButton* btn = button(index))
{
btn->setToolTip(tip);
}
}
QString SegmentBar::tabToolTip(int index) const
{
const QAbstractButton* btn = button(index);
return btn ? btn->toolTip() : QString();
}
#endif
#ifndef QT_NO_WHATSTHIS
void SegmentBar::setTabWhatsThis(int index, const QString& text)
{
if (QAbstractButton* btn = button(index))
{
btn->setWhatsThis(text);
}
}
QString SegmentBar::tabWhatsThis(int index) const
{
const QAbstractButton* btn = button(index);
return btn ? btn->whatsThis() : QString();
}
#endif
QSize SegmentBar::iconSize() const
{
return m_iconSize;
}
void SegmentBar::setIconSize(const QSize& size)
{
if (m_iconSize == size)
{
return;
}
m_iconSize = size;
updateTabs();
}
int SegmentBar::currentIndex() const
{
return m_buttonsLayout->indexOf(m_buttons->checkedButton());
}
int SegmentBar::count() const
{
return m_buttonsLayout->count();
}
void SegmentBar::setCurrentIndex(int index)
{
if ((index == -1 && count() > 0) || index >= count())
{
return;
}
if (QAbstractButton* btn = button(index))
{
btn->setChecked(true);
}
else
{
Q_ASSERT(count() == 0);
emit currentChanged(-1);
}
}
void SegmentBar::initialize(Qt::Orientation orientation)
{
m_minimumTabSize = -1;
QWidget* buttonsWidget = new QWidget(this);
m_buttons = new QButtonGroup(buttonsWidget);
m_buttons->setExclusive(true);
m_buttonsLayout = new QBoxLayout(QBoxLayout::LeftToRight, buttonsWidget);
m_buttonsLayout->setContentsMargins(0, 0, 0, 0);
m_buttonsLayout->setSpacing(0);
m_alignmentLayout = new QBoxLayout(QBoxLayout::LeftToRight, this);
m_alignmentLayout->setContentsMargins(0, 0, 0, 0);
m_alignmentLayout->setSpacing(0);
m_alignmentLayout->addWidget(buttonsWidget);
setOrientation(orientation);
connect(m_buttons, static_cast<void(QButtonGroup::*)(QAbstractButton*)>(&QButtonGroup::buttonClicked),
this, [this](QAbstractButton* btn)
{
emit tabBarClicked(m_buttonsLayout->indexOf(btn));
});
connect(m_buttons, static_cast<void(QButtonGroup::*)(QAbstractButton*, bool)>(&QButtonGroup::buttonToggled),
this, [this](QAbstractButton* btn, bool checked)
{
if (checked)
{
emit currentChanged(m_buttonsLayout->indexOf(btn));
}
});
}
void SegmentBar::updateTabs()
{
m_minimumTabSize = -1;
const QAbstractButton* first = button(0);
const QAbstractButton* last = button(count() - 1);
const auto buttons = m_buttons->buttons();
const bool enabled = updatesEnabled();
setUpdatesEnabled(false);
m_alignmentLayout->setEnabled(false);
m_buttonsLayout->setEnabled(false);
for (QAbstractButton* btn : buttons)
{
Style::removeClass(btn, QStringLiteral("TabOne"));
Style::removeClass(btn, QStringLiteral("TabFirst"));
Style::removeClass(btn, QStringLiteral("TabLast"));
Style::removeClass(btn, QStringLiteral("TabMiddle"));
if (first == last && first == btn)
{
Style::addClass(btn, QStringLiteral("TabOne"));
}
else if (first == btn)
{
Style::addClass(btn, QStringLiteral("TabFirst"));
}
else if (last == btn)
{
Style::addClass(btn, QStringLiteral("TabLast"));
}
else
{
Style::addClass(btn, QStringLiteral("TabMiddle"));
}
btn->setIconSize(m_iconSize);
m_minimumTabSize = qMax(m_minimumTabSize, btn->sizeHint().width());
}
for (QAbstractButton* btn : buttons)
{
btn->setMinimumWidth(m_minimumTabSize);
}
m_buttonsLayout->setEnabled(true);
m_buttonsLayout->activate();
m_alignmentLayout->setEnabled(true);
m_alignmentLayout->activate();
setUpdatesEnabled(enabled);
}
QAbstractButton* SegmentBar::createButton(const QIcon& icon, const QString& text)
{
QPushButton* btn = new QPushButton(this);
btn->setCheckable(true);
btn->setIcon(icon);
btn->setText(text);
btn->setFocusPolicy(Qt::NoFocus);
Style::flagToIgnore(btn);
return btn;
}
QAbstractButton* SegmentBar::button(int index) const
{
QLayoutItem* item = m_buttonsLayout->itemAt(index);
return item ? qobject_cast<QAbstractButton*>(item->widget()) : nullptr;
}
}
#include "Components/Widgets/moc_SegmentBar.cpp"