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"