From 3f0f05f3971750b4b265f3c84e444b9c61ad7909 Mon Sep 17 00:00:00 2001 From: kradchen Date: Wed, 18 Sep 2024 13:06:25 +0800 Subject: [PATCH] feat: Improve date picker, add select item loop logic --- src/components/DateSlidePickerBox.cpp | 5 + src/components/SlidePickerBox.cpp | 304 +++++++++++++++++++------- src/components/SlidePickerBox.h | 4 + 3 files changed, 232 insertions(+), 81 deletions(-) diff --git a/src/components/DateSlidePickerBox.cpp b/src/components/DateSlidePickerBox.cpp index 2577922..d0b0465 100644 --- a/src/components/DateSlidePickerBox.cpp +++ b/src/components/DateSlidePickerBox.cpp @@ -13,11 +13,15 @@ DateSlidePickerBox::DateSlidePickerBox(QWidget *parent) initBox(mHundredYearBox, {"19", "20"}, 56); QStringList tenYearValues{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}; + mTenYearBox->setLoop(true); + mYearBox->setLoop(true); + initBox(mTenYearBox, tenYearValues); initBox(mYearBox, tenYearValues); addSplitLabel(); + mMonthBox->setLoop(true); QStringList monthValues{"01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"}; initBox(mMonthBox, monthValues, 56); @@ -27,6 +31,7 @@ DateSlidePickerBox::DateSlidePickerBox(QWidget *parent) for (int i = 13; i <= 31; i++) { days << QString("%1").arg(i, 2); } + mDayBox->setLoop(true); initBox(mDayBox, days, 56); mBigMonthList.append({"01", "03", "05", "07", "08", "10", "12"}); diff --git a/src/components/SlidePickerBox.cpp b/src/components/SlidePickerBox.cpp index b41afd7..fc84ec5 100644 --- a/src/components/SlidePickerBox.cpp +++ b/src/components/SlidePickerBox.cpp @@ -6,8 +6,8 @@ #include #include - -namespace { +namespace +{ const int LABEL_FONT_SIZE = 80; const int LABEL_CENTER_Y = 150; const int LABEL_HEIGHT = 110; @@ -19,11 +19,7 @@ namespace { const int SELECTED_AREA_BOTTOM = 200; } SlidePickerBox::SlidePickerBox(QWidget *parent) -: QWidget(parent) -, mIsDragging(false) -, mOriginPosY(0) -, mSelectedIndex(0) -, mSelectedLbl(new QLabel(this)) + : QWidget(parent), mIsDragging(false), mOriginPosY(0), mSelectedIndex(0), mLoopItem(false), mSelectedLbl(new QLabel(this)) { this->setFixedHeight(360); mSelectedLbl->setText("2"); @@ -45,46 +41,115 @@ SlidePickerBox::SlidePickerBox(QWidget *parent) linePlaceholderWidget->move(lp); } -void SlidePickerBox::mousePressEvent(QMouseEvent * ev) { +void SlidePickerBox::mousePressEvent(QMouseEvent *ev) +{ mIsDragging = true; mOriginPosY = ev->pos().y(); - QWidget::mousePressEvent( ev); + QWidget::mousePressEvent(ev); } -void SlidePickerBox::mouseMoveEvent(QMouseEvent *ev) { - //只有一个label,无需滑动 - if (mLabels.count() < 2) return; - if (nullptr == mSelectedLbl) return; +void SlidePickerBox::mouseMoveEvent(QMouseEvent *ev) +{ + // 只有一个label,无需滑动 + if (mLabels.count() < 2) + return; + if (nullptr == mSelectedLbl) + return; if (mIsDragging) { int offset = (ev->pos().y() - mOriginPosY); - //防止速度过快 - while(abs(offset)>50) + // 防止速度过快 + while (abs(offset) > 50) { - offset=offset/2; + offset = offset / 2; } - //防止拉过头 + // 防止拉过头 int selItemCenterY = mSelectedLbl->geometry().center().y(); - if (mSelectedLbl == getEnabledLastLabel() && selItemCenterY <= LABEL_CENTER_Y && offset < 0) return; - if (mSelectedLbl == getEnabledFirstLabel() && selItemCenterY >= LABEL_CENTER_Y && offset > 0) return; - int i = 0; - for (auto item : mLabels) + if (!mLoopItem || mLabels.count() < 3) { - if (mDisabledItems.contains(item->text()))continue; - //不需要横向,只需要纵向 - int ny = item->geometry().top() + offset; - item->move(item->geometry().left(),ny); - int centerY = item->geometry().center().y(); - if (centerY <= SELECTED_AREA_BOTTOM+5 - && centerY > SELECTED_AREA_TOP-5) + if (mSelectedLbl == getEnabledLastLabel() && selItemCenterY <= LABEL_CENTER_Y && offset < 0) + return; + if (mSelectedLbl == getEnabledFirstLabel() && selItemCenterY >= LABEL_CENTER_Y && offset > 0) + return; + int i = 0; + for (auto item : mLabels) { - item->setStyleSheet("color:white"); - mSelectedLbl = item; - mSelectedIndex = i; - } else{ - item->setStyleSheet("background:transparent"); + if (mDisabledItems.contains(item->text())) + continue; + // 不需要横向,只需要纵向 + int ny = item->geometry().top() + offset; + item->move(item->geometry().left(), ny); + int centerY = item->geometry().center().y(); + // new in selectd area + if (centerY <= SELECTED_AREA_BOTTOM + 5 && centerY > SELECTED_AREA_TOP - 5) + { + item->setStyleSheet("color:white"); + mSelectedLbl = item; + mSelectedIndex = i; + } + else + { + item->setStyleSheet("background:transparent"); + } + i++; + } + } + else + { + int newSelectedIndex = 0; + for (int i = 0; itext())) + continue; + // 不需要横向,只需要纵向 + int ny = mLabels[i]->geometry().top() + offset; + mLabels[i]->move(mLabels[i]->geometry().left(), ny); + int centerY = mLabels[i]->geometry().center().y(); + // new in selectd area + if (centerY <= SELECTED_AREA_BOTTOM + 5 && centerY > SELECTED_AREA_TOP - 5) + { + mSelectedLbl->setStyleSheet("background:transparent"); + mSelectedLbl = mLabels[i]; + newSelectedIndex = i; + } + + } + + mSelectedLbl->setStyleSheet("color:white"); + if (newSelectedIndex > mSelectedIndex) + { + auto lastVisibelBack = mLabels.back(); + int i = mLabels.length()-2; + while (!lastVisibelBack->isVisible()) + { + lastVisibelBack = mLabels[i--]; + } + do + { + auto first = mLabels.first(); + mLabels.pop_front(); + mLabels.push_back(first); + } while (!mLabels.back()->isVisible()); + mLabels.back()->move(lastVisibelBack->geometry().left(), + lastVisibelBack->geometry().top()+LABEL_HEIGHT); + } + else if(newSelectedIndex < mSelectedIndex) + { + auto lastVisibelFirst = mLabels.first(); + int i = 1; + while (!lastVisibelFirst->isVisible()) + { + lastVisibelFirst = mLabels[i++]; + } + do + { + auto back = mLabels.back(); + mLabels.pop_back(); + mLabels.push_front(back); + } while (!mLabels.first()->isVisible()); + mLabels.first()->move(lastVisibelFirst->geometry().left(), + lastVisibelFirst->geometry().top()-LABEL_HEIGHT); } - i++; } mOriginPosY = ev->pos().y(); repaint(); @@ -92,33 +157,36 @@ void SlidePickerBox::mouseMoveEvent(QMouseEvent *ev) { QWidget::mouseMoveEvent(ev); } -void SlidePickerBox::mouseReleaseEvent(QMouseEvent *ev) { +void SlidePickerBox::mouseReleaseEvent(QMouseEvent *ev) +{ mIsDragging = false; adjustPosition(); QWidget::mouseReleaseEvent(ev); QString v = getSelectedValue(); emit valueChanged(v); } +void SlidePickerBox::adjustPosition() const +{ -void SlidePickerBox::adjustPosition() const { - if(mSelectedLbl == nullptr) + if (mSelectedLbl == nullptr) { return; } if (mSelectedLbl->geometry().center().y() != LABEL_CENTER_Y) { - //选择完毕,选中项回归正位 + // 选择完毕,选中项回归正位 int offset = LABEL_CENTER_Y - mSelectedLbl->geometry().center().y(); for (auto item : mLabels) { - int ny = item->geometry().top()+offset; - item->move(item->geometry().left(),ny); + int ny = item->geometry().top() + offset; + item->move(item->geometry().left(), ny); } } } -void SlidePickerBox::setItems(const QStringList& itemsList) { +void SlidePickerBox::setItems(const QStringList &itemsList) +{ this->mItems = itemsList; hideLabel(mSelectedLbl); for (auto item : mLabels) @@ -127,8 +195,8 @@ void SlidePickerBox::setItems(const QStringList& itemsList) { } mSelectedLbl = nullptr; mLabels.clear(); - QPoint p = {MARGIN_LEFT,-LABEL_CENTER_Y}; - for (const QString& str : this->mItems) + QPoint p = {MARGIN_LEFT, -LABEL_CENTER_Y}; + for (const QString &str : this->mItems) { auto lbl = new QLabel(this); lbl->setText(str); @@ -140,21 +208,42 @@ void SlidePickerBox::setItems(const QStringList& itemsList) { mLabels.push_back(lbl); lbl->move(p); } - mSelectedIndex = mLabels.count() - 1; - if(!mItems.isEmpty()) + if (!mLoopItem || mLabels.count() <= 3) { - setSelectedValue(this->mItems.last()); + mSelectedIndex = mLabels.count() - 1; + if (!mItems.isEmpty()) + { + setSelectedValue(this->mItems.last()); + } + } + else + { + mSelectedIndex = (mLabels.count() + 1) / 2; + if (!mItems.isEmpty()) + { + setSelectedValue(mLabels[mSelectedIndex]->text()); + } } } -QString SlidePickerBox::getSelectedValue() { - if (!mSelectedLbl) return ""; +void SlidePickerBox::setLoop(bool aIsLoop) +{ + mLoopItem = aIsLoop; +} + +QString SlidePickerBox::getSelectedValue() +{ + if (!mSelectedLbl) + return ""; return mSelectedLbl->text(); } -void SlidePickerBox::setCurrentLabel(QLabel *label) { - if (mSelectedLbl)hideLabel(mSelectedLbl); - if (label) { +void SlidePickerBox::setCurrentLabel(QLabel *label) +{ + if (mSelectedLbl) + hideLabel(mSelectedLbl); + if (label) + { QPoint p = {MARGIN_LEFT, MARGIN_TOP}; label->move(p); label->show(); @@ -162,47 +251,92 @@ void SlidePickerBox::setCurrentLabel(QLabel *label) { } } -QLabel * SlidePickerBox::getEnabledFirstLabel() { - if (mDisabledItems.empty()) return mLabels.first(); - for(int idx = 0; idx < mDisabledItems.size(); ++idx){ - if(mDisabledItems.contains(mLabels[idx]->text()))continue; +QLabel *SlidePickerBox::getEnabledFirstLabel() +{ + if (mDisabledItems.empty()) + return mLabels.first(); + for (int idx = 0; idx < mDisabledItems.size(); ++idx) + { + if (mDisabledItems.contains(mLabels[idx]->text())) + continue; return mLabels[idx]; } return nullptr; } -QLabel * SlidePickerBox::getEnabledLastLabel() { - if (mDisabledItems.empty()) return mLabels.last(); - for(int idx = mLabels.size() - 1; idx >= 0; --idx){ - if(mDisabledItems.contains(mLabels[idx]->text()))continue; +QLabel *SlidePickerBox::getEnabledLastLabel() +{ + if (mDisabledItems.empty()) + return mLabels.last(); + for (int idx = mLabels.size() - 1; idx >= 0; --idx) + { + if (mDisabledItems.contains(mLabels[idx]->text())) + continue; return mLabels[idx]; } return nullptr; } -void SlidePickerBox::hideLabel(QLabel *label) { - if (!label) return; +void SlidePickerBox::hideLabel(QLabel *label) +{ + if (!label) + return; QPoint p = {MARGIN_LEFT, -LABEL_CENTER_Y}; label->move(p); } -void SlidePickerBox::setSelectedValue(const QString& val) { - for (int i = 0; i < mLabels.count() ; ++i) { - if(mLabels[i]->text() == val) { - mSelectedIndex = i; - break; +void SlidePickerBox::setSelectedValue(const QString &val) +{ + if (!mLoopItem || mLabels.count() <= 3) + { + for (int i = 0; i < mLabels.count(); ++i) + { + if (mLabels[i]->text() == val) + { + mSelectedIndex = i; + break; + } } } - int firstLabelY = -LABEL_HEIGHT * (mSelectedIndex - 1); - for (int i = 0; i < mLabels.count() ; ++i) { + else + { + int newSelectIndex = 0; + for (int i = 0; i < mLabels.count(); ++i) + { + if (mLabels[i]->text() == val) + { + newSelectIndex = i; + break; + } + } + bool step = newSelectIndex > mSelectedIndex; + int round = abs(newSelectIndex - mSelectedIndex); + for (int i = 0; i < round; i++) + { + if (step) + { + auto item = mLabels.first(); + mLabels.pop_front(); + mLabels.push_back(item); + } + else + { + auto item = mLabels.back(); + mLabels.pop_back(); + mLabels.push_front(item); + } + } + } + int firstLabelY = -LABEL_HEIGHT * (mSelectedIndex-1); + for (int i = 0; i < mLabels.count(); ++i) + { QPoint leftPoint = this->mapTo(this, {MARGIN_LEFT, firstLabelY + i * LABEL_HEIGHT}); mLabels[i]->move(leftPoint); mLabels[i]->show(); mLabels[i]->setStyleSheet("background:transparent"); - } - if(mSelectedIndex >= 0) + if (mSelectedIndex >= 0) { mSelectedLbl = mLabels[mSelectedIndex]; mLabels[mSelectedIndex]->setStyleSheet("color:white"); @@ -210,33 +344,42 @@ void SlidePickerBox::setSelectedValue(const QString& val) { adjustPosition(); } -void SlidePickerBox::resizeLabelWidth() { - for (int i = 0; i < mLabels.count() ; ++i) { +void SlidePickerBox::resizeLabelWidth() +{ + for (int i = 0; i < mLabels.count(); ++i) + { mLabels[i]->setAlignment(Qt::AlignCenter); mLabels[i]->setFixedWidth(this->width() + this->contentsMargins().left() + this->contentsMargins().right()); } } -void SlidePickerBox::disableItem(const QString& val) { - if (!mDisabledItems.contains(val)){ +void SlidePickerBox::disableItem(const QString &val) +{ + if (!mDisabledItems.contains(val)) + { mDisabledItems.append(val); rearrangeLabels(); } } -void SlidePickerBox::enableItem(const QString &val) { - if (mDisabledItems.contains(val)){ +void SlidePickerBox::enableItem(const QString &val) +{ + if (mDisabledItems.contains(val)) + { mDisabledItems.removeOne(val); rearrangeLabels(); } } -void SlidePickerBox::rearrangeLabels() { +void SlidePickerBox::rearrangeLabels() +{ int firstLabelY = -100 * (mSelectedIndex - 1); int visibleItemIndex = 0; - for (int i = 0; i < mLabels.count() ; ++i) { - if (mDisabledItems.contains(mLabels[i]->text())){ - mLabels[i]->hide(); + for (int i = 0; i < mLabels.count(); ++i) + { + if (mDisabledItems.contains(mLabels[i]->text())) + { + mLabels[i]->setVisible(false); continue; } QPoint p = this->mapTo(this, {MARGIN_LEFT, firstLabelY + visibleItemIndex * LABEL_HEIGHT}); @@ -249,4 +392,3 @@ void SlidePickerBox::rearrangeLabels() { mLabels[mSelectedIndex]->setStyleSheet("color:white"); adjustPosition(); } - diff --git a/src/components/SlidePickerBox.h b/src/components/SlidePickerBox.h index 22e6d94..9d4bdf0 100644 --- a/src/components/SlidePickerBox.h +++ b/src/components/SlidePickerBox.h @@ -2,6 +2,7 @@ #define GUI_SLIDEPICKERBOX_H #include +#include class QLabel; class SlidePickerBox:public QWidget { Q_OBJECT @@ -9,6 +10,8 @@ public: explicit SlidePickerBox(QWidget *parent = nullptr); QString getSelectedValue(); void setItems(const QStringList& itemsList); + void setLoop(bool isLoop); + void addItem(QString& item) { this->mItems.append(item); } @@ -37,6 +40,7 @@ protected: private: int mOriginPosY; int mSelectedIndex; + bool mLoopItem; QLabel* mSelectedLbl; QList mLabels; QStringList mItems;