diff --git a/kolfNumInput.cpp b/kolfNumInput.cpp index 18e6aec..1b3c097 100644 --- a/kolfNumInput.cpp +++ b/kolfNumInput.cpp @@ -1,446 +1,446 @@ /* This file is part of the KDE libraries * Initial implementation: * Copyright (c) 1997 Patrick Dowler * Rewritten and maintained by: * Copyright (c) 2000 Dirk Mueller * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kolfNumInput.h" #include #include #include #include #include #include #include static inline int calcDiffByTen(int x, int y) { // calculate ( x - y ) / 10 without overflowing ints: return (x / 10) - (y / 10) + (x % 10 - y % 10) / 10; } // ---------------------------------------------------------------------------- class kolfNumInputPrivate { public: kolfNumInputPrivate(kolfNumInput *q) : q(q), column1Width(0), column2Width(0), label(0), slider(0), labelAlignment(0) { } static kolfNumInputPrivate *get(const kolfNumInput *i) { return i->d; } kolfNumInput *q; int column1Width, column2Width; QLabel *label; QSlider *slider; QSize sliderSize, labelSize; Qt::Alignment labelAlignment; }; #define K_USING_kolfNumInput_P(_d) kolfNumInputPrivate *_d = kolfNumInputPrivate::get(this) kolfNumInput::kolfNumInput(QWidget *parent) : QWidget(parent), d(new kolfNumInputPrivate(this)) { setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed)); setFocusPolicy(Qt::StrongFocus); KConfigDialogManager::changedMap()->insert(QStringLiteral("kpIntNumInput"), SIGNAL(valueChanged(int))); KConfigDialogManager::changedMap()->insert(QStringLiteral("QSpinBox"), SIGNAL(valueChanged(int))); KConfigDialogManager::changedMap()->insert(QStringLiteral("kolfDoubleSpinBox"), SIGNAL(valueChanged(double))); } kolfNumInput::~kolfNumInput() { delete d; } QSlider *kolfNumInput::slider() const { return d->slider; } bool kolfNumInput::showSlider() const { return d->slider; } void kolfNumInput::setLabel(const QString &label, Qt::Alignment a) { if (label.isEmpty()) { delete d->label; d->label = 0; - d->labelAlignment = 0; + d->labelAlignment = {}; } else { if (!d->label) { d->label = new QLabel(this); } d->label->setText(label); d->label->setObjectName(QStringLiteral("kolfNumInput::QLabel")); d->label->setAlignment(a); // if no vertical alignment set, use Top alignment if (!(a & (Qt::AlignTop | Qt::AlignBottom | Qt::AlignVCenter))) { a |= Qt::AlignTop; } d->labelAlignment = a; } layout(); } QString kolfNumInput::label() const { return d->label ? d->label->text() : QString(); } void kolfNumInput::layout() { // label sizeHint d->labelSize = (d->label ? d->label->sizeHint() : QSize(0, 0)); if (d->label && (d->labelAlignment & Qt::AlignVCenter)) { d->column1Width = d->labelSize.width() + 4; } else { d->column1Width = 0; } // slider sizeHint d->sliderSize = (d->slider ? d->slider->sizeHint() : QSize(0, 0)); doLayout(); } QSize kolfNumInput::sizeHint() const { return minimumSizeHint(); } void kolfNumInput::setSteps(int minor, int major) { if (d->slider) { d->slider->setSingleStep(minor); d->slider->setPageStep(major); } } // ---------------------------------------------------------------------------- class kolfDoubleNumInput::kolfDoubleNumInputPrivate { public: kolfDoubleNumInputPrivate() : spin(0) {} QDoubleSpinBox *spin; QSize editSize; QString specialValue; }; kolfDoubleNumInput::kolfDoubleNumInput(QWidget *parent) : kolfNumInput(parent) , d(new kolfDoubleNumInputPrivate()) { initWidget(0.0, 0.0, 9999.0, 0.01, 2); } kolfDoubleNumInput::kolfDoubleNumInput(double lower, double upper, double value, QWidget *parent, double singleStep, int precision) : kolfNumInput(parent) , d(new kolfDoubleNumInputPrivate()) { initWidget(value, lower, upper, singleStep, precision); } kolfDoubleNumInput::~kolfDoubleNumInput() { delete d; } QString kolfDoubleNumInput::specialValueText() const { return d->specialValue; } void kolfDoubleNumInput::initWidget(double value, double lower, double upper, double singleStep, int precision) { d->spin = new QDoubleSpinBox(this); d->spin->setRange(lower, upper); d->spin->setSingleStep(singleStep); d->spin->setValue(value); d->spin->setDecimals(precision); d->spin->setObjectName(QStringLiteral("kolfDoubleNumInput::QDoubleSpinBox")); setFocusProxy(d->spin); connect(d->spin, QOverload::of(&QDoubleSpinBox::valueChanged), this, &kolfDoubleNumInput::valueChanged); layout(); } double kolfDoubleNumInput::mapSliderToSpin(int val) const { K_USING_kolfNumInput_P(priv); // map [slidemin,slidemax] to [spinmin,spinmax] const double spinmin = d->spin->minimum(); const double spinmax = d->spin->maximum(); const double slidemin = priv->slider->minimum(); // cast int to double to avoid const double slidemax = priv->slider->maximum(); // overflow in rel denominator const double rel = (double(val) - slidemin) / (slidemax - slidemin); return spinmin + rel * (spinmax - spinmin); } void kolfDoubleNumInput::sliderMoved(int val) { d->spin->setValue(mapSliderToSpin(val)); } void kolfDoubleNumInput::spinBoxChanged(double val) { K_USING_kolfNumInput_P(priv); const double spinmin = d->spin->minimum(); const double spinmax = d->spin->maximum(); const double slidemin = priv->slider->minimum(); // cast int to double to avoid const double slidemax = priv->slider->maximum(); // overflow in rel denominator const double rel = (val - spinmin) / (spinmax - spinmin); if (priv->slider) { priv->slider->blockSignals(true); priv->slider->setValue(qRound(slidemin + rel * (slidemax - slidemin))); priv->slider->blockSignals(false); } } QSize kolfDoubleNumInput::minimumSizeHint() const { K_USING_kolfNumInput_P(priv); ensurePolished(); int w; int h; h = qMax(d->editSize.height(), priv->sliderSize.height()); // if in extra row, then count it here if (priv->label && (priv->labelAlignment & (Qt::AlignBottom | Qt::AlignTop))) { h += 4 + priv->labelSize.height(); } else { // label is in the same row as the other widgets h = qMax(h, priv->labelSize.height() + 2); } const int spacingHint = style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); w = priv->slider ? priv->slider->sizeHint().width() + spacingHint : 0; w += priv->column1Width + priv->column2Width; if (priv->labelAlignment & (Qt::AlignTop | Qt::AlignBottom)) { w = qMax(w, priv->labelSize.width() + 4); } return QSize(w, h); } void kolfDoubleNumInput::resizeEvent(QResizeEvent *e) { K_USING_kolfNumInput_P(priv); int w = priv->column1Width; int h = 0; const int spacingHint = style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); if (priv->label && (priv->labelAlignment & Qt::AlignTop)) { priv->label->setGeometry(0, 0, e->size().width(), priv->labelSize.height()); h += priv->labelSize.height() + 4; } if (priv->label && (priv->labelAlignment & Qt::AlignVCenter)) { priv->label->setGeometry(0, 0, w, d->editSize.height()); } if (qApp->layoutDirection() == Qt::RightToLeft) { d->spin->setGeometry(w, h, priv->slider ? priv->column2Width : e->size().width() - w, d->editSize.height()); w += priv->column2Width + spacingHint; if (priv->slider) { priv->slider->setGeometry(w, h, e->size().width() - w, d->editSize.height() + spacingHint); } } else if (priv->slider) { priv->slider->setGeometry(w, h, e->size().width() - (priv->column1Width + priv->column2Width + spacingHint), d->editSize.height() + spacingHint); d->spin->setGeometry(w + priv->slider->width() + spacingHint, h, priv->column2Width, d->editSize.height()); } else { d->spin->setGeometry(w, h, e->size().width() - w, d->editSize.height()); } h += d->editSize.height() + 2; if (priv->label && (priv->labelAlignment & Qt::AlignBottom)) { priv->label->setGeometry(0, h, priv->labelSize.width(), priv->labelSize.height()); } } void kolfDoubleNumInput::doLayout() { K_USING_kolfNumInput_P(priv); d->editSize = d->spin->sizeHint(); priv->column2Width = d->editSize.width(); } void kolfDoubleNumInput::setValue(double val) { d->spin->setValue(val); } void kolfDoubleNumInput::setRange(double lower, double upper, double singleStep) { K_USING_kolfNumInput_P(priv); QDoubleSpinBox *spin = d->spin; d->spin->setRange(lower, upper); d->spin->setSingleStep(singleStep); const double range = spin->maximum() - spin->minimum(); const double steps = range * pow(10.0, spin->decimals()); if (!priv->slider) { priv->slider = new QSlider(Qt::Horizontal, this); priv->slider->setTickPosition(QSlider::TicksBelow); // feedback line: when one moves, the other moves, too: connect(priv->slider, &QSlider::valueChanged, this, &kolfDoubleNumInput::sliderMoved); layout(); } if (steps > 1000 ) { priv->slider->setRange(0, 1000); priv->slider->setSingleStep(1); priv->slider->setPageStep(50); } else { const int singleSteps = qRound(steps); priv->slider->setRange(0, singleSteps); priv->slider->setSingleStep(1); const int pageSteps = qBound(1, singleSteps / 20, 10); priv->slider->setPageStep(pageSteps); } spinBoxChanged(spin->value()); connect(spin, QOverload::of(&QDoubleSpinBox::valueChanged), this, &kolfDoubleNumInput::spinBoxChanged); layout(); } void kolfDoubleNumInput::setMinimum(double min) { setRange(min, maximum(), d->spin->singleStep()); } double kolfDoubleNumInput::minimum() const { return d->spin->minimum(); } void kolfDoubleNumInput::setMaximum(double max) { setRange(minimum(), max, d->spin->singleStep()); } double kolfDoubleNumInput::maximum() const { return d->spin->maximum(); } double kolfDoubleNumInput::singleStep() const { return d->spin->singleStep(); } void kolfDoubleNumInput::setSingleStep(double singleStep) { d->spin->setSingleStep(singleStep); } double kolfDoubleNumInput::value() const { return d->spin->value(); } QString kolfDoubleNumInput::suffix() const { return d->spin->suffix(); } void kolfDoubleNumInput::setSuffix(const QString &suffix) { d->spin->setSuffix(suffix); layout(); } void kolfDoubleNumInput::setDecimals(int decimals) { d->spin->setDecimals(decimals); layout(); } int kolfDoubleNumInput::decimals() const { return d->spin->decimals(); } void kolfDoubleNumInput::setSpecialValueText(const QString &text) { d->spin->setSpecialValueText(text); layout(); } void kolfDoubleNumInput::setLabel(const QString &label, Qt::Alignment a) { K_USING_kolfNumInput_P(priv); kolfNumInput::setLabel(label, a); if (priv->label) { priv->label->setBuddy(d->spin); } } #include "moc_kolfNumInput.cpp" diff --git a/obstacles.cpp b/obstacles.cpp index 12fcb45..e4577b2 100644 --- a/obstacles.cpp +++ b/obstacles.cpp @@ -1,872 +1,872 @@ /* Copyright (C) 2002-2005, Jason Katz-Brown Copyright 2010 Stefan Majewsky 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 "obstacles.h" #include "ball.h" #include "game.h" #include "shape.h" #include #include #include #include #include #include #include #include #include //BEGIN Kolf::Bumper Kolf::Bumper::Bumper(QGraphicsItem* parent, b2World* world) : EllipticalCanvasItem(false, QStringLiteral("bumper_off"), parent, world) { const int diameter = 20; setSize(QSizeF(diameter, diameter)); setZBehavior(CanvasItem::IsRaisedByStrut, 4); setSimulationType(CanvasItem::NoSimulation); } bool Kolf::Bumper::collision(Ball* ball) { const double maxSpeed = ball->getMaxBumperBounceSpeed(); const double speed = qMin(maxSpeed, 1.8 + Vector(ball->velocity()).magnitude() * .9); ball->reduceMaxBumperBounceSpeed(); Vector betweenVector(ball->pos() - pos()); betweenVector.setMagnitudeDirection(speed, // add some randomness so we don't go indefinitely betweenVector.direction() + deg2rad((KRandom::random() % 3) - 1) ); ball->setVelocity(betweenVector); ball->setState(Rolling); game->playSound(Sound::Bumper); setSpriteKey(QStringLiteral("bumper_on")); QTimer::singleShot(100, this, &Kolf::Bumper::turnBumperOff); return true; } void Kolf::Bumper::turnBumperOff() { setSpriteKey(QStringLiteral("bumper_off")); } Kolf::Overlay* Kolf::Bumper::createOverlay() { return new Kolf::Overlay(this, this); } //END Kolf::Bumper //BEGIN Kolf::Wall Kolf::Wall::Wall(QGraphicsItem* parent, b2World* world) : QGraphicsLineItem(QLineF(-15, 10, 15, -5), parent) , CanvasItem(world) { setPen(QPen(Qt::darkRed, 3)); setData(0, Rtti_NoCollision); //see also KolfGame::addBorderWall() setZBehavior(CanvasItem::FixedZValue, 5); m_shape = new Kolf::LineShape(line()); addShape(m_shape); } void Kolf::Wall::load(KConfigGroup* cfgGroup) { const QPoint start = cfgGroup->readEntry("startPoint", QPoint(-15, 10)); const QPoint end = cfgGroup->readEntry("endPoint", QPoint(15, -5)); setLine(QLineF(start, end)); } void Kolf::Wall::save(KConfigGroup* cfgGroup) { const QLineF line = this->line(); cfgGroup->writeEntry("startPoint", line.p1().toPoint()); cfgGroup->writeEntry("endPoint", line.p2().toPoint()); } void Kolf::Wall::setVisible(bool visible) { QGraphicsLineItem::setVisible(visible); setSimulationType(visible ? CanvasItem::CollisionSimulation : CanvasItem::NoSimulation); } void Kolf::Wall::setLine(const QLineF& line) { QGraphicsLineItem::setLine(line); m_shape->setLine(line); propagateUpdate(); } void Kolf::Wall::moveBy(double dx, double dy) { QGraphicsLineItem::moveBy(dx, dy); CanvasItem::moveBy(dx, dy); } QPointF Kolf::Wall::getPosition() const { return QGraphicsItem::pos(); } Kolf::Overlay* Kolf::Wall::createOverlay() { return new Kolf::WallOverlay(this); } //END Kolf::Wall //BEGIN Kolf::WallOverlay Kolf::WallOverlay::WallOverlay(Kolf::Wall* wall) : Kolf::Overlay(wall, wall) , m_handle1(new Kolf::OverlayHandle(Kolf::OverlayHandle::SquareShape, this)) , m_handle2(new Kolf::OverlayHandle(Kolf::OverlayHandle::SquareShape, this)) { addHandle(m_handle1); addHandle(m_handle2); connect(m_handle1, &Kolf::OverlayHandle::moveRequest, this, &Kolf::WallOverlay::moveHandle); connect(m_handle2, &Kolf::OverlayHandle::moveRequest, this, &Kolf::WallOverlay::moveHandle); } void Kolf::WallOverlay::update() { Kolf::Overlay::update(); const QLineF line = dynamic_cast(qitem())->line(); m_handle1->setPos(line.p1()); m_handle2->setPos(line.p2()); } void Kolf::WallOverlay::moveHandle(const QPointF& handleScenePos) { //TODO: code duplication to Kolf::FloaterOverlay QPointF handlePos = mapFromScene(handleScenePos); const QObject* handle = sender(); //get handle positions QPointF handle1Pos = m_handle1->pos(); QPointF handle2Pos = m_handle2->pos(); if (handle == m_handle1) handle1Pos = handlePos; else if (handle == m_handle2) handle2Pos = handlePos; //ensure minimum length static const qreal minLength = Kolf::Overlay::MinimumObjectDimension; const QPointF posDiff = handle1Pos - handle2Pos; const qreal length = QLineF(QPointF(), posDiff).length(); if (length < minLength) { const QPointF additionalExtent = posDiff * (minLength / length - 1); if (handle == m_handle1) handle1Pos += additionalExtent; else if (handle == m_handle2) handle2Pos -= additionalExtent; } //apply to item dynamic_cast(qitem())->setLine(QLineF(handle1Pos, handle2Pos)); } //END Kolf::WallOverlay //BEGIN Kolf::RectangleItem Kolf::RectangleItem::RectangleItem(const QString& type, QGraphicsItem* parent, b2World* world) : Tagaro::SpriteObjectItem(Kolf::renderer(), type, parent) , CanvasItem(world) , m_wallPen(QColor("#92772D").darker(), 3) , m_wallAllowed(Kolf::RectangleWallCount, true) , m_walls(Kolf::RectangleWallCount, 0) , m_shape(new Kolf::RectShape(QRectF(0, 0, 1, 1))) { addShape(m_shape); setSimulationType(CanvasItem::NoSimulation); //default size setSize(type == QLatin1String("sign") ? QSize(110, 40) : QSize(80, 40)); } Kolf::RectangleItem::~RectangleItem() { qDeleteAll(m_walls); } bool Kolf::RectangleItem::hasWall(Kolf::WallIndex index) const { return (bool) m_walls[index]; } bool Kolf::RectangleItem::isWallAllowed(Kolf::WallIndex index) const { return m_wallAllowed[index]; } void Kolf::RectangleItem::setWall(Kolf::WallIndex index, bool hasWall) { const bool oldHasWall = (bool) m_walls[index]; if (oldHasWall == hasWall) return; if (hasWall && !m_wallAllowed[index]) return; if (hasWall) { Kolf::Wall* wall = m_walls[index] = new Kolf::Wall(parentItem(), world()); wall->setPos(pos()); applyWallStyle(wall); updateWallPosition(); } else { delete m_walls[index]; m_walls[index] = 0; } propagateUpdate(); emit wallChanged(index, hasWall, m_wallAllowed[index]); } void Kolf::RectangleItem::setWallAllowed(Kolf::WallIndex index, bool wallAllowed) { m_wallAllowed[index] = wallAllowed; //delete wall if one exists at this position currently if (!wallAllowed) setWall(index, false); emit wallChanged(index, hasWall(index), wallAllowed); } void Kolf::RectangleItem::updateWallPosition() { const QRectF rect(QPointF(), size()); Kolf::Wall* const topWall = m_walls[Kolf::TopWallIndex]; Kolf::Wall* const leftWall = m_walls[Kolf::LeftWallIndex]; Kolf::Wall* const rightWall = m_walls[Kolf::RightWallIndex]; Kolf::Wall* const bottomWall = m_walls[Kolf::BottomWallIndex]; if (topWall) topWall->setLine(QLineF(rect.topLeft(), rect.topRight())); if (leftWall) leftWall->setLine(QLineF(rect.topLeft(), rect.bottomLeft())); if (rightWall) rightWall->setLine(QLineF(rect.topRight(), rect.bottomRight())); if (bottomWall) bottomWall->setLine(QLineF(rect.bottomLeft(), rect.bottomRight())); } void Kolf::RectangleItem::setSize(const QSizeF& size) { Tagaro::SpriteObjectItem::setSize(size); m_shape->setRect(QRectF(QPointF(), size)); updateWallPosition(); propagateUpdate(); } QPointF Kolf::RectangleItem::getPosition() const { return QGraphicsItem::pos(); } void Kolf::RectangleItem::moveBy(double dx, double dy) { Tagaro::SpriteObjectItem::moveBy(dx, dy); //move myself const QPointF pos = this->pos(); foreach (Kolf::Wall* wall, m_walls) if (wall) wall->setPos(pos); //update Z order CanvasItem::moveBy(dx, dy); foreach (QGraphicsItem* qitem, collidingItems()) { CanvasItem* citem = dynamic_cast(qitem); if (citem) citem->updateZ(qitem); } } void Kolf::RectangleItem::setWallColor(const QColor& color) { m_wallPen = QPen(color.darker(), 3); foreach (Kolf::Wall* wall, m_walls) applyWallStyle(wall); } void Kolf::RectangleItem::applyWallStyle(Kolf::Wall* wall, bool adjustPainting) { if (!wall) //explicitly allowed, see e.g. setWallColor() return; if (adjustPainting) wall->setPen(m_wallPen); wall->setZBehavior(CanvasItem::IsRaisedByStrut, 3); wall->setStaticStrut(this); } static const char* wallPropNames[] = { "topWallVisible", "leftWallVisible", "rightWallVisible", "botWallVisible" }; void Kolf::RectangleItem::load(KConfigGroup* group) { QSize size = Tagaro::SpriteObjectItem::size().toSize(); size.setWidth(group->readEntry("width", size.width())); size.setHeight(group->readEntry("height", size.height())); setSize(size); for (int i = 0; i < Kolf::RectangleWallCount; ++i) { bool hasWall = this->hasWall((Kolf::WallIndex) i); hasWall = group->readEntry(wallPropNames[i], hasWall); setWall((Kolf::WallIndex) i, hasWall); } } void Kolf::RectangleItem::save(KConfigGroup* group) { const QSize size = Tagaro::SpriteObjectItem::size().toSize(); group->writeEntry("width", size.width()); group->writeEntry("height", size.height()); for (int i = 0; i < Kolf::RectangleWallCount; ++i) { const bool hasWall = this->hasWall((Kolf::WallIndex) i); group->writeEntry(wallPropNames[i], hasWall); } } Config* Kolf::RectangleItem::config(QWidget* parent) { return new Kolf::RectangleConfig(this, parent); } Kolf::Overlay* Kolf::RectangleItem::createOverlay() { return new Kolf::RectangleOverlay(this); } //END Kolf::RectangleItem //BEGIN Kolf::RectangleOverlay Kolf::RectangleOverlay::RectangleOverlay(Kolf::RectangleItem* item) : Kolf::Overlay(item, item) { //TODO: code duplication to Kolf::LandscapeOverlay and Kolf::SlopeOverlay for (int i = 0; i < 4; ++i) { Kolf::OverlayHandle* handle = new Kolf::OverlayHandle(Kolf::OverlayHandle::CircleShape, this); m_handles << handle; addHandle(handle); connect(handle, &Kolf::OverlayHandle::moveRequest, this, &Kolf::RectangleOverlay::moveHandle); } } void Kolf::RectangleOverlay::update() { Kolf::Overlay::update(); const QRectF rect = qitem()->boundingRect(); m_handles[0]->setPos(rect.topLeft()); m_handles[1]->setPos(rect.topRight()); m_handles[2]->setPos(rect.bottomLeft()); m_handles[3]->setPos(rect.bottomRight()); } void Kolf::RectangleOverlay::moveHandle(const QPointF& handleScenePos) { Kolf::OverlayHandle* handle = qobject_cast(sender()); const int handleIndex = m_handles.indexOf(handle); Kolf::RectangleItem* item = dynamic_cast(qitem()); const QPointF handlePos = mapFromScene(handleScenePos); //modify bounding rect using new handlePos QRectF rect(QPointF(), item->size()); if (handleIndex % 2 == 0) rect.setLeft(qMin(handlePos.x(), rect.right())); else rect.setRight(qMax(handlePos.x(), rect.left())); if (handleIndex < 2) rect.setTop(qMin(handlePos.y(), rect.bottom())); else rect.setBottom(qMax(handlePos.y(), rect.top())); item->moveBy(rect.x(), rect.y()); item->setSize(rect.size()); } //END Kolf::RectangleOverlay //BEGIN Kolf::RectangleConfig Kolf::RectangleConfig::RectangleConfig(Kolf::RectangleItem* item, QWidget* parent) : Config(parent) , m_layout(new QGridLayout(this)) , m_wallCheckBoxes(Kolf::RectangleWallCount, 0) , m_item(item) { static const char* captions[] = { I18N_NOOP("&Top"), I18N_NOOP("&Left"), I18N_NOOP("&Right"), I18N_NOOP("&Bottom") }; for (int i = 0; i < Kolf::RectangleWallCount; ++i) { QCheckBox* checkBox = m_wallCheckBoxes[i] = new QCheckBox(i18n(captions[i]), this); checkBox->setEnabled(item->isWallAllowed((Kolf::WallIndex) i)); checkBox->setChecked(item->hasWall((Kolf::WallIndex) i)); connect(checkBox, &QCheckBox::toggled, this, &Kolf::RectangleConfig::setWall); } connect(item, &Kolf::RectangleItem::wallChanged, this, &Kolf::RectangleConfig::wallChanged); m_layout->addWidget(new QLabel(i18n("Walls on:")), 0, 0); m_layout->addWidget(m_wallCheckBoxes[0], 0, 1); m_layout->addWidget(m_wallCheckBoxes[1], 1, 0); m_layout->addWidget(m_wallCheckBoxes[2], 1, 2); m_layout->addWidget(m_wallCheckBoxes[3], 1, 1); m_layout->setRowStretch(2, 10); //Kolf::Sign does not have a special Config class Kolf::Sign* sign = qobject_cast(item); if (sign) { m_layout->addWidget(new QLabel(i18n("Sign HTML:")), 3, 0, 1, 3); KLineEdit* edit = new KLineEdit(sign->text(), this); m_layout->addWidget(edit, 4, 0, 1, 3); connect(edit, &KLineEdit::textChanged, sign, &Kolf::Sign::setText); } //Kolf::Windmill does not have a special Config class Kolf::Windmill* windmill = qobject_cast(item); if (windmill) { QCheckBox* checkBox = new QCheckBox(i18n("Windmill on top"), this); m_layout->addWidget(checkBox, 4, 0, 1, 3); checkBox->setChecked(windmill->guardAtTop()); connect(checkBox, &QCheckBox::toggled, windmill, &Kolf::Windmill::setGuardAtTop); QHBoxLayout* hlayout = new QHBoxLayout; m_layout->addLayout(hlayout, 5, 0, 1, 3); QLabel* label1 = new QLabel(i18n("Slow"), this); hlayout->addWidget(label1); QSlider* slider = new QSlider(Qt::Horizontal, this); hlayout->addWidget(slider); QLabel* label2 = new QLabel(i18n("Fast"), this); hlayout->addWidget(label2); slider->setRange(1, 10); slider->setPageStep(1); slider->setValue(windmill->speed()); connect(slider, &QSlider::valueChanged, windmill, &Kolf::Windmill::setSpeed); } //Kolf::Floater does not have a special Config class Kolf::Floater* floater = qobject_cast(item); if (floater) { m_layout->addWidget(new QLabel(i18n("Moving speed"), this), 4, 0, 1, 3); QHBoxLayout* hlayout = new QHBoxLayout; m_layout->addLayout(hlayout, 5, 0, 1, 3); QLabel* label1 = new QLabel(i18n("Slow"), this); hlayout->addWidget(label1); QSlider* slider = new QSlider(Qt::Horizontal, this); hlayout->addWidget(slider); QLabel* label2 = new QLabel(i18n("Fast"), this); hlayout->addWidget(label2); slider->setRange(0, 20); slider->setPageStep(2); slider->setValue(floater->speed()); connect(slider, &QSlider::valueChanged, floater, &Kolf::Floater::setSpeed); } } void Kolf::RectangleConfig::setWall(bool hasWall) { const int wallIndex = m_wallCheckBoxes.indexOf(qobject_cast(sender())); if (wallIndex >= 0) { m_item->setWall((Kolf::WallIndex) wallIndex, hasWall); changed(); } } void Kolf::RectangleConfig::wallChanged(Kolf::WallIndex index, bool hasWall, bool wallAllowed) { m_wallCheckBoxes[index]->setEnabled(wallAllowed); m_wallCheckBoxes[index]->setChecked(hasWall); } //END Kolf::RectangleConfig //BEGIN Kolf::Bridge Kolf::Bridge::Bridge(QGraphicsItem* parent, b2World* world) : Kolf::RectangleItem(QStringLiteral("bridge"), parent, world) { setZBehavior(CanvasItem::IsStrut, 0); } bool Kolf::Bridge::collision(Ball* ball) { ball->setFrictionMultiplier(.63); return false; } //END Kolf::Bridge //BEGIN Kolf::Floater Kolf::Floater::Floater(QGraphicsItem* parent, b2World* world) : Kolf::RectangleItem(QStringLiteral("floater"), parent, world) , m_motionLine(QLineF(200, 200, 100, 100)) , m_speed(0) , m_velocity(0) , m_position(0) , m_moveByMovesMotionLine(true) , m_animated(true) { setMlPosition(m_position); setZBehavior(CanvasItem::IsStrut, 0); } void Kolf::Floater::editModeChanged(bool editing) { Kolf::RectangleItem::editModeChanged(editing); m_animated = !editing; if (editing) setMlPosition(0); } void Kolf::Floater::moveBy(double dx, double dy) { moveItemsOnStrut(QPointF(dx, dy)); Kolf::RectangleItem::moveBy(dx, dy); if (m_moveByMovesMotionLine) m_motionLine.translate(dx, dy); propagateUpdate(); } QLineF Kolf::Floater::motionLine() const { return m_motionLine; } void Kolf::Floater::setMotionLine(const QLineF& motionLine) { m_motionLine = motionLine; setMlPosition(m_position); propagateUpdate(); } void Kolf::Floater::setMlPosition(qreal position) { m_moveByMovesMotionLine = false; setPosition(m_motionLine.pointAt(position)); m_position = position; m_moveByMovesMotionLine = true; } int Kolf::Floater::speed() const { return m_speed; } void Kolf::Floater::setSpeed(int speed) { m_speed = speed; const qreal velocity = speed / 3.5; m_velocity = (m_velocity < 0) ? -velocity : velocity; propagateUpdate(); } void Kolf::Floater::advance(int phase) { if (phase != 1 || !m_animated) return; //determine movement step const qreal mlLength = m_motionLine.length(); const qreal parameterDiff = m_velocity / mlLength; //determine new position (mirror on end point if end point passed) m_position += parameterDiff; if (m_position < 0) { m_velocity = qAbs(m_velocity); m_position = -m_position; } else if (m_position > 1) { m_velocity = -qAbs(m_velocity); m_position = 2 - m_position; } //apply position setMlPosition(m_position); } void Kolf::Floater::load(KConfigGroup* group) { Kolf::RectangleItem::load(group); QLineF motionLine = m_motionLine; motionLine.setP1(group->readEntry("startPoint", m_motionLine.p1())); motionLine.setP2(group->readEntry("endPoint", m_motionLine.p2())); setMotionLine(motionLine); setSpeed(group->readEntry("speed", m_speed)); } void Kolf::Floater::save(KConfigGroup* group) { Kolf::RectangleItem::save(group); group->writeEntry("startPoint", m_motionLine.p1()); group->writeEntry("endPoint", m_motionLine.p2()); group->writeEntry("speed", m_speed); } Kolf::Overlay* Kolf::Floater::createOverlay() { return new Kolf::FloaterOverlay(this); } //END Kolf::Floater //BEGIN Kolf::FloaterOverlay Kolf::FloaterOverlay::FloaterOverlay(Kolf::Floater* floater) : Kolf::RectangleOverlay(floater) , m_handle1(new Kolf::OverlayHandle(Kolf::OverlayHandle::SquareShape, this)) , m_handle2(new Kolf::OverlayHandle(Kolf::OverlayHandle::SquareShape, this)) , m_motionLineItem(new QGraphicsLineItem(this)) { addHandle(m_handle1); addHandle(m_handle2); connect(m_handle1, &Kolf::OverlayHandle::moveRequest, this, &Kolf::FloaterOverlay::moveMotionLineHandle); connect(m_handle2, &Kolf::OverlayHandle::moveRequest, this, &Kolf::FloaterOverlay::moveMotionLineHandle); addHandle(m_motionLineItem); QPen pen = m_motionLineItem->pen(); pen.setStyle(Qt::DashLine); m_motionLineItem->setPen(pen); } void Kolf::FloaterOverlay::update() { Kolf::RectangleOverlay::update(); const QLineF line = dynamic_cast(qitem())->motionLine().translated(-qitem()->pos()); m_handle1->setPos(line.p1()); m_handle2->setPos(line.p2()); m_motionLineItem->setLine(line); } void Kolf::FloaterOverlay::moveMotionLineHandle(const QPointF& handleScenePos) { //TODO: code duplication to Kolf::WallOverlay QPointF handlePos = mapFromScene(handleScenePos) + qitem()->pos(); const QObject* handle = sender(); //get handle positions QPointF handle1Pos = m_handle1->pos() + qitem()->pos(); QPointF handle2Pos = m_handle2->pos() + qitem()->pos(); if (handle == m_handle1) handle1Pos = handlePos; else if (handle == m_handle2) handle2Pos = handlePos; //ensure minimum length static const qreal minLength = Kolf::Overlay::MinimumObjectDimension; const QPointF posDiff = handle1Pos - handle2Pos; const qreal length = QLineF(QPointF(), posDiff).length(); if (length < minLength) { const QPointF additionalExtent = posDiff * (minLength / length - 1); if (handle == m_handle1) handle1Pos += additionalExtent; else if (handle == m_handle2) handle2Pos -= additionalExtent; } //apply to item dynamic_cast(qitem())->setMotionLine(QLineF(handle1Pos, handle2Pos)); } //END Kolf::FloaterOverlay //BEGIN Kolf::Sign Kolf::Sign::Sign(QGraphicsItem* parent, b2World* world) : Kolf::RectangleItem(QStringLiteral("sign"), parent, world) , m_text(i18n("New Text")) , m_textItem(new QGraphicsTextItem(m_text, this)) { setZBehavior(CanvasItem::FixedZValue, 3); setWallColor(Qt::black); for (int i = 0; i < Kolf::RectangleWallCount; ++i) setWall((Kolf::WallIndex) i, true); //Z value 1 should be enough to keep text above overlay m_textItem->setZValue(1); - m_textItem->setAcceptedMouseButtons(0); + m_textItem->setAcceptedMouseButtons(Qt::NoButton); //TODO: activate QGraphicsItem::ItemClipsChildrenToShape flag after //refactoring (only after it is clear that the text is the only child) } QString Kolf::Sign::text() const { return m_text; } void Kolf::Sign::setText(const QString& text) { m_text = text; m_textItem->setHtml(text); } void Kolf::Sign::setSize(const QSizeF& size) { Kolf::RectangleItem::setSize(size); m_textItem->setTextWidth(size.width()); } void Kolf::Sign::load(KConfigGroup* group) { Kolf::RectangleItem::load(group); setText(group->readEntry("Comment", m_text)); } void Kolf::Sign::save(KConfigGroup* group) { Kolf::RectangleItem::save(group); group->writeEntry("Comment", m_text); } //END Kolf::Sign //BEGIN Kolf::Windmill Kolf::Windmill::Windmill(QGraphicsItem* parent, b2World* world) : Kolf::RectangleItem(QStringLiteral("windmill"), parent, world) , m_leftWall(new Kolf::Wall(parent, world)) , m_rightWall(new Kolf::Wall(parent, world)) , m_guardWall(new Kolf::Wall(parent, world)) , m_guardAtTop(false) , m_speed(0), m_velocity(0) { setZBehavior(CanvasItem::IsStrut, 0); setSpeed(5); //initialize m_speed and m_velocity properly applyWallStyle(m_leftWall); applyWallStyle(m_rightWall); applyWallStyle(m_guardWall, false); //Z-ordering! m_guardWall->setPen(QPen(Qt::black, 5)); setWall(Kolf::TopWallIndex, false); setWall(Kolf::LeftWallIndex, true); setWall(Kolf::RightWallIndex, true); setWallAllowed(Kolf::BottomWallIndex, false); m_guardWall->setLine(QLineF()); updateWallPosition(); } Kolf::Windmill::~Windmill() { delete m_leftWall; delete m_rightWall; delete m_guardWall; } bool Kolf::Windmill::guardAtTop() const { return m_guardAtTop; } void Kolf::Windmill::setGuardAtTop(bool guardAtTop) { if (m_guardAtTop == guardAtTop) return; m_guardAtTop = guardAtTop; //exchange top and bottom walls if (guardAtTop) { const bool hasWall = this->hasWall(Kolf::TopWallIndex); setWallAllowed(Kolf::BottomWallIndex, true); setWallAllowed(Kolf::TopWallIndex, false); setWall(Kolf::BottomWallIndex, hasWall); } else { const bool hasWall = this->hasWall(Kolf::BottomWallIndex); setWallAllowed(Kolf::BottomWallIndex, false); setWallAllowed(Kolf::TopWallIndex, true); setWall(Kolf::TopWallIndex, hasWall); } //recalculate position of guard walls etc. updateWallPosition(); propagateUpdate(); } int Kolf::Windmill::speed() const { return m_speed; } void Kolf::Windmill::setSpeed(int speed) { m_speed = speed; const qreal velocity = speed / 3.0; m_velocity = (m_velocity < 0) ? -velocity : velocity; propagateUpdate(); } void Kolf::Windmill::advance(int phase) { if (phase == 1) { QLineF guardLine = m_guardWall->line().translated(m_velocity, 0); const qreal maxX = qMax(guardLine.x1(), guardLine.x2()); const qreal minX = qMin(guardLine.x1(), guardLine.x2()); QRectF rect(QPointF(), size()); if (minX < rect.left()) { guardLine.translate(rect.left() - minX, 0); m_velocity = qAbs(m_velocity); } else if (maxX > rect.right()) { guardLine.translate(rect.right() - maxX, 0); m_velocity = -qAbs(m_velocity); } m_guardWall->setLine(guardLine); } } void Kolf::Windmill::moveBy(double dx, double dy) { Kolf::RectangleItem::moveBy(dx, dy); const QPointF pos = this->pos(); m_leftWall->setPos(pos); m_rightWall->setPos(pos); m_guardWall->setPos(pos); } void Kolf::Windmill::updateWallPosition() { Kolf::RectangleItem::updateWallPosition(); //parametrize position of guard relative to old rect qreal t = 0.5; if (!m_guardWall->line().isNull()) { //this branch is taken unless this method gets called from the ctor const qreal oldLeft = m_leftWall->line().x1(); const qreal oldRight = m_rightWall->line().x1(); const qreal oldGCenter = m_guardWall->line().pointAt(0.5).x(); t = (oldGCenter - oldLeft) / (oldRight - oldLeft); } //set new positions const QRectF rect(QPointF(), size()); const QPointF leftEnd = m_guardAtTop ? rect.topLeft() : rect.bottomLeft(); const QPointF rightEnd = m_guardAtTop ? rect.topRight() : rect.bottomRight(); const QPointF wallExtent(rect.width() / 4, 0); m_leftWall->setLine(QLineF(leftEnd, leftEnd + wallExtent)); m_rightWall->setLine(QLineF(rightEnd, rightEnd - wallExtent)); //set position of guard to the same relative coordinate as before const qreal gWidth = wallExtent.x() / 1.07 - 2; const qreal gY = m_guardAtTop ? rect.top() - 4 : rect.bottom() + 4; QLineF gLine(rect.left(), gY, rect.left() + gWidth, gY); const qreal currentGCenter = gLine.pointAt(0.5).x(); const qreal desiredGCenter = rect.left() + t * rect.width(); gLine.translate(desiredGCenter - currentGCenter, 0); m_guardWall->setLine(gLine); } void Kolf::Windmill::load(KConfigGroup* group) { Kolf::RectangleItem::load(group); setSpeed(group->readEntry("speed", m_speed)); setGuardAtTop(!group->readEntry("bottom", !m_guardAtTop)); } void Kolf::Windmill::save(KConfigGroup* group) { Kolf::RectangleItem::save(group); group->writeEntry("speed", m_speed); group->writeEntry("bottom", !m_guardAtTop); } //END Kolf::Windmill diff --git a/overlay.cpp b/overlay.cpp index 4c31ca9..f95b89a 100644 --- a/overlay.cpp +++ b/overlay.cpp @@ -1,323 +1,323 @@ /*************************************************************************** * Copyright 2008, 2009, 2010 Stefan Majewsky * * 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 "overlay.h" #include "canvasitem.h" #include "game.h" #include "shape.h" #include "utils-animateditem.h" #include #include #include const qreal Kolf::Overlay::MinimumObjectDimension = 10; static const qreal OverlayHandleSize = 5; static const QPen HandlePen(Qt::blue); static const QBrush ActiveHandleBrush(QColor::fromHsv(240, 200, 255, 128)); static const QBrush NormalHandleBrush(QColor::fromHsv(240, 255, 255, 128)); //BEGIN Kolf::OverlayHandle Kolf::OverlayHandle::OverlayHandle(Kolf::OverlayHandle::Shape shape, QGraphicsItem* parent) : QGraphicsPathItem(parent) { setAcceptHoverEvents(true); setAcceptedMouseButtons(Qt::LeftButton); setPen(HandlePen); setBrush(NormalHandleBrush); //create shape QPainterPath path; switch (shape) { case SquareShape: path.addRect(QRectF(-OverlayHandleSize, -OverlayHandleSize, 2 * OverlayHandleSize, 2 * OverlayHandleSize)); break; case CircleShape: path.addEllipse(QPointF(), OverlayHandleSize, OverlayHandleSize); break; case TriangleShape: path.moveTo(QPointF(OverlayHandleSize, 0.0)); path.lineTo(QPointF(-OverlayHandleSize, OverlayHandleSize)); path.lineTo(QPointF(-OverlayHandleSize, -OverlayHandleSize)); path.closeSubpath(); break; } setPath(path); } void Kolf::OverlayHandle::hoverEnterEvent(QGraphicsSceneHoverEvent* event) { event->accept(); setBrush(ActiveHandleBrush); } void Kolf::OverlayHandle::hoverLeaveEvent(QGraphicsSceneHoverEvent* event) { event->accept(); setBrush(NormalHandleBrush); } void Kolf::OverlayHandle::mousePressEvent(QGraphicsSceneMouseEvent* event) { if (event->button() == Qt::LeftButton) { event->accept(); emit moveStarted(); } } void Kolf::OverlayHandle::mouseMoveEvent(QGraphicsSceneMouseEvent* event) { if (event->buttons() & Qt::LeftButton) { event->accept(); emit moveRequest(event->scenePos()); } } void Kolf::OverlayHandle::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) { if (event->button() == Qt::LeftButton) { event->accept(); emit moveEnded(); } } //END Kolf::OverlayHandle //BEGIN Kolf::OverlayAreaItem Kolf::OverlayAreaItem::OverlayAreaItem(Features features, QGraphicsItem* parent) : QGraphicsPathItem(parent) , m_features(features) { if (m_features & (Clickable | Draggable)) setAcceptedMouseButtons(Qt::LeftButton | Qt::RightButton); if (m_features & Draggable) setCursor(Qt::OpenHandCursor); if (m_features & Hoverable) setAcceptHoverEvents(true); //start invisible setPen(Qt::NoPen); setBrush(Qt::transparent); } void Kolf::OverlayAreaItem::hoverEnterEvent(QGraphicsSceneHoverEvent* event) { if (m_features & Hoverable) { event->accept(); emit hoverEntered(); } else QGraphicsPathItem::hoverEnterEvent(event); } void Kolf::OverlayAreaItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* event) { if (m_features & Hoverable) { event->accept(); emit hoverLeft(); } else QGraphicsPathItem::hoverLeaveEvent(event); } void Kolf::OverlayAreaItem::mousePressEvent(QGraphicsSceneMouseEvent* event) { if (m_features & Clickable) { event->accept(); emit clicked(event->button()); } if (m_features & Draggable) { event->accept(); setCursor(Qt::ClosedHandCursor); } if (!event->isAccepted()) QGraphicsPathItem::mousePressEvent(event); } void Kolf::OverlayAreaItem::mouseMoveEvent(QGraphicsSceneMouseEvent* event) { if (m_features & Draggable) emit dragged(event->scenePos() - event->lastScenePos()); else QGraphicsItem::mouseMoveEvent(event); } void Kolf::OverlayAreaItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) { if (m_features & Draggable) setCursor(Qt::OpenHandCursor); else QGraphicsItem::mouseReleaseEvent(event); } //END Kolf::OverlayAreaItem //BEGIN Kolf::Overlay Kolf::Overlay::Overlay(CanvasItem* citem, QGraphicsItem* qitem, bool hack_addQitemShapeToOutlines) : QGraphicsItem(qitem) , m_citem(citem), m_qitem(qitem) , m_state(Kolf::Overlay::Passive) , m_addQitemShapeToOutlines(hack_addQitemShapeToOutlines) , m_activatorItem(new Kolf::OverlayAreaItem(Kolf::OverlayAreaItem::Clickable | Kolf::OverlayAreaItem::Hoverable, this)) , m_interactorAnimator(new Utils::AnimatedItem(this)) , m_interactorItem(new Kolf::OverlayAreaItem(Kolf::OverlayAreaItem::Clickable | Kolf::OverlayAreaItem::Draggable, m_interactorAnimator)) , m_handleAnimator(new Utils::AnimatedItem(this)) { //overlays have to be shown explicitly hide(); //overlays themselves do not have mouse interaction, and do not paint anything itself - setAcceptedMouseButtons(0); + setAcceptedMouseButtons(Qt::NoButton); setFlag(QGraphicsItem::ItemHasNoContents); //initialize activator area item m_activatorItem->setZValue(1); connect(m_activatorItem, &Kolf::OverlayAreaItem::hoverEntered, this, &Overlay::activatorEntered); connect(m_activatorItem, &Kolf::OverlayAreaItem::hoverLeft, this, &Overlay::activatorLeft); connect(m_activatorItem, &Kolf::OverlayAreaItem::clicked, this, &Overlay::activatorClicked); //initialize interactor area item m_interactorAnimator->setZValue(2); m_interactorAnimator->setOpacity(0); //not visible at first m_interactorItem->setBrush(Qt::green); connect(m_interactorItem, &Kolf::OverlayAreaItem::clicked, this, &Overlay::activatorClicked); connect(m_interactorItem, &Kolf::OverlayAreaItem::dragged, this, &Overlay::interactorDragged); //initialize handle manager m_handleAnimator->setZValue(3); m_handleAnimator->setHideWhenInvisible(true); m_handleAnimator->setOpacity(0); //not visible at first //apply passive state - we need to change to some other state to prevent the setState method from returning early m_state = Active; setState(Passive); } CanvasItem* Kolf::Overlay::citem() const { return m_citem; } QGraphicsItem* Kolf::Overlay::qitem() const { return m_qitem; } void Kolf::Overlay::update() { //update geometry outlines QPainterPath activationOutline, interactionOutline; foreach (Kolf::Shape* shape, m_citem->shapes()) { activationOutline.addPath(shape->activationOutline()); interactionOutline.addPath(shape->interactionOutline()); } //HACK for Kolf::Shape if (m_addQitemShapeToOutlines) { const QPainterPath shape = m_qitem->shape(); activationOutline.addPath(shape); interactionOutline.addPath(shape); } activationOutline.setFillRule(Qt::WindingFill); interactionOutline.setFillRule(Qt::WindingFill); m_activatorItem->setPath(activationOutline); m_interactorItem->setPath(interactionOutline); } void Kolf::Overlay::addHandle(QGraphicsItem* handle) { handle->setParentItem(m_handleAnimator); handle->show(); } Kolf::Overlay::State Kolf::Overlay::state() const { return m_state; } void Kolf::Overlay::setState(Kolf::Overlay::State state) { if (m_state == state) return; m_state = state; //apply new inner properties switch (state) { case Kolf::Overlay::Passive: m_interactorAnimator->setOpacityAnimated(0.0); break; case Kolf::Overlay::Hovered: m_interactorAnimator->setOpacityAnimated(0.3); break; case Kolf::Overlay::Active: m_interactorAnimator->setOpacityAnimated(0.6); break; } m_handleAnimator->setOpacityAnimated(state == Active ? 1.0 : 0.0); //propagate changes emit stateChanged(); if (state == Kolf::Overlay::Active) { KolfGame* game = m_citem->game; if (game) game->setSelectedItem(m_citem); } } void Kolf::Overlay::activatorEntered() { if (m_state == Kolf::Overlay::Passive) setState(Kolf::Overlay::Hovered); } void Kolf::Overlay::activatorLeft() { if (m_state == Kolf::Overlay::Hovered) setState(Kolf::Overlay::Passive); } void Kolf::Overlay::activatorClicked(int button) { Q_UNUSED(button) setState(Kolf::Overlay::Active); } void Kolf::Overlay::interactorDragged(const QPointF& distance) { if (m_state == Kolf::Overlay::Active) m_citem->moveBy(distance.x(), distance.y()); } //default implementation for QGraphicsItem QRectF Kolf::Overlay::boundingRect() const { return QRectF(); } void Kolf::Overlay::paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) { } //END Kolf::Overlay