1 /**********************************************************************************************
2     Copyright (C) 2014 Oliver Eichler <oliver.eichler@gmx.de>
3     Copyright (C) 2017 Norbert Truchsess <norbert.truchsess@t-online.de>
4 
5     This program is free software: you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation, either version 3 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 
18 **********************************************************************************************/
19 
20 #ifndef CCANVAS_H
21 #define CCANVAS_H
22 
23 #include "gis/IGisItem.h"
24 
25 #include <QMap>
26 #include <QPainter>
27 #include <QPointer>
28 #include <QWidget>
29 
30 class IDrawContext;
31 class CMapDraw;
32 class CGrid;
33 class CDemDraw;
34 class CPoiDraw;
35 class QGestureEvent;
36 class CGisDraw;
37 class CRtDraw;
38 class CGisItemWpt;
39 class CGisItemTrk;
40 class CGisItemRte;
41 class CGisItemOvlArea;
42 class CColorLegend;
43 class CMouseAdapter;
44 class QSettings;
45 class QPointF;
46 class IMouse;
47 class QTimer;
48 class QMovie;
49 class QLabel;
50 class QTextBrowser;
51 class IPlot;
52 struct SGisLine;
53 struct poi_t;
54 class CTableTrkInfo;
55 
56 class CCanvas : public QWidget
57 {
58     Q_OBJECT
59 public:
60     CCanvas(QWidget* parent, const QString& name);
61     virtual ~CCanvas();
62 
63     static void setOverrideCursor(const QCursor& cursor, const QString& src);
64     static void restoreOverrideCursor(const QString& src);
65     static void changeOverrideCursor(const QCursor& cursor, const QString& src);
66 
67 
68     void saveConfig(QSettings& cfg);
69     void loadConfig(QSettings& cfg);
70 
71     void setupGrid();
72     void convertGridPos2Str(const QPointF& pos, QString& str, bool simple);
73     void convertRad2Px(QPointF& pos) const;
74     void convertPx2Rad(QPointF& pos) const;
75 
76     void setupBackgroundColor();
77 
78     void setup();
79     QString getProjection();
80     void  setProjection(const QString& proj);
81 
82     enum scales_type_e
83     {
84         eScalesDefault
85         , eScalesSquare
86     };
87 
88     void  setScales(const scales_type_e type);
89     scales_type_e getScalesType();
90 
91     qreal getElevationAt(const QPointF& pos) const;
92     void  getElevationAt(const QPolygonF& pos, QPolygonF& ele) const;
93     void  getElevationAt(SGisLine& line) const;
94 
95     qreal getSlopeAt(const QPointF& pos) const;
96     void getSlopeAt(const QPolygonF& pos, QPolygonF& slope) const;
97 
98     void moveTo(const QPointF& newFocus);
99     void moveMap(const QPointF& delta);
100     void zoomTo(const QRectF& rect);
101     void zoom(int index);
102     void displayInfo(const QPoint& px);
103     ///The POIs can be clustered together, so the icon is not necessarily displayed where the POI is.
104     /// Thus the location where to draw the highlight is separately given
105     void findPoiCloseBy(const QPoint& px, QSet<poi_t>& poiItems, QList<QPointF>& posPoiHighlight) const;
106     ///The POIs can be clustered together, so the icon is not necessarily displayed where the POI is.
107     /// Thus the location where to draw the highlight is separately given
108     void findPoisIn(const QRectF& degRect, QSet<poi_t>& poiItems, QList<QPointF>& posPoiHighlight) const;
109 
110     enum redraw_e
111     {
112         eRedrawNone = 0
113         , eRedrawMap = 0x01
114         , eRedrawDem = 0x02
115         , eRedrawGis = 0x04
116         , eRedrawMouse = 0x08
117         , eRedrawRt = 0x10
118         , eRedrawPoi = 0x20
119         , eRedrawAll = 0xFFFFFFFF
120     };
121 
122     static void triggerCompleteUpdate(CCanvas::redraw_e flags);
123 
124     void abortMouse();
125     void resetMouse();
126     void mouseTrackingLost();
127     void setMouseMoveWpt(CGisItemWpt& wpt);
128     void setMouseRadiusWpt(CGisItemWpt& wpt);
129     void setMouseEditTrk(CGisItemTrk& trk);
130     void setMouseRangeTrk(CGisItemTrk& trk);
131     void setMouseEditTrk(const QPointF& pt);
132     void setMouseEditRte(const QPointF& pt);
133     void setMouseEditRte(CGisItemRte& rte);
134     void setMouseEditArea(CGisItemOvlArea& area);
135     void setMouseEditArea(const QPointF& pt);
136     void setMouseWptBubble(const IGisItem::key_t& key);
137     void setMouseRuler();
138     void setMousePrint();
139     void setMouseSelect();
140 
141     void showProfileAsWindow();
142     void showProfile(bool yes);
143 
144     void buildHelpText();
145 
146     /**
147        @brief Add a message by key to be reported on the canvas
148 
149        Messages from various sources will be collected in a list and displayed in the top left corner
150        of the widget.
151 
152        @note The object reporting has to take care to remove the message by reporting an empty string.
153 
154        @param key   the key to identify the reporting object
155        @param msg   the message to report
156      */
157     void reportStatus(const QString& key, const QString& msg);
158 
159     /**
160        @brief Find a matching street polyline
161 
162        The polyline must be close enough in terms of pixel to point 1 and 2. "Close enough" is defined by
163        the threshold. The returned polyline uses lon/lat as coordinates.
164 
165        @param pt1           first point in [rad]
166        @param pt2           second point in [rad]
167        @param threshold     the "close enough" threshold in [pixel]
168        @param polyline      the resulting polyline, if any, in [rad]
169        @return              Return true if a line has been found.
170      */
171     bool findPolylineCloseBy(const QPointF& pt1, const QPointF& pt2, qint32 threshold, QPolygonF& polyline);
172 
173     void print(QPainter& p, const QRectF& area, const QPointF& focus, bool printScale = true);
174 
175     /**
176        @brief Set a single map file to be shown on the canvas
177 
178        @param filename   the map's file path, can be a resource, too
179      */
180     void setMap(const QString& filename);
181 
182     void followPosition(const QPointF& pos);
183 
184     /// Allows showing the track overlays if they are set in CMainWindow
allowShowTrackOverlays(bool show)185     void allowShowTrackOverlays(bool show)
186     {
187         showTrackOverlays = show;
188     }
189 
190     /// save the size of the track profile if it is in window mode
191     void saveSizeTrackProfile();
192 
193     static qreal gisLayerOpacity;
194 
195     void linkMapViewEnabled();
196 
197 signals:
198     void sigMousePosition(const QPointF& pos, qreal ele, qreal slope);
199     void sigMoveAndZoom(int index, const QPointF& focus);
200     void sigZoom();
201     void sigMove();
202     void sigResize(const QSize& size);
203 
204 public slots:
205     void slotTriggerCompleteUpdate(CCanvas::redraw_e flags);
206     void slotUpdateTrackInfo(bool updateVisuals);
207     void slotCheckTrackOnFocus();
208 
209 protected:
210     bool event(QEvent*) override;
211     bool gestureEvent(QGestureEvent* e);
212     void resizeEvent(QResizeEvent* e) override;
213     void paintEvent(QPaintEvent* e) override;
214     void mousePressEvent(QMouseEvent* e) override;
215     void mouseMoveEvent(QMouseEvent* e) override;
216     void mouseReleaseEvent(QMouseEvent* e) override;
217     void mouseDoubleClickEvent(QMouseEvent* e) override;
218     void wheelEvent(QWheelEvent* e) override;
219     void enterEvent(QEvent* e) override;
220     void leaveEvent(QEvent* e) override;
221     void keyPressEvent(QKeyEvent* e) override;
222 
223 
224 private slots:
225     void slotToolTip();
226 
227 private:
228     void drawStatusMessages(QPainter& p);
229     void drawTrackStatistic(QPainter& p);
230     void drawScale(QPainter& p, QRectF drawRect);
drawScale(QPainter & p)231     void drawScale(QPainter& p)//Default use, drawRect is introduced for correct printing
232     {
233         drawScale(p, rect());
234     }
235     void setZoom(bool in, redraw_e& needsRedraw);
236     void setSizeTrackProfile();
237     /**
238        @brief Resize all registered drwa context objects
239 
240        @param s     the new size
241 
242        @return Return false if one of the draw conext could not be resized
243                because it's thread is running and blocking access to the data
244      */
245     bool setDrawContextSize(const QSize& s);
246 
247     bool isShowMinMaxSummary() const;
248     bool isShowTrackSummary() const;
249     bool isShowTrackInfoTable() const;
250     bool isShowTrackInfoPoints() const;
251     bool isShowTrackProfile() const;
252     bool isShowTrackHighlight() const;
253 
254     bool showTrackOverlays = true;
255 
256     QColor backColor = 0x00FFFFBF;      //< the background color used in case of missing map tiles
257     redraw_e needsRedraw = eRedrawAll;  //< set true to initiate a complete redraw of the screen content
258     CMapDraw* map;                      //< the map object attached to this canvas
259     CDemDraw* dem;                      //< the elevation data layer attached to this canvas
260     CPoiDraw* poi;                      //< the poi database attached to this canvas
261     CGisDraw* gis;                      //< the GIS data layer attached to this canvas
262     CRtDraw* rt;                        //< the real time data layer attached to this canvas
263     CGrid* grid;                        //< the grid attached to this canvas
264 
265     QList<IDrawContext*> allDrawContext;
266 
267     /// the current point of focus (usually the canvas center)
268     QPointF posFocus {0.209439510239, 0.855211333477};
269 
270     /// the mouse handler
271     CMouseAdapter* mouse;
272 
273     /// tool tip timer for vector map tool tips
274     QTimer* timerToolTip;
275     /// the position of the tool tip
276     QPoint posToolTip;
277 
278     /// load indicator for maps
279     QMovie* loadIndicator1;
280     QLabel* mapLoadIndicator;
281 
282     /// load indicator for DEM
283     QMovie* loadIndicator2;
284     QLabel* demLoadIndicator;
285 
286     /// load indicator for POI
287     QMovie* loadIndicator3;
288     QLabel* poiLoadIndicator;
289 
290     QPointer<CColorLegend> colorLegend;
291 
292     /// current accumulated angleDelta, used/required for zooming on trackpads
293     int zoomAngleDelta = 0;
294 
295     /// timer to poll for track gaining/loosing focus
296     QTimer* timerTrackOnFocus;
297     /// the key of the currently focused track
298     IGisItem::key_t keyTrackOnFocus;
299     /// the track profile plot
300     QPointer<IPlot>  plotTrackProfile;
301     /// a label with a track
302     QLabel* labelTrackStatistic;
303 
304     QLabel* labelTrackInfo;
305 
306     QTextBrowser* textStatusMessages;
307     QMap<QString, QString> statusMessages;
308 
309     QMutex mousePressMutex;
310     bool mouseLost = false;
311 
312     QTextBrowser* labelHelp = nullptr;
313 };
314 
315 class CCanvasCursorLock
316 {
317 public:
CCanvasCursorLock(const QCursor & cursor,const QString & src)318     CCanvasCursorLock(const QCursor& cursor, const QString& src)
319         : src(src)
320     {
321         CCanvas::setOverrideCursor(cursor, src);
322     }
323 
~CCanvasCursorLock()324     ~CCanvasCursorLock()
325     {
326         CCanvas::restoreOverrideCursor(src);
327     }
328 
329 private:
330     const QString src;
331 };
332 
333 
334 Q_DECLARE_METATYPE(CCanvas*)
335 
336 #endif //CCANVAS_H
337 
338