1 #include "library/stareditor.h"
2 
3 #include <QStylePainter>
4 
5 #include "library/starrating.h"
6 #include "moc_stareditor.cpp"
7 #include "util/painterscope.h"
8 
9 // We enable mouse tracking on the widget so we can follow the cursor even
10 // when the user doesn't hold down any mouse button. We also turn on
11 // QWidget's auto-fill background feature to obtain an opaque background.
12 // (Without the call, the view's background would shine through the editor.)
13 
14 /// StarEditor inherits QWidget and is used by StarDelegate to let the user
15 /// edit a star rating in the library using the mouse.
16 ///
17 /// The class has been adapted from the official "Star Delegate Example",
18 /// see http://doc.trolltech.com/4.5/itemviews-stardelegate.html
StarEditor(QWidget * parent,QTableView * pTableView,const QModelIndex & index,const QStyleOptionViewItem & option)19 StarEditor::StarEditor(QWidget *parent, QTableView* pTableView,
20                        const QModelIndex& index,
21                        const QStyleOptionViewItem& option)
22         : QWidget(parent),
23           m_pTableView(pTableView),
24           m_index(index),
25           m_styleOption(option) {
26     setMouseTracking(true);
27 }
28 
sizeHint() const29 QSize StarEditor::sizeHint() const {
30     return m_starRating.sizeHint();
31 }
32 
33 // static
renderHelper(QPainter * painter,QTableView * pTableView,const QStyleOptionViewItem & option,StarRating * pStarRating)34 void StarEditor::renderHelper(QPainter* painter,
35                               QTableView* pTableView,
36                               const QStyleOptionViewItem& option,
37                               StarRating* pStarRating) {
38     PainterScope painterScope(painter);
39 
40     painter->setClipRect(option.rect);
41 
42     if (pTableView != nullptr) {
43         QStyle* style = pTableView->style();
44         if (style != nullptr) {
45             style->drawControl(QStyle::CE_ItemViewItem, &option, painter,
46                                pTableView);
47         }
48     }
49 
50     // Set the palette appropriately based on whether the row is selected or
51     // not. We also have to check if it is inactive or not and use the
52     // appropriate ColorGroup.
53     QPalette::ColorGroup cg = option.state & QStyle::State_Enabled
54             ? QPalette::Normal : QPalette::Disabled;
55     if (cg == QPalette::Normal && !(option.state & QStyle::State_Active)) {
56         cg = QPalette::Inactive;
57     }
58 
59     if (option.state & QStyle::State_Selected) {
60         painter->setBrush(option.palette.color(cg, QPalette::HighlightedText));
61     } else {
62         painter->setBrush(option.palette.color(cg, QPalette::Text));
63     }
64 
65     pStarRating->paint(painter, option.rect);
66 }
67 
paintEvent(QPaintEvent *)68 void StarEditor::paintEvent(QPaintEvent*) {
69     // If a StarEditor is open, by definition the mouse is hovering over us.
70     m_styleOption.state |= QStyle::State_MouseOver;
71     m_styleOption.rect = rect();
72 
73     if (m_pTableView) {
74         QItemSelectionModel* selectionModel = m_pTableView->selectionModel();
75         if (selectionModel && selectionModel->isSelected(m_index)) {
76             m_styleOption.state |= QStyle::State_Selected;
77         }
78     }
79 
80     QPainter painter(this);
81     renderHelper(&painter, m_pTableView, m_styleOption, &m_starRating);
82 }
83 
mouseMoveEvent(QMouseEvent * event)84 void StarEditor::mouseMoveEvent(QMouseEvent *event) {
85     int star = starAtPosition(event->x());
86 
87     if (star != m_starRating.starCount() && star != -1) {
88         m_starRating.setStarCount(star);
89         update();
90     }
91 }
92 
leaveEvent(QEvent *)93 void StarEditor::leaveEvent(QEvent*) {
94     m_starRating.setStarCount(0);
95     update();
96 }
97 
mouseReleaseEvent(QMouseEvent *)98 void StarEditor::mouseReleaseEvent(QMouseEvent* /* event */) {
99     emit editingFinished();
100 }
101 
starAtPosition(int x)102 int StarEditor::starAtPosition(int x) {
103     // If the mouse is very close to the left edge, set 0 stars.
104     if (x < m_starRating.sizeHint().width() * 0.05) {
105         return 0;
106     }
107     int star = (x / (m_starRating.sizeHint().width() / m_starRating.maxStarCount())) + 1;
108 
109     if (star <= 0 || star > m_starRating.maxStarCount()) {
110         return 0;
111     }
112     return star;
113 }
114