/*
    Rosegarden
    A sequencer and musical notation editor.

    This program is Copyright 2000-2008
        Guillaume Laurent   <glaurent@telegraph-road.org>,
        Chris Cannam        <cannam@all-day-breakfast.com>,
        Richard Bown        <bownie@bownie.com>

    The moral right of the authors to claim authorship of this work
    has been asserted.

    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.  See the file
    COPYING included with this distribution for more information.
*/

#ifndef TQCANVASGROUPABLEITEM_H
#define TQCANVASGROUPABLEITEM_H

#include <tqcanvas.h>

class TQCanvasItemGroup;

/**
 * This class is meant to be inherited by TQCanvasItem children to make
 * them groupable.
 *
 * On destruction, the item will remove itself from the group it's
 * attached to.
 *
 * @see QCanvasSpriteGroupable
 * @see TQCanvasLineGroupable
 */
class QCanvasGroupableItem
{
    friend class TQCanvasItemGroup;

public:

    /**
     * Create a groupable item, e.g. put the item in the specified
     * TQCanvasItemGroup. If withRelativeCoords is true, the item's
     * position will be translated so that it's coordinates are
     * relative to those of the item group.
     *
     * @see TQCanvasItemGroup#addItemWithRelativeCoords()
     */
    QCanvasGroupableItem(TQCanvasItem*, TQCanvasItemGroup*,
                         bool withRelativeCoords = false);

    virtual ~QCanvasGroupableItem();

    /// Returns the TQCanvasItemGroup this groupable item belongs to
    TQCanvasItemGroup* group() { return m_group; }

    /// Returns the TQCanvasItemGroup this groupable item belongs to
    const TQCanvasItemGroup* group() const { return m_group; }

    /// Returns the TQCanvasItem which this groupable item wraps
    TQCanvasItem *item() { return m_item; }

    /**
     * Same as moveBy(), except that the move is done relative to the
     * item group's coordinates
     */
    virtual void relativeMoveBy(double dx, double dy);

protected:
    /**
     * Detach item from the item group - called by TQCanvasItemGroup only
     *
     * Set m_group to 0, so that on destruction the item won't try to
     * remove itself from the group
     */
    void detach();
    
private:
    //--------------- Data members ---------------------------------

    TQCanvasItemGroup* m_group;
    TQCanvasItem*      m_item;

};


/**
 * This class implements TQCanvasItem groups
 *
 * An item group will keep its items in a fixed relative position when
 * moved, just like in a drawing program where you can "bind" several
 * items together so that they'll behave as a single item.
 *
 * Proper behavior requires collaboration from the TQCanvasView,
 * though. When about to move an item, the TQCanvasView object should
 * first check if it's not a groupable item, and if so fetch its
 * TQCanvasItemGroup and move it instead.
 */
class TQCanvasItemGroup : public TQCanvasItem
{
public: 
    TQCanvasItemGroup(TQCanvas *);
    virtual ~TQCanvasItemGroup();

    virtual void moveBy(double dx, double dy);
    virtual void advance(int stage);
    virtual bool collidesWith(const TQCanvasItem*) const;
    virtual void draw(TQPainter&);
    virtual void setVisible(bool yes);
    virtual void setSelected(bool yes);
    virtual void setEnabled(bool yes);
    virtual void setActive(bool yes);
    virtual int rtti() const;
    virtual TQRect boundingRect() const;
    virtual TQRect boundingRectAdvanced() const;

    /**
     * Add a new item to this group.
     *
     * The item's coordinates are kept as is.
     *
     * @see addItemWithRelativeCoords()
     */
    virtual void addItem(TQCanvasItem *);

    /**
     * Add a new item to this group.
     *
     * The item's coordinates are considered relative to the group.
     * For example, suppose you have a TQCanvasItemGroup whose coords
     * are 10,10. If you call addItemWithRelativeCoords() with an item
     * whose coords are 5,5, the item is moved so that its coords
     * will be 5,5 relative to the group (e.g. 15,15).
     *
     * @see addItem()
     */
    virtual void addItemWithRelativeCoords(TQCanvasItem *);

    /**
     * Remove the specified item from the group
     */
    virtual void removeItem(TQCanvasItem*);

private:
    virtual bool collidesWith(const TQCanvasSprite*,
                              const TQCanvasPolygonalItem*,
                              const TQCanvasRectangle*,
                              const TQCanvasEllipse*,
                              const TQCanvasText* ) const;

protected:
    //--------------- Data members ---------------------------------

    TQCanvasItemList m_items;
};


/**
 * A TQCanvasLine which can be put in a QCanvasGroup
 */
class TQCanvasLineGroupable : public TQCanvasLine, public QCanvasGroupableItem
{
public: 
    TQCanvasLineGroupable(TQCanvas *c, TQCanvasItemGroup *g);
};

/**
 * A TQCanvasRectangle which can be put in a QCanvasGroup
 */
class TQCanvasRectangleGroupable : public TQCanvasRectangle, public QCanvasGroupableItem
{
public: 
    TQCanvasRectangleGroupable(TQCanvas *c, TQCanvasItemGroup *g);
};

/**
 * A TQCanvasText which can be put in a QCanvasGroup
 */
class TQCanvasTextGroupable : public TQCanvasText, public QCanvasGroupableItem
{
public: 
    TQCanvasTextGroupable(TQCanvas *c, TQCanvasItemGroup *g);
    TQCanvasTextGroupable(const TQString&, TQCanvas *c, TQCanvasItemGroup *g);
};

/**
 * A QCanvasSprite that can be put in a QCanvasGroup
 */
class TQCanvasSpriteGroupable : public TQCanvasSprite, public QCanvasGroupableItem
{
public:
    TQCanvasSpriteGroupable(TQCanvasPixmapArray*,
                           TQCanvas*,
                           TQCanvasItemGroup*);
};

#endif
