From fb224608ae6cdf98bf4403aca050056cbe65bd55 Mon Sep 17 00:00:00 2001 From: David Sansome Date: Tue, 26 Oct 2010 19:59:55 +0000 Subject: [PATCH] Add a rating widget, use it in the smart playlist dialog, refactor the playlist delegate to use it. --- src/CMakeLists.txt | 2 + src/playlist/playlistdelegates.cpp | 70 +-------- src/playlist/playlistdelegates.h | 9 +- src/playlist/playlistview.cpp | 2 +- .../smartplaylistsearchtermwidget.cpp | 29 +++- .../smartplaylistsearchtermwidget.h | 4 + .../smartplaylistsearchtermwidget.ui | 21 +++ src/widgets/ratingwidget.cpp | 141 ++++++++++++++++++ src/widgets/ratingwidget.h | 62 ++++++++ 9 files changed, 267 insertions(+), 73 deletions(-) create mode 100644 src/widgets/ratingwidget.cpp create mode 100644 src/widgets/ratingwidget.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5ff8c189a..b6863bbfc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -195,6 +195,7 @@ set(SOURCES widgets/prettyimage.cpp widgets/prettyimageview.cpp widgets/progressitemdelegate.cpp + widgets/ratingwidget.cpp widgets/sliderwidget.cpp widgets/spinbox.cpp widgets/stickyslider.cpp @@ -349,6 +350,7 @@ set(HEADERS widgets/prettyimage.h widgets/prettyimageview.h widgets/progressitemdelegate.h + widgets/ratingwidget.h widgets/sliderwidget.h widgets/spinbox.h widgets/stickyslider.h diff --git a/src/playlist/playlistdelegates.cpp b/src/playlist/playlistdelegates.cpp index c5c82f56a..d26ddedff 100644 --- a/src/playlist/playlistdelegates.cpp +++ b/src/playlist/playlistdelegates.cpp @@ -42,9 +42,6 @@ const float QueuedItemDelegate::kQueueOpacityLowerBound = 0.4; const int PlaylistDelegateBase::kMinHeight = 19; -const int RatingItemDelegate::kStarCount; -const int RatingItemDelegate::kStarSize; - QueuedItemDelegate::QueuedItemDelegate(QObject *parent, int indicator_column) : QStyledItemDelegate(parent), indicator_column_(indicator_column) @@ -292,56 +289,6 @@ QWidget* TextItemDelegate::createEditor( RatingItemDelegate::RatingItemDelegate(QObject* parent) : PlaylistDelegateBase(parent) { - // Load the base pixmaps - QPixmap on(":/star-on.png"); - QPixmap off(":/star-off.png"); - - // Generate the 10 states, better to do it now than on the fly - for (int i=0 ; idrawPixmap(QRect(pos, size), stars_[star], QRect(QPoint(0,0), size)); + painter_.Paint(painter, option.rect, rating); } QSize RatingItemDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index) const { QSize size = PlaylistDelegateBase::sizeHint(option, index); - size.setWidth(size.height() * kStarCount); + size.setWidth(size.height() * RatingPainter::kStarCount); return size; } @@ -382,7 +324,7 @@ QString RatingItemDelegate::displayText( return QString(); // Round to the nearest 0.5 - const double rating = float(int(value.toDouble() * kStarCount * 2 + 0.5)) / 2; + const double rating = float(int(value.toDouble() * RatingPainter::kStarCount * 2 + 0.5)) / 2; return QString::number(rating, 'f', 1); } diff --git a/src/playlist/playlistdelegates.h b/src/playlist/playlistdelegates.h index c2fcf8b2d..7bcbf25f0 100644 --- a/src/playlist/playlistdelegates.h +++ b/src/playlist/playlistdelegates.h @@ -19,6 +19,7 @@ #include "playlist.h" #include "library/library.h" +#include "widgets/ratingwidget.h" #include #include @@ -117,14 +118,8 @@ public: bool is_mouse_over() const { return mouse_over_index_.isValid(); } QModelIndex mouse_over_index() const { return mouse_over_index_; } - static QRect ContentRect(const QRect& total); - static double RatingForPos(const QPoint& pos, const QRect& total_rect); - - static const int kStarCount = 5; - static const int kStarSize = 15; - private: - QPixmap stars_[kStarCount*2+1]; + RatingPainter painter_; QModelIndex mouse_over_index_; QPoint mouse_over_pos_; diff --git a/src/playlist/playlistview.cpp b/src/playlist/playlistview.cpp index c799873b9..2359b87e8 100644 --- a/src/playlist/playlistview.cpp +++ b/src/playlist/playlistview.cpp @@ -523,7 +523,7 @@ void PlaylistView::mousePressEvent(QMouseEvent* event) { if (event->button() == Qt::LeftButton && index.isValid() && index.data(Playlist::Role_CanSetRating).toBool()) { // Calculate which star was clicked - double new_rating = RatingItemDelegate::RatingForPos( + double new_rating = RatingPainter::RatingForPos( event->pos(), visualRect(index)); emit SongRatingSet(index, new_rating); } else { diff --git a/src/smartplaylists/smartplaylistsearchtermwidget.cpp b/src/smartplaylists/smartplaylistsearchtermwidget.cpp index 36032712c..c12941992 100644 --- a/src/smartplaylists/smartplaylistsearchtermwidget.cpp +++ b/src/smartplaylists/smartplaylistsearchtermwidget.cpp @@ -104,7 +104,9 @@ void SmartPlaylistSearchTermWidget::FieldChanged(int index) { // Populate the operator combo box ui_->op->clear(); foreach (SmartPlaylistSearchTerm::Operator op, SmartPlaylistSearchTerm::OperatorsForType(type)) { + const int i = ui_->op->count(); ui_->op->addItem(SmartPlaylistSearchTerm::OperatorText(type, op)); + ui_->op->setItemData(i, op); } // Show the correct value editor @@ -113,7 +115,7 @@ void SmartPlaylistSearchTermWidget::FieldChanged(int index) { case SmartPlaylistSearchTerm::Type_Time: page = ui_->page_time; break; case SmartPlaylistSearchTerm::Type_Number: page = ui_->page_number; break; case SmartPlaylistSearchTerm::Type_Date: page = ui_->page_date; break; - case SmartPlaylistSearchTerm::Type_Rating: page = ui_->page_number; break; // TODO + case SmartPlaylistSearchTerm::Type_Rating: page = ui_->page_rating; break; case SmartPlaylistSearchTerm::Type_Text: page = ui_->page_text; break; } ui_->value_stack->setCurrentWidget(page); @@ -190,6 +192,31 @@ float SmartPlaylistSearchTermWidget::overlay_opacity() const { return overlay_ ? overlay_->opacity() : 0.0; } +SmartPlaylistSearchTerm SmartPlaylistSearchTermWidget::Term() const { + const int field = ui_->field->itemData(ui_->field->currentIndex()).toInt(); + const int op = ui_->op->itemData(ui_->op->currentIndex()).toInt(); + + SmartPlaylistSearchTerm ret; + ret.field_ = SmartPlaylistSearchTerm::Field(field); + ret.operator_ = SmartPlaylistSearchTerm::Operator(op); + + // The value depends on the data type + const QWidget* value_page = ui_->value_stack->currentWidget(); + if (value_page == ui_->page_text) { + ret.value_ = ui_->value_text->text(); + } else if (value_page == ui_->page_number) { + ret.value_ = ui_->value_number->value(); + } else if (value_page == ui_->page_date) { + ret.value_ = ui_->value_date->dateTime().toTime_t(); + } else if (value_page == ui_->page_time) { + ret.value_ = QTime(0,0).secsTo(ui_->value_time->time()); + } else if (value_page == ui_->page_rating) { + ret.value_ = ui_->value_rating->rating(); + } + + return ret; +} + SmartPlaylistSearchTermWidget::Overlay::Overlay(SmartPlaylistSearchTermWidget* parent) diff --git a/src/smartplaylists/smartplaylistsearchtermwidget.h b/src/smartplaylists/smartplaylistsearchtermwidget.h index 4a6528ad3..8ab7cc907 100644 --- a/src/smartplaylists/smartplaylistsearchtermwidget.h +++ b/src/smartplaylists/smartplaylistsearchtermwidget.h @@ -17,6 +17,8 @@ #ifndef SMARTPLAYLISTSEARCHTERMWIDGET_H #define SMARTPLAYLISTSEARCHTERMWIDGET_H +#include "smartplaylistsearchterm.h" + #include #include @@ -40,6 +42,8 @@ public: float overlay_opacity() const; void set_overlay_opacity(float opacity); + SmartPlaylistSearchTerm Term() const; + signals: void Clicked(); void RemoveClicked(); diff --git a/src/smartplaylists/smartplaylistsearchtermwidget.ui b/src/smartplaylists/smartplaylistsearchtermwidget.ui index 6595c4bb5..5fe8a9171 100644 --- a/src/smartplaylists/smartplaylistsearchtermwidget.ui +++ b/src/smartplaylists/smartplaylistsearchtermwidget.ui @@ -78,6 +78,19 @@ + + + + 0 + + + 0 + + + + + + @@ -164,6 +177,14 @@ + + + RatingWidget + QWidget +
widgets/ratingwidget.h
+ 1 +
+
diff --git a/src/widgets/ratingwidget.cpp b/src/widgets/ratingwidget.cpp new file mode 100644 index 000000000..cf44d37d9 --- /dev/null +++ b/src/widgets/ratingwidget.cpp @@ -0,0 +1,141 @@ +/* This file is part of Clementine. + + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Clementine is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Clementine. If not, see . +*/ + +#include "ratingwidget.h" + +#include +#include +#include +#include + +const int RatingPainter::kStarCount; +const int RatingPainter::kStarSize; + +RatingPainter::RatingPainter() { + // Load the base pixmaps + QPixmap on(":/star-on.png"); + QPixmap off(":/star-off.png"); + + // Generate the 10 states, better to do it now than on the fly + for (int i=0 ; idrawPixmap(QRect(pos, size), stars_[star], QRect(QPoint(0,0), size)); +} + + +RatingWidget::RatingWidget(QWidget* parent) + : QWidget(parent), + rating_(0.0), + hover_rating_(-1.0) +{ + setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + setMouseTracking(true); +} + +QSize RatingWidget::sizeHint() const { + return QSize(RatingPainter::kStarSize * RatingPainter::kStarCount, + RatingPainter::kStarSize); +} + +void RatingWidget::set_rating(float rating) { + rating_ = rating; + update(); +} + +void RatingWidget::paintEvent(QPaintEvent* e) { + QStylePainter p(this); + + // Draw the background + QStyleOptionFrameV3 opt; + opt.initFrom(this); + opt.state |= QStyle::State_Sunken; + opt.frameShape = QFrame::StyledPanel; + opt.lineWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &opt, this); + opt.midLineWidth = 0; + + p.drawPrimitive(QStyle::PE_PanelLineEdit, opt); + + // Draw the stars + painter_.Paint(&p, rect(), hover_rating_ == -1.0 ? rating_ : hover_rating_); +} + +void RatingWidget::mousePressEvent(QMouseEvent* e) { + rating_ = RatingPainter::RatingForPos(e->pos(), rect()); +} + +void RatingWidget::mouseMoveEvent(QMouseEvent* e) { + hover_rating_ = RatingPainter::RatingForPos(e->pos(), rect()); + update(); +} + +void RatingWidget::leaveEvent(QEvent*) { + hover_rating_ = -1.0; + update(); +} diff --git a/src/widgets/ratingwidget.h b/src/widgets/ratingwidget.h new file mode 100644 index 000000000..131606c89 --- /dev/null +++ b/src/widgets/ratingwidget.h @@ -0,0 +1,62 @@ +/* This file is part of Clementine. + + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Clementine is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Clementine. If not, see . +*/ + +#ifndef RATINGWIDGET_H +#define RATINGWIDGET_H + +#include +#include + +class RatingPainter { +public: + RatingPainter(); + + static const int kStarCount = 5; + static const int kStarSize = 15; + static QRect Contents(const QRect& rect); + static double RatingForPos(const QPoint& pos, const QRect& rect); + + void Paint(QPainter* painter, const QRect& rect, float rating) const; + +private: + QPixmap stars_[kStarCount*2+1]; +}; + +class RatingWidget : public QWidget { + Q_OBJECT + Q_PROPERTY(float rating READ rating WRITE set_rating); + +public: + RatingWidget(QWidget* parent = 0); + + QSize sizeHint() const; + + float rating() const { return rating_; } + void set_rating(float rating); + +protected: + void paintEvent(QPaintEvent*); + void mousePressEvent(QMouseEvent* e); + void mouseMoveEvent(QMouseEvent* e); + void leaveEvent(QEvent*); + +private: + RatingPainter painter_; + float rating_; + float hover_rating_; +}; + +#endif // RATINGWIDGET_H