File indexing completed on 2024-12-22 03:51:28

0001 /*
0002     Copyright (C) 2002-2005, Jason Katz-Brown <jasonkb@mit.edu>
0003     Copyright 2010 Stefan Majewsky <majewsky@gmx.net>
0004 
0005     This program is free software; you can redistribute it and/or modify
0006     it under the terms of the GNU General Public License as published by
0007     the Free Software Foundation; either version 2 of the License, or
0008     (at your option) any later version.
0009 
0010     This program is distributed in the hope that it will be useful,
0011     but WITHOUT ANY WARRANTY; without even the implied warranty of
0012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013     GNU General Public License for more details.
0014 
0015     You should have received a copy of the GNU General Public License
0016     along with this program; if not, write to the Free Software
0017     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
0018 */
0019 
0020 #include "landscape.h"
0021 #include "ball.h"
0022 #include "game.h"
0023 
0024 #include <QDoubleSpinBox>
0025 #include <QBoxLayout>
0026 #include <QCheckBox>
0027 #include <QLabel>
0028 #include <QSlider>
0029 #include <KComboBox>
0030 #include <KConfigGroup>
0031 #include <KLocalizedString>
0032 
0033 //BEGIN Kolf::LandscapeItem
0034 //END Kolf::LandscapeItem
0035 
0036 Kolf::LandscapeItem::LandscapeItem(const QString& type, QGraphicsItem* parent, b2World* world)
0037     : EllipticalCanvasItem(false, type, parent, world)
0038     , m_blinkEnabled(false)
0039     , m_blinkInterval(50)
0040     , m_blinkFrame(0)
0041 {
0042     setSimulationType(CanvasItem::NoSimulation);
0043 }
0044 
0045 bool Kolf::LandscapeItem::isBlinkEnabled() const
0046 {
0047     return m_blinkEnabled;
0048 }
0049 
0050 void Kolf::LandscapeItem::setBlinkEnabled(bool blinkEnabled)
0051 {
0052     m_blinkEnabled = blinkEnabled;
0053     //reset animation
0054     m_blinkFrame = 0;
0055     setVisible(true);
0056 }
0057 
0058 int Kolf::LandscapeItem::blinkInterval() const
0059 {
0060     return m_blinkInterval;
0061 }
0062 
0063 void Kolf::LandscapeItem::setBlinkInterval(int blinkInterval)
0064 {
0065     m_blinkInterval = blinkInterval;
0066     //reset animation
0067     m_blinkFrame = 0;
0068     setVisible(true);
0069 }
0070 
0071 void Kolf::LandscapeItem::advance(int phase)
0072 {
0073     EllipticalCanvasItem::advance(phase);
0074     if (phase == 1 && m_blinkEnabled)
0075     {
0076         const int actualInterval = 1.8 * (10 + m_blinkInterval);
0077         m_blinkFrame = (m_blinkFrame + 1) % (2 * actualInterval);
0078         setVisible(m_blinkFrame < actualInterval);
0079     }
0080 }
0081 
0082 void Kolf::LandscapeItem::load(KConfigGroup* group)
0083 {
0084     EllipticalCanvasItem::loadSize(group);
0085     setBlinkEnabled(group->readEntry("changeEnabled", m_blinkEnabled));
0086     setBlinkInterval(group->readEntry("changeEvery", m_blinkInterval));
0087 }
0088 
0089 void Kolf::LandscapeItem::save(KConfigGroup* group)
0090 {
0091     EllipticalCanvasItem::saveSize(group);
0092     group->writeEntry("changeEnabled", m_blinkEnabled);
0093     group->writeEntry("changeEvery", m_blinkInterval);
0094 }
0095 
0096 Config* Kolf::LandscapeItem::config(QWidget* parent)
0097 {
0098     return new Kolf::LandscapeConfig(this, parent);
0099 }
0100 
0101 Kolf::Overlay* Kolf::LandscapeItem::createOverlay()
0102 {
0103     return new Kolf::LandscapeOverlay(this);
0104 }
0105 
0106 //BEGIN Kolf::LandscapeOverlay
0107 
0108 Kolf::LandscapeOverlay::LandscapeOverlay(Kolf::LandscapeItem* item)
0109     : Kolf::Overlay(item, item)
0110 {
0111     //TODO: code duplication to Kolf::RectangleOverlay and Kolf::SlopeOverlay
0112     for (int i = 0; i < 4; ++i)
0113     {
0114         Kolf::OverlayHandle* handle = new Kolf::OverlayHandle(Kolf::OverlayHandle::CircleShape, this);
0115         m_handles << handle;
0116         addHandle(handle);
0117         connect(handle, &Kolf::OverlayHandle::moveRequest, this, &Kolf::LandscapeOverlay::moveHandle);
0118     }
0119 }
0120 
0121 void Kolf::LandscapeOverlay::update()
0122 {
0123     Kolf::Overlay::update();
0124     const QRectF rect = qitem()->boundingRect();
0125     m_handles[0]->setPos(rect.topLeft());
0126     m_handles[1]->setPos(rect.topRight());
0127     m_handles[2]->setPos(rect.bottomLeft());
0128     m_handles[3]->setPos(rect.bottomRight());
0129 }
0130 
0131 void Kolf::LandscapeOverlay::moveHandle(const QPointF& handleScenePos)
0132 {
0133     const QPointF handlePos = mapFromScene(handleScenePos);
0134     //factor 2: item bounding rect is always centered around (0,0)
0135     QSizeF newSize(2 * qAbs(handlePos.x()), 2 * qAbs(handlePos.y()));
0136     dynamic_cast<Kolf::LandscapeItem*>(qitem())->setSize(newSize);
0137 }
0138 
0139 //END Kolf::LandscapeOverlay
0140 //BEGIN Kolf::LandscapeConfig
0141 
0142 Kolf::LandscapeConfig::LandscapeConfig(Kolf::LandscapeItem* item, QWidget* parent)
0143     : Config(parent)
0144 {
0145     QVBoxLayout* vlayout = new QVBoxLayout(this);
0146     QCheckBox* checkBox = new QCheckBox(i18n("Enable show/hide"), this);
0147     vlayout->addWidget(checkBox);
0148 
0149     QHBoxLayout* hlayout = new QHBoxLayout;
0150     vlayout->addLayout(hlayout);
0151     QLabel* label1 = new QLabel(i18n("Slow"), this);
0152     hlayout->addWidget(label1);
0153     QSlider* slider = new QSlider(Qt::Horizontal, this);
0154     hlayout->addWidget(slider);
0155     QLabel* label2 = new QLabel(i18n("Fast"), this);
0156     hlayout->addWidget(label2);
0157 
0158     vlayout->addStretch();
0159 
0160     checkBox->setChecked(true);
0161     connect(checkBox, &QCheckBox::toggled, label1, &QLabel::setEnabled);
0162     connect(checkBox, &QCheckBox::toggled, label2, &QLabel::setEnabled);
0163     connect(checkBox, &QCheckBox::toggled, slider, &QSlider::setEnabled);
0164     connect(checkBox, &QCheckBox::toggled, item, &Kolf::LandscapeItem::setBlinkEnabled);
0165     checkBox->setChecked(item->isBlinkEnabled());
0166     slider->setRange(1, 100);
0167     slider->setPageStep(5);
0168     slider->setValue(100 - item->blinkInterval());
0169     connect(slider, &QSlider::valueChanged, this, &Kolf::LandscapeConfig::setBlinkInterval);
0170     connect(this, &Kolf::LandscapeConfig::blinkIntervalChanged, item, &Kolf::LandscapeItem::setBlinkInterval);
0171 }
0172 
0173 void Kolf::LandscapeConfig::setBlinkInterval(int sliderValue)
0174 {
0175     Q_EMIT blinkIntervalChanged(100 - sliderValue);
0176 }
0177 
0178 //END Kolf::LandscapeConfig
0179 //BEGIN Kolf::Puddle
0180 
0181 Kolf::Puddle::Puddle(QGraphicsItem* parent, b2World* world)
0182     : Kolf::LandscapeItem(QStringLiteral("puddle"), parent, world)
0183 {
0184     setData(0, Rtti_DontPlaceOn);
0185     setSize(QSizeF(45, 30));
0186     setZBehavior(CanvasItem::FixedZValue, 3);
0187 }
0188 
0189 bool Kolf::Puddle::collision(Ball* ball)
0190 {
0191     if (!ball->isVisible())
0192         return false;
0193     if (!contains(ball->pos() - pos()))
0194         return true;
0195     //ball is visible and has reached the puddle
0196     game->playSound(Sound::Puddle);
0197     ball->setAddStroke(ball->addStroke() + 1);
0198     ball->setPlaceOnGround(true);
0199     ball->setVisible(false);
0200     ball->setState(Stopped);
0201     ball->setVelocity(Vector());
0202     if (game && game->curBall() == ball)
0203         game->stoppedBall();
0204     return false;
0205 }
0206 
0207 //END Kolf::Puddle
0208 //BEGIN Kolf::Sand
0209 
0210 Kolf::Sand::Sand(QGraphicsItem* parent, b2World* world)
0211     : Kolf::LandscapeItem(QStringLiteral("sand"), parent, world)
0212 {
0213     setSize(QSizeF(45, 40));
0214     setZBehavior(CanvasItem::FixedZValue, 2);
0215 }
0216 
0217 bool Kolf::Sand::collision(Ball* ball)
0218 {
0219     if (contains(ball->pos() - pos()))
0220         ball->setFrictionMultiplier(7);
0221     return true;
0222 }
0223 
0224 //END Kolf::Sand
0225 //BEGIN Kolf::Slope
0226 
0227 struct SlopeData
0228 {
0229     QStringList gradientKeys, translatedGradientKeys;
0230     QStringList spriteKeys, reversedSpriteKeys;
0231     SlopeData()
0232     {
0233         gradientKeys << QStringLiteral("Vertical")
0234                      << QStringLiteral("Horizontal")
0235                      << QStringLiteral("Diagonal")
0236                      << QStringLiteral("Opposite Diagonal")
0237                      << QStringLiteral("Elliptic");
0238         translatedGradientKeys << i18n("Vertical")
0239                      << i18n("Horizontal")
0240                      << i18n("Diagonal")
0241                      << i18n("Opposite Diagonal")
0242                      << i18n("Elliptic");
0243         spriteKeys   << QStringLiteral("slope_n")
0244                      << QStringLiteral("slope_w")
0245                      << QStringLiteral("slope_nw")
0246                      << QStringLiteral("slope_ne")
0247                      << QStringLiteral("slope_bump");
0248         reversedSpriteKeys << QStringLiteral("slope_s")
0249                      << QStringLiteral("slope_e")
0250                      << QStringLiteral("slope_se")
0251                      << QStringLiteral("slope_sw")
0252                      << QStringLiteral("slope_dip");
0253     }
0254 };
0255 Q_GLOBAL_STATIC(SlopeData, g_slopeData)
0256 
0257 Kolf::Slope::Slope(QGraphicsItem* parent, b2World* world)
0258     : Tagaro::SpriteObjectItem(Kolf::renderer(), QString(), parent)
0259     , CanvasItem(world)
0260     , m_grade(4)
0261     , m_reversed(false)
0262     , m_stuckOnGround(false)
0263     , m_type(Kolf::VerticalSlope)
0264     , m_gradeItem(new QGraphicsSimpleTextItem(this))
0265 {
0266     m_gradeItem->setBrush(Qt::white);
0267     m_gradeItem->setVisible(false);
0268     m_gradeItem->setZValue(1);
0269     for (int i = 0; i < 4; ++i)
0270     {
0271         ArrowItem* arrow = new ArrowItem(this);
0272         arrow->setLength(0);
0273         arrow->setVisible(false);
0274         m_arrows << arrow;
0275     }
0276     setSize(QSizeF(40, 40));
0277     m_stuckOnGround = true; //so that the following call does not return early
0278     setStuckOnGround(false); //initializes Z behavior
0279     updateAppearance();
0280 }
0281 
0282 double Kolf::Slope::grade() const
0283 {
0284     return m_grade;
0285 }
0286 
0287 void Kolf::Slope::setGrade(double grade)
0288 {
0289     if (m_grade != grade && grade > 0)
0290     {
0291         m_grade = grade;
0292         updateAppearance();
0293         propagateUpdate();
0294     }
0295 }
0296 
0297 bool Kolf::Slope::isReversed() const
0298 {
0299     return m_reversed;
0300 }
0301 
0302 void Kolf::Slope::setReversed(bool reversed)
0303 {
0304     if (m_reversed != reversed)
0305     {
0306         m_reversed = reversed;
0307         updateAppearance();
0308         propagateUpdate();
0309     }
0310 }
0311 
0312 Kolf::SlopeType Kolf::Slope::slopeType() const
0313 {
0314     return m_type;
0315 }
0316 
0317 void Kolf::Slope::setSlopeType(int type)
0318 {
0319     if (m_type != type && type >= 0)
0320     {
0321         m_type = (Kolf::SlopeType) type;
0322         updateAppearance();
0323         propagateUpdate();
0324     }
0325 }
0326 
0327 bool Kolf::Slope::isStuckOnGround() const
0328 {
0329     return m_stuckOnGround;
0330 }
0331 
0332 void Kolf::Slope::setStuckOnGround(bool stuckOnGround)
0333 {
0334     if (m_stuckOnGround != stuckOnGround)
0335     {
0336         m_stuckOnGround = stuckOnGround;
0337         setZBehavior(m_stuckOnGround ? CanvasItem::FixedZValue : CanvasItem::IsRaisedByStrut, 1);
0338         propagateUpdate();
0339     }
0340 }
0341 
0342 QPainterPath Kolf::Slope::shape() const
0343 {
0344     const QRectF rect = boundingRect();
0345     QPainterPath path;
0346     if (m_type == Kolf::CrossDiagonalSlope) {
0347         QPolygonF polygon(3);
0348         polygon[0] = rect.topLeft();
0349         polygon[1] = rect.bottomRight();
0350         polygon[2] = m_reversed ? rect.topRight() : rect.bottomLeft();
0351         path.addPolygon(polygon);
0352     } else if (m_type == Kolf::DiagonalSlope) {
0353         QPolygonF polygon(3);
0354         polygon[0] = rect.topRight();
0355         polygon[1] = rect.bottomLeft();
0356         polygon[2] = m_reversed ? rect.topLeft() : rect.bottomRight();
0357         path.addPolygon(polygon);
0358     } else if (m_type == Kolf::EllipticSlope) {
0359         path.addEllipse(rect);
0360     } else {
0361         path.addRect(rect);
0362     }
0363     return path;
0364 }
0365 
0366 void Kolf::Slope::setSize(const QSizeF& size)
0367 {
0368     if (m_type == Kolf::EllipticSlope)
0369     {
0370         const double extent = qMin(size.width(), size.height());
0371         Tagaro::SpriteObjectItem::setSize(extent, extent);
0372     }
0373     else
0374         Tagaro::SpriteObjectItem::setSize(size);
0375     updateInfo();
0376     propagateUpdate();
0377     updateZ(this);
0378 }
0379 
0380 QPointF Kolf::Slope::getPosition() const
0381 {
0382     return Tagaro::SpriteObjectItem::pos();
0383 }
0384 
0385 void Kolf::Slope::moveBy(double dx, double dy)
0386 {
0387     Tagaro::SpriteObjectItem::moveBy(dx, dy);
0388     CanvasItem::moveBy(dx, dy);
0389 }
0390 
0391 void Kolf::Slope::load(KConfigGroup* group)
0392 {
0393     setGrade(group->readEntry("grade", m_grade));
0394     setReversed(group->readEntry("reversed", m_reversed));
0395     setStuckOnGround(group->readEntry("stuckOnGround", m_stuckOnGround));
0396     //gradient is a bit more complicated
0397     const QString type = group->readEntry("gradient", g_slopeData->gradientKeys.value(m_type));
0398     setSlopeType(g_slopeData->gradientKeys.indexOf(type));
0399     //read size
0400     QSizeF size = Tagaro::SpriteObjectItem::size();
0401     size.setWidth(group->readEntry("width", size.width()));
0402     size.setHeight(group->readEntry("height", size.height()));
0403     setSize(size);
0404 }
0405 
0406 void Kolf::Slope::save(KConfigGroup* group)
0407 {
0408     group->writeEntry("grade", m_grade);
0409     group->writeEntry("reversed", m_reversed);
0410     group->writeEntry("stuckOnGround", m_stuckOnGround);
0411     group->writeEntry("gradient", g_slopeData->gradientKeys.value(m_type));
0412     const QSizeF size = Tagaro::SpriteObjectItem::size();
0413     group->writeEntry("width", size.width());
0414     group->writeEntry("height", size.height());
0415 }
0416 
0417 void Kolf::Slope::updateAppearance()
0418 {
0419     updateInfo();
0420     //set pixmap
0421     setSpriteKey((m_reversed ? g_slopeData->reversedSpriteKeys : g_slopeData->spriteKeys).value(m_type));
0422 }
0423 
0424 void Kolf::Slope::updateInfo()
0425 {
0426     m_gradeItem->setText(QString::number(m_grade));
0427     const QPointF textOffset = m_gradeItem->boundingRect().center();
0428     //update arrows
0429     const QSizeF size = Tagaro::SpriteObjectItem::size();
0430     const double width = size.width(), height = size.height();
0431     const double length = sqrt(width * width + height * height) / 4;
0432     if (m_type == Kolf::EllipticSlope)
0433     {
0434         double angle = 0;
0435         for (int i = 0; i < 4; ++i, angle += M_PI / 2)
0436         {
0437             ArrowItem* arrow = m_arrows[i];
0438             arrow->setLength(length);
0439             arrow->setAngle(angle);
0440             arrow->setReversed(m_reversed);
0441             arrow->setPos(QPointF(width / 2, height / 2));
0442         }
0443         m_gradeItem->setPos(QPointF(width / 2, height / 2) - textOffset);
0444     }
0445     else
0446     {
0447         double angle = 0;
0448         double x = .5 * width, y = .5 * height;
0449         switch ((int) m_type)
0450         {
0451             case Kolf::HorizontalSlope:
0452                 angle = 0;
0453                 break;
0454             case Kolf::VerticalSlope:
0455                 angle = M_PI / 2;
0456                 break;
0457             case Kolf::DiagonalSlope:
0458                 angle = atan(width / height);
0459                 x = m_reversed ? .25 * width : .75 * width;
0460                 y = m_reversed ? .25 * height : .75 * height;
0461                 break;
0462             case Kolf::CrossDiagonalSlope:
0463                 angle = M_PI - atan(width / height);
0464                 x = m_reversed ? .75 * width : .25 * width;
0465                 y = m_reversed ? .25 * height : .75 * height;
0466                 break;
0467         }
0468         //only one arrow needed - hide all others
0469         for (int i = 1; i < 4; ++i)
0470             m_arrows[i]->setLength(0);
0471         ArrowItem* arrow = m_arrows[0];
0472         arrow->setLength(length);
0473         arrow->setAngle(m_reversed ? angle : angle + M_PI);
0474         arrow->setPos(QPointF(x, y));
0475         m_gradeItem->setPos(QPointF(x, y) - textOffset);
0476     }
0477 }
0478 
0479 bool Kolf::Slope::collision(Ball* ball)
0480 {
0481     Vector v = ball->velocity();
0482     double addto = 0.013 * m_grade;
0483 
0484     const bool diag = m_type == Kolf::DiagonalSlope || m_type == Kolf::CrossDiagonalSlope;
0485     const bool circle = m_type == Kolf::EllipticSlope;
0486 
0487     double slopeAngle = 0;
0488     const double width = size().width(), height = size().height();
0489 
0490     if (diag)
0491         slopeAngle = atan(width / height);
0492     else if (circle)
0493     {
0494         const QPointF start = pos() + QPointF(width, height) / 2.0;
0495         const QPointF end = ball->pos();
0496 
0497         Vector betweenVector = start - end;
0498         const double factor = betweenVector.magnitude() / (width / 2.0);
0499         slopeAngle = betweenVector.direction();
0500 
0501         // this little bit by Daniel
0502         addto *= factor * M_PI / 2;
0503         addto = sin(addto);
0504     }
0505 
0506     if (!m_reversed)
0507         addto = -addto;
0508     switch ((int) m_type)
0509     {
0510         case Kolf::HorizontalSlope:
0511             v.rx() += addto;
0512             break;
0513         case Kolf::VerticalSlope:
0514             v.ry() += addto;
0515             break;
0516         case Kolf::DiagonalSlope:
0517         case Kolf::EllipticSlope:
0518             v.rx() += cos(slopeAngle) * addto;
0519             v.ry() += sin(slopeAngle) * addto;
0520             break;
0521         case Kolf::CrossDiagonalSlope:
0522             v.rx() -= cos(slopeAngle) * addto;
0523             v.ry() += sin(slopeAngle) * addto;
0524             break;
0525     }
0526     ball->setVelocity(v);
0527     ball->setState(v.isNull() ? Stopped : Rolling);
0528     // do NOT do terrain collidingItems
0529     return false;
0530 }
0531 
0532 bool Kolf::Slope::terrainCollisions() const
0533 {
0534     return true;
0535 }
0536 
0537 QList<QGraphicsItem*> Kolf::Slope::infoItems() const
0538 {
0539     QList<QGraphicsItem*> result;
0540     for (ArrowItem* arrow : m_arrows)
0541         result << arrow;
0542     result << m_gradeItem;
0543     return result;
0544 }
0545 
0546 Config* Kolf::Slope::config(QWidget* parent)
0547 {
0548     return new Kolf::SlopeConfig(this, parent);
0549 }
0550 
0551 Kolf::Overlay* Kolf::Slope::createOverlay()
0552 {
0553     return new Kolf::SlopeOverlay(this);
0554 }
0555 
0556 //END Kolf::Slope
0557 //BEGIN Kolf::SlopeConfig
0558 
0559 Kolf::SlopeConfig::SlopeConfig(Kolf::Slope* slope, QWidget* parent)
0560     : Config(parent)
0561 {
0562     QGridLayout* layout = new QGridLayout(this);
0563 
0564     KComboBox* typeBox = new KComboBox(this);
0565     typeBox->addItems(g_slopeData->translatedGradientKeys);
0566     typeBox->setCurrentIndex(slope->slopeType());
0567         connect(typeBox, &KComboBox::currentIndexChanged, slope,
0568                 &Kolf::Slope::setSlopeType);
0569         layout->addWidget(typeBox, 0, 0, 1, 2);
0570 
0571     QCheckBox* reversed = new QCheckBox(i18n("Reverse direction"), this);
0572     reversed->setChecked(slope->isReversed());
0573     connect(reversed, &QCheckBox::toggled, slope, &Kolf::Slope::setReversed);
0574     layout->addWidget(reversed, 1, 0);
0575 
0576     QCheckBox* stuck = new QCheckBox(i18n("Unmovable"), this);
0577     stuck->setChecked(slope->isStuckOnGround());
0578     stuck->setWhatsThis(i18n("Whether or not this slope can be moved by other objects, like floaters."));
0579     connect(stuck, &QCheckBox::toggled, slope, &Kolf::Slope::setStuckOnGround);
0580     layout->addWidget(stuck, 1, 1);
0581 
0582     layout->addWidget(new QLabel(i18n("Grade:"), this), 2, 0);
0583 
0584     QDoubleSpinBox* grade = new QDoubleSpinBox(this);
0585     grade->setRange(0, 8);
0586     grade->setSingleStep(1);
0587     grade->setValue(slope->grade());
0588         connect(grade, &QDoubleSpinBox::valueChanged, slope,
0589                 &Kolf::Slope::setGrade);
0590         layout->addWidget(grade, 2, 1);
0591 
0592     layout->setRowStretch(4, 10);
0593 }
0594 
0595 //END Kolf::SlopeConfig
0596 //BEGIN Kolf::SlopeOverlay
0597 
0598 Kolf::SlopeOverlay::SlopeOverlay(Kolf::Slope* slope)
0599     : Kolf::Overlay(slope, slope, true) //true = add shape to outlines
0600 {
0601     //TODO: code duplication to Kolf::LandscapeOverlay and Kolf::RectangleOverlay
0602     for (int i = 0; i < 4; ++i)
0603     {
0604         Kolf::OverlayHandle* handle = new Kolf::OverlayHandle(Kolf::OverlayHandle::CircleShape, this);
0605         m_handles << handle;
0606         addHandle(handle);
0607         connect(handle, &Kolf::OverlayHandle::moveRequest, this, &Kolf::SlopeOverlay::moveHandle);
0608     }
0609 }
0610 
0611 void Kolf::SlopeOverlay::update()
0612 {
0613     Kolf::Overlay::update();
0614     const QRectF rect = qitem()->boundingRect();
0615     m_handles[0]->setPos(rect.topLeft());
0616     m_handles[1]->setPos(rect.topRight());
0617     m_handles[2]->setPos(rect.bottomLeft());
0618     m_handles[3]->setPos(rect.bottomRight());
0619 }
0620 
0621 void Kolf::SlopeOverlay::moveHandle(const QPointF& handleScenePos)
0622 {
0623     Kolf::OverlayHandle* handle = qobject_cast<Kolf::OverlayHandle*>(sender());
0624     const int handleIndex = m_handles.indexOf(handle);
0625     Kolf::Slope* item = dynamic_cast<Kolf::Slope*>(qitem());
0626     const QPointF handlePos = mapFromScene(handleScenePos);
0627     //modify bounding rect using new handlePos
0628     QRectF rect(QPointF(), item->size());
0629     if (handleIndex % 2 == 0)
0630         rect.setLeft(qMin(handlePos.x(), rect.right()));
0631     else
0632         rect.setRight(qMax(handlePos.x(), rect.left()));
0633     if (handleIndex < 2)
0634         rect.setTop(qMin(handlePos.y(), rect.bottom()));
0635     else
0636         rect.setBottom(qMax(handlePos.y(), rect.top()));
0637     item->moveBy(rect.x(), rect.y());
0638     item->setSize(rect.size());
0639 }
0640 
0641 //END Kolf::SlopeOverlay
0642 
0643 #include "moc_landscape.cpp"