RetroShare/retroshare-gui/src/gui/common/FlowLayout.h
2014-10-12 20:07:12 +00:00

349 lines
11 KiB
C++

/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
/** WARNING: QT Designer don't accept Custom Layout, maybe on QT5
*You can get widget's children like this:
* FlowLayout *flowLayout = new FlowLayout;
* //First Get Item in Qt Designer
* int count = ui->id->children().count();
* for (int curs = 0; curs < count; ++curs){
* QObject *obj = ui->id->children().at(curs);
* QWidget *wid = qobject_cast<QWidget *>(obj);
* if (wid) flowLayout->addWidget(wid);
* }//for (int curs = 0; curs < count; ++curs)
*/
#ifndef FLOWLAYOUT_H
#define FLOWLAYOUT_H
#include <QKeyEvent>
#include <QLayout>
#include <QPainter>
#include <QRect>
#include <QScrollArea>
#include <QStyle>
#include <QStyleOption>
#include <QWidget>
#include <QWidgetItem>
/// \class FlowLayoutItem
/// \brief The FlowLayoutItem class
///FlowLayoutItem represents FlowLayout item.
///Derivatives from it to make a custom widget
///and to get Drag and Drop better.
class FlowLayoutItem : public QWidget
{
Q_OBJECT
public:
FlowLayoutItem(QString name=QString(), QWidget *parent=0) : QWidget(parent), m_myName(name){
setFocusPolicy(Qt::StrongFocus);
setAcceptDrops(true);
}
~FlowLayoutItem(){}
/// \brief getImage
/// \return Image to represent your widget (not necessary all the widget).
virtual const QPixmap getImage() =0;
/// \brief getDragImage
/// \return Image to represent your widget when dragged (not necessary all the widget).
virtual const QPixmap getDragImage() =0;
/// \brief setName
/// \param value
virtual void setName(QString value) {m_myName=value;}
/// \brief getName
/// \return the name of your widget;
virtual const QString getName() const {return m_myName;}
/// \brief setIsSelected
/// \param value
virtual void setIsSelected(bool value) {m_isSelected=value;}
/// \brief getSelected
/// \return if item is selected
virtual bool isSelected() const {return m_isSelected;}
/// \brief setCurrent
/// \param value
virtual void setIsCurrent(bool value) {m_isCurrent=value;}
/// \brief isCurrent
/// \return if item is the current one
virtual bool isCurrent() const {return m_isCurrent;}
/// \brief paintEvent
///To get Style working on widget and not on all children.
void paintEvent(QPaintEvent *)
{
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}
signals:
/// \brief flowLayoutItemDropped
/// \param listItem: QList with all item dropped.
/// \param bAccept: set it to true to accept drop event.
///Signales when the widget is dropped.
void flowLayoutItemDropped(QList <FlowLayoutItem*> listItem, bool &bAccept);
/// \brief updated
///Signales when the image (getImage) is updated.
void imageUpdated();
protected:
void keyPressEvent(QKeyEvent *event){event->ignore();}
void keyReleaseEvent(QKeyEvent *event){event->ignore();}
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void dragEnterEvent(QDragEnterEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
void dropEvent(QDropEvent *event);
QString m_myName;
bool m_isSelected;
bool m_isCurrent;
private:
void performDrag();
private:
QPoint m_startPos;
};
/// \class FlowLayout
/// \brief The FlowLayout class
///Class FlowLayout arranges child widgets from left to right
///and top to bottom in a top-level widget.
///The items are first laid out horizontally and
///then vertically when each line in the layout runs out of space.
class FlowLayout : public QLayout
{
Q_OBJECT
Q_PROPERTY(int horizontalSpacing READ horizontalSpacing WRITE setHorizontalSpacing)
Q_PROPERTY(int verticalSpacing READ verticalSpacing WRITE setVerticalSpacing)
Q_PROPERTY(Qt::Orientations expandingDirections READ expandingDirections)
Q_PROPERTY(int count READ count)
Q_PROPERTY(QSize minimumSize READ minimumSize)
Q_PROPERTY(QLayoutItem *currentItem READ currentItem)
Q_PROPERTY(int currentIndex READ currentIndex)
public:
FlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1);
FlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1);
~FlowLayout();
///
/// \brief addItem QLayoutItem
/// \param item
///to add a new item. (normally called by addWidget)
void addItem(QLayoutItem *item);
///
/// \brief addItem FlowLayoutItem
/// \param item
///To add a new FlowLayoutItem item.
void addItem(FlowLayoutItem *item);
///
/// \brief horizontalSpacing
/// \return int
///Returns the horizontal spacing of items in the layout.
int horizontalSpacing() const;
///
/// \brief setHorizontalSpacing
/// \param h
///To set the horizontal spacing of items in the layout.
void setHorizontalSpacing(int &h);
///
/// \brief verticalSpacing
/// \return int
///Returns the vertical spacing of items in the layout.
int verticalSpacing() const;
///
/// \brief setVerticalSpacing
/// \param v
///To set the horizontal spacing of items in the layout.
void setVerticalSpacing(int &v);
///
/// \brief expandingDirections
/// \return Qt::Orientations
///Returns the Qt::Orientations in which the layout can make
/// use of more space than its sizeHint().
Qt::Orientations expandingDirections() const;
///
/// \brief hasHeightForWidth
/// \return bool
///Indicates if heightForWidth() is implemented.
bool hasHeightForWidth() const;
///
/// \brief heightForWidth
/// \return int
///To adjust to widgets of which height is dependent on width.
int heightForWidth(int) const;
///
/// \brief count
/// \return int
///Returns items count.
int count() const;
///
/// \brief itemAt
/// \param index
/// \return QLayoutItem*
///Returns item at index position.
QLayoutItem *itemAt(int index) const;
///
/// \brief itemAtGlobal
/// \param p
/// \return QLayoutItem*
///Returns item at position indicate with p. This position is on global screen coordinates.
QLayoutItem *itemAtGlobal(const QPoint &p) const;
///
/// \brief itemAtParent
/// \param p
/// \return QLayoutItem*
///Returns item at position indicate with p. This position is on parent screen coordinates.
QLayoutItem *itemAtParent(const QPoint &p) const;
///
/// \brief indexAtGlobal
/// \param p
/// \return int
///Returns index of item at position indicate with p. This position is on global screen coordinates.
int indexAtGlobal(const QPoint &p) const;
///
/// \brief indexAtParent
/// \param p
/// \return int
///Returns index of item at position indicate with p. This position is on parent screen coordinates.
int indexAtParent(const QPoint &p) const;
///
/// \brief minimumSize
/// \return QSize
///Returns the minimum size of all child items.
QSize minimumSize() const;
///
/// \brief setGeometry
/// \param rect
///Set the geometry of the layout relative to its parent and excluding the window frame.
///It's for redraw item list when it was resized.
void setGeometry(const QRect &rect);
///
/// \brief sizeHint
/// \return QSize
///Returns recommended (minimum) size.
QSize sizeHint() const;
///
/// \brief takeAt
/// \param index
/// \return QLayoutItem*
///Take an item in list (erase it).
QLayoutItem *takeAt(int index);
///
/// \brief selectionList
/// \return QList<QLayoutItem *>
///Returns the list of selected items.
QList<QLayoutItem *> selectionList() const { return m_selectionList;}
///
/// \brief currentItem
/// \return QLayoutItem *
///Returns the current (only one) item.
QLayoutItem *currentItem() const { return m_itemList.value(m_currentIndex);}
///
/// \brief currentIndex
/// \return int
///Returns index of current item.
int currentIndex() const { return m_currentIndex;}
protected:
bool eventFilter(QObject *obj, QEvent *event);
void unsetCurrent();
void setCurrent();
private:
// Redraw all the layout
int doLayout(const QRect &rect, bool testOnly) const;
//To get the default spacing for either the top-level layouts or the sublayouts.
//The default spacing for top-level layouts, when the parent is a QWidget,
//will be determined by querying the style.
//The default spacing for sublayouts, when the parent is a QLayout,
//will be determined by querying the spacing of the parent layout.
int smartSpacing(QStyle::PixelMetric pm) const;
//Execute drag action.
void performDrag();
//Update selection with m_selStartIndex and m_selStopIndex.
//If invert, item selection is toggled.
void addSelection(bool invert);
QList<QLayoutItem *> m_itemList;
QList<QLayoutItem *> m_selectionList;
int m_selStartIndex;
int m_selStopIndex;
int m_currentIndex;
QPoint m_startPos;
int m_hSpace;
int m_vSpace;
};
///
/// \brief The FlowLayoutWidget class
///Class FlowLayoutWidget provide a simple widget with FlowLayout as layout.
///This could be integrate on QtDesigner
class FlowLayoutWidget : public QWidget
{
Q_OBJECT
public:
FlowLayoutWidget(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1);
FlowLayoutWidget(int margin = -1, int hSpacing = -1, int vSpacing = -1);
~FlowLayoutWidget();
protected:
bool eventFilter(QObject *obj, QEvent *event);
private:
void updateParent();
QScrollArea *m_saParent;
QScrollBar *m_sbVertical;
int m_lastYPos;
};
#endif