Rework 3d light configuration GUI so that point and directional

lights aren't separated into distinct tabs

This hopefully avoids the papercut issue where its not obvious
to users exactly which existing lights are in a scene, and also
follows the UI pattern used elsewhere (e.g. symbol layers)
This commit is contained in:
Nyall Dawson 2020-10-21 16:17:58 +10:00
parent dd593fd716
commit 3019b82100
5 changed files with 699 additions and 556 deletions

View File

@ -135,8 +135,7 @@ Qgs3DMapConfigWidget::Qgs3DMapConfigWidget( Qgs3DMapSettings *map, QgsMapCanvas
QgsPhongMaterialSettings terrainShadingMaterial = mMap->terrainShadingMaterial();
widgetTerrainMaterial->setSettings( &terrainShadingMaterial, nullptr );
widgetLights->setPointLights( mMap->pointLights() );
widgetLights->setDirectionalLights( mMap->directionalLights() );
widgetLights->setLights( mMap->pointLights(), mMap->directionalLights() );
connect( cboTerrainType, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &Qgs3DMapConfigWidget::onTerrainTypeChanged );
connect( cboTerrainLayer, static_cast<void ( QComboBox::* )( int )>( &QgsMapLayerComboBox::currentIndexChanged ), this, &Qgs3DMapConfigWidget::onTerrainLayerChanged );

View File

@ -20,21 +20,36 @@
#include "qgssettings.h"
#include <QMessageBox>
#include <QMenu>
QgsLightsWidget::QgsLightsWidget( QWidget *parent )
: QWidget( parent )
{
setupUi( this );
mLightsModel = new QgsLightsModel( this );
mLightsListView->setModel( mLightsModel );
connect( mLightsListView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsLightsWidget::selectedLightChanged );
btnAddLight->setIcon( QIcon( QgsApplication::iconPath( "symbologyAdd.svg" ) ) );
btnRemoveLight->setIcon( QIcon( QgsApplication::iconPath( "symbologyRemove.svg" ) ) );
dialAzimuth->setMaximum( 359 );
connect( btnAddLight, &QToolButton::clicked, this, &QgsLightsWidget::onAddLight );
QMenu *addLightMenu = new QMenu( this );
QAction *addPointLight = new QAction( tr( "Point Light" ), addLightMenu );
connect( addPointLight, &QAction::triggered, this, &QgsLightsWidget::onAddLight );
addLightMenu->addAction( addPointLight );
QAction *addDirectionalLight = new QAction( tr( "Directional Light" ), addLightMenu );
connect( addDirectionalLight, &QAction::triggered, this, &QgsLightsWidget::onAddDirectionalLight );
addLightMenu->addAction( addDirectionalLight );
btnAddLight->setMenu( addLightMenu );
connect( btnRemoveLight, &QToolButton::clicked, this, &QgsLightsWidget::onRemoveLight );
connect( cboLights, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, &QgsLightsWidget::onCurrentLightChanged );
connect( spinPositionX, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ), this, &QgsLightsWidget::updateCurrentLightParameters );
connect( spinPositionY, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ), this, &QgsLightsWidget::updateCurrentLightParameters );
connect( spinPositionZ, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ), this, &QgsLightsWidget::updateCurrentLightParameters );
@ -44,13 +59,6 @@ QgsLightsWidget::QgsLightsWidget( QWidget *parent )
connect( spinA1, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ), this, &QgsLightsWidget::updateCurrentLightParameters );
connect( spinA2, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ), this, &QgsLightsWidget::updateCurrentLightParameters );
btnAddDirectionalLight->setIcon( QIcon( QgsApplication::iconPath( "symbologyAdd.svg" ) ) );
btnRemoveDirectionalLight->setIcon( QIcon( QgsApplication::iconPath( "symbologyRemove.svg" ) ) );
connect( btnAddDirectionalLight, &QToolButton::clicked, this, &QgsLightsWidget::onAddDirectionalLight );
connect( btnRemoveDirectionalLight, &QToolButton::clicked, this, &QgsLightsWidget::onRemoveDirectionalLight );
connect( cboDirectionalLights, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, &QgsLightsWidget::onCurrentDirectionalLightChanged );
connect( spinDirectionalIntensity, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ), this, &QgsLightsWidget::updateCurrentDirectionalLightParameters );
connect( btnDirectionalColor, &QgsColorButton::colorChanged, this, &QgsLightsWidget::updateCurrentDirectionalLightParameters );
@ -59,46 +67,55 @@ QgsLightsWidget::QgsLightsWidget( QWidget *parent )
connect( spinBoxAzimuth, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ), this, &QgsLightsWidget::onDirectionChange );
connect( spinBoxAltitude, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ), this, &QgsLightsWidget::onDirectionChange );
tabWidget->setCurrentIndex( QgsSettings().value( QStringLiteral( "UI/last3DLightsTab" ), 1 ).toInt() );
mLightsListView->selectionModel()->select( mLightsModel->index( 0, 0 ), QItemSelectionModel::ClearAndSelect );
selectedLightChanged( mLightsListView->selectionModel()->selection(), QItemSelection() );
}
QgsLightsWidget::~QgsLightsWidget()
void QgsLightsWidget::setLights( const QList<QgsPointLightSettings> &pointLights, const QList<QgsDirectionalLightSettings> &directionalLights )
{
QgsSettings().setValue( QStringLiteral( "UI/last3DLightsTab" ), tabWidget->currentIndex() );
}
void QgsLightsWidget::setPointLights( const QList<QgsPointLightSettings> &pointLights )
{
mPointLights = pointLights;
updateLightsList();
cboLights->setCurrentIndex( 0 );
onCurrentLightChanged( 0 );
}
void QgsLightsWidget::setDirectionalLights( const QList<QgsDirectionalLightSettings> &directionalLights )
{
mDirectionalLights = directionalLights;
updateDirectionalLightsList();
cboDirectionalLights->setCurrentIndex( 0 );
onCurrentDirectionalLightChanged( 0 );
mLightsModel->setPointLights( pointLights );
mLightsModel->setDirectionalLights( directionalLights );
mLightsListView->selectionModel()->select( mLightsModel->index( 0, 0 ), QItemSelectionModel::ClearAndSelect );
selectedLightChanged( mLightsListView->selectionModel()->selection(), QItemSelection() );
}
QList<QgsPointLightSettings> QgsLightsWidget::pointLights()
{
return mPointLights;
return mLightsModel->pointLights();
}
QList<QgsDirectionalLightSettings> QgsLightsWidget::directionalLights()
{
return mDirectionalLights;
return mLightsModel->directionalLights();
}
void QgsLightsWidget::onCurrentLightChanged( int index )
void QgsLightsWidget::selectedLightChanged( const QItemSelection &selected, const QItemSelection & )
{
if ( index < 0 || index >= cboLights->count() )
if ( selected.empty() )
{
mStackedWidget->setCurrentIndex( 0 );
return;
}
QgsPointLightSettings light = mPointLights.at( index );
const QgsLightsModel::LightType lightType = static_cast< QgsLightsModel::LightType >( mLightsModel->data( selected.indexes().at( 0 ), QgsLightsModel::LightTypeRole ).toInt() );
const int listIndex = mLightsModel->data( selected.indexes().at( 0 ), QgsLightsModel::LightListIndex ).toInt();
switch ( lightType )
{
case QgsLightsModel::Point:
mStackedWidget->setCurrentIndex( 1 );
showSettingsForPointLight( mLightsModel->pointLights().at( listIndex ) );
break;
case QgsLightsModel::Directional:
mStackedWidget->setCurrentIndex( 2 );
showSettingsForDirectionalLight( mLightsModel->directionalLights().at( listIndex ) );
break;
}
}
void QgsLightsWidget::showSettingsForPointLight( const QgsPointLightSettings &light )
{
whileBlocking( spinPositionX )->setValue( light.position().x() );
whileBlocking( spinPositionY )->setValue( light.position().y() );
whileBlocking( spinPositionZ )->setValue( light.position().z() );
@ -109,12 +126,8 @@ void QgsLightsWidget::onCurrentLightChanged( int index )
whileBlocking( spinA2 )->setValue( light.quadraticAttenuation() );
}
void QgsLightsWidget::onCurrentDirectionalLightChanged( int index )
void QgsLightsWidget::showSettingsForDirectionalLight( const QgsDirectionalLightSettings &light )
{
if ( index < 0 || index >= cboDirectionalLights->count() )
return;
QgsDirectionalLightSettings light = mDirectionalLights.at( index );
mDirectionX = light.direction().x();
mDirectionY = light.direction().y();
mDirectionZ = light.direction().z();
@ -126,9 +139,7 @@ void QgsLightsWidget::onCurrentDirectionalLightChanged( int index )
void QgsLightsWidget::updateCurrentLightParameters()
{
int index = cboLights->currentIndex();
if ( index < 0 || index >= cboLights->count() )
return;
const int listIndex = mLightsModel->data( mLightsListView->selectionModel()->selection().indexes().at( 0 ), QgsLightsModel::LightListIndex ).toInt();
QgsPointLightSettings light;
light.setPosition( QgsVector3D( spinPositionX->value(), spinPositionY->value(), spinPositionZ->value() ) );
@ -137,7 +148,8 @@ void QgsLightsWidget::updateCurrentLightParameters()
light.setConstantAttenuation( spinA0->value() );
light.setLinearAttenuation( spinA1->value() );
light.setQuadraticAttenuation( spinA2->value() );
mPointLights[index] = light;
mLightsModel->setPointLightSettings( listIndex, light );
}
void QgsLightsWidget::updateCurrentDirectionalLightParameters()
@ -146,77 +158,54 @@ void QgsLightsWidget::updateCurrentDirectionalLightParameters()
labelY->setText( QString::number( mDirectionY, 'f', 2 ) );
labelZ->setText( QString::number( mDirectionZ, 'f', 2 ) );
int index = cboDirectionalLights->currentIndex();
if ( index < 0 || index >= cboDirectionalLights->count() )
return;
const int listIndex = mLightsModel->data( mLightsListView->selectionModel()->selection().indexes().at( 0 ), QgsLightsModel::LightListIndex ).toInt();
QgsDirectionalLightSettings light;
light.setDirection( QgsVector3D( mDirectionX, mDirectionY, mDirectionZ ) );
light.setColor( btnDirectionalColor->color() );
light.setIntensity( spinDirectionalIntensity->value() );
mDirectionalLights[index] = light;
mLightsModel->setDirectionalLightSettings( listIndex, light );
}
void QgsLightsWidget::onAddLight()
{
if ( mPointLights.count() >= 8 )
if ( mLightsModel->pointLights().size() >= 8 )
{
QMessageBox::warning( this, tr( "Add Light" ), tr( "It is not possible to add more than 8 lights to the scene." ) );
return;
}
mPointLights << QgsPointLightSettings();
updateLightsList();
cboLights->setCurrentIndex( cboLights->count() - 1 );
// To set default parameters of the light
onCurrentDirectionalLightChanged( 0 );
const QModelIndex newIndex = mLightsModel->addPointLight( QgsPointLightSettings() );
mLightsListView->selectionModel()->select( newIndex, QItemSelectionModel::ClearAndSelect );
}
void QgsLightsWidget::onAddDirectionalLight()
{
if ( mDirectionalLights.count() > 4 )
if ( mLightsModel->directionalLights().size() >= 4 )
{
QMessageBox::warning( this, tr( "Add Directional Light" ), tr( "It is not possible to add more than 4 directional lights to the scene." ) );
return;
}
mDirectionalLights << QgsDirectionalLightSettings();
updateDirectionalLightsList();
cboDirectionalLights->setCurrentIndex( cboDirectionalLights->count() - 1 );
// To set default parameters of the light
onCurrentDirectionalLightChanged( 0 );
emit directionalLightsCountChanged( cboDirectionalLights->count() );
const QModelIndex newIndex = mLightsModel->addDirectionalLight( QgsDirectionalLightSettings() );
mLightsListView->selectionModel()->select( newIndex, QItemSelectionModel::ClearAndSelect );
}
void QgsLightsWidget::onRemoveLight()
{
int index = cboLights->currentIndex();
if ( index < 0 || index >= cboLights->count() )
const QItemSelection selected = mLightsListView->selectionModel()->selection();
if ( selected.empty() )
{
return;
}
mPointLights.removeAt( index );
updateLightsList();
if ( index >= cboLights->count() )
--index; // in case we removed the last light
cboLights->setCurrentIndex( index );
onCurrentLightChanged( index );
}
const int directionalCount = mLightsModel->directionalLights().size();
void QgsLightsWidget::onRemoveDirectionalLight()
{
int index = cboDirectionalLights->currentIndex();
if ( index < 0 || index >= cboDirectionalLights->count() )
return;
mLightsModel->removeRows( selected.indexes().at( 0 ).row(), 1 );
mDirectionalLights.removeAt( index );
updateDirectionalLightsList();
if ( index >= cboDirectionalLights->count() )
--index; // in case we removed the last light
cboDirectionalLights->setCurrentIndex( index );
onCurrentDirectionalLightChanged( index );
emit directionalLightsCountChanged( cboDirectionalLights->count() );
if ( mLightsModel->directionalLights().size() != directionalCount )
emit directionalLightsCountChanged( mLightsModel->directionalLights().size() );
}
void QgsLightsWidget::setAzimuthAltitude()
@ -236,16 +225,16 @@ void QgsLightsWidget::setAzimuthAltitude()
azimuthAngle = std::fmod( azimuthAngle + 360.0, 360.0 );
}
dialAzimuth->setValue( int( azimuthAngle + 180 ) % 360 );
spinBoxAzimuth->setValue( azimuthAngle );
whileBlocking( dialAzimuth )->setValue( int( azimuthAngle + 180 ) % 360 );
whileBlocking( spinBoxAzimuth )->setValue( azimuthAngle );
if ( horizontalVectorMagnitude == 0 )
altitudeAngle = mDirectionY >= 0 ? 90 : -90;
altitudeAngle = mDirectionY >= 0 ? -90 : 90;
else
altitudeAngle = -atan( mDirectionY / horizontalVectorMagnitude ) / M_PI * 180;
spinBoxAltitude->setValue( altitudeAngle );
sliderAltitude->setValue( altitudeAngle );
whileBlocking( spinBoxAltitude )->setValue( altitudeAngle );
whileBlocking( sliderAltitude )->setValue( altitudeAngle );
updateCurrentDirectionalLightParameters();
}
@ -265,24 +254,140 @@ void QgsLightsWidget::onDirectionChange()
updateCurrentDirectionalLightParameters();
}
void QgsLightsWidget::updateLightsList()
//
// QgsLightsModel
//
QgsLightsModel::QgsLightsModel( QObject *parent )
: QAbstractListModel( parent )
{
cboLights->blockSignals( true );
cboLights->clear();
for ( int i = 0; i < mPointLights.count(); ++i )
{
cboLights->addItem( tr( "Light %1" ).arg( i + 1 ) );
}
cboLights->blockSignals( false );
}
void QgsLightsWidget::updateDirectionalLightsList()
int QgsLightsModel::rowCount( const QModelIndex &parent ) const
{
cboDirectionalLights->blockSignals( true );
cboDirectionalLights->clear();
for ( int i = 0; i < mDirectionalLights.count(); ++i )
{
cboDirectionalLights->addItem( tr( "Directional light %1" ).arg( i + 1 ) );
}
cboDirectionalLights->blockSignals( false );
Q_UNUSED( parent )
return mPointLights.size() + mDirectionalLights.size();
}
QVariant QgsLightsModel::data( const QModelIndex &index, int role ) const
{
if ( index.row() < 0 || index.row() >= rowCount( QModelIndex() ) )
return QVariant();
const LightType lightType = index.row() < mPointLights.size() ? Point : Directional;
const int lightListRow = lightType == Point ? index.row() : index.row() - mPointLights.size();
switch ( role )
{
case Qt::DisplayRole:
case Qt::ToolTipRole:
case Qt::EditRole:
switch ( lightType )
{
case Point:
return tr( "Point light %1" ).arg( lightListRow + 1 );
case Directional:
return tr( "Directional light %1" ).arg( lightListRow + 1 );
}
break;
case LightTypeRole:
return lightType;
case LightListIndex:
return lightListRow;
case Qt::DecorationRole:
return QgsApplication::getThemeIcon( QStringLiteral( "/mActionHighlightFeature.svg" ) );
default:
break;
}
return QVariant();
}
bool QgsLightsModel::removeRows( int row, int count, const QModelIndex &parent )
{
beginRemoveRows( parent, row, row + count - 1 );
for ( int i = row + count - 1; i >= row; --i )
{
const LightType lightType = i < mPointLights.size() ? Point : Directional;
const int lightListRow = lightType == Point ? i : i - mPointLights.size();
switch ( lightType )
{
case Point:
mPointLights.removeAt( lightListRow );
break;
case Directional:
mDirectionalLights.removeAt( lightListRow );
break;
}
}
endRemoveRows();
return true;
}
void QgsLightsModel::setPointLights( const QList<QgsPointLightSettings> &lights )
{
beginRemoveRows( QModelIndex(), 0, mPointLights.size() - 1 );
mPointLights.clear();
endRemoveRows();
beginInsertRows( QModelIndex(), 0, lights.size() - 1 );
mPointLights = lights;
endInsertRows();
}
void QgsLightsModel::setDirectionalLights( const QList<QgsDirectionalLightSettings> &lights )
{
beginRemoveRows( QModelIndex(), mPointLights.size(), mPointLights.size() + mDirectionalLights.size() - 1 );
mDirectionalLights.clear();
endRemoveRows();
beginInsertRows( QModelIndex(), mPointLights.size(), mPointLights.size() + lights.size() - 1 );
mDirectionalLights = lights;
endInsertRows();
}
QList<QgsPointLightSettings> QgsLightsModel::pointLights() const
{
return mPointLights;
}
QList<QgsDirectionalLightSettings> QgsLightsModel::directionalLights() const
{
return mDirectionalLights;
}
void QgsLightsModel::setPointLightSettings( int index, const QgsPointLightSettings &light )
{
mPointLights[ index ] = light;
}
void QgsLightsModel::setDirectionalLightSettings( int index, const QgsDirectionalLightSettings &light )
{
mDirectionalLights[ index ] = light;
}
QModelIndex QgsLightsModel::addPointLight( const QgsPointLightSettings &light )
{
beginInsertRows( QModelIndex(), mPointLights.size(), mPointLights.size() );
mPointLights.append( light );
endInsertRows();
return index( mPointLights.size() - 1 );
}
QModelIndex QgsLightsModel::addDirectionalLight( const QgsDirectionalLightSettings &light )
{
beginInsertRows( QModelIndex(), mPointLights.size() + mDirectionalLights.size(), mPointLights.size() + mDirectionalLights.size() );
mDirectionalLights.append( light );
endInsertRows();
return index( mPointLights.size() + mDirectionalLights.size() - 1 );
}

View File

@ -23,6 +23,47 @@
#include "qgspointlightsettings.h"
#include "qgsdirectionallightsettings.h"
class QgsLightsModel : public QAbstractListModel
{
Q_OBJECT
public:
enum LightType
{
Point,
Directional
};
enum Role
{
LightTypeRole = Qt::UserRole,
LightListIndex,
};
explicit QgsLightsModel( QObject *parent = nullptr );
int rowCount( const QModelIndex &parent ) const override;
QVariant data( const QModelIndex &index, int role ) const override;
bool removeRows( int row, int count, const QModelIndex &parent = QModelIndex() ) override;
void setPointLights( const QList<QgsPointLightSettings> &lights );
void setDirectionalLights( const QList<QgsDirectionalLightSettings> &lights );
QList<QgsPointLightSettings> pointLights() const;
QList<QgsDirectionalLightSettings> directionalLights() const;
void setPointLightSettings( int index, const QgsPointLightSettings &light );
void setDirectionalLightSettings( int index, const QgsDirectionalLightSettings &light );
QModelIndex addPointLight( const QgsPointLightSettings &light );
QModelIndex addDirectionalLight( const QgsDirectionalLightSettings &light );
private:
QList<QgsPointLightSettings> mPointLights;
QList<QgsDirectionalLightSettings> mDirectionalLights;
};
/**
* Widget for configuration of lights in 3D map scene
* \since QGIS 3.6
@ -32,10 +73,9 @@ class QgsLightsWidget : public QWidget, private Ui::QgsLightsWidget
Q_OBJECT
public:
explicit QgsLightsWidget( QWidget *parent = nullptr );
~QgsLightsWidget() override;
void setPointLights( const QList<QgsPointLightSettings> &pointLights );
void setDirectionalLights( const QList<QgsDirectionalLightSettings> &directionalLights );
void setLights( const QList<QgsPointLightSettings> &pointLights,
const QList<QgsDirectionalLightSettings> &directionalLights );
QList<QgsPointLightSettings> pointLights();
QList<QgsDirectionalLightSettings> directionalLights();
@ -43,27 +83,26 @@ class QgsLightsWidget : public QWidget, private Ui::QgsLightsWidget
signals:
void directionalLightsCountChanged( int count );
private slots:
void onCurrentLightChanged( int index );
void selectedLightChanged( const QItemSelection &selected, const QItemSelection &deselected );
void updateCurrentLightParameters();
void onAddLight();
void onRemoveLight();
void onCurrentDirectionalLightChanged( int index );
void updateCurrentDirectionalLightParameters();
void onAddDirectionalLight();
void onRemoveDirectionalLight();
void setAzimuthAltitude();
void onDirectionChange();
private:
void updateLightsList();
void updateDirectionalLightsList();
void showSettingsForPointLight( const QgsPointLightSettings &settings );
void showSettingsForDirectionalLight( const QgsDirectionalLightSettings &settings );
private:
QList<QgsPointLightSettings> mPointLights;
QList<QgsDirectionalLightSettings> mDirectionalLights;
double mDirectionX = 0;
double mDirectionY = -1;
double mDirectionZ = 0;
QgsLightsModel *mLightsModel = nullptr;
};
#endif // QGSLIGHTSWIDGET_H

View File

@ -179,7 +179,7 @@
<item>
<widget class="QStackedWidget" name="m3DOptionsStackedWidget">
<property name="currentIndex">
<number>0</number>
<number>1</number>
</property>
<widget class="QWidget" name="mPageTerrain">
<layout class="QVBoxLayout" name="verticalLayout_61">
@ -205,7 +205,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>705</width>
<width>703</width>
<height>604</height>
</rect>
</property>
@ -393,8 +393,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>705</width>
<height>620</height>
<width>703</width>
<height>604</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayoutLight">
@ -477,8 +477,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>705</width>
<height>620</height>
<width>151</width>
<height>47</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayoutShadow">
@ -567,8 +567,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>705</width>
<height>620</height>
<width>175</width>
<height>132</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayoutCameraSkybox">
@ -667,8 +667,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>705</width>
<height>620</height>
<width>304</width>
<height>330</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayoutAdvanced">

View File

@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<width>425</width>
<height>633</height>
</rect>
</property>
@ -15,430 +15,36 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>1</number>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="topMargin">
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>Point lights</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QComboBox" name="cboLights"/>
</item>
<item>
<widget class="QToolButton" name="btnAddLight">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="btnRemoveLight">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
<item>
<widget class="QListView" name="mLightsListView"/>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<item>
<widget class="QToolButton" name="btnAddLight">
<property name="text">
<string>...</string>
</property>
<property name="popupMode">
<enum>QToolButton::InstantPopup</enum>
</property>
</widget>
</item>
<item row="1" column="0">
<layout class="QGridLayout" name="gridLayout">
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Z</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QgsDoubleSpinBox" name="spinPositionX">
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>-9999999.000000000000000</double>
</property>
<property name="maximum">
<double>9999999.000000000000000</double>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;A&lt;span style=&quot; vertical-align:sub;&quot;&gt;2&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QgsDoubleSpinBox" name="spinIntensity">
<property name="decimals">
<number>1</number>
</property>
<property name="maximum">
<double>999999.000000000000000</double>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;A&lt;span style=&quot; vertical-align:sub;&quot;&gt;0&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="1" column="1" rowspan="2">
<widget class="QgsDoubleSpinBox" name="spinPositionY">
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>-9999999.000000000000000</double>
</property>
<property name="maximum">
<double>9999999.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0" rowspan="2">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Y</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QgsDoubleSpinBox" name="spinPositionZ">
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>-9999999.000000000000000</double>
</property>
<property name="maximum">
<double>9999999.000000000000000</double>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QgsColorButton" name="btnColor">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>120</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QgsDoubleSpinBox" name="spinA0">
<property name="maximum">
<double>9.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QgsDoubleSpinBox" name="spinA1">
<property name="maximum">
<double>9.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QgsDoubleSpinBox" name="spinA2">
<property name="maximum">
<double>9.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Intensity</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;A&lt;span style=&quot; vertical-align:sub;&quot;&gt;1&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Color</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>X</string>
</property>
</widget>
</item>
<item row="6" column="0" colspan="2">
<widget class="QLabel" name="label_6">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Attenuation (A&lt;span style=&quot; vertical-align:sub;&quot;&gt;0&lt;/span&gt;+A&lt;span style=&quot; vertical-align:sub;&quot;&gt;1&lt;/span&gt;*D+A&lt;span style=&quot; vertical-align:sub;&quot;&gt;2&lt;/span&gt;*D&lt;span style=&quot; vertical-align:super;&quot;&gt;2&lt;/span&gt;)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Directional lights</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_4">
<item row="1" column="0" colspan="3">
<layout class="QGridLayout" name="gridLayout_3">
<item row="7" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Intensity</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<layout class="QHBoxLayout" name="directionLightLayout">
<property name="topMargin">
<number>11</number>
</property>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_12">
<property name="text">
<string>Azimuth</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="spinBoxAzimuth">
<property name="suffix">
<string>°</string>
</property>
<property name="maximum">
<double>360.000000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="directionCmpassWidget" native="true"/>
</item>
<item>
<widget class="QDial" name="dialAzimuth">
<property name="minimum">
<number>0</number>
</property>
<property name="value">
<number>0</number>
</property>
<property name="sliderPosition">
<number>0</number>
</property>
<property name="wrapping">
<bool>true</bool>
</property>
<property name="notchTarget">
<double>10.000000000000000</double>
</property>
<property name="notchesVisible">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="altitudeSpinBox">
<property name="text">
<string>Altitude</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="spinBoxAltitude">
<property name="suffix">
<string>°</string>
</property>
<property name="minimum">
<double>-90.000000000000000</double>
</property>
<property name="maximum">
<double>90.000000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="sliderAltitude">
<property name="minimum">
<number>-90</number>
</property>
<property name="maximum">
<number>90</number>
</property>
<property name="tracking">
<bool>true</bool>
</property>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="tickPosition">
<enum>QSlider::NoTicks</enum>
</property>
<property name="tickInterval">
<number>2</number>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="7" column="1">
<widget class="QgsDoubleSpinBox" name="spinDirectionalIntensity">
<property name="decimals">
<number>1</number>
</property>
<property name="maximum">
<double>999999.000000000000000</double>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_16">
<property name="text">
<string>Color</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QgsColorButton" name="btnDirectionalColor">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>120</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Light Direction</string>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QGridLayout" name="gridLayout_5">
<property name="topMargin">
<number>0</number>
</property>
<item row="0" column="2">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Y</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLabel" name="labelY">
<property name="text">
<string>--</string>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Z</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_17">
<property name="text">
<string>X</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="labelX">
<property name="text">
<string>--</string>
</property>
</widget>
</item>
<item row="0" column="5">
<widget class="QLabel" name="labelZ">
<property name="text">
<string>--</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item row="0" column="2">
<widget class="QToolButton" name="btnRemoveDirectionalLight">
<item>
<widget class="QToolButton" name="btnRemoveLight">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="2" column="0">
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
@ -451,16 +57,417 @@
</property>
</spacer>
</item>
<item row="0" column="0">
<widget class="QComboBox" name="cboDirectionalLights"/>
</item>
<item row="0" column="1">
<widget class="QToolButton" name="btnAddDirectionalLight">
</layout>
</item>
</layout>
</item>
<item>
<widget class="QStackedWidget" name="mStackedWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="page_2"/>
<widget class="QWidget" name="page">
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>...</string>
<string>Z</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QgsDoubleSpinBox" name="spinPositionX">
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>-9999999.000000000000000</double>
</property>
<property name="maximum">
<double>9999999.000000000000000</double>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;A&lt;span style=&quot; vertical-align:sub;&quot;&gt;2&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QgsDoubleSpinBox" name="spinIntensity">
<property name="decimals">
<number>1</number>
</property>
<property name="maximum">
<double>999999.000000000000000</double>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;A&lt;span style=&quot; vertical-align:sub;&quot;&gt;0&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="1" column="1" rowspan="2">
<widget class="QgsDoubleSpinBox" name="spinPositionY">
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>-9999999.000000000000000</double>
</property>
<property name="maximum">
<double>9999999.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0" rowspan="2">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Y</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QgsDoubleSpinBox" name="spinPositionZ">
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>-9999999.000000000000000</double>
</property>
<property name="maximum">
<double>9999999.000000000000000</double>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QgsColorButton" name="btnColor">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>120</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QgsDoubleSpinBox" name="spinA0">
<property name="maximum">
<double>9.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QgsDoubleSpinBox" name="spinA1">
<property name="maximum">
<double>9.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QgsDoubleSpinBox" name="spinA2">
<property name="maximum">
<double>9.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Intensity</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;A&lt;span style=&quot; vertical-align:sub;&quot;&gt;1&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Color</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>X</string>
</property>
</widget>
</item>
<item row="6" column="0" colspan="2">
<widget class="QLabel" name="label_6">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Attenuation (A&lt;span style=&quot; vertical-align:sub;&quot;&gt;0&lt;/span&gt;+A&lt;span style=&quot; vertical-align:sub;&quot;&gt;1&lt;/span&gt;&amp;times;D+A&lt;span style=&quot; vertical-align:sub;&quot;&gt;2&lt;/span&gt;&amp;times;D&lt;span style=&quot; vertical-align:super;&quot;&gt;2&lt;/span&gt;)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_3">
<layout class="QGridLayout" name="gridLayout_3">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="7" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Intensity</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<layout class="QHBoxLayout" name="directionLightLayout">
<property name="topMargin">
<number>11</number>
</property>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_12">
<property name="text">
<string>Azimuth</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="spinBoxAzimuth">
<property name="suffix">
<string>°</string>
</property>
<property name="maximum">
<double>360.000000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="directionCmpassWidget" native="true"/>
</item>
<item>
<widget class="QDial" name="dialAzimuth">
<property name="minimum">
<number>0</number>
</property>
<property name="value">
<number>0</number>
</property>
<property name="sliderPosition">
<number>0</number>
</property>
<property name="wrapping">
<bool>true</bool>
</property>
<property name="notchTarget">
<double>10.000000000000000</double>
</property>
<property name="notchesVisible">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="altitudeSpinBox">
<property name="text">
<string>Altitude</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="spinBoxAltitude">
<property name="suffix">
<string>°</string>
</property>
<property name="minimum">
<double>-90.000000000000000</double>
</property>
<property name="maximum">
<double>90.000000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="sliderAltitude">
<property name="minimum">
<number>-90</number>
</property>
<property name="maximum">
<number>90</number>
</property>
<property name="tracking">
<bool>true</bool>
</property>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="tickPosition">
<enum>QSlider::NoTicks</enum>
</property>
<property name="tickInterval">
<number>2</number>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="7" column="1">
<widget class="QgsDoubleSpinBox" name="spinDirectionalIntensity">
<property name="decimals">
<number>1</number>
</property>
<property name="maximum">
<double>999999.000000000000000</double>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_16">
<property name="text">
<string>Color</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QgsColorButton" name="btnDirectionalColor">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>120</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Light Direction</string>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QGridLayout" name="gridLayout_5">
<property name="topMargin">
<number>0</number>
</property>
<item row="0" column="2">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Y</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLabel" name="labelY">
<property name="text">
<string>--</string>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Z</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_17">
<property name="text">
<string>X</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="labelX">
<property name="text">
<string>--</string>
</property>
</widget>
</item>
<item row="0" column="5">
<widget class="QLabel" name="labelZ">
<property name="text">
<string>--</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
@ -481,10 +488,6 @@
</customwidget>
</customwidgets>
<tabstops>
<tabstop>tabWidget</tabstop>
<tabstop>cboLights</tabstop>
<tabstop>btnAddLight</tabstop>
<tabstop>btnRemoveLight</tabstop>
<tabstop>spinPositionX</tabstop>
<tabstop>spinPositionY</tabstop>
<tabstop>spinPositionZ</tabstop>
@ -493,9 +496,6 @@
<tabstop>spinA0</tabstop>
<tabstop>spinA1</tabstop>
<tabstop>spinA2</tabstop>
<tabstop>cboDirectionalLights</tabstop>
<tabstop>btnAddDirectionalLight</tabstop>
<tabstop>btnRemoveDirectionalLight</tabstop>
<tabstop>btnDirectionalColor</tabstop>
<tabstop>spinDirectionalIntensity</tabstop>
</tabstops>