/**************************************************************************** ** ** 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 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 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); }