Merge branch 'master' into fullscreen_button_hide
authorSami Rämö <sami.ramo@ixonos.com>
Wed, 11 Aug 2010 13:22:17 +0000 (16:22 +0300)
committerSami Rämö <sami.ramo@ixonos.com>
Wed, 11 Aug 2010 13:22:17 +0000 (16:22 +0300)
23 files changed:
doc/testing/functionality-tests.doc
src/coordinates/geocoordinate.cpp
src/coordinates/scenecoordinate.cpp
src/coordinates/scenecoordinate.h
src/engine/engine.cpp
src/engine/engine.h
src/map/baselocationitem.cpp
src/map/frienditemshandler.cpp
src/map/mapcommon.h
src/map/mapengine.cpp
src/map/mapengine.h
src/map/mapscene.cpp
src/map/mapscene.h
src/map/osm.h
src/src.pro
src/ui/indicatorbutton.cpp
src/ui/indicatorbutton.h
src/ui/indicatorbuttonpanel.cpp [new file with mode: 0644]
src/ui/indicatorbuttonpanel.h [new file with mode: 0644]
src/ui/mainwindow.cpp
src/ui/mainwindow.h
src/ui/panelcommon.h
tests/coordinates/scenecoordinate/testscenecoordinate.cpp

index afb4b71..b74b9b7 100644 (file)
Binary files a/doc/testing/functionality-tests.doc and b/doc/testing/functionality-tests.doc differ
index 67e612e..bbac688 100644 (file)
@@ -66,7 +66,7 @@ void GeoCoordinate::convertFrom(const SceneCoordinate &coordinate)
 
     const int MAP_PIXELS_Y = OSM_MAP_MAX_PIXEL_Y + 1;
 
-    double longitude = coordinate.x() / OMS_MAP_PIXELS_X * 360.0 - 180;
+    double longitude = coordinate.x() / OSM_MAP_PIXELS_X * 360.0 - 180;
 
     double n = M_PI - 2.0 * M_PI * coordinate.y() / MAP_PIXELS_Y;
     double latitude = 180.0 / M_PI * atan(0.5 * (exp(n) - exp(-n)));
index fbe4204..9b423cb 100644 (file)
@@ -22,6 +22,7 @@
 #include <cmath>
 
 #include <QDebug>
+#include <QLineF>
 #include <QPointF>
 #include <QVariant>
 
@@ -51,6 +52,32 @@ SceneCoordinate::SceneCoordinate(const GeoCoordinate &coordinate)
     convertFrom(coordinate);
 }
 
+qreal SceneCoordinate::azimuthTo(const SceneCoordinate &to) const
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    // construct a line from this coordinate to target coordinate
+    QLineF line = QLineF(this->toPointF(), to.toPointF());
+
+    // get the angle from the line. Because QLineF::angle() returns positive value for a
+    // counter-clockwise direction, and we want the positive value to be in clockwise direction,
+    // the value is negated
+    qreal angle = -line.angle();
+
+    // QLineF::angle() returns value which has zero at the 3 o'clock position, and we want to have
+    // the zero pointing to the north, so we have to add 90 degrees
+    angle += 90;
+
+    // QLineF::angle() returns values from -180 to 180, an we want only positive values from 0 to
+    // 360 degrees, so full 360 degrees is added if the result would otherwise be negative
+    if (angle < 0)
+        angle += 360;
+
+    Q_ASSERT_X(angle >= 0.0 && angle <= 360, "return value", "value is out of range");
+
+    return angle;
+}
+
 void SceneCoordinate::convertFrom(const GeoCoordinate &coordinate)
 {
     qDebug() << __PRETTY_FUNCTION__;
index 8d823c8..7b92159 100644 (file)
@@ -63,6 +63,16 @@ public:
  ******************************************************************************/
 public:
     /**
+    * @brief Returns the azimuth from this coordinate to other coordinate
+    *
+    * Zero is pointing to north. Returned value is from 0 to 360.
+    *
+    * @param to Target coordinate
+    * @returns Azimuth in degrees
+    */
+    qreal azimuthTo(const SceneCoordinate &to) const;
+
+    /**
     * @brief Check if coordinate is (0.0, 0.0)
     *
     * @returns True if both X and Y are 0.0, otherwise false
index 4c1183f..9906d1a 100644 (file)
@@ -167,6 +167,8 @@ void SituareEngine::disableAutoCentering()
 
 void SituareEngine::draggingModeTriggered()
 {
+    qDebug() << __PRETTY_FUNCTION__;
+
     if (m_mce)
         m_mce->vibrationFeedback();
 }
@@ -696,6 +698,9 @@ void SituareEngine::signalsFromMapEngine()
 
     connect(m_mapEngine, SIGNAL(newMapResolution(qreal)),
             m_ui, SIGNAL(newMapResolution(qreal)));
+
+    connect(m_mapEngine, SIGNAL(directionIndicatorValuesUpdate(qreal, qreal, bool)),
+            m_ui, SIGNAL(directionIndicatorValuesUpdate(qreal, qreal, bool)));
 }
 
 void SituareEngine::signalsFromRoutingService()
index 8a1dd24..e2af9b4 100644 (file)
@@ -303,6 +303,16 @@ signals:
     void clearUpdateLocationDialogData();
 
     /**
+    * @brief Signal when direction and distance from current map center point to current GPS
+    *        location is changed
+    *
+    * @param direction Direction in degrees
+    * @param distance Distance in meters
+    * @param draw Should the indicator triangle be drawn or not
+    */
+    void directionIndicatorValuesUpdate(qreal direction, qreal distance, bool draw);
+
+    /**
     * @brief Signals when new friends data is ready
     *
     * @param friendList List of User instances (friends)
index 8dbc8d5..6ab1866 100644 (file)
@@ -50,9 +50,9 @@ QRect BaseLocationItem::sceneTransformedBoundingRect(int zoomLevel) const
 
     // normalize rect's center point to be inside the map
     if (center.x() < OSM_MAP_MIN_PIXEL_X)
-        rect.translate(OMS_MAP_PIXELS_X, 0);
+        rect.translate(OSM_MAP_PIXELS_X, 0);
     else if (center.x() > OSM_MAP_MAX_PIXEL_X)
-        rect.translate(-OMS_MAP_PIXELS_X, 0);
+        rect.translate(-OSM_MAP_PIXELS_X, 0);
 
     return rect;
 }
index b96a3b3..053987d 100644 (file)
@@ -108,11 +108,11 @@ bool FriendItemsHandler::collides(BaseLocationItem *item1, BaseLocationItem *ite
         return true;
 
     if (item1Rect.left() < (OSM_MAP_MIN_PIXEL_X + item1Rect.width() / 2)) {
-        QRect translated = item1Rect.translated(OMS_MAP_PIXELS_X, 0);
+        QRect translated = item1Rect.translated(OSM_MAP_PIXELS_X, 0);
         if (translated.intersects(item2Rect))
             return true;
     } else if (item1Rect.right() > (OSM_MAP_MAX_PIXEL_X  - item1Rect.width() / 2)) {
-        QRect translated = item1Rect.translated(-OMS_MAP_PIXELS_X, 0);
+        QRect translated = item1Rect.translated(-OSM_MAP_PIXELS_X, 0);
         if (translated.intersects(item2Rect))
             return true;
     }
index b229be3..3eeb869 100644 (file)
@@ -43,13 +43,13 @@ const double MAP_SCENE_VERTICAL_OVERSIZE_FACTOR = 0.5; ///< MapScene vertical ov
 * @var MAP_SCENE_MIN_PIXEL_X
 * @brief First scene horizontal pixel
 */
-const int MAP_SCENE_MIN_PIXEL_X = -OMS_MAP_PIXELS_X * MAP_SCENE_VERTICAL_OVERSIZE_FACTOR;
+const int MAP_SCENE_MIN_PIXEL_X = -OSM_MAP_PIXELS_X * MAP_SCENE_VERTICAL_OVERSIZE_FACTOR;
 
 /**
 * @var MAP_SCENE_MAX_PIXEL_X
 * @brief Last scene horizontal pixel
 */
-const int MAP_SCENE_MAX_PIXEL_X = OMS_MAP_PIXELS_X * (1 + MAP_SCENE_VERTICAL_OVERSIZE_FACTOR) - 1;
+const int MAP_SCENE_MAX_PIXEL_X = OSM_MAP_PIXELS_X * (1 + MAP_SCENE_VERTICAL_OVERSIZE_FACTOR) - 1;
 
 ////////////////////////////////////////////////////////////////////////////////
 // DEFAULT VALUES
@@ -76,7 +76,7 @@ const int MAP_GRID_PADDING = 0;  ///< Grid padding used in tile grid calculation
 
 const QString OSM_LICENSE = QString::fromUtf8("© OpenStreetMap contributors, CC-BY-SA");
 
-const int AUTO_CENTERING_DISABLE_DISTANCE = 100; ///< Distance in pixels
+const int AUTO_CENTERING_DISABLE_DISTANCE = 50; ///< Distance in pixels
 
 //String constants for storing map settings:
 const QString MAP_LAST_ZOOMLEVEL = "LAST_MAP_ZOOM_LEVEL";   ///< Maps last zoom level before logout
index d3935a9..98a9504 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <QtAlgorithms>
 #include <QDebug>
+#include <QGraphicsView>
 #include <QString>
 #include <QStringList>
 #include <QUrl>
@@ -33,6 +34,7 @@
 #include <QRect>
 
 #include "common.h"
+#include "coordinates/geocoordinate.h"
 #include "frienditemshandler.h"
 #include "gpslocationitem.h"
 #include "mapcommon.h"
@@ -179,6 +181,20 @@ QPoint MapEngine::convertSceneCoordinateToTileNumber(int zoomLevel, SceneCoordin
     return QPoint(x, y);
 }
 
+QRectF MapEngine::currentViewSceneRect() const
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    const QPoint ONE_PIXEL = QPoint(1, 1);
+
+    QGraphicsView *view = m_mapScene->views().at(0);
+    QPointF sceneTopLeft = view->mapToScene(0, 0);
+    QPoint viewBottomRight = QPoint(view->size().width(), view->size().height()) - ONE_PIXEL;
+    QPointF sceneBottomRight = view->mapToScene(viewBottomRight);
+
+    return QRectF(sceneTopLeft, sceneBottomRight);
+}
+
 void MapEngine::disableAutoCenteringIfRequired(SceneCoordinate coordinate)
 {
     if (isAutoCenteringEnabled()) {
@@ -202,7 +218,7 @@ void MapEngine::friendsPositionsUpdated()
 {
     qDebug() << __PRETTY_FUNCTION__;
 
-    m_mapScene->spanItems(m_zoomLevel, m_sceneCoordinate, m_viewSize);
+    m_mapScene->spanItems(currentViewSceneRect());
 }
 
 void MapEngine::getTiles(SceneCoordinate coordinate)
@@ -236,13 +252,15 @@ void MapEngine::gpsPositionUpdate(GeoCoordinate position, qreal accuracy)
 {
     qDebug() << __PRETTY_FUNCTION__;
 
+    m_gpsPosition = position;
+
     // update GPS location item (but only if accuracy is a valid number)
     if (!isnan(accuracy)) {
         qreal resolution = MapScene::horizontalResolutionAtLatitude(position.latitude());
         m_gpsLocationItem->updateItem(SceneCoordinate(position).toPointF(), accuracy, resolution);
     }
 
-    m_mapScene->spanItems(m_zoomLevel, m_sceneCoordinate, m_viewSize);
+    m_mapScene->spanItems(currentViewSceneRect());
 
     // do automatic centering (if enabled)
     if (m_autoCenteringEnabled) {
@@ -250,6 +268,8 @@ void MapEngine::gpsPositionUpdate(GeoCoordinate position, qreal accuracy)
         m_scrollStartedByGps = true;
         scrollToPosition(m_lastAutomaticPosition);
     }
+
+    updateDirectionIndicator();
 }
 
 void MapEngine::init()
@@ -347,7 +367,7 @@ void MapEngine::receiveOwnLocation(User *user)
         m_ownLocation->hide();
     }
 
-    m_mapScene->spanItems(m_zoomLevel, m_sceneCoordinate, m_viewSize);
+    m_mapScene->spanItems(currentViewSceneRect());
 }
 
 QGraphicsScene* MapEngine::scene()
@@ -391,6 +411,9 @@ void MapEngine::setAutoCentering(bool enabled)
     qDebug() << __PRETTY_FUNCTION__;
 
     m_autoCenteringEnabled = enabled;
+
+    if (!m_autoCenteringEnabled && m_gpsLocationItem->isVisible())
+        updateDirectionIndicator();
 }
 
 void MapEngine::setCenterPosition(SceneCoordinate coordinate)
@@ -416,8 +439,10 @@ void MapEngine::setCenterPosition(SceneCoordinate coordinate)
         m_mapScene->removeOutOfViewTiles(m_viewTilesGrid, m_zoomLevel);
     }
 
-    m_mapScene->spanItems(m_zoomLevel, m_sceneCoordinate, m_viewSize);
+    m_mapScene->spanItems(currentViewSceneRect());
     emit newMapResolution(viewResolution());
+
+    updateDirectionIndicator();
 }
 
 void MapEngine::setGPSEnabled(bool enabled)
@@ -477,6 +502,23 @@ void MapEngine::setTilesGridSize(const QSize &viewSize)
     m_tilesGridSize.setWidth(gridWidth);
 }
 
+void MapEngine::updateDirectionIndicator()
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    qreal distance = m_gpsPosition.distanceTo(m_sceneCoordinate);
+
+    qreal direction = m_sceneCoordinate.azimuthTo(SceneCoordinate(m_gpsPosition));
+
+    // direction indicator triangle should be drawn only if the gps location item is not currently
+    // visible on the view
+    bool drawDirectionIndicatorTriangle = true;
+    if (currentViewSceneRect().contains(m_gpsLocationItem->pos()))
+        drawDirectionIndicatorTriangle = false;
+
+    emit directionIndicatorValuesUpdate(direction, distance, drawDirectionIndicatorTriangle);
+}
+
 void MapEngine::updateViewTilesSceneRect()
 {
     qDebug() << __PRETTY_FUNCTION__;
@@ -525,6 +567,8 @@ void MapEngine::viewZoomFinished()
 {
     qDebug() << __PRETTY_FUNCTION__;
 
+    updateDirectionIndicator();
+
     if (m_zoomedIn) {
         m_zoomedIn = false;
         m_mapScene->removeOutOfViewTiles(m_viewTilesGrid, m_zoomLevel);
@@ -543,7 +587,7 @@ void MapEngine::zoomed()
     m_mapScene->setZoomLevel(m_zoomLevel);
     getTiles(m_sceneCoordinate);
     m_mapScene->setSceneVerticalOverlap(m_viewSize.height(), m_zoomLevel);
-    m_mapScene->spanItems(m_zoomLevel, m_sceneCoordinate, m_viewSize);
+    m_mapScene->spanItems(currentViewSceneRect());
     emit newMapResolution(viewResolution());
 }
 
index b421974..f05254e 100644 (file)
@@ -189,6 +189,13 @@ private:
     void centerAndZoomTo(QRect rect);
 
     /**
+    * @brief Returns the rect of the current scene area drawn on the view
+    *
+    * @returns Rect of the current scene area drawn on the view
+    */
+    QRectF currentViewSceneRect() const;
+
+    /**
      * @brief Request disabling of auto centering if centered too far from the real location.
      *
      * @param coordinate scene's center coordinate
@@ -227,6 +234,13 @@ private:
     void setTilesGridSize(const QSize &viewSize);
 
     /**
+     * @brief Updates direction and distance values to indicator button
+     *
+     * Calculate and update direction and distance values and send those to indicator button
+     */
+    void updateDirectionIndicator();
+
+    /**
      * @brief Updates the current view rect including margins
      *
      * Calculates tiles rect in scene based on m_viewTilesGrid and
@@ -283,20 +297,20 @@ private slots:
     void mapImageReceived(int zoomLevel, int x, int y, const QPixmap &image);
 
     /**
-    * @brief Called when MapScroller state is changed
-    *
-    * Does check if the smooth scroll effect was interrupted and should the auto centering
-    * feature to be disabled.
-    *
-    * @param newState New state
-    */
+     * @brief Called when MapScroller state is changed
+     *
+     * Does check if the smooth scroll effect was interrupted and should the auto centering
+     * feature to be disabled.
+     *
+     * @param newState New state
+     */
     void scrollerStateChanged(QAbstractAnimation::State newState);
 
     /**
-    * @brief Scroll smoothly to given scene position
-    *
-    * @param coordinate Target position in the scene
-    */
+     * @brief Scroll smoothly to given scene position
+     *
+     * @param coordinate Target position in the scene
+     */
     void scrollToPosition(SceneCoordinate coordinate);
 
     /**
@@ -336,6 +350,16 @@ private slots:
  ******************************************************************************/
 signals:
     /**
+    * @brief Signal when direction and distance from current map center point to current GPS
+    *        location is changed
+    *
+    * @param direction Direction in degrees
+    * @param distance Distance in meters
+    * @param draw Should the indicator triangle be drawn or not
+    */
+    void directionIndicatorValuesUpdate(qreal direction, qreal distance, bool draw);
+
+    /**
     * @brief Signals error
     *
     * @param context error context
@@ -428,6 +452,7 @@ private:
     QSize m_viewSize;               ///< Current view size
 
     FriendItemsHandler *m_friendItemsHandler;   ///< Handler for friend and group items
+    GeoCoordinate m_gpsPosition;                ///< Latest GPS position
     GPSLocationItem *m_gpsLocationItem;         ///< Item pointing current location from GPS
     MapFetcher *m_mapFetcher;                   ///< Fetcher for map tiles
     MapRouteItem *m_mapRouteItem;               ///< Map route item
index 2712dbc..8a130b3 100644 (file)
@@ -168,7 +168,7 @@ void MapScene::removeOutOfViewTiles(QRect tilesGrid, int zoomLevel)
                               - tilesGridWidthHalf
                               + MAP_GRID_PADDING))) {
         QRect oppositeRect = m_tilesSceneRect;
-        oppositeRect.translate(-OMS_MAP_PIXELS_X, 0);
+        oppositeRect.translate(-OSM_MAP_PIXELS_X, 0);
         QList<QGraphicsItem *> oppositeItems = items(oppositeRect, Qt::IntersectsItemBoundingRect);
         foreach (QGraphicsItem *item, oppositeItems)
             allItems.removeOne(item);
@@ -178,7 +178,7 @@ void MapScene::removeOutOfViewTiles(QRect tilesGrid, int zoomLevel)
     // side of the world which are removed from allTiles
     if (tilesGrid.left() < (tilesGridWidthHalf - MAP_GRID_PADDING)) {
         QRect oppositeRect = m_tilesSceneRect;
-        oppositeRect.translate(OMS_MAP_PIXELS_X, 0);
+        oppositeRect.translate(OSM_MAP_PIXELS_X, 0);
         QList<QGraphicsItem *> oppositeItems = items(oppositeRect, Qt::IntersectsItemBoundingRect);
         foreach (QGraphicsItem *item, oppositeItems)
             allItems.removeOne(item);
@@ -266,7 +266,7 @@ void MapScene::setZoomLevel(int zoomLevel)
     m_zoomLevel = zoomLevel;
 }
 
-void MapScene::spanItems(int zoomLevel, SceneCoordinate coordinate, QSize viewSize)
+void MapScene::spanItems(QRectF viewSceneRect)
 {
     qDebug() << __PRETTY_FUNCTION__;
 
@@ -276,23 +276,18 @@ void MapScene::spanItems(int zoomLevel, SceneCoordinate coordinate, QSize viewSi
     leftRect.setBottom(OSM_MAP_MAX_PIXEL_Y);
     QRect rightRect = leftRect;
 
-    // calculate current horizontal area shown on the view
-    int viewSceneWidth = (1 << (OSM_MAX_ZOOM_LEVEL - zoomLevel)) * viewSize.width();
-    int viewSceneLeft = coordinate.x() - viewSceneWidth / 2;
-    int viewSceneRight = coordinate.x() + viewSceneWidth / 2;
-
     // limit rects to include only area which really must be moved
-    leftRect.setRight(-1 - (OMS_MAP_PIXELS_X - 1 - viewSceneRight));
-    rightRect.setLeft(OMS_MAP_PIXELS_X + viewSceneLeft);
+    leftRect.setRight(-1 - (OSM_MAP_PIXELS_X - 1 - viewSceneRect.right()));
+    rightRect.setLeft(OSM_MAP_PIXELS_X + viewSceneRect.left());
 
-    Q_ASSERT_X(leftRect.right() < viewSceneLeft, "spanning rect right value", "move rect is in the view area");
-    Q_ASSERT_X(rightRect.left() > viewSceneRight, "spanning rect left value", "move rect is in the view area");
+    Q_ASSERT_X(leftRect.right() < viewSceneRect.left(), "spanning rect right value", "move rect is in the view area");
+    Q_ASSERT_X(rightRect.left() > viewSceneRect.right(), "spanning rect left value", "move rect is in the view area");
 
     // move all items which intersects the rects
     if (leftRect.left() < leftRect.right())
-        moveIntersectingItemsHorizontally(leftRect, OMS_MAP_PIXELS_X);
+        moveIntersectingItemsHorizontally(leftRect, OSM_MAP_PIXELS_X);
     if (rightRect.left() < rightRect.right())
-        moveIntersectingItemsHorizontally(rightRect, -OMS_MAP_PIXELS_X);
+        moveIntersectingItemsHorizontally(rightRect, -OSM_MAP_PIXELS_X);
 }
 
 void MapScene::tilesSceneRectUpdated(QRect tilesSceneRect)
index 695a0de..7f221da 100644 (file)
@@ -156,11 +156,9 @@ public:
     /**
       * @brief Span items (others than MapTile) to opposite side of the scene
       *
-      * @param zoomLevel Current zoom level
-      * @param coordinate Scene coordinates of the current center point
-      * @param viewSize Current size of the view
+      * @param viewSceneRect Scene area which is currently drawn on the view
       */
-    void spanItems(int zoomLevel, SceneCoordinate coordinate, QSize viewSize);
+    void spanItems(QRectF viewSceneRect);
 
     /**
     * @brief Save new tiles scene rect
index 8dc78ba..a13ef54 100644 (file)
@@ -41,15 +41,15 @@ const double OSM_MAX_LATITUDE = 85.05112877980659237802;
 
 // MAP PIXELS
 /**
-* @var OMS_MAP_PIXELS_X
+* @var OSM_MAP_PIXELS_X
 * @brief Amount of horizontal pixels in map
 */
-const int OMS_MAP_PIXELS_X = OSM_TILES_PER_SIDE * OSM_TILE_SIZE_X;
+const int OSM_MAP_PIXELS_X = OSM_TILES_PER_SIDE * OSM_TILE_SIZE_X;
 
 const int OSM_MAP_MIN_PIXEL_X = 0;                ///< First map horizontal pixel index
 const int OSM_MAP_MIN_PIXEL_Y = 0;                ///< First map vertical pixel index
 
-const int OSM_MAP_MAX_PIXEL_X = OMS_MAP_PIXELS_X - 1; ///< Last map horizontal pixel index
+const int OSM_MAP_MAX_PIXEL_X = OSM_MAP_PIXELS_X - 1; ///< Last map horizontal pixel index
 /**
 * @var OSM_MAP_MAX_PIXEL_Y
 * @brief Last map vertical pixel index
index 18b79dc..16b9a21 100644 (file)
@@ -67,6 +67,7 @@ SOURCES += main.cpp \
     ui/listitemdelegate.cpp \
     ui/friendlistitemdelegate.cpp \
     ui/searchdialog.cpp \
+    ui/indicatorbuttonpanel.cpp\
     routing/geocodingservice.cpp
 HEADERS += application.h \
     common.h \
@@ -135,6 +136,7 @@ HEADERS += application.h \
     ui/friendlistitemdelegate.h \
     ui/listcommon.h \
     ui/searchdialog.h \
+    ui/indicatorbuttonpanel.h\
     error.h \
     routing/geocodingservice.h
 QT += network \
index f6c2aeb..e392bef 100644 (file)
@@ -2,8 +2,9 @@
    Situare - A location system for Facebook
    Copyright (C) 2010  Ixonos Plc. Authors:
 
-       Kaj Wallin - kaj.wallin@ixonos.com
        Katri Kaikkonen - katri.kaikkonen@ixonos.com
+       Kaj Wallin - kaj.wallin@ixonos.com
+       Sami Rämö - sami.ramo@ixonos.com
 
    Situare is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
 #include <QPainter>
 #include <QSettings>
 
-#include "math.h"
-
-#include "indicatorbutton.h"
-
 #include "common.h"
+#include "math.h"
 #include "panelcommon.h"
 
-enum State {OFF, ON};           ///< Enumerator for led state
-
-const int ROUNDING_RADIUS = 9;  ///< Roundness of the rounded edge
-const int BUTTON_WIDTH = 66;    ///< Button width
-const int BUTTON_HEIGHT = 66;   ///< Button height
+#include "indicatorbutton.h"
 
-const qreal OPACITY = 0.50;     ///< Opacity of the background in percents
+enum State {OFF, ON};                       ///< Enumerator for led state
 
 IndicatorButton::IndicatorButton(QWidget *parent)
     : QToolButton(parent),
-      m_isDraggable(false)
+      m_drawTriangle(false),
+      m_direction(0)
 {
-    m_indicatorLeds[OFF].load(":res/images/gps_position.png");
-    m_indicatorLeds[ON].load(":res/images/gps_position_s.png");
-    setFixedSize(BUTTON_WIDTH, BUTTON_HEIGHT);
+    qDebug() << __PRETTY_FUNCTION__;
 
-    QSettings settings(DIRECTORY_NAME, FILE_NAME);
-    QPoint savedLocation = settings.value(DIRECTION_INDICATOR_BUTTON_POSITION,
-                                          QPoint(DIRECTION_INDICATOR_POSITION_X,
-                                                 DIRECTION_INDICATOR_POSITION_Y)).toPoint();
+    const qreal OPACITY = 0.50;
+    const int BUTTON_WIDTH = 66;
+    const int BUTTON_HEIGHT = 66;
 
-    if(savedLocation.x() > DEFAULT_SCREEN_WIDTH || savedLocation.y() > DEFAULT_SCREEN_HEIGHT) {
-        savedLocation.rx() = DIRECTION_INDICATOR_POSITION_X;
-        savedLocation.ry() = DIRECTION_INDICATOR_POSITION_Y;
-    }
+    m_indicatorLeds[OFF].load(":res/images/gps_position.png");
+    m_indicatorLeds[ON].load(":res/images/gps_position_s.png");
 
-    move(savedLocation);
+    setFixedSize(BUTTON_WIDTH, BUTTON_HEIGHT);
 
     // Normal background
     m_normalColor = new QColor(Qt::black);
     m_normalColor->setAlpha(floor(OPACITY * 255));
 
-    // Selected bakcground
+    // Selected background
     m_selectedGradient = new QLinearGradient(0, 0, 0, this->height());
     m_selectedGradient->setColorAt(0.02, QColor(0, 113, 181));
     m_selectedGradient->setColorAt(0.25, QColor(24, 142, 214));
@@ -71,26 +61,9 @@ IndicatorButton::IndicatorButton(QWidget *parent)
     m_selectedGradient->setColorAt(0.75, QColor(82, 195, 255));
     m_selectedGradient->setColorAt(0.98, QColor(115, 215, 255));
 
-    m_dragStartTimer = new QTimer(this);
-    m_dragStartTimer->setSingleShot(true);
-    m_dragStartTimer->setInterval(DRAG_INIT_TIME);
-
-    m_forceReleaseTimer = new QTimer(this);
-    m_forceReleaseTimer->setSingleShot(true);
-    m_forceReleaseTimer->setInterval(FORCE_RELEASE_TIME);
-
-    connect(this, SIGNAL(pressed()),
-            m_dragStartTimer, SLOT(start()));
-    connect(this, SIGNAL(released()),
-            m_dragStartTimer, SLOT(stop()));
     connect(this, SIGNAL(clicked(bool)),
             this, SIGNAL(autoCenteringTriggered(bool)));
 
-    connect(m_dragStartTimer, SIGNAL(timeout()),
-            this, SLOT(timerExpired()));
-    connect(m_forceReleaseTimer, SIGNAL(timeout()),
-            this, SLOT(forceMouseRelease()));
-
     setCheckable(true);
 }
 
@@ -102,171 +75,113 @@ IndicatorButton::~IndicatorButton()
     delete m_selectedGradient;
 }
 
-void IndicatorButton::mousePressEvent(QMouseEvent *event)
+const QPoint& IndicatorButton::eventPosition()
 {
     qDebug() << __PRETTY_FUNCTION__;
 
-    if (event->button() == Qt::LeftButton)
-        m_dragPosition = event->pos();
-
-    m_eventPosition = mapToParent(event->pos());
-    m_dragStartTimer->start();
-    setDown(true);
+    return m_eventPosition;
 }
 
 void IndicatorButton::mouseMoveEvent(QMouseEvent *event)
 {
     qDebug() << __PRETTY_FUNCTION__;
 
-    if(m_isDraggable) {
-        if (event->buttons() & Qt::LeftButton) {
-            QPoint newLocation = mapToParent(event->pos()) - m_dragPosition;
+    QToolButton::mouseMoveEvent(event);
 
-            if (newLocation.x() < SIDEBAR_WIDTH)
-                newLocation.rx() = SIDEBAR_WIDTH;
-             else if (newLocation.x() > m_screenSize.width() - width() - SIDEBAR_WIDTH)
-                newLocation.rx() =  m_screenSize.width() - width() - SIDEBAR_WIDTH;
-
-            if (newLocation.y() < 0)
-                newLocation.ry() = 0;
-            else if (newLocation.y() > m_screenSize.height() - height())
-                newLocation.ry() = m_screenSize.height() - height();
-
-            move(newLocation);
-        }
-    } else {
-        if(!rect().contains(event->pos())) {
-            m_dragStartTimer->stop();
-            setDown(false);
-        }
-    }
+    event->ignore();
 }
 
-void IndicatorButton::mouseReleaseEvent(QMouseEvent *event)
+void IndicatorButton::mousePressEvent(QMouseEvent *event)
 {
     qDebug() << __PRETTY_FUNCTION__;
 
-    m_dragStartTimer->stop();
+    QToolButton::mousePressEvent(event);
 
-    if(m_isDraggable) {
-        setDraggable(false);
-        QSettings settings(DIRECTORY_NAME, FILE_NAME);
-        settings.setValue(DIRECTION_INDICATOR_BUTTON_POSITION, pos());
-    } else {
-        if(this->rect().contains(event->pos())) {
-            if(isChecked()) {
-                setChecked(false);
-                emit autoCenteringTriggered(false);
-            } else {
-                setChecked(true);
-                emit autoCenteringTriggered(true);
-            }
-        }
-    }
-    setDown(false);
+    event->ignore();
 }
 
-void IndicatorButton::setDraggable(bool mode, QPoint eventPosition)
+void IndicatorButton::mouseReleaseEvent(QMouseEvent *event)
 {
     qDebug() << __PRETTY_FUNCTION__;
 
-    m_isDraggable = mode;
+    QToolButton::mouseReleaseEvent(event);
 
-    if(mode) {
-        emit draggingModeTriggered();
-        m_forceReleaseTimer->start();
-        m_dragPosition = eventPosition;
-    } else {
-        m_forceReleaseTimer->stop();
-    }
-    update();
+    event->ignore();
 }
 
-void IndicatorButton::screenResized(const QSize &newSize)
+void IndicatorButton::paintEvent(QPaintEvent *event)
 {
     qDebug() << __PRETTY_FUNCTION__;
 
-    int oldHeight = 0;
-    int oldWidth = 0;
-
-    if(m_screenSize.height() < 0)
-        oldHeight = DEFAULT_NON_FULLSCREEN_HEIGHT;
-    else
-        oldHeight = m_screenSize.height();
-
-    if(m_screenSize.width() < 0)
-        oldWidth = DEFAULT_SCREEN_WIDTH;
-    else
-        oldWidth = m_screenSize.width();
+    const int ROUNDING_RADIUS = 9;
 
-    m_screenSize = newSize;
+    Q_UNUSED(event);
 
-    QPoint resizedPosition = pos();
-    if(resizedPosition.x() > (newSize.width() - rect().width()))
-        resizedPosition.rx() = newSize.width() - rect().width();
-    else if (resizedPosition.x() < SIDEBAR_WIDTH)
-        resizedPosition.rx() = SIDEBAR_WIDTH;
-    if(resizedPosition.y() > (newSize.height() - rect().height()))
-        resizedPosition.ry() = newSize.height() - rect().height();
-    else if (resizedPosition.y() < 0)
-        resizedPosition.ry() = 0;
+    QPainterPath backgroundPath;
+    backgroundPath.addRoundedRect(this->rect(), ROUNDING_RADIUS, ROUNDING_RADIUS);
 
-    if((pos().y() + rect().center().y()) > (oldHeight/2))
-        resizedPosition.ry() = newSize.height() - (oldHeight - pos().y());
+    QPainter painter(this);
+    painter.setRenderHint(QPainter::Antialiasing);
 
-    if((pos().x() + rect().center().x()) > (oldWidth/2))
-        resizedPosition.rx() = newSize.width() - (oldWidth - pos().x());
+    if (isDown())
+        painter.fillPath(backgroundPath, QBrush(*m_selectedGradient));
+    else
+        painter.fillPath(backgroundPath, QBrush(*m_normalColor));
 
-    move(resizedPosition);
-}
+    const QPointF CENTER = QPointF(this->width(), this->height()) / 2;
 
-const QPoint& IndicatorButton::eventPosition()
-{
-    qDebug() << __PRETTY_FUNCTION__;
+    if (isChecked()) {
+        const QPointF offset = QPointF(m_indicatorLeds[ON].width(),
+                                       m_indicatorLeds[ON].height()) / 2;
 
-    return m_eventPosition;
-}
+        painter.drawPixmap(CENTER - offset, m_indicatorLeds[ON]);
+    } else {
+        const QPointF offset = QPointF(m_indicatorLeds[OFF].width(),
+                                       m_indicatorLeds[OFF].height()) / 2;
 
-void IndicatorButton::forceMouseRelease()
-{
-    qDebug() << __PRETTY_FUNCTION__;
+        painter.drawPixmap(CENTER - offset, m_indicatorLeds[OFF]);
+    }
 
-    releaseMouse();
-    setDraggable(false);
-}
+    // draw the direction indicator triangle only when autocentering is disabled and MapEngine
+    // doesn't deny drawing (because GPS location item is visible)
+    if (!isChecked() && m_drawTriangle) {
+        const int TRIANGLE_WIDTH = 10;
+        const int TRIANGLE_HEIGHT = 10;
+        const int TRIANGLE_DISTANCE_FROM_CENTER = 15;
 
-void IndicatorButton::paintEvent(QPaintEvent *event)
-{
-    qDebug() << __PRETTY_FUNCTION__;
+        const int POINTS = 3;
+        const QPointF points[POINTS] = {
+            QPointF(-TRIANGLE_WIDTH / 2, -TRIANGLE_DISTANCE_FROM_CENTER),
+            QPointF(0, -(TRIANGLE_DISTANCE_FROM_CENTER + TRIANGLE_HEIGHT)),
+            QPointF(TRIANGLE_WIDTH / 2, -TRIANGLE_DISTANCE_FROM_CENTER)
+        };
 
-    Q_UNUSED(event);
+        // base triangle is facing up, and needs to be rotated to the required direction
+        QTransform rotationTransform;
+        rotationTransform.rotate(m_direction);
 
-    QPainterPath backgroundPath;
-    backgroundPath.addRoundedRect(this->rect(), ROUNDING_RADIUS, ROUNDING_RADIUS);
+        // origin is in the top left corner of the button, and needs to be translated to the
+        // center of the button
+        QTransform translateTransform;
+        translateTransform.translate(CENTER.x(), CENTER.y());
 
-    QPainter painter(this);
-    painter.setRenderHint(QPainter::Antialiasing);
+        painter.setTransform(rotationTransform * translateTransform);
 
-    if(m_isDraggable)
-        painter.fillPath(backgroundPath, QBrush(Qt::Dense4Pattern));
-    else if (isDown())
-        painter.fillPath(backgroundPath, QBrush(*m_selectedGradient));
-    else
-        painter.fillPath(backgroundPath, QBrush(*m_normalColor));
+        // setting the look of the triangle
+        painter.setBrush(Qt::red);
+        painter.setPen(Qt::red);
 
-    if(isChecked())
-        painter.drawPixmap((this->width() / 2) - (m_indicatorLeds[ON].width() / 2),
-                           (this->height() / 2) - (m_indicatorLeds[ON].height() / 2),
-                           m_indicatorLeds[ON]);
-    else
-        painter.drawPixmap((this->width() / 2) - (m_indicatorLeds[OFF].width() / 2),
-                           (this->height() / 2) - (m_indicatorLeds[OFF].height() / 2),
-                           m_indicatorLeds[OFF]);
+        painter.drawPolygon(points, POINTS);
+    }
 }
 
-void IndicatorButton::timerExpired()
+void IndicatorButton::setDirection(qreal direction, bool draw)
 {
     qDebug() << __PRETTY_FUNCTION__;
 
-    setDraggable(true, m_dragPosition);
+    m_direction = direction;
+    m_drawTriangle = draw;
+
+    update();
 }
+
index 4dc31f7..0380cce 100644 (file)
@@ -2,8 +2,9 @@
     Situare - A location system for Facebook
     Copyright (C) 2010  Ixonos Plc. Authors:
 
-        Kaj Wallin - kaj.wallin@ixonos.com
         Katri Kaikkonen - katri.kaikkonen@ixonos.com
+        Kaj Wallin - kaj.wallin@ixonos.com
+        Sami Rämö - sami.ramo@ixonos.com
 
     Situare is free software; you can redistribute it and/or
     modify it under the terms of the GNU General Public License
@@ -32,8 +33,7 @@
  * @brief Indicator button class
  *
  * @author Katri Kaikkonen - katri.kaikkonen (at) ixonos.com
- *
- * @class IndicatorButton indicatorbutton.h "ui/indicatorbutton.h"
+ * @author Sami Rämö - sami.ramo (at) ixonos.com
  */
 class IndicatorButton : public  QToolButton
 {
@@ -57,14 +57,14 @@ public:
  ******************************************************************************/
 protected:
     /**
-     * @brief Move event for the distance indicator button
+     * @brief Event handler for mouse move events
      *
      * @param event Mouse event
      */
     void mouseMoveEvent(QMouseEvent *event);
 
     /**
-     * @brief Press event for the distance indicator button
+     * @brief Event handler for mouse press events
      *
      * @param event Mouse event
      */
@@ -95,27 +95,13 @@ public slots:
     const QPoint& eventPosition();
 
     /**
-     * @brief Slot to redraw the panel after window resize event
+     * @brief Sets direction information for the distance indicator button
      *
-     * @param size Size of the new screen
-     */
-    void screenResized(const QSize &size);
-
-    /**
-     * @brief Toggle distance indicator button draggability
-     */
-    void setDraggable(bool mode, QPoint eventPosition = QPoint(0,0));
-
-private slots:
-    /**
-     * @brief Safeguard slot to release mouse grab if something goes horribly wrong
-     */
-    void forceMouseRelease();
-
-    /**
-     * @brief Slot that handles drag initialization once timer has timed out
+     * Paints the button and its icon
+     * @param Direction to the GPS position (in degrees)
+     * @param Draw direction triangle
      */
-    void timerExpired();
+    void setDirection(qreal direction, bool draw);
 
 /*******************************************************************************
  * SIGNALS
@@ -128,16 +114,13 @@ signals:
      */
     void autoCenteringTriggered(bool enabled);
 
-    /**
-    * @brief Dragging mode triggered.
-    */
-    void draggingModeTriggered();
-
 /*******************************************************************************
  * DATA MEMBERS
  ******************************************************************************/
 private:
-    bool m_isDraggable;             ///< Boolean for tracking the draggability state
+    bool m_drawTriangle;                    ///< Should the direction triange be drawn
+
+    qreal m_direction;                      ///< Direction to the GPS position (in degrees)
 
     QColor *m_normalColor;                  ///< Normal background color
 
@@ -145,13 +128,8 @@ private:
 
     QPixmap m_indicatorLeds[2];             ///< Placeholder for images
 
-    QPoint m_dragPosition;          ///< Location from where the widget is grabbed
-    QPoint m_eventPosition;         ///< Position of mousePressEvent
-
-    QSize m_screenSize;             ///< Store for the screen size
-
-    QTimer *m_dragStartTimer;       ///< Timer to init draggability of the distance indicator button
-    QTimer *m_forceReleaseTimer;    ///< Timer to run forceMouseRelease
+    QPoint m_dragPosition;                  ///< Location from where the widget is grabbed
+    QPoint m_eventPosition;                 ///< Position of mousePressEvent
 };
 
 #endif // INDICATORBUTTON_H
diff --git a/src/ui/indicatorbuttonpanel.cpp b/src/ui/indicatorbuttonpanel.cpp
new file mode 100644 (file)
index 0000000..a34369e
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+   Situare - A location system for Facebook
+   Copyright (C) 2010  Ixonos Plc. Authors:
+
+       Pekka Nissinen - pekka.nissinen@ixonos.com
+       Kaj Wallin - kaj.wallin@ixonos.com
+       Katri Kaikkonen - katri.kaikkonen@ixonos.com
+
+   Situare is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License
+   version 2 as published by the Free Software Foundation.
+
+   Situare is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with Situare; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+   USA.
+*/
+
+#include <QDebug>
+#include <QPainter>
+#include <QSettings>
+
+#include "common.h"
+#include "indicatorbutton.h"
+#include "panelcommon.h"
+
+#include "indicatorbuttonpanel.h"
+
+const QString DIRECTION_INDICATOR_BUTTON_POSITION = "DIRECTION_INDICATOR_POSITION";
+
+IndicatorButtonPanel::IndicatorButtonPanel(QWidget *parent)
+    : QWidget(parent),
+      m_isDraggable(false)
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    const int DIRECTION_INDICATOR_POSITION_X = 10 + PANEL_PEEK_AMOUNT;
+    const int DIRECTION_INDICATOR_POSITION_Y = 290;
+
+    const int INDICATOR_BUTTON_PANEL_SPACING = 5;
+
+    const qreal OPACITY = 0.50;
+    const int MARGIN_LEFT = 0;
+    const int MARGIN_TOP = 3;
+    const int MARGIN_RIGHT = 0;
+    const int MARGIN_BOTTOM = 0;
+    const int LABEL_MARGIN_TOP = 0;
+
+    const int PANEL_WIDTH = 90;
+    const int PANEL_HEIGHT = 100;
+
+    QVBoxLayout *verticalLayout = new QVBoxLayout;
+    setLayout(verticalLayout);
+    verticalLayout->setContentsMargins(MARGIN_LEFT, MARGIN_TOP, MARGIN_RIGHT, MARGIN_BOTTOM);
+    verticalLayout->setSpacing(INDICATOR_BUTTON_PANEL_SPACING);
+
+    m_indicatorButton = new IndicatorButton(this);
+
+    m_distanceTextLabel = new QLabel();
+    m_distanceTextLabel->setFont(QFont(NOKIA_FONT_SMALL));
+    m_distanceTextLabel->setAlignment(Qt::AlignHCenter);
+    m_distanceTextLabel->setContentsMargins(MARGIN_LEFT, LABEL_MARGIN_TOP, MARGIN_RIGHT
+                                            , MARGIN_BOTTOM);
+
+    m_normalColor = new QColor(Qt::black);
+    m_normalColor->setAlpha(OPACITY * 255);
+
+    verticalLayout->addWidget(m_indicatorButton, 0, Qt::AlignHCenter);
+    verticalLayout->addWidget(m_distanceTextLabel, 0, Qt::AlignHCenter);
+    verticalLayout->addStretch();
+
+    setFixedSize(PANEL_WIDTH, PANEL_HEIGHT);
+
+    QSettings settings(DIRECTORY_NAME, FILE_NAME);
+    QPoint savedLocation = settings.value(DIRECTION_INDICATOR_BUTTON_POSITION,
+                                          QPoint(DIRECTION_INDICATOR_POSITION_X,
+                                                 DIRECTION_INDICATOR_POSITION_Y)).toPoint();
+
+    if((savedLocation.x() > DEFAULT_SCREEN_WIDTH) || (savedLocation.y() > DEFAULT_SCREEN_HEIGHT)) {
+        savedLocation.rx() = DIRECTION_INDICATOR_POSITION_X;
+        savedLocation.ry() = DIRECTION_INDICATOR_POSITION_Y;
+    }
+
+    move(savedLocation);
+
+    m_dragStartTimer = new QTimer(this);
+    m_dragStartTimer->setSingleShot(true);
+    m_dragStartTimer->setInterval(DRAG_INIT_TIME);
+
+    m_forceReleaseTimer = new QTimer(this);
+    m_forceReleaseTimer->setSingleShot(true);
+    m_forceReleaseTimer->setInterval(FORCE_RELEASE_TIME);
+
+    connect(m_dragStartTimer, SIGNAL(timeout()),
+            this, SLOT(timerExpired()));
+
+    connect(m_forceReleaseTimer, SIGNAL(timeout()),
+            this, SLOT(forceMouseRelease()));
+
+    connect(this, SIGNAL(directionIndicatorValuesUpdate(qreal, qreal, bool)),
+            this, SLOT(updateValues(qreal, qreal, bool)));
+
+    connect(m_indicatorButton, SIGNAL(autoCenteringTriggered(bool)),
+            this, SIGNAL(autoCenteringTriggered(bool)));
+}
+
+void IndicatorButtonPanel::forceMouseRelease()
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    releaseMouse();
+    setDraggable(false);
+}
+
+void IndicatorButtonPanel::mouseMoveEvent(QMouseEvent *event)
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    if(m_isDraggable) {
+        if (event->buttons() & Qt::LeftButton) {
+            QPoint newLocation = mapToParent(event->pos()) - m_dragPosition;
+
+            if (newLocation.x() < SIDEBAR_WIDTH)
+                newLocation.rx() = SIDEBAR_WIDTH;
+            else if (newLocation.x() > m_screenSize.width() - width() - SIDEBAR_WIDTH)
+                newLocation.rx() =  m_screenSize.width() - width() - SIDEBAR_WIDTH;
+
+            if (newLocation.y() < 0)
+                newLocation.ry() = 0;
+            else if (newLocation.y() > m_screenSize.height() - height())
+                newLocation.ry() = m_screenSize.height() - height();
+
+            move(newLocation);
+        }
+    } else {
+        if(!rect().contains(event->pos()))
+            m_dragStartTimer->stop();
+    }
+}
+
+void IndicatorButtonPanel::mousePressEvent(QMouseEvent *event)
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    m_dragPosition = event->pos();
+    m_dragStartTimer->start();
+}
+
+void IndicatorButtonPanel::mouseReleaseEvent(QMouseEvent *event)
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    m_dragStartTimer->stop();
+
+    Q_UNUSED(event);
+    if(m_isDraggable) {
+        setDraggable(false);
+
+        QSettings settings(DIRECTORY_NAME, FILE_NAME);
+        settings.setValue(DIRECTION_INDICATOR_BUTTON_POSITION, pos());
+    }
+}
+
+void IndicatorButtonPanel::paintEvent(QPaintEvent *event)
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    Q_UNUSED(event);
+
+    QPainter painter(this);
+    painter.setRenderHint(QPainter::Antialiasing);
+
+    if (!m_indicatorButton->isChecked()) {
+        const int EXTRA_SPACE_LEFT = -5;
+        const int EXTRA_SPACE_TOP = 0;
+        const int EXTRA_SPACE_RIGHT = +5;
+        const int EXTRA_SPACE_BOTTOM = 0;
+
+        const int RADIUS_WIDTH = 5;
+        const int RADIUS_HEIGHT = 5;
+
+        QPainterPath backgroundPath;
+        QRect distanceLabelRect = m_distanceTextLabel->rect();
+
+        distanceLabelRect.translate(m_distanceTextLabel->pos());
+        distanceLabelRect.adjust(EXTRA_SPACE_LEFT, EXTRA_SPACE_TOP, EXTRA_SPACE_RIGHT
+                                 , EXTRA_SPACE_BOTTOM);
+        backgroundPath.addRoundedRect(distanceLabelRect, RADIUS_WIDTH, RADIUS_HEIGHT);
+        painter.fillPath(backgroundPath, QBrush(*m_normalColor));
+
+        update();
+    }
+
+    if(m_isDraggable) {
+        const int ROUNDING_RADIUS = 9;
+
+        QPainterPath backgroundPath;
+        backgroundPath.addRoundedRect(this->rect(), ROUNDING_RADIUS, ROUNDING_RADIUS);
+        painter.fillPath(backgroundPath, QBrush(Qt::Dense4Pattern));
+        painter.setPen(Qt::black);
+    }
+}
+
+void IndicatorButtonPanel::screenResized(const QSize &newSize)
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    int oldHeight = 0;
+    int oldWidth = 0;
+
+    if(m_screenSize.height() < 0)
+        oldHeight = DEFAULT_NON_FULLSCREEN_HEIGHT;
+    else
+        oldHeight = m_screenSize.height();
+
+    if(m_screenSize.width() < 0)
+        oldWidth = DEFAULT_SCREEN_WIDTH;
+    else
+        oldWidth = m_screenSize.width();
+
+    m_screenSize = newSize;
+
+    QPoint resizedPosition = pos();
+    if(resizedPosition.x() > (newSize.width() - rect().width()))
+        resizedPosition.rx() = newSize.width() - rect().width();
+    else if (resizedPosition.x() < SIDEBAR_WIDTH)
+        resizedPosition.rx() = SIDEBAR_WIDTH;
+    if(resizedPosition.y() > (newSize.height() - rect().height()))
+        resizedPosition.ry() = newSize.height() - rect().height();
+    else if (resizedPosition.y() < 0)
+        resizedPosition.ry() = 0;
+
+    if((pos().y() + rect().center().y()) > (oldHeight/2))
+        resizedPosition.ry() = newSize.height() - (oldHeight - pos().y());
+
+    if((pos().x() + rect().center().x()) > (oldWidth/2))
+        resizedPosition.rx() = newSize.width() - (oldWidth - pos().x());
+
+    move(resizedPosition);
+}
+
+void IndicatorButtonPanel::setDraggable(bool mode, QPoint eventPosition)
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    m_isDraggable = mode;
+
+    if(mode) {
+        emit draggingModeTriggered();
+        grabMouse();
+        m_forceReleaseTimer->start();
+        m_dragPosition = eventPosition;
+    } else {
+        releaseMouse();
+        m_forceReleaseTimer->stop();
+        m_indicatorButton->setDown(false);
+    }
+    update();
+}
+
+void IndicatorButtonPanel::setIndicatorButtonEnabled(bool enabled)
+{
+        m_indicatorButton->setChecked(enabled);
+        m_distanceTextLabel->setVisible(!enabled);
+}
+
+void IndicatorButtonPanel::timerExpired()
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    setDraggable(true, m_dragPosition);
+}
+
+void IndicatorButtonPanel::updateValues(qreal direction, qreal distance, bool draw)
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    const int MAX_TO_METERS = 999.5;
+    const int MAX_TO_KM_WITH_DESIMAL = 99950;
+    const int MIN_TO_METERS = 10;
+    const int M_TO_KM = 1000;                   ///< Meters to kilometers conversion
+
+    QString UNIT_KILOMETER = " km";
+    QString UNIT_METER = " m";
+
+    m_indicatorButton->setDirection(direction, draw);
+
+    m_distance = distance;
+
+    if(m_distance < MIN_TO_METERS)
+    {
+        m_distanceText.setNum(10);
+        m_distanceText.prepend("< ");
+        m_distanceText.append(UNIT_METER);
+    }
+    else if(m_distance < MAX_TO_METERS)
+    {
+        m_distanceText.setNum(m_distance, 0 , 0);
+        m_distanceText.append(UNIT_METER);
+    }
+    else if(m_distance < MAX_TO_KM_WITH_DESIMAL)
+    {
+        m_distanceText.setNum(m_distance / M_TO_KM, 1, 1);
+        m_distanceText.append(UNIT_KILOMETER);
+    }
+    else {
+        m_distanceText.setNum(m_distance / M_TO_KM, 0, 0);
+        m_distanceText.append(UNIT_KILOMETER);
+    }
+
+    m_distanceTextLabel->setText(m_distanceText);
+
+    update();
+}
+
diff --git a/src/ui/indicatorbuttonpanel.h b/src/ui/indicatorbuttonpanel.h
new file mode 100644 (file)
index 0000000..5b29bcf
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+   Situare - A location system for Facebook
+   Copyright (C) 2010  Ixonos Plc. Authors:
+
+       Pekka Nissinen - pekka.nissinen@ixonos.com
+       Kaj Wallin - kaj.wallin@ixonos.com
+       Katri Kaikkonen - katri.kaikkonen@ixonos.com
+
+   Situare is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License
+   version 2 as published by the Free Software Foundation.
+
+   Situare is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with Situare; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+   USA.
+*/
+
+#ifndef INDICATORBUTTONPANEL_H
+#define INDICATORBUTTONPANEL_H
+
+#include <QGraphicsItem>
+#include <QGridLayout>
+#include <QLabel>
+#include <QMouseEvent>
+#include <QTimer>
+#include <QWidget>
+
+#include "indicatorbutton.h"
+
+/**
+ * @brief Draggable panel for indicator button
+ *
+ * @author Katri Kaikkonen - katri.kaikkonen (at) ixonos.com
+ * @author Pekka Nissinen - pekka.nissinen (at) ixonos.com
+ * @author Kaj Wallin - kaj.wallin (at) ixonos.com
+ */
+class IndicatorButtonPanel : public QWidget
+{
+    Q_OBJECT
+
+public:
+    /**
+     * @brief Constructor
+     *
+     * @param parent Parent
+     */
+    IndicatorButtonPanel(QWidget *parent = 0);
+
+/*******************************************************************************
+ * BASE CLASS INHERITED AND REIMPLEMENTED MEMBER FUNCTIONS
+ ******************************************************************************/
+protected:
+    /**
+     * @brief Move event for the indicator button panel
+     *
+     * @param event Event
+     */
+    void mouseMoveEvent(QMouseEvent *event);
+
+    /**
+     * @brief Press event for the indicator button panel
+     *
+     * @param event Event
+     */
+    void mousePressEvent(QMouseEvent *event);
+
+    /**
+     * @brief Event handler for mouse release events
+     *
+     * @param event Mouse event
+     */
+    void mouseReleaseEvent(QMouseEvent *event);
+
+    /**
+     * @brief Event handler for paint events
+     *
+     * Paints the panel
+     * @param event Paint event
+     */
+    void paintEvent(QPaintEvent *event);
+
+/*******************************************************************************
+ * MEMBER FUNCTIONS AND SLOTS
+ ******************************************************************************/
+public slots:
+    /**
+     * @brief Called when direction and distance from current map center point to current GPS
+     *        location is changed
+     *
+     * @param direction Direction in degrees
+     * @param distance Distance in meters
+     * @param draw Should the indicator triangle be drawn or not
+     */
+    void updateValues(qreal direction, qreal distance, bool draw);
+
+    /**
+     * @brief Set indicator button enabled.
+     *
+     * @param enabled true if enabled, false otherwise
+     */
+    void setIndicatorButtonEnabled(bool enabled);
+
+    /**
+     * @brief Toggle indicator button panel draggability
+     *
+     * @param mode True if draggable, otherwise false
+     * @param distance Start value for dragging
+     */
+    void setDraggable(bool mode, QPoint eventPosition = QPoint(0,0));
+
+    /**
+     * @brief Slot to redraw the panel after window resize event
+     *
+     * @param size Size of the new screen
+     */
+    void screenResized(const QSize &size);
+
+private slots:
+    /**
+     * @brief Safeguard slot to release mouse grab if something goes horribly wrong
+     */
+    void forceMouseRelease();
+
+    /**
+     * @brief Slot that handles drag initialization once timer has timed out
+     */
+    void timerExpired();
+
+/*******************************************************************************
+ * SIGNALS
+ ******************************************************************************/
+signals:
+    /**
+     * @brief Automatic centering setting changed by user
+     *
+     * @param enabled True if automatic centering is enabled, otherwise false
+     */
+    void autoCenteringTriggered(bool enabled);
+
+    /**
+     * @brief Signal when direction and distance from current map center point to current GPS
+     *        location is changed
+     *
+     * @param direction Direction in degrees
+     * @param distance Distance in meters
+     * @param draw Should the indicator triangle be drawn or not
+     */
+    void directionIndicatorValuesUpdate(qreal direction, qreal distance, bool draw);
+
+    /**
+     * @brief Dragging mode triggered.
+     */
+    void draggingModeTriggered();
+
+/*******************************************************************************
+ * DATA MEMBERS
+ ******************************************************************************/
+private:
+    bool m_isDraggable;                     ///< Boolean for tracking the draggability state
+
+    qreal m_distance;                       ///< Distance to the GPS position
+
+    QColor *m_normalColor;                  ///< Normal background color
+
+    QLabel *m_distanceTextLabel;            ///< Pointer to distanceTextLabel
+
+    QPoint m_dragPosition;                  ///< Location from where the widget is grabbed
+
+    QSize m_screenSize;                     ///< Store for the screen size
+
+    QString m_distanceText;                 ///< Text description of the distance
+
+    QTimer *m_dragStartTimer;               ///< Timer to init draggability of the zoom panel
+    QTimer *m_forceReleaseTimer;            ///< Timer to run forceMouseRelease;
+
+    IndicatorButton *m_indicatorButton;     ///< Indicator button
+};
+
+#endif // INDICATORBUTTONPANEL_H
index 5a4c343..78ee9f8 100644 (file)
@@ -7,6 +7,7 @@
       Jussi Laitinen jussi.laitinen@ixonos.com
       Sami Rämö - sami.ramo@ixonos.com
       Ville Tiensuu - ville.tiensuu@ixonos.com
+      Katri Kaikkonen - katri.kaikkonen@ixonos.com
 
    Situare is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
 #include "error.h"
 #include "friendlistpanel.h"
 #include "fullscreenbutton.h"
-#include "indicatorbutton.h"
 #include "logindialog.h"
 #include "mapscale.h"
 #include "searchdialog.h"
 #include "settingsdialog.h"
 #include "userinfopanel.h"
 #include "zoombuttonpanel.h"
+#include "indicatorbuttonpanel.h"
 
 #include "mainwindow.h"
 
@@ -63,7 +64,7 @@ MainWindow::MainWindow(QWidget *parent)
     m_password(),
     m_webView(0),
     m_fullScreenButton(0),
-    m_indicatorButton(0),
+    m_indicatorButtonPanel(0),
     m_mapScale(0),
     m_cookieJar(0)
 {
@@ -95,8 +96,8 @@ MainWindow::MainWindow(QWidget *parent)
         m_osmLicense->stackUnder(m_zoomButtonPanel);
     }
     m_ownLocationCrosshair->stackUnder(m_osmLicense);
-    m_indicatorButton->stackUnder(m_ownLocationCrosshair);
-    m_mapScale->stackUnder(m_indicatorButton);
+    m_indicatorButtonPanel->stackUnder(m_ownLocationCrosshair);
+    m_mapScale->stackUnder(m_indicatorButtonPanel);
     m_mapView->stackUnder(m_mapScale);
 
     grabZoomKeys(true);
@@ -185,19 +186,22 @@ void MainWindow::buildFriendListPanel()
             m_friendsListPanel, SLOT(friendImageReady(User*)));
 }
 
-void MainWindow::buildIndicatorButton()
+void MainWindow::buildIndicatorButtonPanel()
 {
     qDebug() << __PRETTY_FUNCTION__;
 
-    m_indicatorButton = new IndicatorButton(this);
+    m_indicatorButtonPanel = new IndicatorButtonPanel(this);
 
-    connect(m_indicatorButton, SIGNAL(autoCenteringTriggered(bool)),
+    connect(m_indicatorButtonPanel, SIGNAL(autoCenteringTriggered(bool)),
         this, SIGNAL(autoCenteringTriggered(bool)));
 
     connect(m_mapView, SIGNAL(viewResized(QSize)),
-            m_indicatorButton, SLOT(screenResized(QSize)));
+            m_indicatorButtonPanel, SLOT(screenResized(QSize)));
 
-    connect(m_indicatorButton, SIGNAL(draggingModeTriggered()),
+    connect(this, SIGNAL(directionIndicatorValuesUpdate(qreal, qreal, bool)),
+            m_indicatorButtonPanel, SIGNAL(directionIndicatorValuesUpdate(qreal, qreal, bool)));
+
+    connect(m_indicatorButtonPanel, SIGNAL(draggingModeTriggered()),
             this, SIGNAL(draggingModeTriggered()));
 }
 
@@ -258,7 +262,7 @@ void MainWindow::buildMap()
     buildOsmLicense();
     buildManualLocationCrosshair();
     buildFullScreenButton();
-    buildIndicatorButton();
+    buildIndicatorButtonPanel();
     buildMapScale();
 
     connect(m_mapView, SIGNAL(viewScrolled(SceneCoordinate)),
@@ -817,8 +821,7 @@ void MainWindow::setIndicatorButtonEnabled(bool enabled)
 {
     qDebug() << __PRETTY_FUNCTION__;
 
-    m_indicatorButton->setChecked(enabled);
-
+    m_indicatorButtonPanel->setIndicatorButtonEnabled(enabled);
 }
 
 void MainWindow::setMapViewScene(QGraphicsScene *scene)
index 2875c50..dc8230f 100644 (file)
@@ -41,7 +41,7 @@ class QWebView;
 class FacebookAuthentication;
 class FullScreenButton;
 class FriendListPanel;
-class IndicatorButton;
+class IndicatorButtonPanel;
 class GeoCoordinate;
 class MapScale;
 class MapScene;
@@ -151,9 +151,9 @@ public:
 
 public slots:
     /**
-     * @brief Build direction indicator button and connect slots
+     * @brief Build direction indicator button panel and connect signals
      */
-    void buildIndicatorButton();
+    void buildIndicatorButtonPanel();
 
     /**
      * @brief Builds information box with message.
@@ -423,6 +423,16 @@ signals:
     void centerToSceneCoordinates(const SceneCoordinate &coordinate);
 
     /**
+    * @brief Signal when direction and distance from current map center point to current GPS
+    *        location is changed
+    *
+    * @param direction Direction in degrees
+    * @param distance Distance in meters
+    * @param draw Should the indicator triangle be drawn or not
+    */
+    void directionIndicatorValuesUpdate(qreal direction, qreal distance, bool draw);
+
+    /**
      * @brief Signal for enabling automatic location update.
      *
      * @param enabled true if enabled, false otherwise
@@ -641,7 +651,7 @@ private:
 
     FriendListPanel *m_friendsListPanel;    ///< Instance of friends list panel
     FullScreenButton *m_fullScreenButton;   ///< Instance of the fullscreen toggle button
-    IndicatorButton *m_indicatorButton;     ///< Instance of direction indicator button
+    IndicatorButtonPanel *m_indicatorButtonPanel;     ///< Instance of direction indicator button
     MapScale *m_mapScale;                   ///< Instance of the map scale
     MapView *m_mapView;                     ///< Instance of the map view
     NetworkCookieJar *m_cookieJar;          ///< Placeholder for QNetworkCookies
index 892bf88..2d3968d 100644 (file)
@@ -123,20 +123,9 @@ const int USERPANEL_OPENED_X = 0;                 ///< Horizontal position of a
 // Zoom button panel settings
 const int ZOOM_BUTTON_PANEL_POSITION_X = 10 +
                                          PANEL_PEEK_AMOUNT; ///< Horizontal position of zoom panel
-const int ZOOM_BUTTON_PANEL_POSITION_Y = 10; ///< Vertical position of zoom panel
-const int ZOOM_BUTTON_PANEL_BUTTON_SPACING = 4; ///< Size of a zoom button spacing
+const int ZOOM_BUTTON_PANEL_POSITION_Y = 10;                ///< Vertical position of zoom panel
+const int ZOOM_BUTTON_PANEL_BUTTON_SPACING = 4;             ///< Size of a zoom button spacing
 
 const QString ZOOMPANEL_POSITION = "Zoom_Panel_Position";
 
-// Direction indicator button settings
-/**
- * @brief Horizontal position of direction indicator button
- *
- * @var DIRECTION_INDICATOR_POSITION_X
- */
-const int DIRECTION_INDICATOR_POSITION_X = 10 + PANEL_PEEK_AMOUNT;
-const int DIRECTION_INDICATOR_POSITION_Y = 315; ///< Vertical position of direction indicator button
-
-const QString DIRECTION_INDICATOR_BUTTON_POSITION = "Direction_Indicator_Position";
-
 #endif // PANELCOMMON_H
index dac47bb..c8f7250 100644 (file)
 const double X = 12.345678;
 const double Y = -89.765432;
 
+const double ORIGIN = 1000;
+const double DELTA = 500;
+
 class TestSceneCoordinate : public QObject
 {
     Q_OBJECT
 
 private Q_SLOTS:
+    void azimuthTo();
+    void azimuthTo_data();
     void constructors();
     void conversion();
     void conversion_data();
@@ -54,6 +59,31 @@ namespace QTest {
     }
 }
 
+void TestSceneCoordinate::azimuthTo()
+{
+    QFETCH(SceneCoordinate, to);
+    QFETCH(qreal, expectedAzimuth);
+
+    SceneCoordinate from(ORIGIN, ORIGIN);
+
+    QCOMPARE(from.azimuthTo(to), expectedAzimuth);
+}
+
+void TestSceneCoordinate::azimuthTo_data()
+{
+    QTest::addColumn<SceneCoordinate>("to");
+    QTest::addColumn<qreal>("expectedAzimuth");
+
+    QTest::newRow("N") <<  SceneCoordinate(ORIGIN, ORIGIN - DELTA) << 0.0;
+    QTest::newRow("NE") <<  SceneCoordinate(ORIGIN + DELTA, ORIGIN - DELTA) << 45.0;
+    QTest::newRow("E") <<  SceneCoordinate(ORIGIN + DELTA, ORIGIN) << 90.0;
+    QTest::newRow("SE") <<  SceneCoordinate(ORIGIN + DELTA, ORIGIN + DELTA) << 135.0;
+    QTest::newRow("S") <<  SceneCoordinate(ORIGIN, ORIGIN + DELTA) << 180.0;
+    QTest::newRow("SW") <<  SceneCoordinate(ORIGIN - DELTA, ORIGIN + DELTA) << 225.0;
+    QTest::newRow("W") <<  SceneCoordinate(ORIGIN - DELTA, ORIGIN) << 270.0;
+    QTest::newRow("NW") <<  SceneCoordinate(ORIGIN - DELTA, ORIGIN - DELTA) << 315.0;
+}
+
 void TestSceneCoordinate::constructors()
 {
     SceneCoordinate coordinate;