diff --git a/src/dialogs/edittagdialog.cpp b/src/dialogs/edittagdialog.cpp index c0e0180c5..e29311cc5 100644 --- a/src/dialogs/edittagdialog.cpp +++ b/src/dialogs/edittagdialog.cpp @@ -199,6 +199,7 @@ EditTagDialog::EditTagDialog(const SharedPtr network, } else if (RatingBox *ratingbox = qobject_cast(widget)) { QObject::connect(ratingbox, &RatingWidget::RatingChanged, this, &EditTagDialog::FieldValueEdited); + QObject::connect(ratingbox, &RatingBox::Reset, this, &EditTagDialog::ResetField); } } } @@ -544,6 +545,20 @@ bool EditTagDialog::DoesValueVary(const QModelIndexList &sel, const QString &id) bool EditTagDialog::IsValueModified(const QModelIndexList &sel, const QString &id) const { + if (id == u"track"_s || id == u"disc"_s || id == u"year"_s) { + return std::any_of(sel.begin(), sel.end(), [this, id](const QModelIndex &i) { + const int original = data_[i.row()].original_value(id).toInt(); + const int current = data_[i.row()].current_value(id).toInt(); + return original != current && (original != -1 || current != 0); + }); + } + else if (id == u"rating"_s) { + return std::any_of(sel.begin(), sel.end(), [this, id](const QModelIndex &i) { + const float original = data_[i.row()].original_value(id).toFloat(); + const float current = data_[i.row()].current_value(id).toFloat(); + return original != current && (original != -1 || current != 0); + }); + } return std::any_of(sel.begin(), sel.end(), [this, id](const QModelIndex &i) { return data_[i.row()].original_value(id) != data_[i.row()].current_value(id); }); } @@ -605,7 +620,15 @@ void EditTagDialog::UpdateModifiedField(const FieldData &field, const QModelInde QFont new_font(font()); new_font.setBold(modified); field.label_->setFont(new_font); - if (field.editor_) field.editor_->setFont(new_font); + if (field.editor_) { + if (ExtendedEditor *editor = dynamic_cast(field.editor_)) { + editor->set_font(new_font); + editor->set_reset_button(modified); + } + else { + field.editor_->setFont(new_font); + } + } } diff --git a/src/dialogs/edittagdialog.ui b/src/dialogs/edittagdialog.ui index e1e4da0a7..c9dc2716f 100644 --- a/src/dialogs/edittagdialog.ui +++ b/src/dialogs/edittagdialog.ui @@ -944,7 +944,7 @@ - false + true false @@ -1011,6 +1011,9 @@ 0 + + true + true @@ -1072,7 +1075,20 @@ - + + + + 140 + 16777215 + + + + true + + + false + + @@ -1217,6 +1233,7 @@ grouping genre compilation + rating fetch_tag comment lyrics diff --git a/src/widgets/lineedit.cpp b/src/widgets/lineedit.cpp index 3af3c2a83..0380b04f4 100644 --- a/src/widgets/lineedit.cpp +++ b/src/widgets/lineedit.cpp @@ -37,12 +37,18 @@ #include #include #include +#include #include "core/iconloader.h" #include "lineedit.h" using namespace Qt::Literals::StringLiterals; +namespace { +constexpr int kClearIconSize = 16; +constexpr int kResetIconSize = 16; +} // namespace + ExtendedEditor::ExtendedEditor(QWidget *widget, int extra_right_padding, bool draw_hint) : LineEditInterface(widget), has_clear_button_(true), @@ -54,7 +60,7 @@ ExtendedEditor::ExtendedEditor(QWidget *widget, int extra_right_padding, bool dr is_rtl_(false) { clear_button_->setIcon(IconLoader::Load(u"edit-clear-locationbar-ltr"_s)); - clear_button_->setIconSize(QSize(16, 16)); + clear_button_->setIconSize(QSize(kClearIconSize, kClearIconSize)); clear_button_->setCursor(Qt::ArrowCursor); clear_button_->setStyleSheet(u"QToolButton { border: none; padding: 0px; }"_s); clear_button_->setToolTip(QWidget::tr("Clear")); @@ -64,7 +70,7 @@ ExtendedEditor::ExtendedEditor(QWidget *widget, int extra_right_padding, bool dr opt.initFrom(widget); reset_button_->setIcon(widget->style()->standardIcon(QStyle::SP_DialogResetButton, &opt, widget)); - reset_button_->setIconSize(QSize(16, 16)); + reset_button_->setIconSize(QSize(kResetIconSize, kResetIconSize)); reset_button_->setCursor(Qt::ArrowCursor); reset_button_->setStyleSheet(u"QToolButton { border: none; padding: 0px; }"_s); reset_button_->setToolTip(QWidget::tr("Reset")); @@ -220,9 +226,21 @@ SpinBox::SpinBox(QWidget *parent) : QSpinBox(parent), ExtendedEditor(this, 14, false) { + if (QGuiApplication::isRightToLeft()) { + extra_right_padding_ = 0; // Up/down arrows on left + } QObject::connect(reset_button_, &QToolButton::clicked, this, &SpinBox::Reset); } +QString SpinBox::textFromValue(int val) const { + + if (val <= 0 && !hint_.isEmpty()) { + return u"-"_s; + } + return QSpinBox::textFromValue(val); + +} + void SpinBox::paintEvent(QPaintEvent *e) { QSpinBox::paintEvent(e); Paint(this); @@ -234,8 +252,10 @@ void SpinBox::resizeEvent(QResizeEvent *e) { } CheckBox::CheckBox(QWidget *parent) - : QCheckBox(parent), ExtendedEditor(this, 14, false) { + : QCheckBox(parent), ExtendedEditor(this, 4, false) { + has_clear_button_ = false; + is_rtl_ = QGuiApplication::isRightToLeft(); QObject::connect(reset_button_, &QToolButton::clicked, this, &CheckBox::Reset); } @@ -250,20 +270,46 @@ void CheckBox::resizeEvent(QResizeEvent *e) { Resize(); } -QString SpinBox::textFromValue(int val) const { +void CheckBox::Resize() { - if (val <= 0 && !hint_.isEmpty()) { - return u"-"_s; + const QSize sz = widget_->sizeHint(); + const int frame_width = widget_->style()->pixelMetric(QStyle::PM_DefaultFrameWidth); + const int y = (rect().height() - sz.height()) / 2 - frame_width; // Less frame width as outside + + if (!is_rtl_) { + reset_button_->move(frame_width + sz.width() + extra_right_padding_, y); // Using `extra_right_padding_` as how far to right of checkbox + } + else { + reset_button_->move(rect().width() - (frame_width + sz.width() + kResetIconSize + extra_right_padding_), y); } - return QSpinBox::textFromValue(val); } RatingBox::RatingBox(QWidget *parent) : RatingWidget(parent), - ExtendedEditor(this) { + ExtendedEditor(this, 6) { - clear_button_->hide(); - reset_button_->hide(); + has_clear_button_ = false; + QObject::connect(reset_button_, &QToolButton::clicked, this, &RatingBox::Reset); + +} + +void RatingBox::paintEvent(QPaintEvent *e) { + RatingWidget::paintEvent(e); + Paint(this); +} + +void RatingBox::resizeEvent(QResizeEvent *e) { + RatingWidget::resizeEvent(e); + Resize(); +} + +void RatingBox::Resize() { + + const QSize sz = widget_->sizeHint(); + const int frame_width = widget_->style()->pixelMetric(QStyle::PM_DefaultFrameWidth); + const int y = (rect().height() - sz.height()) / 2 + frame_width; // Plus frame width as inside + + reset_button_->move(frame_width + rect().width() - (kResetIconSize + extra_right_padding_), y); } diff --git a/src/widgets/lineedit.h b/src/widgets/lineedit.h index 5edced794..62284e822 100644 --- a/src/widgets/lineedit.h +++ b/src/widgets/lineedit.h @@ -48,6 +48,7 @@ class LineEditInterface { virtual ~LineEditInterface() {} virtual void set_enabled(const bool enabled) = 0; + virtual void set_font(const QFont &font) = 0; virtual void set_focus() = 0; virtual void clear() = 0; @@ -90,7 +91,7 @@ class ExtendedEditor : public LineEditInterface { protected: void Paint(QPaintDevice *device); - void Resize(); + virtual void Resize(); private: void UpdateButtonGeometry(); @@ -121,6 +122,7 @@ class LineEdit : public QLineEdit, public ExtendedEditor { // ExtendedEditor void set_enabled(bool enabled) override { QLineEdit::setEnabled(enabled); } + void set_font(const QFont &font) override { QLineEdit::setFont(font); } QVariant value() const override { return QLineEdit::text(); } void set_value(const QVariant &value) override { QLineEdit::setText(value.toString()); } @@ -130,8 +132,8 @@ class LineEdit : public QLineEdit, public ExtendedEditor { void clear() override { QLineEdit::clear(); } protected: - void paintEvent(QPaintEvent*) override; - void resizeEvent(QResizeEvent*) override; + void paintEvent(QPaintEvent *e) override; + void resizeEvent(QResizeEvent *e) override; private: bool is_rtl() const { return is_rtl_; } @@ -155,6 +157,7 @@ class TextEdit : public QPlainTextEdit, public ExtendedEditor { // ExtendedEditor void set_enabled(bool enabled) override { QPlainTextEdit::setEnabled(enabled); } + void set_font(const QFont &font) override { QPlainTextEdit::setFont(font); } QVariant value() const override { return QPlainTextEdit::toPlainText(); } void set_value(const QVariant &value) override { QPlainTextEdit::setPlainText(value.toString()); } @@ -164,8 +167,8 @@ class TextEdit : public QPlainTextEdit, public ExtendedEditor { void clear() override { QPlainTextEdit::clear(); } protected: - void paintEvent(QPaintEvent*) override; - void resizeEvent(QResizeEvent*) override; + void paintEvent(QPaintEvent *e) override; + void resizeEvent(QResizeEvent *e) override; Q_SIGNALS: void Reset(); @@ -185,6 +188,7 @@ class SpinBox : public QSpinBox, public ExtendedEditor { // ExtendedEditor void set_enabled(bool enabled) override { QSpinBox::setEnabled(enabled); } + void set_font(const QFont &font) override { QSpinBox::setFont(font); } QVariant value() const override { return QSpinBox::value(); } void set_value(const QVariant &value) override { QSpinBox::setValue(value.toInt()); } @@ -195,8 +199,8 @@ class SpinBox : public QSpinBox, public ExtendedEditor { void clear() override { QSpinBox::clear(); } protected: - void paintEvent(QPaintEvent*) override; - void resizeEvent(QResizeEvent*) override; + void paintEvent(QPaintEvent *e) override; + void resizeEvent(QResizeEvent *e) override; Q_SIGNALS: void Reset(); @@ -213,19 +217,23 @@ class CheckBox : public QCheckBox, public ExtendedEditor { // ExtendedEditor void set_enabled(bool enabled) override { QCheckBox::setEnabled(enabled); } + void set_font(const QFont &font) override { QCheckBox::setFont(font); } bool is_empty() const override { return text().isEmpty() || text() == QStringLiteral("0"); } QVariant value() const override { return QCheckBox::isChecked(); } void set_value(const QVariant &value) override { QCheckBox::setCheckState(value.toBool() ? Qt::Checked : Qt::Unchecked); } void set_partially() override { QCheckBox::setCheckState(Qt::PartiallyChecked); } + protected: + void Resize() override; + public Q_SLOTS: void set_focus() override { QCheckBox::setFocus(); } void clear() override { QCheckBox::setChecked(false); } protected: - void paintEvent(QPaintEvent*) override; - void resizeEvent(QResizeEvent*) override; + void paintEvent(QPaintEvent *e) override; + void resizeEvent(QResizeEvent *e) override; Q_SIGNALS: void Reset(); @@ -240,16 +248,27 @@ class RatingBox : public RatingWidget, public ExtendedEditor { explicit RatingBox(QWidget *parent = nullptr); void set_enabled(bool enabled) override { RatingWidget::setEnabled(enabled); } + void set_font(const QFont &font) override { RatingWidget::setFont(font); } QVariant value() const override { return RatingWidget::rating(); } void set_value(const QVariant &value) override { RatingWidget::set_rating(value.toFloat()); } void set_partially() override { RatingWidget::set_rating(0.0F); } + protected: + void Resize() override; + public Q_SLOTS: void set_focus() override { RatingWidget::setFocus(); } void clear() override {} + protected: + void paintEvent(QPaintEvent *e) override; + void resizeEvent(QResizeEvent *e) override; + + Q_SIGNALS: + void Reset(); + }; #endif // LINEEDIT_H diff --git a/src/widgets/ratingwidget.cpp b/src/widgets/ratingwidget.cpp index 245e53de6..fed04f069 100644 --- a/src/widgets/ratingwidget.cpp +++ b/src/widgets/ratingwidget.cpp @@ -113,6 +113,7 @@ RatingWidget::RatingWidget(QWidget *parent) : QWidget(parent), rating_(0.0), hov setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); setMouseTracking(true); + setFocusPolicy(Qt::StrongFocus); } @@ -173,3 +174,31 @@ void RatingWidget::leaveEvent(QEvent *e) { update(); } + +void RatingWidget::keyPressEvent(QKeyEvent *e) { + + constexpr float arrow_incr = 0.5f / RatingPainter::kStarCount; + + float rating = -1.0f; + + if (e->key() >= Qt::Key_0 && e->key() <= Qt::Key_9) { + rating = qBound(0.0f, static_cast(e->key() - Qt::Key_0) / RatingPainter::kStarCount, 1.0f); + } + else if (e->key() == Qt::Key_Left) { + rating = qBound(0.0f, rating_ - arrow_incr, 1.0f); + } + else if (e->key() == Qt::Key_Right) { + rating = qBound(0.0f, rating_ + arrow_incr, 1.0f); + } + + if (rating != -1.0f) { + if (rating != rating_) { + rating_ = rating; + Q_EMIT RatingChanged(rating_); + } + } + else { + QWidget::keyPressEvent(e); + } + +} diff --git a/src/widgets/ratingwidget.h b/src/widgets/ratingwidget.h index 3788153e2..192def571 100644 --- a/src/widgets/ratingwidget.h +++ b/src/widgets/ratingwidget.h @@ -63,6 +63,7 @@ class RatingWidget : public QWidget { void mousePressEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; void leaveEvent(QEvent *e) override; + void keyPressEvent(QKeyEvent *e) override; private: RatingPainter painter_;