mirror of
https://bitbucket.org/smil3y/kde-extraapps.git
synced 2025-02-24 10:52:53 +00:00
354 lines
14 KiB
C++
354 lines
14 KiB
C++
/*
|
|
Copyright 2008-2009 by Frederik Gladhorn <gladhorn@kde.org>
|
|
Copyright 2008-2009 by Sascha Peilicke <sasch.pe@gmx.de>
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of
|
|
the License or (at your option) version 3 or any later version
|
|
accepted by the membership of KDE e.V. (or its successor approved
|
|
by the membership of KDE e.V.), which shall act as a proxy
|
|
defined in Section 14 of version 3 of the license.
|
|
|
|
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "marble.h"
|
|
|
|
#include <marble/GeoPainter.h>
|
|
#include <marble/MapThemeManager.h>
|
|
#include <marble/MarbleMap.h>
|
|
#include <marble/MarbleModel.h>
|
|
#include <marble/RenderPlugin.h>
|
|
#include <marble/SunLocator.h>
|
|
#include <marble/ViewportParams.h>
|
|
|
|
#include <QGraphicsSceneMouseEvent>
|
|
#include <QStandardItemModel>
|
|
#include <QTimer>
|
|
|
|
#define DRAG_THRESHOLD 3 // Distance (pixel) before starting drag updates
|
|
#define DEFAULT_UPDATE_INTERVAL 300000 // Wait time between redraws in msecs (5 min)
|
|
|
|
#define MOVEMENT_KEY "movement" // Type of movement
|
|
#define ROTATION_LON_KEY "rotateLongitude" // Amount of rotation (degrees/second)
|
|
#define ROTATION_LAT_KEY "rotateLatitude"
|
|
#define ROTATION_TIMEOUT_KEY "rotationTimeout"
|
|
#define POSITION_LON_KEY "positionLongitude" // Last position
|
|
#define POSITION_LAT_KEY "positionLatitude"
|
|
#define ZOOM_KEY "zoom" // Zoom distance
|
|
#define MAP_THEME_KEY "mapTheme" // Marble settings
|
|
#define PROJECTION_KEY "projection" // Projection type
|
|
#define QUALITY_KEY "quality" // Render quality
|
|
#define SHOW_PLACEMARKS_KEY "showPlacemarks"
|
|
|
|
namespace Marble {
|
|
|
|
MarbleWallpaper::MarbleWallpaper(QObject * parent, const QVariantList & args)
|
|
: Plasma::Wallpaper(parent, args), m_timer(0), m_map(0)
|
|
{
|
|
setPreviewDuringConfiguration(true);
|
|
KGlobal::locale()->insertCatalog(QLatin1String( "marble" ));
|
|
}
|
|
|
|
MarbleWallpaper::~MarbleWallpaper()
|
|
{
|
|
delete m_map;
|
|
delete m_timer;
|
|
}
|
|
|
|
void MarbleWallpaper::init(const KConfigGroup &config)
|
|
{
|
|
qreal home_lon = 0;
|
|
qreal home_lat = 0;
|
|
int home_zoom = 0;
|
|
|
|
// Only on first start, otherwise opening the config dialog lets us
|
|
// lose the current position
|
|
if (!isInitialized()) {
|
|
m_map = new MarbleMap();
|
|
|
|
// Get default position from marble to initialize on first startup (empty config)
|
|
m_map->model()->home(home_lon, home_lat, home_zoom);
|
|
m_map->model()->setClockDateTime( QDateTime::currentDateTime().toUTC() );
|
|
|
|
// These settings apply to Marble's "satellite" view mostly, e.g. make it beautiful
|
|
m_map->setShowClouds(true);
|
|
m_map->setShowCityLights(false);
|
|
m_map->setShowSunShading(true);
|
|
|
|
// Disable all render plugins (scale bar, compass, etc.) except the "stars" plugin
|
|
foreach (RenderPlugin *item, m_map->renderPlugins()) {
|
|
if (item->nameId() == QLatin1String( "stars" )) {
|
|
item->setVisible(true);
|
|
item->setEnabled(true);
|
|
} else {
|
|
item->setVisible(false);
|
|
item->setEnabled(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Read setting values or use defaults
|
|
m_mapTheme = config.readEntry(MAP_THEME_KEY, QString::fromLatin1("earth/bluemarble/bluemarble.dgml"));
|
|
m_movement = static_cast<Movement>(config.readEntry(MOVEMENT_KEY, static_cast<int>(Interactive)));
|
|
m_positionLon = config.readEntry(POSITION_LON_KEY, home_lon);
|
|
m_positionLat = config.readEntry(POSITION_LAT_KEY, home_lat);
|
|
m_projection = static_cast<Projection>(config.readEntry(PROJECTION_KEY, static_cast<int>(Spherical)));
|
|
m_quality = static_cast<MapQuality>(config.readEntry(QUALITY_KEY, static_cast<int>(NormalQuality)));
|
|
m_rotationLat = config.readEntry(ROTATION_LAT_KEY, 0.0);
|
|
m_rotationLon = config.readEntry(ROTATION_LON_KEY, 0.025);
|
|
m_rotationTimeout = config.readEntry(ROTATION_TIMEOUT_KEY, 10000);
|
|
m_showPlacemarks = config.readEntry(SHOW_PLACEMARKS_KEY, false);
|
|
m_zoom = config.readEntry(ZOOM_KEY, home_zoom);
|
|
|
|
m_map->setMapThemeId(m_mapTheme);
|
|
m_map->setProjection(m_projection);
|
|
m_map->setShowCities(m_showPlacemarks);
|
|
m_map->setShowOtherPlaces(m_showPlacemarks);
|
|
m_map->setShowPlaces(m_showPlacemarks);
|
|
m_map->setShowTerrain(m_showPlacemarks);
|
|
|
|
if (!isInitialized()) {
|
|
qreal radius = pow(M_E, (m_zoom / 200.0));
|
|
m_map->setRadius(radius);
|
|
m_map->centerOn(m_positionLon, m_positionLat);
|
|
}
|
|
updateGlobe();
|
|
}
|
|
|
|
QWidget *MarbleWallpaper::createConfigurationInterface(QWidget *parent)
|
|
{
|
|
QWidget *configWidget = new QWidget(parent);
|
|
m_ui.setupUi(configWidget);
|
|
m_ui.movement->setCurrentIndex(static_cast<int>(m_movement));
|
|
m_ui.projection->setCurrentIndex(static_cast<int>(m_projection));
|
|
// The first MapQuality value is wireframe, which we don't show in the list
|
|
m_ui.quality->setCurrentIndex(static_cast<int>(m_quality) - 1);
|
|
m_ui.rotationLon->setValue(m_rotationLon);
|
|
m_ui.rotationLat->setValue(m_rotationLat);
|
|
m_ui.timeout->setValue(m_rotationTimeout / 1000);
|
|
m_ui.showPlacemarks->setChecked(m_showPlacemarks);
|
|
|
|
MapThemeManager themeManager;
|
|
// FIXME: Going manually through the model is ugly as hell, but plugging the
|
|
// model into the view didn't work for me
|
|
for (int i = 0; i < themeManager.mapThemeModel()->rowCount(); i++) {
|
|
QModelIndex index = themeManager.mapThemeModel()->index(i, 0, QModelIndex());
|
|
QString theme = themeManager.mapThemeModel()->data(index, Qt::DisplayRole).toString();
|
|
QIcon icon = qvariant_cast<QIcon>(themeManager.mapThemeModel()->data(index, Qt::DecorationRole));
|
|
QModelIndex fileIndex = themeManager.mapThemeModel()->index(i, 0, QModelIndex());
|
|
QString themeFile = themeManager.mapThemeModel()->data(fileIndex, Qt::UserRole + 1).toString();
|
|
m_ui.themeList->addItem(icon, theme, themeFile);
|
|
if (m_mapTheme == themeFile) {
|
|
m_ui.themeList->setCurrentIndex(i);
|
|
}
|
|
}
|
|
|
|
// Trigger initial visual movement setup
|
|
updateConfigScreen(static_cast<int>(m_movement));
|
|
|
|
connect(m_ui.movement, SIGNAL(currentIndexChanged(int)), SLOT(updateConfigScreen(int)));
|
|
connect(m_ui.movement, SIGNAL(currentIndexChanged(int)), SLOT(updateSettings()));
|
|
connect(m_ui.projection, SIGNAL(currentIndexChanged(int)), SLOT(updateSettings()));
|
|
connect(m_ui.quality, SIGNAL(currentIndexChanged(int)), SLOT(updateSettings()));
|
|
connect(m_ui.rotationLon, SIGNAL(valueChanged(double)), SLOT(updateSettings()));
|
|
connect(m_ui.rotationLat, SIGNAL(valueChanged(double)), SLOT(updateSettings()));
|
|
connect(m_ui.timeout, SIGNAL(valueChanged(double)), SLOT(updateSettings()));
|
|
connect(m_ui.showPlacemarks, SIGNAL(stateChanged(int)), SLOT(updateSettings()));
|
|
connect(m_ui.themeList, SIGNAL(currentIndexChanged(int)), SLOT(changeTheme(int)));
|
|
|
|
// Notify the plasma background dialog of changes
|
|
connect(this, SIGNAL(settingsChanged(bool)), parent, SLOT(settingsChanged(bool)));
|
|
|
|
return configWidget;
|
|
}
|
|
|
|
void MarbleWallpaper::save(KConfigGroup &config)
|
|
{
|
|
if (m_map) {
|
|
config.writeEntry(MAP_THEME_KEY, m_map->mapThemeId());
|
|
config.writeEntry(POSITION_LAT_KEY, m_map->centerLatitude());
|
|
config.writeEntry(POSITION_LON_KEY, m_map->centerLongitude());
|
|
}
|
|
|
|
config.writeEntry(MOVEMENT_KEY, static_cast<int>(m_movement));
|
|
config.writeEntry(ZOOM_KEY, m_zoom);
|
|
config.writeEntry(PROJECTION_KEY, static_cast<int>(m_projection));
|
|
config.writeEntry(QUALITY_KEY, static_cast<int>(m_quality));
|
|
config.writeEntry(ROTATION_LAT_KEY, m_rotationLat);
|
|
config.writeEntry(ROTATION_LON_KEY, m_rotationLon);
|
|
config.writeEntry(ROTATION_TIMEOUT_KEY, m_rotationTimeout);
|
|
config.writeEntry(SHOW_PLACEMARKS_KEY, m_showPlacemarks);
|
|
}
|
|
|
|
void MarbleWallpaper::paint(QPainter *painter, const QRectF &exposedRect)
|
|
{
|
|
// Update the pixmap
|
|
if (m_pixmap.size() != boundingRect().size().toSize()) {
|
|
m_pixmap = QPixmap(boundingRect().size().toSize());
|
|
}
|
|
if (m_pixmap.size().isEmpty()) {
|
|
return;
|
|
}
|
|
m_map->setSize(m_pixmap.size());
|
|
m_pixmap.fill(QColor(0x00, 0x00, 0x00, 0xFF));
|
|
GeoPainter gp(&m_pixmap, m_map->viewport(), m_quality);
|
|
QRect mapRect(0, 0, m_map->width(), m_map->height());
|
|
m_map->paint(gp, mapRect);
|
|
|
|
// Draw the requested part of the pixmap
|
|
painter->drawPixmap(exposedRect, m_pixmap, exposedRect.translated(-boundingRect().topLeft()));
|
|
}
|
|
|
|
void MarbleWallpaper::wheelEvent(QGraphicsSceneWheelEvent *event)
|
|
{
|
|
if (m_movement == Interactive) {
|
|
event->accept();
|
|
m_zoom = qMax(qreal(0), m_zoom + (event->delta() > 0 ? 40 : -40));
|
|
qreal radius = pow(M_E, (m_zoom / 200.0));
|
|
m_map->setRadius(radius);
|
|
|
|
emit update(boundingRect());
|
|
}
|
|
}
|
|
|
|
void MarbleWallpaper::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
|
{
|
|
if (m_movement == Interactive && event->buttons() == Qt::LeftButton) {
|
|
event->accept();
|
|
int polarity = m_map->viewport()->polarity();
|
|
|
|
qreal radius = (qreal)(m_map->radius());
|
|
int deltaX = event->screenPos().x() - m_dragStartPositionX;
|
|
int deltaY = event->screenPos().y() - m_dragStartPositionY;
|
|
|
|
// Only start dragging after a certain distance
|
|
if (abs(deltaX) <= DRAG_THRESHOLD && abs(deltaY) <= DRAG_THRESHOLD) {
|
|
return;
|
|
}
|
|
|
|
// Reverse spin direction if globe is turned upside down
|
|
qreal const direction = polarity < 0 ? -1 : 1;
|
|
|
|
m_positionLon = RAD2DEG * (qreal)(m_leftPressedTranslationX)
|
|
- 90.0 * direction * deltaX / radius;
|
|
m_positionLat = RAD2DEG * (qreal)(m_leftPressedTranslationY)
|
|
+ 90.0 * deltaY / radius;
|
|
m_map->centerOn(m_positionLon, m_positionLat);
|
|
|
|
emit update(boundingRect());
|
|
}
|
|
}
|
|
|
|
void MarbleWallpaper::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
|
{
|
|
if (m_movement == Interactive && event->buttons() == Qt::LeftButton) {
|
|
event->accept();
|
|
|
|
// On the single event of a mouse button press these
|
|
// values get stored, to enable us to e.g. calculate the
|
|
// distance of a mouse drag while the mouse button is
|
|
// still down.
|
|
m_dragStartPositionX = event->screenPos().x();
|
|
m_dragStartPositionY = event->screenPos().y();
|
|
|
|
// Calculate translation of center point
|
|
m_leftPressedTranslationX = m_map->centerLongitude() * DEG2RAD;
|
|
m_leftPressedTranslationY = m_map->centerLatitude() * DEG2RAD;
|
|
}
|
|
}
|
|
|
|
void MarbleWallpaper::updateGlobe()
|
|
{
|
|
if (!m_timer) {
|
|
m_timer = new QTimer(this);
|
|
connect(m_timer, SIGNAL(timeout()), SLOT(updateGlobe()));
|
|
} else {
|
|
m_timer->stop();
|
|
}
|
|
|
|
if (m_movement == Rotate || m_movement == FollowSun) {
|
|
m_timer->setInterval(m_rotationTimeout);
|
|
} else {
|
|
m_timer->setInterval(DEFAULT_UPDATE_INTERVAL);
|
|
}
|
|
m_timer->start();
|
|
|
|
if (m_movement == FollowSun) {
|
|
m_map->model()->sunLocator()->update();
|
|
if (m_map->model()->sunLocator()->getLon() == m_map->centerLongitude()) {
|
|
return;
|
|
}
|
|
m_positionLon = m_map->model()->sunLocator()->getLon();
|
|
m_positionLat = m_map->model()->sunLocator()->getLat();
|
|
m_map->centerOn(m_positionLon, m_positionLat);
|
|
} else if (m_movement == Rotate) {
|
|
m_map->rotateBy(m_rotationLon * m_rotationTimeout / 1000,
|
|
m_rotationLat * m_rotationTimeout / 1000);
|
|
m_positionLon = m_map->centerLongitude();
|
|
m_positionLat = m_map->centerLatitude();
|
|
}
|
|
emit update(boundingRect());
|
|
}
|
|
|
|
void MarbleWallpaper::updateSettings()
|
|
{
|
|
m_projection = static_cast<Projection>(m_ui.projection->currentIndex());
|
|
m_rotationLon = m_ui.rotationLon->value();
|
|
m_rotationLat = m_ui.rotationLat->value();
|
|
m_rotationTimeout = m_ui.timeout->value() * 1000;
|
|
// The first MapQuality value is wireframe, which we don't show in the list
|
|
m_quality = static_cast<MapQuality>(m_ui.quality->currentIndex() + 1);
|
|
m_showPlacemarks = m_ui.showPlacemarks->isChecked();
|
|
|
|
emit settingsChanged(true);
|
|
}
|
|
|
|
void MarbleWallpaper::changeTheme(int index)
|
|
{
|
|
m_mapTheme = m_ui.themeList->itemData(index).toString();
|
|
m_map->setMapThemeId(m_mapTheme);
|
|
|
|
emit update(boundingRect());
|
|
emit settingsChanged(true);
|
|
}
|
|
|
|
void MarbleWallpaper::updateConfigScreen(int index)
|
|
{
|
|
m_movement = static_cast<Movement>(index);
|
|
|
|
m_ui.mouseInstructions->setVisible(m_movement == Interactive);
|
|
if (m_movement == Rotate) {
|
|
m_ui.rotationLat->setVisible(true);
|
|
m_ui.rotationLon->setVisible(true);
|
|
m_ui.labelRotationLat->setVisible(true);
|
|
m_ui.labelRotationLon->setVisible(true);
|
|
} else {
|
|
m_ui.rotationLat->setVisible(false);
|
|
m_ui.rotationLon->setVisible(false);
|
|
m_ui.labelRotationLat->setVisible(false);
|
|
m_ui.labelRotationLon->setVisible(false);
|
|
}
|
|
if (m_movement == FollowSun || m_movement == Rotate) {
|
|
m_ui.timeout->setVisible(true);
|
|
m_ui.labelTimeout->setVisible(true);
|
|
} else {
|
|
m_ui.timeout->setVisible(false);
|
|
m_ui.labelTimeout->setVisible(false);
|
|
}
|
|
|
|
emit settingsChanged(true);
|
|
}
|
|
|
|
} // Marble namespace
|
|
|
|
#include "moc_marble.cpp"
|
|
|
|
// vim: sw=4 sts=4 et tw=100
|