diff options
Diffstat (limited to 'qdialskulpturestyle.cpp')
-rw-r--r-- | qdialskulpturestyle.cpp | 433 |
1 files changed, 433 insertions, 0 deletions
diff --git a/qdialskulpturestyle.cpp b/qdialskulpturestyle.cpp new file mode 100644 index 0000000..e7be93b --- /dev/null +++ b/qdialskulpturestyle.cpp @@ -0,0 +1,433 @@ +/****************************************************************************** + + Skulpture - Classical Three-Dimensional Artwork for Qt 4 + + Copyright (c) 2007-2009 Christoph Feck <christoph@maxiom.de> + + This program 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 2 + of the License, or (at your option) any later version. + + This program 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 this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +*****************************************************************************/ +#include <cmath> +#include <QStyleOptionSlider> +#include <QPixmapCache> +#include <QPainter> + +#include "qdialskulpturestyle.hpp" + +static const bool UsePixmapCache = true; + +static void +paintIndicatorCached(QPainter *painter, const QStyleOption *option, void (*paintIndicator)(QPainter *painter, const QStyleOption *option), bool useCache, const QString &pixmapName) +{ + QPixmap pixmap; + + if (!useCache || !QPixmapCache::find(pixmapName, pixmap)) { + pixmap = QPixmap(option->rect.size()); +#if 1 + pixmap.fill(Qt::transparent); + // pixmap.fill(Qt::red); +#else + pixmap.fill(option->palette.color(QPalette::Window)); +#endif + QPainter p(&pixmap); + QStyleOption opt = *option; + opt.rect = QRect(QPoint(0, 0), option->rect.size()); + // p.setCompositionMode(QPainter::CompositionMode_Clear); + // p.setCompositionMode(QPainter::CompositionMode_Source); + // p.fillRect(opt.rect, Qt::transparent); + // p.setCompositionMode(QPainter::CompositionMode_SourceOver); + p.setFont(painter->font()); + p.setRenderHint(QPainter::Antialiasing, true); + paintIndicator(&p, &opt); + p.end(); + if (useCache) { + QPixmapCache::insert(pixmapName, pixmap); + // qDebug() << "inserted into cache:" << pixmapName; + } + } + painter->drawPixmap(option->rect, pixmap); +} + +void +paintDialBase(QPainter *painter, const QStyleOption *option) +{ +// painter->fillRect(option->rect, Qt::red); +// painter->save(); +// painter->setRenderHint(QPainter::Antialiasing, true); + int d = qMin(option->rect.width(), option->rect.height()); +/* if (d > 20 && option->notchTarget > 0) { + d += -1; + } +*/ QRectF r((option->rect.width() - d) / 2.0, (option->rect.height() - d) / 2.0, d, d); + const qreal angle = option->direction == Qt::LeftToRight ? 135.0 : 45.0; +// const qreal angle = 90; + + painter->setPen(Qt::NoPen); + QColor border_color = option->palette.color(QPalette::Window); +#if 0 + { + QRadialGradient depth_gradient(r.center(), d / 2); +// depth_gradient.setColorAt(0.0, QColor(0, 0, 0, 255)); + depth_gradient.setColorAt(0.5, QColor(0, 0, 0, 255)); + depth_gradient.setColorAt(1.0, QColor(0, 0, 0, 0)); + painter->setBrush(depth_gradient); + painter->drawEllipse(r); + } +#endif +#if 1 + if (option->state & QStyle::State_HasFocus && option->state & QStyle::State_KeyboardFocusChange) { + painter->setBrush(option->palette.color(QPalette::Highlight).darker(180)); + r.adjust(1, 1, -1, -1); + painter->drawEllipse(r); + painter->setBrush(border_color); + r.adjust(1, 1, -1, -1); + painter->drawEllipse(r); + r.adjust(1, 1, -1, -1); + } else { + painter->setBrush(border_color); + r.adjust(1, 1, -1, -1); + painter->drawEllipse(r); + r.adjust(1, 1, -1, -1); + QConicalGradient border_gradient(r.center(), angle); + if (!(option->state & QStyle::State_Enabled)) { + border_color = border_color.lighter(120); + } + border_gradient.setColorAt(0.0, border_color.darker(180)); + border_gradient.setColorAt(0.3, border_color.darker(130)); + border_gradient.setColorAt(0.5, border_color.darker(170)); + border_gradient.setColorAt(0.7, border_color.darker(130)); + border_gradient.setColorAt(1.0, border_color.darker(180)); + painter->setBrush(border_gradient); +// painter->setBrush(Qt::blue); + painter->drawEllipse(r); + r.adjust(1, 1, -1, -1); + } + d -= 6; + + QColor dial_color; + if (option->state & QStyle::State_Enabled) { + dial_color = option->palette.color(QPalette::Button).lighter(101); + if (option->state & QStyle::State_MouseOver) { + dial_color = dial_color.lighter(103); + } + } else { + dial_color = option->palette.color(QPalette::Window); + } + qreal t = option->state & QStyle::State_Enabled ? 2.0 : 1.5; + if (1) { + // ###: work around Qt 4.3.0 bug? (this works for 4.3.1) + QConicalGradient border_gradient(r.center(), angle); + border_gradient.setColorAt(0.0, dial_color.lighter(120)); + border_gradient.setColorAt(0.2, dial_color); + border_gradient.setColorAt(0.5, dial_color.darker(130)); + border_gradient.setColorAt(0.8, dial_color); + border_gradient.setColorAt(1.0, dial_color.lighter(120)); + painter->setPen(QPen(border_gradient, t)); + } else { + painter->setPen(QPen(Qt::red, t)); + } +#if 0 + QLinearGradient dial_gradient(r.topLeft(), r.bottomLeft()); + dial_gradient.setColorAt(0.0, dial_color.darker(105)); + dial_gradient.setColorAt(0.5, dial_color.lighter(102)); + dial_gradient.setColorAt(1.0, dial_color.lighter(105)); +#elif 1 + QLinearGradient dial_gradient(option->direction == Qt::LeftToRight ? r.topLeft() : r.topRight(), option->direction == Qt::LeftToRight ? r.bottomRight() : r.bottomLeft()); +// QLinearGradient dial_gradient(r.topLeft(), r.bottomLeft()); + if (true || option->state & QStyle::State_Enabled) { +#if 1 + dial_gradient.setColorAt(0.0, dial_color.darker(106)); + dial_gradient.setColorAt(1.0, dial_color.lighter(104)); +#else + dial_gradient.setColorAt(0.0, dial_color.lighter(101)); + dial_gradient.setColorAt(0.5, dial_color.darker(103)); + dial_gradient.setColorAt(1.0, dial_color.lighter(104)); +#endif + } else { + dial_gradient.setColorAt(0.0, dial_color); + dial_gradient.setColorAt(1.0, dial_color); + } +#elif 0 + QConicalGradient dial_gradient(r.center(), angle); + dial_gradient.setColorAt(0.0, dial_color.lighter(102)); + dial_gradient.setColorAt(0.5, dial_color.darker(103)); + dial_gradient.setColorAt(1.0, dial_color.lighter(102)); +#else + QBrush dial_gradient(dial_color); +#endif + painter->setBrush(dial_gradient); + t = t / 2; + painter->drawEllipse(r.adjusted(t, t, -t, -t)); + +// painter->setPen(Qt::NoPen); +// painter->setBrush(dial_color); +// painter->drawEllipse(r.adjusted(d / 4, d / 4, - d / 4, - d / 4)); + +#if 0 + QLinearGradient border2_gradient(r.topLeft(), r.bottomRight()); + border2_gradient.setColorAt(1.0, dial_color.darker(425)); + border2_gradient.setColorAt(0.9, dial_color); + border2_gradient.setColorAt(0.0, dial_color.darker(400)); + painter->setPen(QPen(border2_gradient, 1.3)); + painter->setBrush(Qt::NoBrush); + painter->drawEllipse(r.adjusted(0.3, 0.3, -0.3, -0.3)); +#endif +// painter->restore(); +#endif +} + +void +paintCachedDialBase(QPainter *painter, const QStyleOptionSlider *option) +{ + bool useCache = UsePixmapCache; + QString pixmapName; + QRect r = option->rect; + int d = qMin(r.width(), r.height()); + + if (/* option->state & (QStyle::State_HasFocus | QStyle::State_MouseOver) ||*/ d > 128) { + useCache = false; + } + if (useCache) { + uint state = uint(option->state) & (QStyle::State_Enabled | QStyle::State_On | QStyle::State_MouseOver | QStyle::State_KeyboardFocusChange | QStyle::State_HasFocus); + if (!(state & QStyle::State_Enabled)) { + state &= ~(QStyle::State_MouseOver | QStyle::State_HasFocus | QStyle::State_KeyboardFocusChange); + } + // state &= ~(QStyle::State_HasFocus); + pixmapName.sprintf("scp-qdb-%x-%x-%llx-%x", state, option->direction, option->palette.cacheKey(), d); + } + paintIndicatorCached(painter, option, paintDialBase, useCache, pixmapName); +} + +void +paintIndicatorDial(QPainter *painter, const QStyleOptionSlider *option) +{ + int d = qMin(option->rect.width(), option->rect.height()); + QRect rect(option->rect.center() - QPoint((d - 1) / 2, (d - 1) / 2), QSize(d, d)); + QStyleOptionSlider opt; + opt.QStyleOption::operator=(*option); + opt.rect = rect; + paintCachedDialBase(painter, &opt); +} + +QColor +shaded_color(const QColor &color, int shade) +{ +#if 1 + const qreal contrast = 1.0; + int r, g, b; + color.getRgb(&r, &g, &b); + int gray = qGray(r, g, b); + gray = qMax(r, qMax(g, b)); + gray = (r + b + g + 3 * gray) / 6; + if (shade < 0) { + qreal k = 220.0 / 255.0 * shade; + k *= contrast; + int a = 255; + if (gray > 0) { + a = int(k * 255 / (0 - gray)); + if (a < 0) a = 0; + if (a > 255) a = 255; + } + return QColor(0, 0, 0, a); + } else { + qreal k = (255 - 220.0) / (255.0) * shade; + k *= contrast; + int a = 255; + if (gray < 255) { + a = int(k * 255 / (255 - gray)); + if (a < 0) a = 0; + if (a > 255) a = 255; + } + return QColor(255, 255, 255, a); + } +#else + if (shade < 0) { + return QColor(0, 0, 0, -shade); + } else { + return QColor(255, 255, 255, shade); + } +#endif +} + +static void +paintGrip(QPainter *painter, const QStyleOption *option) +{ +// painter->fillRect(option->rect, Qt::red); + int d = qMin(option->rect.width(), option->rect.height()); + // good values are 3 (very small), 4 (small), 5 (good), 7 (large), 9 (huge) + // int d = 5; + QRectF rect(QRectF(option->rect).center() - QPointF(d / 2.0, d / 2.0), QSizeF(d, d)); + const qreal angle = option->direction == Qt::LeftToRight ? 135.0 : 45.0; +// const qreal angle = 90; + QColor color; + qreal opacity = 0.9; + + painter->save(); + painter->setPen(Qt::NoPen); + if (option->state & QStyle::State_Enabled) { + if (option->state & QStyle::State_Sunken) { + color = option->palette.color(QPalette::Highlight).darker(110); + } else { + color = option->palette.color(QPalette::Button); + } + } else { + color = option->palette.color(QPalette::Button); + opacity = 0.5; + } + + QConicalGradient gradient1(rect.center(), angle); + gradient1.setColorAt(0.0, shaded_color(color, -110)); + gradient1.setColorAt(0.25, shaded_color(color, -30)); + gradient1.setColorAt(0.5, shaded_color(color, 180)); + gradient1.setColorAt(0.75, shaded_color(color, -30)); + gradient1.setColorAt(1.0, shaded_color(color, -110)); + painter->setBrush(color); + painter->drawEllipse(rect); + painter->setBrush(gradient1); +#if (QT_VERSION >= QT_VERSION_CHECK(4, 2, 0)) + // ### merge opacity into color + painter->setOpacity(opacity); +#endif + painter->drawEllipse(rect); +#if (QT_VERSION >= QT_VERSION_CHECK(4, 2, 0)) + painter->setOpacity(1.0); + if (d > 2) { + QConicalGradient gradient2(rect.center(), angle); + gradient2.setColorAt(0.0, shaded_color(color, -40)); + gradient2.setColorAt(0.25, shaded_color(color, 0)); + gradient2.setColorAt(0.5, shaded_color(color, 210)); + gradient2.setColorAt(0.75, shaded_color(color, 0)); + gradient2.setColorAt(1.0, shaded_color(color, -40)); + rect.adjust(1, 1, -1, -1); + painter->setBrush(color); + painter->drawEllipse(rect); + painter->setBrush(gradient2); + painter->setOpacity(opacity); + painter->drawEllipse(rect); + painter->setOpacity(1.0); + if (d > 8) { + QConicalGradient gradient3(rect.center(), angle); + gradient3.setColorAt(0.0, shaded_color(color, -10)); + gradient3.setColorAt(0.25, shaded_color(color, 0)); + gradient3.setColorAt(0.5, shaded_color(color, 180)); + gradient3.setColorAt(0.75, shaded_color(color, 0)); + gradient3.setColorAt(1.0, shaded_color(color, -10)); + rect.adjust(2, 2, -2, -2); + painter->setBrush(color); + painter->drawEllipse(rect); + painter->setBrush(gradient3); + painter->setOpacity(opacity); + painter->drawEllipse(rect); + painter->setOpacity(1.0); + } + } +#endif + painter->restore(); +} + +void +paintCachedGrip(QPainter *painter, const QStyleOption *option, QPalette::ColorRole /*bgrole*/) +{ + bool useCache = UsePixmapCache; + QString pixmapName; + + if (/* option->state & (QStyle::State_HasFocus | QStyle::State_MouseOver) ||*/ option->rect.width() * option->rect.height() > 4096) { + useCache = false; + } + if (useCache) { + uint state = uint(option->state) & (QStyle::State_Enabled | QStyle::State_On | QStyle::State_MouseOver | QStyle::State_Sunken | QStyle::State_HasFocus); + if (!(state & QStyle::State_Enabled)) { + state &= ~(QStyle::State_MouseOver | QStyle::State_HasFocus); + } + state &= ~(QStyle::State_HasFocus); + QByteArray colorName = option->palette.color(QPalette::Button).name().toLatin1(); + pixmapName.sprintf("scp-isg-%x-%x-%s-%x-%x", state, option->direction, colorName.constData(), option->rect.width(), option->rect.height()); + } + paintIndicatorCached(painter, option, paintGrip, useCache, pixmapName); +} + +void +QDialSkulptureStyle::drawComplexControl( ComplexControl cc, + const QStyleOptionComplex *optc, + QPainter *painter, + const QWidget *widget) const +{ + + if (cc != QStyle::CC_Dial) { + QCommonStyle::drawComplexControl(cc, optc, painter, widget); + return; + } + + const QStyleOptionSlider *option = qstyleoption_cast<const QStyleOptionSlider *>(optc); + if (option == NULL) + return; + + int d = qMin(option->rect.width() & ~1, option->rect.height() & ~1); + QStyleOptionSlider opt = *option; + const QAbstractSlider *slider = NULL; + // always highlight knob if pressed (even if mouse is not over knob) + if ((option->state & QStyle::State_HasFocus) && (slider = qobject_cast<const QAbstractSlider *>(widget))) { + if (slider->isSliderDown()) { + opt.state |= QStyle::State_MouseOver; + } + } + + // tickmarks + opt.palette.setColor(QPalette::Inactive, QPalette::WindowText, QColor(80, 80, 80, 255)); + opt.palette.setColor(QPalette::Active, QPalette::WindowText, QColor(80, 80, 80, 255)); + opt.state &= ~QStyle::State_HasFocus; + opt.rect.setWidth(opt.rect.width() & ~1); + opt.rect.setHeight(opt.rect.height() & ~1); + //((QCommonStyle *) this)-> + QCommonStyle::drawComplexControl(QStyle::CC_Dial, &opt, painter, widget); + + // focus rectangle + if (option->state & QStyle::State_HasFocus) { + QStyleOptionFocusRect focus; + opt.state |= QStyle::State_HasFocus; + focus.QStyleOption::operator=(opt); + focus.rect.adjust(-1, -1, 1, 1); + //drawPrimitive(QStyle::PE_FrameFocusRect, &focus, painter, widget); + } + opt.palette = option->palette; + + // dial base + if (d <= 256) { + paintIndicatorDial(painter, &opt); + } else { + // large dials are slow to render, do not render them + } + + // dial knob + d -= 6; + int gripSize = (option->fontMetrics.height() / 4) * 2 - 1; + opt.rect.setSize(QSize(gripSize, gripSize)); + opt.rect.moveCenter(option->rect.center()); + // angle calculation from qcommonstyle.cpp (c) Trolltech 1992-2007, ASA. + qreal angle; + int sliderPosition = option->upsideDown ? option->sliderPosition : (option->maximum - option->sliderPosition); + int range = option->maximum - option->minimum; + if (!range) { + angle = M_PI / 2; + } else if (option->dialWrapping) { + angle = M_PI * 1.5 - (sliderPosition - option->minimum) * 2 * M_PI / range; + } else { + angle = (M_PI * 8 - (sliderPosition - option->minimum) * 10 * M_PI / range) / 6; + } + + qreal rr = d / 2.0 - gripSize - 2; + opt.rect.translate(int(0.5 + rr * cos(angle)), int(0.5 - rr * sin(angle))); + paintCachedGrip(painter, &opt, option->state & QStyle::State_Enabled ? QPalette::Button : QPalette::Window); +} |