Commit eb8bc814 authored by Dennis Nienhüser's avatar Dennis Nienhüser

Add basic support for dynamic style changes

- Add new StyleBuilder class
- Move style related code from GeoDataFeature to StyleBuilder
- Move style related code from osm parser to StyleBuilder
- Have geo feature style initialization done in geographics items,
  not the parser. Pass a render context when creating styles
- Dummy implementation using the render context (tile level)
  to change the styling of highways depending on the tile zoom level
parent ea6e1173
......@@ -267,6 +267,8 @@ set(marblewidget_SRCS
kineticmodel.cpp
NewstuffModel.cpp
MarbleZip.cpp
StyleBuilder.cpp
cloudsync/CloudSyncManager.cpp
cloudsync/RouteSyncManager.cpp
......
......@@ -645,7 +645,7 @@ class GEODATA_EXPORT GeoDataFeature : public GeoDataObject
static QColor defaultLabelColor();
static void setDefaultLabelColor( const QColor& color );
static QSharedPointer<Marble::GeoDataStyle> presetStyle( GeoDataVisualCategory category );
static QSharedPointer<const GeoDataStyle> presetStyle( GeoDataVisualCategory category );
static QString visualCategoryName(GeoDataVisualCategory category);
......
......@@ -24,6 +24,7 @@
#include "GeoDataStyle.h"
#include "GeoDataSnippet.h"
#include "MarbleDirs.h"
#include "StyleBuilder.h"
namespace Marble
{
......@@ -124,75 +125,6 @@ class GeoDataFeaturePrivate
return GeoDataTypes::GeoDataFeatureType;
}
static void initializeDefaultStyles();
static GeoDataStyle::Ptr createOsmPOIStyle( const QFont &font, const QString &bitmap,
const QColor &textColor = Qt::black,
const QColor &color = QColor( 0xBE, 0xAD, 0xAD ),
const QColor &outline = QColor( 0xBE, 0xAD, 0xAD ).darker()
)
{
GeoDataStyle::Ptr style = createStyle(1, 0, color, outline, true, true, Qt::SolidPattern, Qt::SolidLine, Qt::RoundCap, false);
QString const imagePath = MarbleDirs::path( "bitmaps/osmcarto/symbols/48/" + bitmap + ".png" );
style->setIconStyle( GeoDataIconStyle( imagePath) );
style->iconStyle().setScale(0.67);
style->setLabelStyle( GeoDataLabelStyle( font, textColor ) );
style->labelStyle().setAlignment(GeoDataLabelStyle::Center);
return style;
}
static GeoDataStyle::Ptr createHighwayStyle( const QString &bitmap, const QColor& color, const QColor& outlineColor,
const QFont& font = QFont(QLatin1String("Arial")), const QColor& fontColor = Qt::black,
qreal width = 1, qreal realWidth = 0.0,
Qt::PenStyle penStyle = Qt::SolidLine,
Qt::PenCapStyle capStyle = Qt::RoundCap,
bool lineBackground = false)
{
GeoDataStyle::Ptr style = createStyle( width, realWidth, color, outlineColor, true, true,
Qt::SolidPattern, penStyle, capStyle, lineBackground, QVector< qreal >(),
font, fontColor );
if( !bitmap.isEmpty() ) {
style->setIconStyle( GeoDataIconStyle( MarbleDirs::path( "bitmaps/" + bitmap + ".png" ) ) );
}
return style;
}
static GeoDataStyle::Ptr createWayStyle( const QColor& color, const QColor& outlineColor,
bool fill = true, bool outline = true,
Qt::BrushStyle brushStyle = Qt::SolidPattern,
const QString& texturePath = QString())
{
return createStyle( 1, 0, color, outlineColor, fill, outline, brushStyle, Qt::SolidLine, Qt::RoundCap, false, QVector< qreal >(), QFont("Arial"), Qt::black, texturePath );
}
static GeoDataStyle::Ptr createStyle( qreal width, qreal realWidth, const QColor& color,
const QColor& outlineColor, bool fill, bool outline,
Qt::BrushStyle brushStyle, Qt::PenStyle penStyle,
Qt::PenCapStyle capStyle, bool lineBackground,
const QVector< qreal >& dashPattern = QVector< qreal >(),
const QFont& font = QFont(QLatin1String("Arial")), const QColor& fontColor = Qt::black,
const QString& texturePath = QString())
{
GeoDataStyle *style = new GeoDataStyle;
GeoDataLineStyle lineStyle( outlineColor );
lineStyle.setCapStyle( capStyle );
lineStyle.setPenStyle( penStyle );
lineStyle.setWidth( width );
lineStyle.setPhysicalWidth( realWidth );
lineStyle.setBackground( lineBackground );
lineStyle.setDashPattern( dashPattern );
GeoDataPolyStyle polyStyle( color );
polyStyle.setOutline( outline );
polyStyle.setFill( fill );
polyStyle.setBrushStyle( brushStyle );
polyStyle.setTexturePath( texturePath );
GeoDataLabelStyle labelStyle(font, fontColor);
style->setLineStyle( lineStyle );
style->setPolyStyle( polyStyle );
style->setLabelStyle( labelStyle );
return GeoDataStyle::Ptr(style);
}
QString m_name; // Name of the feature. Is shown on screen
GeoDataSnippet m_snippet; // Snippet of the feature.
QString m_description; // A longer textual description
......@@ -226,8 +158,7 @@ class GeoDataFeaturePrivate
static QFont s_defaultFont;
static QColor s_defaultLabelColor;
static GeoDataStyle::Ptr s_defaultStyle[GeoDataFeature::LastIndex];
static bool s_defaultStyleInitialized;
static StyleBuilder s_styleBuilder;
};
} // namespace Marble
......
......@@ -18,6 +18,8 @@
#include "GeoDataStyle.h"
#include "MarbleDebug.h"
#include <qmath.h>
namespace Marble
{
......@@ -47,6 +49,9 @@ const GeoDataLatLonAltBox& GeoLineStringGraphicsItem::latLonAltBox() const
void GeoLineStringGraphicsItem::paint(GeoPainter* painter, const ViewportParams* viewport , const QString &layer)
{
int const tileLevel = qLn( viewport->radius() * 4 / 256 ) / qLn( 2.0 );
setRenderContext(RenderContext(tileLevel));
if (layer.endsWith("/outline")) {
if (painter->mapQuality() == HighQuality || painter->mapQuality() == PrintQuality) {
paintOutline(painter, viewport);
......
......@@ -76,11 +76,6 @@ void GeoGraphicsItem::setLatLonAltBox( const GeoDataLatLonAltBox& latLonAltBox )
d->m_latLonAltBox = latLonAltBox;
}
void GeoGraphicsItem::setStyle( const GeoDataStyle::ConstPtr &style )
{
d->m_style = style;
}
void GeoGraphicsItem::setHighlightStyle( const GeoDataStyle::ConstPtr &highlightStyle)
{
/**
......@@ -99,9 +94,20 @@ GeoDataStyle::ConstPtr GeoGraphicsItem::style() const
if ( d->m_highlighted && d->m_highlightStyle ) {
return d->m_highlightStyle;
}
if (!d->m_style) {
auto const styling = StyleParameters(d->m_feature, d->m_renderContext.tileLevel());
d->m_style = d->m_styleBuilder->createStyle(styling);
}
return d->m_style;
}
void GeoGraphicsItem::setStyleBuilder(const StyleBuilder::Ptr &styleBuilder)
{
d->m_styleBuilder = styleBuilder;
}
qreal GeoGraphicsItem::zValue() const
{
return d->m_zValue;
......@@ -132,6 +138,14 @@ void GeoGraphicsItem::setPaintLayers(const QStringList &paintLayers)
d->m_paintLayers = paintLayers;
}
void GeoGraphicsItem::setRenderContext(const RenderContext &renderContext)
{
if (renderContext != d->m_renderContext) {
d->m_renderContext = renderContext;
d->m_style = GeoDataStyle::ConstPtr();
}
}
int GeoGraphicsItem::minZoomLevel() const
{
return d->m_minZoomLevel;
......@@ -147,3 +161,23 @@ bool GeoGraphicsItem::zValueLessThan(GeoGraphicsItem *one, GeoGraphicsItem *two)
return one->d->m_zValue < two->d->m_zValue;
}
bool RenderContext::operator==(const RenderContext &other) const
{
return m_tileLevel == other.m_tileLevel;
}
bool RenderContext::operator!=(const RenderContext &other) const
{
return !operator==(other);
}
int RenderContext::tileLevel() const
{
return m_tileLevel;
}
RenderContext::RenderContext(int tileLevel) :
m_tileLevel(tileLevel)
{
// nothing to do
}
......@@ -15,6 +15,7 @@
// Marble
#include "marble_export.h"
#include "GeoDataStyle.h"
#include "StyleBuilder.h"
class QString;
......@@ -27,6 +28,19 @@ class GeoGraphicsItemPrivate;
class GeoPainter;
class ViewportParams;
class RenderContext
{
public:
bool operator==(const RenderContext &other) const;
bool operator!=(const RenderContext &other) const;
RenderContext(int tileLevel=-1);
int tileLevel() const;
private:
int m_tileLevel;
};
class MARBLE_EXPORT GeoGraphicsItem
{
public:
......@@ -98,7 +112,7 @@ class MARBLE_EXPORT GeoGraphicsItem
/**
* Set the style for the item.
*/
void setStyle(const GeoDataStyle::ConstPtr &style );
void setStyleBuilder(const StyleBuilder::Ptr &styleBuilder );
/**
* Set the style which will be used when
......@@ -136,6 +150,8 @@ class MARBLE_EXPORT GeoGraphicsItem
void setPaintLayers(const QStringList &paintLayers);
void setRenderContext(const RenderContext &renderContext);
protected:
GeoGraphicsItemPrivate *const d;
};
......
......@@ -16,6 +16,8 @@
#include "GeoDataLatLonAltBox.h"
#include "GeoDataStyle.h"
#include "ViewportParams.h"
#include "StyleBuilder.h"
#include "GeoGraphicsItem.h"
namespace Marble
{
......@@ -42,7 +44,9 @@ class GeoGraphicsItemPrivate
int m_minZoomLevel;
const GeoDataFeature *m_feature;
GeoDataLatLonAltBox m_latLonAltBox;
RenderContext m_renderContext;
GeoDataStyle::ConstPtr m_style;
StyleBuilder::Ptr m_styleBuilder;
QStringList m_paintLayers;
......
......@@ -44,6 +44,7 @@
#include "MarblePlacemarkModel.h"
#include "GeoDataTreeModel.h"
#include <OsmPlacemarkData.h>
#include "StyleBuilder.h"
// Qt
#include <qmath.h>
......@@ -75,6 +76,8 @@ public:
QMap<qint64,OsmQueue> m_osmWayItems;
QMap<qint64,OsmQueue> m_osmRelationItems;
StyleBuilder::Ptr m_styleBuilder;
private:
static void initializeDefaultValues();
static QString createPaintLayerOrder(const QString &itemType, GeoDataFeature::GeoDataVisualCategory visualCategory, const QString &subType = QString());
......@@ -90,7 +93,8 @@ int GeometryLayerPrivate::s_maximumZoomLevel = 0;
QStringList s_paintLayerOrder;
GeometryLayerPrivate::GeometryLayerPrivate( const QAbstractItemModel *model )
: m_model( model )
: m_model( model ),
m_styleBuilder(new StyleBuilder)
{
initializeDefaultValues();
}
......@@ -518,7 +522,7 @@ void GeometryLayerPrivate::createGraphicsItemFromGeometry(const GeoDataGeometry*
}
if ( !item )
return;
item->setStyle( placemark->style() );
item->setStyleBuilder(m_styleBuilder);
item->setVisible( placemark->isGloballyVisible() );
item->setMinZoomLevel( s_defaultMinZoomLevels[placemark->visualCategory()] );
m_scene.addItem( item );
......@@ -539,7 +543,7 @@ void GeometryLayerPrivate::createGraphicsItemFromOverlay( const GeoDataOverlay *
}
if ( item ) {
item->setStyle( overlay->style() );
item->setStyleBuilder(m_styleBuilder);
item->setVisible( overlay->isGloballyVisible() );
m_scene.addItem( item );
}
......
......@@ -53,39 +53,6 @@ void OsmNode::create(GeoDataDocument *document) const
placemark->setVisualCategory(category);
placemark->setStyle( GeoDataStyle::Ptr() );
if (category == GeoDataFeature::NaturalTree) {
qreal const lat = m_coordinates.latitude(GeoDataCoordinates::Degree);
if (qAbs(lat) > 15) {
/** @todo Should maybe auto-adjust to MarbleClock at some point */
int const month = QDate::currentDate().month();
QString season;
bool const southernHemisphere = lat < 0;
if (southernHemisphere) {
if (month >= 3 && month <= 5) {
season = "autumn";
} else if (month >= 6 && month <= 8) {
season = "winter";
}
} else {
if (month >= 9 && month <= 11) {
season = "autumn";
} else if (month == 12 || month == 1 || month == 2) {
season = "winter";
}
}
if (!season.isEmpty()) {
GeoDataIconStyle iconStyle = placemark->style()->iconStyle();
QString const bitmap = QString("bitmaps/osmcarto/symbols/48/individual/tree-29-%1.png").arg(season);
iconStyle.setIconPath(MarbleDirs::path(bitmap));
GeoDataStyle::Ptr style(new GeoDataStyle(*placemark->style()));
style->setIconStyle(iconStyle);
placemark->setStyle(style);
}
}
}
placemark->setZoomLevel( 18 );
if (category >= GeoDataFeature::PlaceCity && category <= GeoDataFeature::PlaceVillage) {
int const population = m_osmData.tagValue("population").toInt();
......
......@@ -56,36 +56,6 @@ void OsmWay::create(GeoDataDocument *document, const OsmNodes &nodes) const
}
*linearRing = linearRing->optimized();
if(placemark->visualCategory() == GeoDataFeature::AmenityGraveyard ||
placemark->visualCategory() == GeoDataFeature::LanduseCemetery) {
bool adjustStyle = true;
GeoDataPolyStyle polyStyle = placemark->style()->polyStyle();
if( m_osmData.containsTag("religion","jewish") ){
polyStyle.setTexturePath(MarbleDirs::path("bitmaps/osmcarto/patterns/grave_yard_jewish.png"));
} else if( m_osmData.containsTag("religion","christian") ){
polyStyle.setTexturePath(MarbleDirs::path("bitmaps/osmcarto/patterns/grave_yard_christian.png"));
} else if( m_osmData.containsTag("religion","INT-generic") ){
polyStyle.setTexturePath(MarbleDirs::path("bitmaps/osmcarto/patterns/grave_yard_generic.png"));
} else {
adjustStyle = false;
}
if (adjustStyle) {
GeoDataStyle::Ptr style(new GeoDataStyle(*placemark->style()));
style->setPolyStyle(polyStyle);
placemark->setStyle(style);
}
}
QList<GeoDataFeature::GeoDataVisualCategory> categories = OsmPresetLibrary::visualCategories(m_osmData);
foreach(GeoDataFeature::GeoDataVisualCategory category, categories) {
const GeoDataStyle::Ptr categoryStyle = GeoDataFeature::presetStyle(category);
if (!categoryStyle->iconStyle().iconPath().isEmpty()) {
GeoDataStyle::Ptr style(new GeoDataStyle(*placemark->style()));
style->setIconStyle(categoryStyle->iconStyle());
placemark->setStyle(style);
}
}
} else {
GeoDataLineString* lineString = new GeoDataLineString;
placemark->setGeometry(lineString);
......@@ -103,60 +73,6 @@ void OsmWay::create(GeoDataDocument *document, const OsmNodes &nodes) const
}
*lineString = lineString->optimized();
GeoDataPolyStyle polyStyle = placemark->style()->polyStyle();
GeoDataLineStyle lineStyle = placemark->style()->lineStyle();
lineStyle.setCosmeticOutline(true);
if (placemark->visualCategory() >= GeoDataFeature::HighwayService &&
placemark->visualCategory() <= GeoDataFeature::HighwayMotorway) {
bool const isOneWay = m_osmData.containsTag("oneway", "yes") || m_osmData.containsTag("oneway", "-1");
int const lanes = isOneWay ? 1 : 2; // also for motorway which implicitly is one way, but has two lanes and each direction has its own highway
double const laneWidth = 3.0;
double const margins = placemark->visualCategory() == GeoDataFeature::HighwayMotorway ? 2.0 : (isOneWay ? 1.0 : 0.0);
double const physicalWidth = margins + lanes * laneWidth;
lineStyle.setPhysicalWidth(physicalWidth);
QString const accessValue = m_osmData.tagValue("access");
if (accessValue == "private" || accessValue == "no" || accessValue == "agricultural" || accessValue == "delivery" || accessValue == "forestry") {
QColor polyColor = polyStyle.color();
qreal hue, sat, val;
polyColor.getHsvF(&hue, &sat, &val);
polyColor.setHsvF(0.98, qMin(1.0, 0.2 + sat), val);
polyStyle.setColor(polyColor);
lineStyle.setColor(lineStyle.color().darker(150));
}
if (m_osmData.containsTag("tunnel", "yes") ) {
QColor polyColor = polyStyle.color();
qreal hue, sat, val;
polyColor.getHsvF(&hue, &sat, &val);
polyColor.setHsvF(hue, 0.25 * sat, 0.95 * val);
polyStyle.setColor(polyColor);
lineStyle.setColor(lineStyle.color().lighter(115));
}
} else if (placemark->visualCategory() == GeoDataFeature::NaturalWater) {
QString const widthValue = m_osmData.tagValue("width").replace(" meters", QString()).replace(" m", QString());
bool ok;
float const width = widthValue.toFloat(&ok);
lineStyle.setPhysicalWidth(ok ? qBound(0.1f, width, 200.0f) : 0.0f);
}
GeoDataStyle::Ptr style(new GeoDataStyle(*placemark->style()));
style->setPolyStyle(polyStyle);
style->setLineStyle(lineStyle);
placemark->setStyle(style);
}
bool const hideLabel = placemark->visualCategory() == GeoDataFeature::HighwayTrack
|| (placemark->visualCategory() >= GeoDataFeature::RailwayRail && placemark->visualCategory() <= GeoDataFeature::RailwayFunicular);
if (hideLabel) {
GeoDataStyle::Ptr style(new GeoDataStyle(*placemark->style()));
style->labelStyle().setColor(QColor(Qt::transparent));
placemark->setStyle(style);
}
OsmObjectManager::registerId(m_osmData.id());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment