123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339 |
- #include "CycleListWidget.h"
- #include "QFluentWidgets.h"
- #include "ScrollArea.h"
- #include <QEvent>
- #include <QEvent>
- #include <QPainter>
- #include <QWheelEvent>
- ScrollIcon::ScrollIcon(IconType type, Qfw::Theme t) : FluentIconBase(""), m_theme(t), m_type(type)
- {
- iconEngine->setIconPath(iconPath());
- }
- ScrollIcon::~ScrollIcon() { }
- QString ScrollIcon::iconName(ScrollIcon::IconType type)
- {
- switch (type) {
- case UP:
- return "Up";
- case DOWN:
- return "Down";
- }
- return "Unknown";
- }
- QString ScrollIcon::iconPath()
- {
- QString colorName;
- if (m_theme == Qfw::Theme::AUTO) {
- colorName = QFWIns.isDarkTheme() ? "white" : "black";
- } else {
- if (m_theme == Qfw::DARK) {
- colorName = "white";
- } else {
- colorName = "black";
- }
- }
- return QString(":/qfluentwidgets/images/time_picker/%1_%2.svg").arg(iconName(m_type)).arg(colorName);
- }
- QIcon ScrollIcon::icon()
- {
- return QIcon(iconEngine->clone());
- }
- QString ScrollIcon::typeName() const
- {
- return iconName(m_type);
- }
- QString ScrollIcon::enumName() const
- {
- QMetaEnum metaEnum = QMetaEnum::fromType<IconType>();
- return metaEnum.valueToKey(m_type);
- }
- FluentIconBase *ScrollIcon::clone()
- {
- return new ScrollIcon(m_type, m_theme);
- }
- Qfw::Theme ScrollIcon::theme() const
- {
- return m_theme;
- }
- void ScrollIcon::setTheme(const Qfw::Theme &theme)
- {
- m_theme = theme;
- iconEngine->setIconPath(iconPath());
- }
- ScrollButton::ScrollButton(FluentIconBase *icon, QWidget *parent) : QToolButton(parent), isPressed(false), m_icon(icon)
- {
- installEventFilter(this);
- }
- bool ScrollButton::eventFilter(QObject *watched, QEvent *event)
- {
- if (watched == this) {
- if (event->type() == QEvent::MouseButtonPress) {
- isPressed = true;
- update();
- } else if (event->type() == QEvent::MouseButtonRelease) {
- isPressed = false;
- update();
- }
- }
- return QToolButton::eventFilter(watched, event);
- }
- void ScrollButton::paintEvent(QPaintEvent *event)
- {
- QToolButton::paintEvent(event);
- QPainter painter(this);
- painter.setRenderHints(QPainter::Antialiasing);
- int w, h;
- if (!isPressed) {
- w = 10;
- h = 10;
- } else {
- w = 8;
- h = 8;
- }
- int x = (this->width() - w) / 2;
- int y = (this->height() - h) / 2;
- m_icon->render(&painter, QRect(x, y, w, h));
- }
- CycleListWidget::CycleListWidget(const QVariantList &items, const QSize &itemSize, Qt::AlignmentFlag align,
- QWidget *parent)
- : QListWidget(parent), m_itemSize(itemSize), m_align(align), m_isCycle(false), m_currentIndex(-1)
- {
- m_upButton = new ScrollButton(new ScrollIcon(ScrollIcon::UP), this);
- m_downButton = new ScrollButton(new ScrollIcon(ScrollIcon::DOWN), this);
- m_scrollDuration = 250;
- m_originItems = items;
- vScrollBar = new SmoothScrollBar(this);
- m_visibleNumber = 9;
- // repeat adding items to achieve circular scrolling
- setItems(items);
- this->setVerticalScrollMode(ScrollPerPixel);
- this->setVerticalScrollBar(vScrollBar);
- this->vScrollBar->setScrollAnimation(m_scrollDuration);
- this->setViewportMargins(0, 0, 0, 0);
- this->setFixedSize(itemSize.width() + 8, itemSize.height() * m_visibleNumber);
- // hide scroll bar
- this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- m_upButton->hide();
- m_downButton->hide();
- connect(m_upButton, &ScrollButton::clicked, this, &CycleListWidget::scrollUp);
- connect(m_downButton, &ScrollButton::clicked, this, &CycleListWidget::scrollDown);
- connect(this, &CycleListWidget::itemClicked, this, &CycleListWidget::onItemClicked);
- this->installEventFilter(this);
- }
- void CycleListWidget::setItems(const QVariantList &items)
- {
- this->clear();
- createItems(items);
- }
- int CycleListWidget::currentIndex() const
- {
- return m_currentIndex;
- }
- void CycleListWidget::setCurrentIndex(int index)
- {
- if (!m_isCycle) {
- int n = m_visibleNumber / 2;
- m_currentIndex = qMax(n, qMin(n + m_originItems.count() - 1, index));
- } else {
- int N = this->count() / 2;
- int m = (m_visibleNumber + 1) / 2;
- m_currentIndex = index;
- // scroll to center to achieve circular scrolling
- if (index >= this->count() - m) {
- m_currentIndex = N + index - this->count();
- QListWidget::scrollToItem(this->item(this->currentIndex() - 1), PositionAtCenter);
- } else if (index <= m - 1) {
- m_currentIndex = N + index;
- QListWidget::scrollToItem(this->item(N + index + 1), PositionAtCenter);
- }
- }
- }
- QListWidgetItem *CycleListWidget::currentItem() const
- {
- return this->item(this->currentIndex());
- }
- /// scroll to item, scroll to center position
- void CycleListWidget::scrollToItem(QListWidgetItem *item, QAbstractItemView::ScrollHint /*hint*/)
- {
- int index = this->row(item);
- int y = item->sizeHint().height() * (index - m_visibleNumber / 2);
- vScrollBar->scrollTo(y);
- // clear selection
- clearSelection();
- item->setSelected(false);
- emit currentItemChanged(item);
- }
- void CycleListWidget::setSelectedItem(const QString &text)
- {
- if (text.isEmpty()) {
- return;
- }
- auto items = this->findItems(text, Qt::MatchExactly);
- if (items.isEmpty()) {
- return;
- }
- if (items.count() >= 2) {
- setCurrentIndex(this->row(items.at(1)));
- } else {
- setCurrentIndex(this->row(items.at(0)));
- }
- QListWidget::scrollToItem(this->currentItem(), QListWidget::PositionAtCenter);
- }
- QSize CycleListWidget::itemSize() const
- {
- return m_itemSize;
- }
- bool CycleListWidget::eventFilter(QObject *watched, QEvent *event)
- {
- if (watched != this || event->type() != QEvent::KeyPress) {
- return QListWidget::eventFilter(watched, event);
- }
- if (event->type() == QEvent::KeyPress) {
- QKeyEvent *keyEvt = static_cast<QKeyEvent *>(event);
- if (keyEvt->key() == Qt::Key_Down) {
- scrollDown();
- return true;
- } else if (keyEvt->key() == Qt::Key_Up) {
- scrollUp();
- return true;
- }
- }
- return QListWidget::eventFilter(watched, event);
- }
- void CycleListWidget::wheelEvent(QWheelEvent *event)
- {
- if (event->angleDelta().y() < 0) {
- scrollDown();
- } else {
- scrollUp();
- }
- }
- void CycleListWidget::leaveEvent(QEvent * /*event*/)
- {
- m_upButton->hide();
- m_downButton->hide();
- }
- void CycleListWidget::resizeEvent(QResizeEvent * /*event*/)
- {
- m_upButton->resize(this->width(), 34);
- m_downButton->resize(this->width(), 34);
- m_downButton->move(0, this->height() - 34);
- }
- void CycleListWidget::enterEvent(QEvent * /*event*/)
- {
- m_upButton->show();
- m_downButton->show();
- }
- void CycleListWidget::createItems(const QVariantList &items)
- {
- const int N = items.count();
- m_isCycle = (N > m_visibleNumber);
- if (m_isCycle) {
- addColumnItems(items);
- addColumnItems(items);
- m_currentIndex = items.count();
- QListWidget::scrollToItem(this->item(this->currentIndex() - m_visibleNumber / 2), QListWidget::PositionAtTop);
- } else {
- int n = m_visibleNumber / 2; // add empty items to enable scrolling
- QVariantList emptyList;
- for (int i = 0; i < n; ++i) {
- emptyList << "";
- }
- addColumnItems(emptyList, true);
- addColumnItems(items);
- addColumnItems(emptyList, true);
- m_currentIndex = n;
- }
- }
- void CycleListWidget::addColumnItems(const QVariantList &items, bool disabled)
- {
- for (auto i : items) {
- auto item = new QListWidgetItem(i.toString(), this);
- item->setSizeHint(this->m_itemSize);
- item->setTextAlignment(this->m_align | Qt::AlignVCenter);
- if (disabled) {
- item->setFlags(Qt::NoItemFlags);
- }
- this->addItem(item);
- }
- }
- // scroll up an item
- void CycleListWidget::scrollUp()
- {
- this->setCurrentIndex(m_currentIndex - 1);
- this->scrollToItem(this->currentItem());
- }
- // scroll down an item
- void CycleListWidget::scrollDown()
- {
- this->setCurrentIndex(m_currentIndex + 1);
- this->scrollToItem(this->currentItem());
- }
- void CycleListWidget::onItemClicked(QListWidgetItem *item)
- {
- this->setCurrentIndex(this->row(item));
- this->scrollToItem(this->currentItem());
- }
|