summaryrefslogtreecommitdiffstats
path: root/weather/src/citycarroussel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'weather/src/citycarroussel.cpp')
-rw-r--r--weather/src/citycarroussel.cpp472
1 files changed, 472 insertions, 0 deletions
diff --git a/weather/src/citycarroussel.cpp b/weather/src/citycarroussel.cpp
new file mode 100644
index 0000000..3f2d5a3
--- /dev/null
+++ b/weather/src/citycarroussel.cpp
@@ -0,0 +1,472 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: openBossa - INdT (renato.chencarek@openbossa.org)
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** the openBossa stream from INdT (renato.chencarek@openbossa.org).
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "citycarroussel.h"
+#include "settings.h"
+#include "pixmaploader.h"
+#include "titlebar.h"
+
+#include <QFont>
+
+struct ForecastEnvironment
+{
+ QPixmap picture;
+ QPixmap effect;
+ QString description;
+};
+
+struct ForecastBackgroundData
+{
+ const Forecast::ForecastType type;
+ const char * nightName;
+ const char* dayName;
+ const Forecast::Effect effect;
+ const char* description;
+
+ static ForecastEnvironment getEnvironment(Forecast::ForecastType forecast, bool night);
+
+private:
+ QString picName(bool night) const { return night ? nightName : dayName; }
+
+};
+
+static ForecastBackgroundData BackgroundData[Forecast::UnknownForecast + 1] = {
+ {Forecast::MostlyCloudy, "bg_night_rain", "bg_day_rain", Forecast::NoEffect, "mostly cloudy"},
+ {Forecast::Cloudy, "bg_night_rain", "bg_day_rain", Forecast::NoEffect, "cloudy"},
+ {Forecast::MostlySunny, "bg_night_clear", "bg_day_clear", Forecast::NoEffect, "mostly sunny"},
+ {Forecast::PartlyCloudy, "bg_night_clear", "bg_day_clear", Forecast::NoEffect, "partially cloudy"},
+ {Forecast::Sunny, "bg_night_clear", "bg_day_clear", Forecast::NoEffect, "sunny"},
+ {Forecast::Flurries, "bg_night_rain", "bg_day_rain", Forecast::NoEffect, "flurries"},
+ {Forecast::Fog, "bg_night_rain", "bg_day_heavyrain", Forecast::FogEffect, "fog"},
+ {Forecast::Haze, "bg_night_rain", "bg_day_heavyrain", Forecast::HazeEffect, "haze"},
+ {Forecast::Sand, "bg_night_rain", "bg_day_heavyrain", Forecast::HazeEffect, "sand"},
+ {Forecast::Dust, "bg_night_rain", "bg_day_heavyrain", Forecast::HazeEffect, "dust"},
+ {Forecast::Icy, "bg_night_rain", "bg_day_heavyrain", Forecast::NoEffect, "icy"},
+ {Forecast::Sleet, "bg_night_rain", "bg_day_heavyrain", Forecast::NoEffect, "sleet"},
+ {Forecast::ChanceOfSleet, "bg_night_rain", "bg_day_heavyrain", Forecast::NoEffect, "chance of sleet"},
+ {Forecast::Snow, "bg_night_rain", "bg_day_heavyrain", Forecast::NoEffect, "snow"},
+ {Forecast::ChanceOfSnow, "bg_night_rain", "bg_day_heavyrain", Forecast::NoEffect, "chance of snow"},
+ {Forecast::Mist, "bg_night_rain", "bg_day_rain", Forecast::NoEffect, "mist"},
+ {Forecast::Rain, "bg_night_rain", "bg_day_heavyrain", Forecast::NoEffect, "rain"},
+ {Forecast::ChanceOfRain, "bg_night_rain", "bg_day_heavyrain", Forecast::NoEffect, "chance of rain"},
+ {Forecast::Storm, "bg_night_rain", "bg_day_heavyrain", Forecast::NoEffect, "storm"},
+ {Forecast::ChanceOfStorm, "bg_night_rain", "bg_day_heavyrain", Forecast::NoEffect, "chance of storm"},
+ {Forecast::Thunderstorm, "bg_night_rain", "bg_day_heavyrain", Forecast::NoEffect, "thunderstorm"},
+ {Forecast::ChanceOfThunderstorm, "bg_night_rain", "bg_day_heavyrain", Forecast::NoEffect, "chance of thunderstorm"},
+ {Forecast::UnknownForecast, "bg_night_rain", "bg_night_rain", Forecast::NoEffect, "unknown"}
+};
+
+
+ForecastEnvironment ForecastBackgroundData::getEnvironment(Forecast::ForecastType forecast,
+ bool night)
+{
+ ForecastEnvironment result;
+ for (int i = 0; i < Forecast::UnknownForecast; ++i) {
+ if (forecast == BackgroundData[i].type) {
+ result.picture = PixmapLoader::getPic(BackgroundData[i].picName(night));
+
+ const Forecast::Effect effect = BackgroundData[i].effect;
+ const QString name = effect == Forecast::HazeEffect ? "haze"
+ : effect == Forecast::FogEffect ? "fog"
+ : QString();
+ result.effect = name.isNull() ? QPixmap() : PixmapLoader::getPic(name);
+
+ result.description = BackgroundData[i].description;
+ if (night)
+ result.description.append(" at night");
+ }
+ }
+ return result;
+}
+
+// ForecastBackground
+
+ForecastBackground::ForecastBackground(QGraphicsItem *parent)
+ : QGraphicsPixmapItem(parent)
+ , m_forecast(Forecast::UnknownForecast)
+ , m_night(false)
+ , m_effect(0)
+{
+ setShapeMode(QGraphicsPixmapItem::BoundingRectShape);
+ setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
+}
+
+void ForecastBackground::setForecast(Forecast::ForecastType forecast, bool night)
+{
+ if (forecast == m_forecast && night == m_night)
+ return;
+ m_forecast = forecast;
+ m_night = night;
+ ForecastEnvironment environment = ForecastBackgroundData::getEnvironment(m_forecast, m_night);
+ setPixmap(environment.picture);
+ m_description = environment.description;
+
+ if (environment.effect.isNull()) {
+ delete m_effect;
+ m_effect = 0;
+ }
+ else {
+ if (!m_effect) {
+ m_effect = new QGraphicsPixmapItem(this);
+ m_effect->setZValue(20.0);
+ m_effect->setPos(0.0, 0.0);
+ }
+ m_effect->setPixmap(environment.effect);
+ }
+}
+
+void ForecastBackground::setReferencePos(qreal pos)
+{
+ m_pos = pos;
+ m_displacement = 0;
+ setPos(m_pos, 0.0);
+}
+
+void ForecastBackground::setDisplacement(qreal displacement)
+{
+ m_displacement = displacement;
+ setPos(m_pos + m_displacement, 0.0);
+}
+
+
+void ForecastBackground::addCompanion(QGraphicsItem *item)
+{
+ if (m_companion.indexOf(item) == -1)
+ m_companion.append(item);
+
+}
+
+void ForecastBackground::removeCompanion(QGraphicsItem *item)
+{
+ m_companion.removeAll(item);
+}
+
+QVariant ForecastBackground::itemChange(GraphicsItemChange change, const QVariant &value)
+{
+ if (change == ItemPositionChange) {
+ const QPointF move = value.toPointF() - pos();
+ for (int i = 0; i < m_companion.count(); ++i)
+ m_companion[i]->moveBy(move.x(), move.y());
+ }
+ return QGraphicsPixmapItem::itemChange(change, value);
+}
+
+// CityCarrousselGesture
+
+CityCarrousselGesture::CityCarrousselGesture(CityCarroussel &carroussel, QGraphicsItem *parent)
+ : GestureBox(parent)
+ , m_carroussel(carroussel)
+ , m_active(true)
+ , m_aborted(false)
+ , m_startPoint(0.0)
+{
+}
+
+void CityCarrousselGesture::gestureMousePress(QPointF pos, bool &startGesture, bool &acceptClick)
+{
+ Q_UNUSED(pos);
+ Q_UNUSED(acceptClick);
+ startGesture = m_carroussel.active();
+}
+
+void CityCarrousselGesture::gestureStart(QPointF pos)
+{
+ m_startPoint = pos.x();
+ m_aborted = false;
+}
+
+void CityCarrousselGesture::gestureMove(QPointF pos, QPointF movement, QPointF speed)
+{
+ Q_UNUSED(movement);
+ Q_UNUSED(speed);
+ if (!m_aborted)
+ m_carroussel.setGestureDisplacement(pos.x() - m_startPoint);
+}
+
+void CityCarrousselGesture::gestureEnd(QPointF pos, QPointF speed)
+{
+ Q_UNUSED(pos);
+ Q_UNUSED(speed);
+ if (!m_aborted)
+ m_carroussel.move(0);
+}
+
+// CityCarroussel
+
+static const qreal transparencyRef = 58.0 / 480.0;
+static const qreal marginRef = 47.0 / 480.0;
+static const qreal backgroundPosRef = -(transparencyRef + marginRef);
+static const qreal backgroundWidthRef = 635.0 / 480.0;
+
+CityCarroussel::CityCarroussel(QGraphicsItem *parent)
+ : QGraphicsItem(parent)
+ , m_view(0)
+ , m_displacement(0.0)
+ , m_gestureBox(new CityCarrousselGesture(*this, this))
+ , m_boundingRect(QPointF(0.0, 0.0), Settings::windowSize())
+ , m_backgroundWidth(backgroundWidthRef * m_boundingRect.width())
+ , m_backgroundPos(backgroundPosRef * m_boundingRect.width())
+ , m_transparencySize(transparencyRef * m_boundingRect.width())
+ , m_distance(m_backgroundWidth - m_transparencySize)
+ , m_active(true)
+ , m_deleteAfterMove(false)
+{
+ m_gestureBox->setRect(boundingRect());
+ m_carroussel.add(&m_data);
+ m_carroussel.add(&m_background);
+ m_carroussel.add(&m_cityInfo);
+
+ TitleBar *titleBar = new TitleBar(this);
+ titleBar->setPos(0.0, 0.0);
+ titleBar->setZValue(100.0);
+
+ QPixmap barPic = PixmapLoader::getPic("city_name_background_bigger");
+ QGraphicsPixmapItem * cityBar = new QGraphicsPixmapItem(barPic, this);
+ cityBar->setPos(Settings::scaleWidth(-20.0), Settings::scaleHeight(735.0));
+ cityBar->setZValue(10.0);
+
+ m_positions[0] = m_backgroundPos - m_distance;
+ m_positions[1] = m_backgroundPos;
+ m_positions[2] = m_backgroundPos + m_distance;
+
+ for (int i = -1; i <= 1; ++i) {
+ ForecastBackground *background = new ForecastBackground(this);
+ m_background.add(background);
+
+ CityInfoDisplay *city = new CityInfoDisplay(this);
+ m_cityInfo.add(city);
+ city->setPos(background->pos().x() - m_backgroundPos + Settings::windowSize().width() / 2,
+ background->pos().y() + Settings::scaleHeight(525.0));
+ city->setZValue(11.0);
+ background->addCompanion(city);
+ }
+
+ updateBackground(-1);
+ updateBackground(0);
+ updateBackground(1);
+}
+
+CityCarroussel::~CityCarroussel()
+{
+}
+
+int CityCarroussel::loadImages()
+{
+ for (int i = 0; i < Forecast::UnknownForecast;++i) {
+ PixmapLoader::load(BackgroundData[i].nightName);
+ PixmapLoader::load(BackgroundData[i].dayName);
+ }
+ PixmapLoader::load("haze");
+ PixmapLoader::load("fog");
+ PixmapLoader::load("city_name_background_bigger");
+ return Forecast::UnknownForecast + 3;
+
+}
+
+void CityCarroussel::setActive(bool value)
+{
+ if (value == m_active)
+ return;
+ m_active = value;
+ if (m_active)
+ connect(m_cityInfo[0], SIGNAL(nameClicked()), this, SIGNAL(cityNameClicked()));
+ else
+ disconnect(m_cityInfo[0]);
+}
+
+QRectF CityCarroussel::boundingRect () const
+{
+ return m_boundingRect;
+}
+
+void CityCarroussel::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt, QWidget *widget)
+{
+ Q_UNUSED(painter);
+ Q_UNUSED(opt);
+ Q_UNUSED(widget);
+}
+
+void CityCarroussel::add(ForecastData item)
+{
+ int idx = m_data.add(item);
+ if (idx < -1 || idx > 1)
+ return;
+ if (m_data.count()< 3) {
+ updateBackground(-1);
+ updateBackground(0);
+ updateBackground(1);
+ } else
+ updateBackground(idx);
+ if (idx == 0)
+ updateMainItem();
+}
+
+void CityCarroussel::update(QList<ForecastData> items)
+{
+ if (items.isEmpty())
+ return;
+
+ bool wasEmpty = m_data.count() == 0;
+ bool transitionNeeded = false;
+
+ if (!wasEmpty) {
+ for (int i = 0; i < items.count(); ++i) {
+ if (items[i].key() == m_data[0].key()) {
+ for (int j = 0; j < i; ++j)
+ items.append(items.takeFirst());
+ break;
+ }
+ }
+ transitionNeeded = m_data[0] != items[0];
+ if (transitionNeeded)
+ items.push_front(m_data[0]);
+ }
+
+ m_data.reset(items, 0);
+ updateBackground(-1);
+ updateBackground(1);
+
+ if (wasEmpty) {
+ updateBackground(0);
+ updateMainItem();
+ }
+ if (transitionNeeded) {
+ move(-1, true);
+ }
+}
+
+void CityCarroussel::updateMainItem()
+{
+ delete m_view;
+ m_view = ForecastView::createView(m_data[0].type(), m_data[0].night());
+ if (m_view) {
+ connect(m_cityInfo[0], SIGNAL(nameClicked()), this, SIGNAL(cityNameClicked()));
+ m_view->setPos(-m_positions[1], 0.0);
+ m_view->setZValue(10.0);
+ m_view->setParentItem(m_background[0]);
+ m_view->reset();
+
+ QAbstractAnimation * animation = m_view->getAnimation();
+ if (animation)
+ animation->start(QAbstractAnimation::DeleteWhenStopped);
+ }
+}
+
+void CityCarroussel::updateBackground(int idx)
+{
+ if (m_data.count() == 0)
+ m_background[idx]->reset();
+ else
+ m_background[idx]->setForecast(m_data[idx].type(), m_data[idx].night());
+ m_background[idx]->setZValue(idx);
+ m_background[idx]->setReferencePos(m_positions[idx + 1]);
+ QString cityName = m_data.count() ? m_data[idx].cityName() : QString("unknown");
+ m_cityInfo[idx]->setCityName(cityName);
+ if (m_data.count() > 0)
+ m_cityInfo[idx]->setTemperature(m_data[idx].lower(),
+ m_data[idx].upper(), m_data[idx].current());
+ else
+ m_cityInfo[idx]->setTemperature(0, 0, 0);
+}
+
+void CityCarroussel::moveEnd(int direction)
+{
+ m_displacement = 0.0;
+ m_gestureBox->setActive(true);
+ if (direction) {
+ m_carroussel.move(-direction);
+ for (int i = -1; i <= 1; ++i) {
+ m_background[i]->setReferencePos(m_positions[i + 1]);
+ m_background[i]->setZValue(i);
+ }
+ if (m_deleteAfterMove) {
+ m_data.remove(direction);
+ updateBackground(direction);
+ }
+
+ updateBackground(-direction);
+ updateMainItem();
+ }
+}
+
+void CityCarroussel::setDisplacement(qreal displacement)
+{
+ m_displacement = displacement;
+ for (int i = -1; i <= 1; ++i)
+ m_background[i]->setDisplacement(m_displacement);
+ if (m_view)
+ m_view->setElementsDisplacement(m_displacement / m_distance);
+}
+
+void CityCarroussel::setGestureDisplacement(qreal displacement)
+{
+ if (qAbs(displacement) > boundingRect().width() * 0.5) {
+ move(displacement < 0 ? -1 : 1);
+ }
+ else
+ setDisplacement(displacement);
+}
+
+void CityCarroussel::move(int direction, bool deleteLastItem)
+{
+ m_gestureBox->setActive(false);
+ m_gestureBox->abort();
+ disconnect(m_cityInfo[0]);
+ m_deleteAfterMove = deleteLastItem;
+
+ QPropertyAnimation *animation = new QPropertyAnimation(this, "displacement");
+
+ animation->setEndValue(direction * m_distance);
+ animation->setEasingCurve(QEasingCurve::OutQuart);
+ animation->setDuration(500);
+
+ switch(direction) {
+ case -1:
+ connect(animation, SIGNAL(finished()), this, SLOT(moveLeftEnd()));
+ break;
+ case 0:
+ connect(animation, SIGNAL(finished()), this, SLOT(moveBackEnd()));
+ break;
+ case 1:
+ connect(animation, SIGNAL(finished()), this, SLOT(moveRightEnd()));
+ break;
+ }
+ animation->start(QAbstractAnimation::DeleteWhenStopped);
+}
+
+
+
+
+
+
+
+
+