diff options
Diffstat (limited to 'weather/src/citycarroussel.cpp')
-rw-r--r-- | weather/src/citycarroussel.cpp | 472 |
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); +} + + + + + + + + + |