The previous tutorial showed how to override the customPaint() method in MarbleWidget to paint on top of the map. It is also possible to paint at different layer positions. This is similar to providing a z-order of elements being painted.

To achieve this, we'll take a look at an example. Instead of deriving from MarbleWidget, we create our own Marble::LayerInterface class. After passing it to Marble, it will be included in painting similar to how customPaint() was called. This time however we are able to specify at which layer to paint.

To illustrate the painting in different layers, the code below paints a clock and implements the ability to dynamically switch its layer position by pressing '+'. Notice how the current layer position is indicated in the window title. When painting in the "STARS" layer, you won't see anything -- we'll paint behind the map. In the "SURFACE" layer, city names and other placemarks will be painted on top of us. In contrast, "ORBIT" will make us paint over placemarks, while float items (info boxes) still paint above us. This will change when we paint in the "USER TOOLS" layer.

#include <marble/MarbleWidget.h>#include <marble/MarbleMap.h>#include <marble/MarbleModel.h>#include <marble/GeoPainter.h>#include <marble/LayerInterface.h>#include <QtCore/QTime>#include <QtCore/QTimer>#include <QtGui/QApplication>#include <QtGui/QKeyEvent>usingnamespaceMarble;classMyPaintLayer:publicQObject,publicLayerInterface{public:// ConstructorMyPaintLayer(MarbleWidget*widget);// Implemented from LayerInterfacevirtualQStringListrenderPosition()const;// Implemented from LayerInterfacevirtualboolrender(GeoPainter*painter,ViewportParams*viewport,constQString&renderPos="NONE",GeoSceneLayer*layer=0);// Overriding QObjectvirtualbooleventFilter(QObject*obj,QEvent*event);GeoDataCoordinatesapproximate(constGeoDataCoordinates&base,qrealangle,qrealdist)const;private:MarbleWidget*m_widget;intm_index;};MyPaintLayer::MyPaintLayer(MarbleWidget*widget):m_widget(widget),m_index(0){// nothing to do}QStringListMyPaintLayer::renderPosition()const{// We will paint in exactly one of the following layers.// The current one can be changed by pressing the '+' keyQStringListlayers=QStringList()<<"SURFACE"<<"HOVERS_ABOVE_SURFACE";layers<<"ORBIT"<<"USER_TOOLS"<<"STARS";intindex=m_index%layers.size();returnQStringList()<<layers.at(index);}boolMyPaintLayer::eventFilter(QObject*obj,QEvent*event){// Adjust the current layer when '+' is pressedif(event->type()==QEvent::KeyPress){QKeyEvent*keyEvent=static_cast<QKeyEvent*>(event);if(keyEvent->key()==Qt::Key_Plus){++m_index;returntrue;}}returnfalse;}GeoDataCoordinatesMyPaintLayer::approximate(constGeoDataCoordinates&base,qrealangle,qrealdist)const{// This is just a rough estimation that ignores projections.// It only works for short distances. Don't use in real code.GeoDataCoordinates::Unitdeg=GeoDataCoordinates::Degree;returnGeoDataCoordinates(base.longitude(deg)+1.5*dist*sin(angle),base.latitude(deg)+dist*cos(angle),0.0,deg);}boolMyPaintLayer::render(GeoPainter*painter,ViewportParams*viewport,constQString&renderPos,GeoSceneLayer*layer){// Have window title reflect the current paint layerm_widget->setWindowTitle(renderPosition().first());GeoDataCoordinateshome(8.4,48.0,0.0,GeoDataCoordinates::Degree);QTimenow=QTime::currentTime();painter->setRenderHint(QPainter::Antialiasing,true);// Large circle built by 60 small circlespainter->setPen(QPen(QBrush(QColor::fromRgb(255,255,255,200)),3.0,Qt::SolidLine,Qt::RoundCap));for(inti=0;i<60;++i)painter->drawEllipse(approximate(home,M_PI*i/30.0,1.0),5,5);// hour, minute, second handpainter->drawLine(home,approximate(home,M_PI*now.minute()/30.0,0.75));painter->drawLine(home,approximate(home,M_PI*now.hour()/6.0,0.5));painter->setPen(QPen(QBrush(Qt::red),4.0,Qt::SolidLine,Qt::RoundCap));painter->drawLine(home,approximate(home,M_PI*now.second()/30.0,1.0));returntrue;}intmain(intargc,char**argv){QApplicationapp(argc,argv);MarbleWidget*mapWidget=newMarbleWidget;// Create and register our paint layerMyPaintLayer*layer=newMyPaintLayer(mapWidget);// Uncomment for older versions of Marble:// mapWidget->map()->model()->addLayer(layer);mapWidget->addLayer(layer);// Install an event handler: Pressing + will change the layer we paint atmapWidget->installEventFilter(layer);// Finish widget creation.mapWidget->setMapThemeId("earth/bluemarble/bluemarble.dgml");mapWidget->show();// Update each second to give the clock second resolutionQTimerseconds;seconds.setInterval(1000);QObject::connect(&seconds,SIGNAL(timeout()),mapWidget,SLOT(updateChangedMap()));seconds.start();returnapp.exec();}