1 /****************************************************************************
3 ** Copyright (C) Qxt Foundation. Some rights reserved.
5 ** This file is part of the QxtGui module of the Qt eXTension library
7 ** This library is free software; you can redistribute it and/or modify it
8 ** under the terms of th Common Public License, version 1.0, as published by
11 ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
12 ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
13 ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
14 ** FITNESS FOR A PARTICULAR PURPOSE.
16 ** You should have received a copy of the CPL along with this file.
17 ** See the LICENSE file and the cpl1.0.txt file included with the source
18 ** distribution for more information. If you did not receive a copy of the
19 ** license, contact the Qxt Foundation.
21 ** <http://libqxt.sourceforge.net> <foundation@libqxt.org>
23 ****************************************************************************/
26 #include <QStyleOptionSlider>
27 #include <QPainterPath>
28 #include <QMouseEvent>
31 class QxtStarsPrivate : public QxtPrivate<QxtStars>
34 QXT_DECLARE_PUBLIC(QxtStars);
36 int pixelPosToRangeValue(int pos) const;
37 inline int pick(const QPoint& pt) const;
38 QStyleOptionSlider getStyleOption() const;
39 QSize getStarSize() const;
46 QxtStarsPrivate::QxtStarsPrivate()
47 : snapBackPosition(0), readOnly(false)
49 star.moveTo(14.285716,-43.352104);
50 star.lineTo(38.404536,9.1654726);
51 star.lineTo(95.804846,15.875014);
52 star.lineTo(53.310787,55.042197);
53 star.lineTo(64.667306,111.7065);
54 star.lineTo(14.285714,83.395573);
55 star.lineTo(-36.095881,111.7065);
56 star.lineTo(-24.739359,55.042198);
57 star.lineTo(-67.233416,15.875009);
58 star.lineTo(-9.8331075,9.1654728);
62 int QxtStarsPrivate::pixelPosToRangeValue(int pos) const
64 const QxtStars* p = &qxt_p();
65 QStyleOptionSlider opt = getStyleOption();
66 QRect gr = p->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderGroove, p);
67 QRect sr = p->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, p);
68 int sliderMin, sliderMax, sliderLength;
70 gr.setSize(qxt_p().sizeHint());
71 if (p->orientation() == Qt::Horizontal)
73 sliderLength = sr.width();
75 sliderMax = gr.right() - sliderLength + 1;
79 sliderLength = sr.height();
81 sliderMax = gr.bottom() - sliderLength + 1;
83 return QStyle::sliderValueFromPosition(p->minimum(), p->maximum(), pos - sliderMin,
84 sliderMax - sliderMin, opt.upsideDown);
87 inline int QxtStarsPrivate::pick(const QPoint& pt) const
89 return qxt_p().orientation() == Qt::Horizontal ? pt.x() : pt.y();
92 // TODO: get rid of this in Qt 4.3
93 QStyleOptionSlider QxtStarsPrivate::getStyleOption() const
95 const QxtStars* p = &qxt_p();
96 QStyleOptionSlider opt;
98 opt.subControls = QStyle::SC_None;
99 opt.activeSubControls = QStyle::SC_None;
100 opt.orientation = p->orientation();
101 opt.maximum = p->maximum();
102 opt.minimum = p->minimum();
103 opt.upsideDown = (p->orientation() == Qt::Horizontal) ?
104 (p->invertedAppearance() != (opt.direction == Qt::RightToLeft)) : (!p->invertedAppearance());
105 opt.direction = Qt::LeftToRight; // we use the upsideDown option instead
106 opt.sliderPosition = p->sliderPosition();
107 opt.sliderValue = p->value();
108 opt.singleStep = p->singleStep();
109 opt.pageStep = p->pageStep();
110 if (p->orientation() == Qt::Horizontal)
111 opt.state |= QStyle::State_Horizontal;
115 QSize QxtStarsPrivate::getStarSize() const
117 QSize size = starSize;
118 if (!size.isValid() || size.isNull())
120 const int width = qxt_p().style()->pixelMetric(QStyle::PM_SmallIconSize);
121 size = QSize(width, width);
127 \class QxtStars QxtStars
129 \brief A stars assessment widget.
131 QxtStars is an optionally interactive stars assessment widget.
133 By default, orientation is \b Qt::Horizonal and range is from \b 0 to \b 5.
135 The stars are rendered accoring to palette with the following color roles:
137 <tr><td><b>ColorRole</b></td><td><b>Element</b></td></tr>
138 <tr><td>QPalette::Text</td><td>outlines</td></tr>
139 <tr><td>QPalette::Base</td><td>unselected stars</td></tr>
140 <tr><td>QPalette::Highlight</td><td>selected stars</td></tr>
143 \image html qxtstars.png "QxtStars in action."
147 \fn QxtStars::valueChanged(int value)
149 This signal is emitted whenever the value has been changed.
153 Constructs a new QxtStars with \a parent.
155 QxtStars::QxtStars(QWidget* parent) : QAbstractSlider(parent)
157 QXT_INIT_PRIVATE(QxtStars);
158 setOrientation(Qt::Horizontal);
159 setFocusPolicy(Qt::FocusPolicy(style()->styleHint(QStyle::SH_Button_FocusPolicy)));
160 setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
167 QxtStars::~QxtStars()
171 \property QxtStars::readOnly
172 \brief This property holds whether stars are adjustable
174 In read-only mode, the user is not able to change the value.
175 The default value is \b false.
177 bool QxtStars::isReadOnly() const
179 return qxt_d().readOnly;
182 void QxtStars::setReadOnly(bool readOnly)
184 if (qxt_d().readOnly != readOnly)
186 qxt_d().readOnly = readOnly;
188 setFocusPolicy(Qt::NoFocus);
190 setFocusPolicy(Qt::FocusPolicy(style()->styleHint(QStyle::SH_Button_FocusPolicy)));
195 \property QxtStars::starSize
196 \brief This property holds the size of star icons
198 The default value is \b QStyle::PM_SmallIconSize.
200 QSize QxtStars::starSize() const
202 return qxt_d().starSize;
205 void QxtStars::setStarSize(const QSize& size)
207 if (qxt_d().starSize != size)
209 qxt_d().starSize = size;
215 QSize QxtStars::sizeHint() const
217 return minimumSizeHint();
220 QSize QxtStars::minimumSizeHint() const
222 QSize size = qxt_d().getStarSize();
223 size.rwidth() *= maximum() - minimum();
224 if (orientation() == Qt::Vertical)
229 void QxtStars::paintEvent(QPaintEvent* event)
231 QAbstractSlider::paintEvent(event);
233 QPainter painter(this);
235 painter.setPen(palette().color(QPalette::Text));
236 painter.setRenderHint(QPainter::Antialiasing);
238 const bool invert = invertedAppearance();
239 const QSize size = qxt_d().getStarSize();
240 const QRectF star = qxt_d().star.boundingRect();
241 painter.scale(size.width() / star.width(), size.height() / star.height());
242 const int count = maximum() - minimum();
243 if (orientation() == Qt::Horizontal)
245 painter.translate(-star.x(), -star.y());
246 if (invert != isRightToLeft())
247 painter.translate((count - 1) * star.width(), 0);
251 painter.translate(-star.x(), -star.y());
253 painter.translate(0, (count - 1) * star.height());
255 for (int i = 0; i < count; ++i)
257 if (value() > minimum() + i)
258 painter.setBrush(palette().highlight());
260 painter.setBrush(palette().base());
261 painter.drawPath(qxt_d().star);
263 if (orientation() == Qt::Horizontal)
264 painter.translate(invert != isRightToLeft() ? -star.width() : star.width(), 0);
266 painter.translate(0, invert ? star.height() : -star.height());
272 QStyleOptionFocusRect opt;
274 opt.rect.setSize(sizeHint());
275 style()->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, &painter, this);
279 void QxtStars::keyPressEvent(QKeyEvent* event)
281 if (qxt_d().readOnly)
286 QAbstractSlider::keyPressEvent(event);
289 void QxtStars::mousePressEvent(QMouseEvent* event)
291 if (qxt_d().readOnly)
296 QAbstractSlider::mousePressEvent(event);
298 if (maximum() == minimum() || (event->buttons() ^ event->button()))
305 QStyleOptionSlider opt = qxt_d().getStyleOption();
306 const QRect sliderRect = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);
307 const QPoint center = sliderRect.center() - sliderRect.topLeft();
308 const int pos = qxt_d().pixelPosToRangeValue(qxt_d().pick(event->pos() - center));
309 setSliderPosition(pos);
310 triggerAction(SliderMove);
311 setRepeatAction(SliderNoAction);
312 qxt_d().snapBackPosition = pos;
316 void QxtStars::mouseMoveEvent(QMouseEvent* event)
318 if (qxt_d().readOnly)
323 QAbstractSlider::mouseMoveEvent(event);
326 int newPosition = qxt_d().pixelPosToRangeValue(qxt_d().pick(event->pos()));
327 QStyleOptionSlider opt = qxt_d().getStyleOption();
328 int m = style()->pixelMetric(QStyle::PM_MaximumDragDistance, &opt, this);
332 r.adjust(-m, -m, m, m);
333 if (!r.contains(event->pos()))
334 newPosition = qxt_d().snapBackPosition;
336 setSliderPosition(newPosition);
339 void QxtStars::mouseReleaseEvent(QMouseEvent* event)
341 if (qxt_d().readOnly)
346 QAbstractSlider::mouseReleaseEvent(event);
348 if (event->buttons())
355 setRepeatAction(SliderNoAction);