File indexing completed on 2025-02-02 07:28:21

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 #ifndef KOLF_CANVASITEM_H
0021 #define KOLF_CANVASITEM_H
0022 
0023 #include <config.h>
0024 #include "vector.h"
0025 #include "tagaro/spriteobjectitem.h"
0026 
0027 #include <QGraphicsRectItem>
0028 
0029 class b2Body;
0030 class b2World;
0031 
0032 class Ball;
0033 class KConfigGroup;
0034 class KolfGame;
0035 
0036 namespace Kolf
0037 {
0038     class EllipseShape;
0039     class Overlay;
0040     class Shape;
0041 }
0042 
0043 enum RttiCodes { Rtti_NoCollision = 1001, Rtti_DontPlaceOn = 1002, Rtti_Putter = 1004 };
0044 
0045 class CanvasItem
0046 {
0047 public:
0048     explicit CanvasItem(b2World* world);
0049     virtual ~CanvasItem();
0050     ///load your settings from the KConfigGroup, which represents a course.
0051     virtual void load(KConfigGroup *) {}
0052     ///save your settings.
0053     virtual void save(KConfigGroup *cfg);
0054     ///called for information when shot started
0055     virtual void shotStarted() {}
0056     ///called when the edit mode has been changed.
0057     virtual void editModeChanged(bool editing);
0058     ///Returns whether all items of this type of item (based on data()) that are "colliding" (ie, in the same spot) with ball should get collision() called.
0059     virtual bool terrainCollisions() const { return false; }
0060     ///Returns a Config that can be used to configure this item by the user. The default implementation returns one that says 'No configuration options'.
0061     virtual Config *config(QWidget *parent) { return new DefaultConfig(parent); }
0062     ///Returns other items that should be movable (besides this one of course).
0063     virtual QList<QGraphicsItem *> moveableItems() const { return QList<QGraphicsItem *>(); }
0064 
0065     void setId(int newId) { m_id = newId; }
0066     int curId() const { return m_id; }
0067 
0068     ///Called on ball's collision. Return if terrain collidingItems should be processed.
0069     virtual bool collision(Ball *ball) { Q_UNUSED(ball) return false; }
0070 
0071     ///Reimplement if you want extra items to have access to the game object.
0072     virtual void setGame(KolfGame *game) { this->game = game; }
0073 
0074     QString name() const { return m_name; }
0075     void setName(const QString &newname) { m_name = newname; }
0076     virtual void setSize(const QSizeF&) {}
0077 
0078     virtual void moveBy(double dx, double dy);
0079 
0080     //The following is needed temporarily while CanvasItem is not a QGraphicsItem by itself.
0081     void setPosition(const QPointF& pos) { const QPointF diff = pos - getPosition(); moveBy(diff.x(), diff.y()); }
0082     virtual QPointF getPosition() const = 0;
0083 
0084     enum ZBehavior { FixedZValue = 0, IsStrut = 1, IsRaisedByStrut = 2 };
0085     ///This specifies how the object is Z-ordered.
0086     ///\li FixedZValue: No special behavior.
0087     ///\li IsStrut: This item is a vertical strut. It raises certain
0088     ///    items when they move on top of it. Its zValue is \a zValueStep.
0089     ///\li IsRaisedByStrut: This item can be raised by struts underneath
0090     ///    it. \a zValueStep is the amount by which the zValue is raised
0091     ///    then. (i.e. \a zValue is relative to the strut)
0092     //TODO: account for overlapping struts
0093     void setZBehavior(ZBehavior behavior, qreal zValue);
0094     ///Struts are normally found by collision detection. This method
0095     ///configures a static strut for this item (on a semantic basis;
0096     ///e.g. the RectangleItem is the static strut for its walls).
0097     void setStaticStrut(CanvasItem* citem);
0098     void updateZ(QGraphicsItem* self);
0099     void moveItemsOnStrut(const QPointF& posDiff);
0100     static bool mayCollide(CanvasItem* citem1, CanvasItem* citem2);
0101 protected:
0102     friend class Kolf::Overlay; //for delivery of Kolf::Overlay::stateChanged signal
0103     ///pointer to main KolfGame
0104     KolfGame *game;
0105 private:
0106     QString m_name;
0107     int m_id;
0108     CanvasItem::ZBehavior m_zBehavior;
0109     qreal m_zValue;
0110     CanvasItem* m_strut;
0111     CanvasItem* m_staticStrut;
0112     QList<CanvasItem*> m_struttedItems;
0113 
0114 //AFTER THIS LINE follows what I have inserted during the refactoring
0115     public:
0116         enum SimulationFlag
0117         {
0118             CollisionFlag = 1 << 0,
0119             KinematicSimulationFlag = 1 << 1,
0120             DynamicSimulationFlag = 1 << 2
0121         };
0122         enum SimulationType
0123         {
0124             ///The object is immovable.
0125             NoSimulation = 0,
0126             ///The object is immovable, but other objects can interact with it.
0127             CollisionSimulation = CollisionFlag,
0128             ///The object moves according to its kinematic state.
0129             KinematicSimulation = CollisionSimulation | KinematicSimulationFlag,
0130             ///This object collides with the shapes of other objects, and forces
0131             ///can act on it.
0132             DynamicSimulation = KinematicSimulation | DynamicSimulationFlag
0133         };
0134 
0135         b2World* world() const;
0136         QList<Kolf::Shape*> shapes() const { return m_shapes; }
0137         Kolf::Overlay* overlay(bool createIfNecessary = true);
0138         ///@return items inside this CanvasItem which shall only be shown when
0139         ///the user toggles additional info. Hide these items by default!
0140         virtual QList<QGraphicsItem*> infoItems() const { return QList<QGraphicsItem*>(); }
0141 
0142         ///This is the velocity used by the physics engine: In each time step,
0143         ///the position of this canvas item changes by the value of this property.
0144         QPointF velocity() const;
0145         void setVelocity(const QPointF& velocity);
0146     protected:
0147         void addShape(Kolf::Shape* shape);
0148         ///Configure how this object will participate in physical simulation.
0149         void setSimulationType(CanvasItem::SimulationType type);
0150 
0151         friend class ::KolfGame; //for the following two methods
0152         ///The physics engine calls this method to prepare the object for the following simulation step. Subclass implementations have to call the base implementation just before returning.
0153         virtual void startSimulation();
0154         ///The physics engine calls this method after calculating the next frame, to let the objects update their representation. Subclass implementations have to call the base implementation before anything else.
0155         virtual void endSimulation();
0156 
0157         ///Creates the optimal overlay for this object. The implementation does not have to propagate its properties to the overlay, as the overlay is updated just after it has been created.
0158         ///@warning Do not actually call this function from subclass implementations. Use overlay() instead.
0159         virtual Kolf::Overlay* createOverlay() { return nullptr; } //TODO: make this pure virtual when all CanvasItems are QGraphicsItems and implement createOverlay() (and then disallow createOverlay() == 0)
0160         ///This function should be called whenever the value of an object's property changes. This will most prominently cause the overlay to be updated (if it exists).
0161         void propagateUpdate();
0162     private:
0163         friend class Kolf::Shape; //for access to m_body
0164         b2Body* m_body;
0165 
0166         Kolf::Overlay* m_overlay;
0167         QList<Kolf::Shape*> m_shapes;
0168         CanvasItem::SimulationType m_simulationType;
0169 };
0170 
0171 //WARNING: pos() is at center (not at top-left edge of bounding rect!)
0172 class EllipticalCanvasItem : public Tagaro::SpriteObjectItem, public CanvasItem
0173 {
0174     public:
0175         EllipticalCanvasItem(bool withEllipse, const QString& spriteKey, QGraphicsItem* parent, b2World* world);
0176         QGraphicsEllipseItem* ellipseItem() const { return m_ellipseItem; }
0177 
0178         bool contains(const QPointF& point) const override;
0179         QPainterPath shape() const override;
0180 
0181         QRectF rect() const;
0182         double width() const { return Tagaro::SpriteObjectItem::size().width(); }
0183         double height() const { return Tagaro::SpriteObjectItem::size().height(); }
0184 
0185         void setSize(const QSizeF& size) override;
0186         void setSize(qreal width, qreal height) { setSize(QSizeF(width, height)); }
0187         void moveBy(double x, double y) override;
0188 
0189         void saveSize(KConfigGroup* group);
0190         void loadSize(KConfigGroup* group);
0191 
0192         QPointF getPosition() const override { return QGraphicsItem::pos(); }
0193     private:
0194         QGraphicsEllipseItem* m_ellipseItem;
0195         Kolf::EllipseShape* m_shape;
0196 };
0197 
0198 class ArrowItem : public QGraphicsPathItem
0199 {
0200     public:
0201         explicit ArrowItem(QGraphicsItem* parent);
0202 
0203         qreal angle() const;
0204         void setAngle(qreal angle);
0205         qreal length() const;
0206         void setLength(qreal length);
0207         bool isReversed() const;
0208         void setReversed(bool reversed);
0209 
0210         Vector vector() const;
0211     private:
0212         void updatePath();
0213         qreal m_angle, m_length;
0214         bool m_reversed;
0215 };
0216 
0217 #endif