SVN checkout 11/12/2010
[monav:monav.git] / client / paintwidget.cpp
1 /*
2 Copyright 2010  Christian Vetter veaac.fdirct@gmail.com
3
4 This file is part of MoNav.
5
6 MoNav is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 MoNav is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with MoNav.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "paintwidget.h"
21 #include "ui_paintwidget.h"
22 #include "utils/qthelpers.h"
23 #include "mapdata.h"
24 #include "routinglogic.h"
25
26 #include <QPainter>
27 #include <QMouseEvent>
28 #include <QWheelEvent>
29 #include <QtDebug>
30 #include <algorithm>
31
32 PaintWidget::PaintWidget(QWidget *parent) :
33         QWidget( parent ),
34         m_ui( new Ui::PaintWidget )
35 {
36         m_ui->setupUi( this );
37         if ( MapData::instance()->loaded() ) {
38                 setAttribute( Qt::WA_OpaquePaintEvent, true );
39                 setAttribute( Qt::WA_NoSystemBackground, true );
40         }
41         m_lastMouseX = 0;
42         m_lastMouseY = 0;
43         m_wheelDelta = 0;
44         m_fixed = false;
45         m_mouseDown = false;
46         m_drag = false;
47         m_request.zoom = 0;
48         m_request.center = RoutingLogic::instance()->source().ToProjectedCoordinate();
49
50         dataLoaded();
51         sourceChanged();
52         waypointsChanged();
53         routeChanged();
54
55         connect( MapData::instance(), SIGNAL(dataLoaded()), this, SLOT(dataLoaded()) );
56         connect( RoutingLogic::instance(), SIGNAL(sourceChanged()), this, SLOT(sourceChanged()) );
57         connect( RoutingLogic::instance(), SIGNAL(routeChanged()), this, SLOT(routeChanged()) );
58         connect( RoutingLogic::instance(), SIGNAL(waypointsChanged()), this, SLOT(waypointsChanged()) );
59 }
60
61 PaintWidget::~PaintWidget()
62 {
63         delete m_ui;
64 }
65
66 void PaintWidget::dataLoaded()
67 {
68         IRenderer* renderer = MapData::instance()->renderer();
69         if ( renderer == NULL )
70                 return;
71
72         setAttribute( Qt::WA_OpaquePaintEvent, true );
73         setAttribute( Qt::WA_NoSystemBackground, true );
74         renderer->SetUpdateSlot( this, SLOT(update()) );
75         update();
76 }
77
78 void PaintWidget::setFixed( bool f )
79 {
80         m_fixed = f;
81         update();
82 }
83
84 void PaintWidget::setCenter( const ProjectedCoordinate c )
85 {
86         m_request.center = c;
87         update();
88 }
89
90 void PaintWidget::setZoom( int z )
91 {
92         m_request.zoom = z;
93         update();
94 }
95
96 void PaintWidget::setMaxZoom( int z )
97 {
98         m_maxZoom = z;
99 }
100
101 void PaintWidget::sourceChanged()
102 {
103         m_request.position = RoutingLogic::instance()->source();
104         m_request.heading = RoutingLogic::instance()->gpsInfo().heading;
105         update();
106 }
107
108 void PaintWidget::waypointsChanged()
109 {
110         m_request.target = RoutingLogic::instance()->target();
111         update();
112 }
113
114 void PaintWidget::setPOIs( QVector< UnsignedCoordinate > p )
115 {
116         m_request.POIs = p;
117         update();
118 }
119
120 void PaintWidget::setPOI( UnsignedCoordinate p )
121 {
122         m_request.POIs = QVector< UnsignedCoordinate >( 1, p );
123         update();
124 }
125
126 void PaintWidget::routeChanged()
127 {
128         m_request.route = RoutingLogic::instance()->route();
129         update();
130 }
131
132 void PaintWidget::setEdges( QVector< int > edgeSegments, QVector< UnsignedCoordinate > edges )
133 {
134         m_request.edgeSegments = edgeSegments;
135         m_request.edges = edges;
136         if ( isVisible() )
137                 update();
138 }
139 void PaintWidget::setVirtualZoom( int z )
140 {
141         m_request.virtualZoom = z;
142         if ( isVisible() )
143                 update();
144 }
145
146 void PaintWidget::mousePressEvent( QMouseEvent* event )
147 {
148         event->accept();
149         if ( m_fixed )
150                 return;
151         if ( event->button() != Qt::LeftButton )
152                 return;
153         m_startMouseX = m_lastMouseX = event->x();
154         m_startMouseY = m_lastMouseY = event->y();
155         m_mouseDown = true;
156         m_drag = false;
157 }
158
159 void PaintWidget::mouseMoveEvent( QMouseEvent* event )
160 {
161         event->accept();
162         if ( m_fixed || !m_mouseDown )
163                 return;
164         if ( ( event->buttons() & Qt::LeftButton ) == 0 )
165                 return;
166         int minDiff = 7;
167 #ifdef Q_WS_MAEMO_5
168         minDiff = 15;
169 #endif
170         if ( abs( event->x() - m_startMouseX ) + abs( event->y() - m_startMouseY ) > minDiff )
171                 m_drag = true;
172         if ( !m_drag )
173                 return;
174
175         IRenderer* renderer = MapData::instance()->renderer();
176         if ( renderer == NULL )
177                 return;
178
179         m_request.center = renderer->Move( event->x() - m_lastMouseX, event->y() - m_lastMouseY, m_request );
180         m_lastMouseX = event->x();
181         m_lastMouseY = event->y();
182         update();
183 }
184
185 void PaintWidget::mouseReleaseEvent( QMouseEvent* event )
186 {
187         event->accept();
188         m_mouseDown = false;
189         if ( m_fixed )
190                 return;
191         if ( m_drag )
192                 return;
193         if ( event->button() != Qt::LeftButton )
194                 return;
195
196         IRenderer* renderer = MapData::instance()->renderer();
197         if ( renderer == NULL )
198                 return;
199
200         emit mouseClicked( renderer->PointToCoordinate( event->x() - width() / 2, event->y() - height() / 2, m_request ) );
201 }
202
203 void PaintWidget::wheelEvent( QWheelEvent * event )
204 {
205         IRenderer* renderer = MapData::instance()->renderer();
206         if ( renderer == NULL )
207                 return;
208
209         // 15 degrees is a full mousewheel "click"
210         int numDegrees = event->delta() / 8 + m_wheelDelta;
211         int numSteps = numDegrees / 15;
212         m_wheelDelta = numDegrees % 15;
213
214         // limit zoom
215         int newZoom = m_request.zoom + numSteps;
216         if ( newZoom < 0 )
217                 newZoom = 0;
218         if ( newZoom > m_maxZoom )
219                 newZoom = m_maxZoom;
220
221         // avoid looping event calls
222         if ( newZoom == m_request.zoom )
223                 return;
224
225         // zoom in/out on current mouse position
226         m_request.center = renderer->Move( width() / 2 - event->x(), height() / 2 - event->y(), m_request );
227         m_request.zoom = newZoom;
228         m_request.center = renderer->Move( event->x() - width() / 2, event->y() - height() / 2, m_request );
229
230         emit zoomChanged( newZoom );
231         update();
232         event->accept();
233 }
234
235 void PaintWidget::paintEvent( QPaintEvent* )
236 {
237         if ( !isVisible() )
238                 return;
239
240         IRenderer* renderer = MapData::instance()->renderer();
241         if ( renderer == NULL )
242                 return;
243
244         if ( m_fixed ) {
245                 m_request.center = m_request.position.ToProjectedCoordinate();
246
247                 //gradually change the screen rotation to match the heading
248                 double diff = m_request.rotation + m_request.heading;
249                 while ( diff <= -180 )
250                         diff += 360;
251                 while ( diff >= 180 )
252                         diff -=360;
253                 //to filter out noise stop when close enough
254                 if ( diff > 0 )
255                         diff = std::max( 0.0, diff - 15 );
256                 if ( diff < 0 )
257                         diff = std::min( 0.0, diff + 15 );
258                 m_request.rotation -= diff / 2;
259
260                 //normalize
261                 while ( m_request.rotation < 0 )
262                         m_request.rotation += 360;
263                 while ( m_request.rotation >= 360 )
264                         m_request.rotation -= 360;
265                 int radius = height() * 0.25;
266
267                 m_request.center = renderer->PointToCoordinate( 0, -radius, m_request );
268         } else {
269                 m_request.rotation = 0;
270         }
271
272         QPainter painter( this );
273         Timer time;
274         renderer->Paint( &painter, m_request );
275         qDebug() << "Rendering:" << time.elapsed() << "ms";
276 }
277
278 void PaintWidget::contextMenuEvent(QContextMenuEvent *event )
279 {
280         emit contextMenu( event->globalPos() );
281 }