d5357824d786c411c6a279be85abcf392fdfaa70
[situare] / src / ui / indicatorbuttonpanel.cpp
1 /*
2    Situare - A location system for Facebook
3    Copyright (C) 2010  Ixonos Plc. Authors:
4
5        Pekka Nissinen - pekka.nissinen@ixonos.com
6        Kaj Wallin - kaj.wallin@ixonos.com
7        Katri Kaikkonen - katri.kaikkonen@ixonos.com
8
9    Situare is free software; you can redistribute it and/or
10    modify it under the terms of the GNU General Public License
11    version 2 as published by the Free Software Foundation.
12
13    Situare is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with Situare; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
21    USA.
22 */
23
24 #include <QDebug>
25 #include <QPainter>
26 #include <QSettings>
27
28 #include "common.h"
29 #include "indicatorbutton.h"
30 #include "panelcommon.h"
31
32 #include "indicatorbuttonpanel.h"
33
34 const QString DIRECTION_INDICATOR_BUTTON_POSITION = "DIRECTION_INDICATOR_POSITION";
35
36 IndicatorButtonPanel::IndicatorButtonPanel(QWidget *parent)
37     : QWidget(parent),
38       m_isDraggable(false)
39 {
40     qDebug() << __PRETTY_FUNCTION__;
41
42     const int DIRECTION_INDICATOR_POSITION_X = 10;
43     const int DIRECTION_INDICATOR_POSITION_Y = 290;
44
45     const int INDICATOR_BUTTON_PANEL_SPACING = 5;
46
47     const qreal OPACITY = 0.50;
48     const int MARGIN_LEFT = 0;
49     const int MARGIN_TOP = 3;
50     const int MARGIN_RIGHT = 0;
51     const int MARGIN_BOTTOM = 0;
52     const int LABEL_MARGIN_TOP = 0;
53
54     const int PANEL_WIDTH = 90;
55     const int PANEL_HEIGHT = 100;
56
57     QVBoxLayout *verticalLayout = new QVBoxLayout;
58     setLayout(verticalLayout);
59     verticalLayout->setContentsMargins(MARGIN_LEFT, MARGIN_TOP, MARGIN_RIGHT, MARGIN_BOTTOM);
60     verticalLayout->setSpacing(INDICATOR_BUTTON_PANEL_SPACING);
61
62     m_indicatorButton = new IndicatorButton(this);
63
64     m_distanceTextLabel = new QLabel();
65     m_distanceTextLabel->setFont(QFont(NOKIA_FONT_SMALL));
66     m_distanceTextLabel->setAlignment(Qt::AlignHCenter);
67     m_distanceTextLabel->setContentsMargins(MARGIN_LEFT, LABEL_MARGIN_TOP, MARGIN_RIGHT
68                                             , MARGIN_BOTTOM);
69
70     m_normalColor = new QColor(Qt::black);
71     m_normalColor->setAlpha(OPACITY * 255);
72
73     verticalLayout->addWidget(m_indicatorButton, 0, Qt::AlignHCenter);
74     verticalLayout->addWidget(m_distanceTextLabel, 0, Qt::AlignHCenter);
75     verticalLayout->addStretch();
76
77     setFixedSize(PANEL_WIDTH, PANEL_HEIGHT);
78
79     QSettings settings(DIRECTORY_NAME, FILE_NAME);
80     QPoint savedLocation = settings.value(DIRECTION_INDICATOR_BUTTON_POSITION,
81                                           QPoint(DIRECTION_INDICATOR_POSITION_X,
82                                                  DIRECTION_INDICATOR_POSITION_Y)).toPoint();
83
84     if ((savedLocation.x() > DEFAULT_SCREEN_WIDTH) || (savedLocation.y() > DEFAULT_SCREEN_HEIGHT)) {
85         savedLocation.rx() = DIRECTION_INDICATOR_POSITION_X;
86         savedLocation.ry() = DIRECTION_INDICATOR_POSITION_Y;
87     }
88
89     move(savedLocation);
90
91     m_dragStartTimer = new QTimer(this);
92     m_dragStartTimer->setSingleShot(true);
93     m_dragStartTimer->setInterval(DRAG_INIT_TIME);
94
95     m_forceReleaseTimer = new QTimer(this);
96     m_forceReleaseTimer->setSingleShot(true);
97     m_forceReleaseTimer->setInterval(FORCE_RELEASE_TIME);
98
99     connect(m_dragStartTimer, SIGNAL(timeout()),
100             this, SLOT(timerExpired()));
101
102     connect(m_forceReleaseTimer, SIGNAL(timeout()),
103             this, SLOT(forceMouseRelease()));
104
105     connect(this, SIGNAL(directionIndicatorValuesUpdate(qreal, qreal, bool)),
106             this, SLOT(updateValues(qreal, qreal, bool)));
107
108     connect(m_indicatorButton, SIGNAL(autoCenteringTriggered(bool)),
109             this, SIGNAL(autoCenteringTriggered(bool)));
110 }
111
112 IndicatorButtonPanel::~IndicatorButtonPanel()
113 {
114     qDebug() << __PRETTY_FUNCTION__;
115
116     delete m_normalColor;
117 }
118
119 void IndicatorButtonPanel::forceMouseRelease()
120 {
121     qDebug() << __PRETTY_FUNCTION__;
122
123     releaseMouse();
124     setDraggable(false);
125 }
126
127 void IndicatorButtonPanel::mouseMoveEvent(QMouseEvent *event)
128 {
129     qDebug() << __PRETTY_FUNCTION__;
130
131     if (m_isDraggable) {
132         if (event->buttons() & Qt::LeftButton) {
133             QPoint newLocation = mapToParent(event->pos()) - m_dragPosition;
134
135             if (newLocation.x() < 0)
136                 newLocation.rx() = 0;
137             else if (newLocation.x() > (m_screenSize.width() - width() - PANEL_BAR_WIDTH))
138                 newLocation.rx() =  m_screenSize.width() - width() - PANEL_BAR_WIDTH;
139
140             if (newLocation.y() < 0)
141                 newLocation.ry() = 0;
142             else if (newLocation.y() > (m_screenSize.height() - height()))
143                 newLocation.ry() = m_screenSize.height() - height();
144
145             move(newLocation);
146         }
147     } else {
148         if (!rect().contains(event->pos()))
149             m_dragStartTimer->stop();
150     }
151 }
152
153 void IndicatorButtonPanel::mousePressEvent(QMouseEvent *event)
154 {
155     qDebug() << __PRETTY_FUNCTION__;
156
157     m_dragPosition = event->pos();
158     m_dragStartTimer->start();
159 }
160
161 void IndicatorButtonPanel::mouseReleaseEvent(QMouseEvent *event)
162 {
163     qDebug() << __PRETTY_FUNCTION__;
164
165     m_dragStartTimer->stop();
166
167     Q_UNUSED(event);
168     if (m_isDraggable) {
169         setDraggable(false);
170
171         QSettings settings(DIRECTORY_NAME, FILE_NAME);
172         settings.setValue(DIRECTION_INDICATOR_BUTTON_POSITION, pos());
173     }
174 }
175
176 void IndicatorButtonPanel::paintEvent(QPaintEvent *event)
177 {
178     qDebug() << __PRETTY_FUNCTION__;
179
180     Q_UNUSED(event);
181
182     QPainter painter(this);
183     painter.setRenderHint(QPainter::Antialiasing);
184
185     if (!m_indicatorButton->isChecked()) {
186         const int EXTRA_SPACE_LEFT = -5;
187         const int EXTRA_SPACE_TOP = 0;
188         const int EXTRA_SPACE_RIGHT = +5;
189         const int EXTRA_SPACE_BOTTOM = 0;
190
191         const int RADIUS_WIDTH = 5;
192         const int RADIUS_HEIGHT = 5;
193
194         QPainterPath backgroundPath;
195         QRect distanceLabelRect = m_distanceTextLabel->rect();
196
197         distanceLabelRect.translate(m_distanceTextLabel->pos());
198         distanceLabelRect.adjust(EXTRA_SPACE_LEFT, EXTRA_SPACE_TOP, EXTRA_SPACE_RIGHT
199                                  , EXTRA_SPACE_BOTTOM);
200         backgroundPath.addRoundedRect(distanceLabelRect, RADIUS_WIDTH, RADIUS_HEIGHT);
201         painter.fillPath(backgroundPath, QBrush(*m_normalColor));
202     }
203
204     if (m_isDraggable) {
205         const int ROUNDING_RADIUS = 9;
206
207         QPainterPath backgroundPath;
208         backgroundPath.addRoundedRect(this->rect(), ROUNDING_RADIUS, ROUNDING_RADIUS);
209         painter.fillPath(backgroundPath, QBrush(Qt::Dense4Pattern));
210         painter.setPen(Qt::black);
211     }
212 }
213
214 void IndicatorButtonPanel::screenResized(const QSize &newSize)
215 {
216     qDebug() << __PRETTY_FUNCTION__;
217
218     int oldHeight = 0;
219     int oldWidth = 0;
220
221     if (m_screenSize.height() < 0)
222         oldHeight = DEFAULT_NON_FULLSCREEN_HEIGHT;
223     else
224         oldHeight = m_screenSize.height();
225
226     if (m_screenSize.width() < 0)
227         oldWidth = DEFAULT_SCREEN_WIDTH;
228     else
229         oldWidth = m_screenSize.width();
230
231     m_screenSize = newSize;
232
233     QPoint resizedPosition = pos();
234
235     if (resizedPosition.x() < 0)
236         resizedPosition.rx() = 0;
237     else if (resizedPosition.x() > (newSize.width() - rect().width() - PANEL_BAR_WIDTH))
238         resizedPosition.rx() = newSize.width() - rect().width() - PANEL_BAR_WIDTH;
239
240     if (resizedPosition.y() < 0)
241         resizedPosition.ry() = 0;
242     else if (resizedPosition.y() > (newSize.height() - rect().height()))
243         resizedPosition.ry() = newSize.height() - rect().height();
244
245     if ((pos().y() + rect().center().y()) > (oldHeight / 2))
246         resizedPosition.ry() = newSize.height() - (oldHeight - pos().y());
247
248     if ((pos().x() + rect().center().x()) > (oldWidth / 2))
249         resizedPosition.rx() = newSize.width() - (oldWidth - pos().x());
250
251     move(resizedPosition);
252 }
253
254 void IndicatorButtonPanel::setDraggable(bool mode, QPoint eventPosition)
255 {
256     qDebug() << __PRETTY_FUNCTION__;
257
258     m_isDraggable = mode;
259
260     if (mode) {
261         emit draggingModeTriggered();
262         grabMouse();
263         m_forceReleaseTimer->start();
264         m_dragPosition = eventPosition;
265     } else {
266         releaseMouse();
267         m_forceReleaseTimer->stop();
268         m_indicatorButton->setDown(false);
269     }
270     update();
271 }
272
273 void IndicatorButtonPanel::setIndicatorButtonEnabled(bool enabled)
274 {
275     qDebug() << __PRETTY_FUNCTION__;
276
277     m_indicatorButton->setChecked(enabled);
278     m_distanceTextLabel->setVisible(!enabled);
279
280     update();
281 }
282
283 void IndicatorButtonPanel::timerExpired()
284 {
285     qDebug() << __PRETTY_FUNCTION__;
286
287     setDraggable(true, m_dragPosition);
288 }
289
290 void IndicatorButtonPanel::updateValues(qreal direction, qreal distance, bool draw)
291 {
292     qDebug() << __PRETTY_FUNCTION__;
293
294     const int MAX_TO_METERS = 999.5;
295     const int MAX_TO_KM_WITH_DESIMAL = 99950;
296     const int MIN_TO_METERS = 10;
297     const int M_TO_KM = 1000;                   ///< Meters to kilometers conversion
298
299     QString UNIT_KILOMETER = " km";
300     QString UNIT_METER = " m";
301
302     m_indicatorButton->setDirection(direction, draw);
303
304     m_distance = distance;
305
306     if (m_distance < MIN_TO_METERS) {
307         m_distanceText.setNum(10);
308         m_distanceText.prepend("< ");
309         m_distanceText.append(UNIT_METER);
310     } else if (m_distance < MAX_TO_METERS) {
311         m_distanceText.setNum(m_distance, 'f', 0);
312         m_distanceText.append(UNIT_METER);
313     } else if (m_distance < MAX_TO_KM_WITH_DESIMAL) {
314         m_distanceText.setNum(m_distance / M_TO_KM, 'f', 1);
315         m_distanceText.append(UNIT_KILOMETER);
316     } else {
317         m_distanceText.setNum(m_distance / M_TO_KM, 'f', 0);
318         m_distanceText.append(UNIT_KILOMETER);
319     }
320
321     m_distanceTextLabel->setText(m_distanceText);
322
323     update();
324 }