maxter@41: /**************************************************************************** maxter@41: ** maxter@41: ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). maxter@41: ** Contact: Qt Software Information (qt-info@nokia.com) maxter@41: ** maxter@41: ** This file is part of the demonstration applications of the Qt Toolkit. maxter@41: ** maxter@41: ** $QT_BEGIN_LICENSE:LGPL$ maxter@41: ** Commercial Usage maxter@41: ** Licensees holding valid Qt Commercial licenses may use this file in maxter@41: ** accordance with the Qt Commercial License Agreement provided with the maxter@41: ** Software or, alternatively, in accordance with the terms contained in maxter@41: ** a written agreement between you and Nokia. maxter@41: ** maxter@41: ** GNU Lesser General Public License Usage maxter@41: ** Alternatively, this file may be used under the terms of the GNU Lesser maxter@41: ** General Public License version 2.1 as published by the Free Software maxter@41: ** Foundation and appearing in the file LICENSE.LGPL included in the maxter@41: ** packaging of this file. Please review the following information to maxter@41: ** ensure the GNU Lesser General Public License version 2.1 requirements maxter@41: ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. maxter@41: ** maxter@41: ** In addition, as a special exception, Nokia gives you certain maxter@41: ** additional rights. These rights are described in the Nokia Qt LGPL maxter@41: ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this maxter@41: ** package. maxter@41: ** maxter@41: ** GNU General Public License Usage maxter@41: ** Alternatively, this file may be used under the terms of the GNU maxter@41: ** General Public License version 3.0 as published by the Free Software maxter@41: ** Foundation and appearing in the file LICENSE.GPL included in the maxter@41: ** packaging of this file. Please review the following information to maxter@41: ** ensure the GNU General Public License version 3.0 requirements will be maxter@41: ** met: http://www.gnu.org/copyleft/gpl.html. maxter@41: ** maxter@41: ** If you are unsure which license is appropriate for your use, please maxter@41: ** contact the sales department at qt-sales@nokia.com. maxter@41: ** $QT_END_LICENSE$ maxter@41: ** maxter@41: ****************************************************************************/ mwarning@162: module hoverpoints; maxter@41: maxter@41: version (QT_OPENGL_SUPPORT) maxter@41: import qt.opengl.QGLWidget; maxter@41: maxter@41: version (D_Version2) {} maxter@41: else maxter@41: import tango.core.Array : sort; maxter@41: maxter@41: import maxter@41: qt.gui.QWidget, maxter@344: qtd.Array, maxter@41: arthurwidgets; maxter@41: maxter@41: final class HoverPoints : QObject maxter@41: { maxter@41: public: maxter@41: enum PointShape { maxter@41: CircleShape, maxter@41: RectangleShape maxter@41: } maxter@41: maxter@41: enum LockType { maxter@41: LockToLeft = 0x01, maxter@41: LockToRight = 0x02, maxter@41: LockToTop = 0x04, maxter@41: LockToBottom = 0x08 maxter@41: } maxter@41: maxter@41: enum SortType { maxter@41: NoSort, maxter@41: XSort, maxter@41: YSort maxter@41: } maxter@41: maxter@41: enum ConnectionType { maxter@41: NoConnection, maxter@41: LineConnection, maxter@41: CurveConnection maxter@41: } maxter@41: maxter@41: private: maxter@41: QWidget m_widget; maxter@41: maxter@41: QPolygonF m_points; maxter@41: QRectF m_bounds; maxter@41: PointShape m_shape; maxter@41: SortType m_sortType; maxter@41: ConnectionType m_connectionType; maxter@41: maxter@41: uint[] m_locks; maxter@41: maxter@41: QSizeF m_pointSize; maxter@41: int m_currentIndex; maxter@41: bool m_editable; maxter@41: bool m_enabled; maxter@41: maxter@41: QPen m_pointPen; maxter@41: QBrush m_pointBrush; maxter@41: QPen m_connectionPen; maxter@41: maxter@41: public: maxter@41: mixin Signal!("pointsChanged", QPolygonF /*points*/); maxter@41: maxter@41: this(QWidget widget, PointShape shape) maxter@41: { maxter@41: super(widget); maxter@41: maxter@41: m_widget = widget; maxter@41: widget.installEventFilter(this); maxter@41: maxter@41: m_connectionType = ConnectionType.CurveConnection; maxter@41: m_sortType = SortType.NoSort; maxter@41: m_shape = shape; maxter@41: m_pointPen = new QPen(new QBrush(new QColor(255, 255, 255, 191)), 1); maxter@41: m_connectionPen = new QPen(new QBrush(new QColor(255, 255, 255, 127)), 2); maxter@41: m_pointBrush = new QBrush(new QColor(191, 191, 191, 127)); maxter@41: m_pointSize = QSizeF(11, 11); maxter@41: m_currentIndex = -1; maxter@41: m_editable = true; maxter@41: m_enabled = true; maxter@41: maxter@41: pointsChanged.connect(&m_widget.update); maxter@41: } maxter@41: maxter@41: void setBoundingRect(QRectF boundingRect) { m_bounds = boundingRect; } maxter@41: maxter@41: maxter@41: QRectF pointBoundingRect(int i) maxter@41: { maxter@41: QPointF p = m_points.at(i); maxter@41: qreal w = m_pointSize.width(); maxter@41: qreal h = m_pointSize.height(); maxter@41: qreal x = p.x() - w / 2; maxter@41: qreal y = p.y() - h / 2; maxter@41: return new QRectF(x, y, w, h); maxter@41: } maxter@41: maxter@41: QRectF boundingRect() maxter@41: { maxter@41: if (m_bounds.isEmpty()) maxter@41: return new QRectF(m_widget.rect()); maxter@41: else maxter@41: return m_bounds; maxter@41: } maxter@41: maxter@41: QPolygonF points() { return m_points; } maxter@41: maxter@41: QSizeF pointSize() { return m_pointSize; } maxter@41: void setPointSize(QSizeF size) { m_pointSize = size; } maxter@41: maxter@41: SortType sortType() { return m_sortType; } maxter@41: void setSortType(SortType sortType) { m_sortType = sortType; } maxter@41: maxter@41: ConnectionType connectionType() { return m_connectionType; } maxter@41: void setConnectionType(ConnectionType connectionType) { m_connectionType = connectionType; } maxter@41: maxter@41: void setConnectionPen(QPen pen) { m_connectionPen = pen; } maxter@41: void setShapePen(QPen pen) { m_pointPen = pen; } maxter@41: void setShapeBrush(QBrush brush) { m_pointBrush = brush; } maxter@41: maxter@41: void setPointLock(int pos, LockType lock) { m_locks[pos] = lock; } maxter@41: maxter@41: void setEditable(bool editable) { m_editable = editable; } maxter@41: bool editable() { return m_editable; } maxter@41: maxter@41: void setEnabled(bool enabled) maxter@41: { maxter@41: if (m_enabled != enabled) { maxter@41: m_enabled = enabled; maxter@41: m_widget.update(); maxter@41: } maxter@41: } maxter@41: maxter@41: maxter@41: override bool eventFilter(QObject object, QEvent event) maxter@41: { maxter@41: if ((object == m_widget) && m_enabled) { maxter@41: switch (event.type()) { maxter@41: maxter@41: case QEvent.MouseButtonPress: maxter@41: { maxter@41: QMouseEvent me = cast(QMouseEvent) event; maxter@41: maxter@41: QPointF clickPos = me.pos(); maxter@41: int index = -1; maxter@41: for (int i=0; i clickPos.x()) { maxter@41: pos = i; maxter@41: break; maxter@41: } maxter@41: } else if (m_sortType == SortType.YSort) { maxter@41: for (int i=0; i clickPos.y()) { maxter@41: pos = i; maxter@41: break; maxter@41: } maxter@41: } maxter@41: maxter@41: // TODO: implement QPoligon(F).insert maxter@41: auto tmpPoints = m_points.toList; maxter@41: tmpPoints.insert(pos, clickPos); maxter@41: m_points = new QPolygonF(tmpPoints); maxter@41: maxter@41: m_locks.insert(pos, 0u); maxter@41: m_currentIndex = pos; maxter@41: firePointChange(); maxter@41: } else { maxter@41: m_currentIndex = index; maxter@41: } maxter@41: return true; maxter@41: maxter@41: } else if (me.button() == Qt.RightButton) { maxter@41: if ((index >= 0) && m_editable) { maxter@41: if (m_locks[index] == 0) { maxter@41: m_locks.removeAt(index); maxter@41: m_points.remove(index); maxter@41: } maxter@41: firePointChange(); maxter@41: return true; maxter@41: } maxter@41: } maxter@41: maxter@41: } maxter@41: break; maxter@41: maxter@41: case QEvent.MouseButtonRelease: maxter@41: m_currentIndex = -1; maxter@41: break; maxter@41: maxter@41: case QEvent.MouseMove: maxter@41: if (m_currentIndex >= 0) maxter@41: movePoint(m_currentIndex, QPointF((cast(QMouseEvent)event).pos)); maxter@41: break; maxter@41: maxter@41: case QEvent.Resize: maxter@41: { maxter@41: QResizeEvent e = cast(QResizeEvent) event; maxter@41: if (e.oldSize().width() == 0 || e.oldSize().height() == 0) maxter@41: break; maxter@41: qreal stretch_x = e.size().width() / cast(qreal)e.oldSize.width; maxter@41: qreal stretch_y = e.size().height() / cast(qreal)e.oldSize.height; maxter@41: for (int i=0; i 0) { maxter@41: m_locks.length = m_points.size; maxter@41: maxter@41: m_locks[] = 0; maxter@41: } maxter@41: } maxter@41: maxter@41: void movePoint(int index, QPointF point, bool emitUpdate = true) maxter@41: { maxter@41: m_points.replace(index, bound_point(point, boundingRect(), m_locks[index])); maxter@41: if (emitUpdate) maxter@41: firePointChange(); maxter@41: } maxter@41: maxter@41: void firePointChange() maxter@41: { maxter@41: // printf("HoverPoints.firePointChange(), current=%d\n", m_currentIndex); maxter@41: maxter@41: if (m_sortType != SortType.NoSort) { maxter@41: maxter@41: QPointF oldCurrent; maxter@41: if (m_currentIndex != -1) { maxter@41: oldCurrent = m_points.at(m_currentIndex); maxter@41: } maxter@41: maxter@41: if (m_sortType == SortType.XSort) maxter@41: { maxter@41: auto tmpPoints = m_points.toList; maxter@41: sort(tmpPoints, &x_less_than); maxter@41: m_points = new QPolygonF(tmpPoints); maxter@41: } maxter@41: else if (m_sortType == SortType.YSort) maxter@41: { maxter@41: auto tmpPoints = m_points.toList; maxter@41: sort(tmpPoints, &y_less_than); maxter@41: m_points = new QPolygonF(tmpPoints); maxter@41: } maxter@41: maxter@41: // Compensate for changed order... maxter@41: if (m_currentIndex != -1) { maxter@41: for (int i=0; i right || (lock & HoverPoints.LockType.LockToRight)) p.x = right; maxter@41: maxter@41: if (p.y() < top || (lock & HoverPoints.LockType.LockToTop)) p.y = top; maxter@41: else if (p.y() > bottom || (lock & HoverPoints.LockType.LockToBottom)) p.y = bottom; maxter@41: maxter@41: return p; maxter@41: } maxter@41: maxter@41: private bool x_less_than(QPointF p1, QPointF p2) maxter@41: { maxter@41: return p1.x() < p2.x(); maxter@41: } maxter@41: maxter@41: private bool y_less_than(QPointF p1, QPointF p2) maxter@41: { maxter@41: return p1.y() < p2.y(); maxter@41: }