mirror of
https://github.com/qgis/QGIS.git
synced 2025-12-24 00:05:18 -05:00
Allow adding/editing 3d symbols in style manager dialog
This commit is contained in:
parent
ae3f2c319c
commit
d8e44539f1
@ -40,6 +40,40 @@ Caller takes ownership of the returned symbol.
|
||||
%End
|
||||
};
|
||||
|
||||
|
||||
|
||||
class Qgs3DSymbolDialog : QDialog
|
||||
{
|
||||
%Docstring
|
||||
A dialog for configuring a 3D symbol.
|
||||
|
||||
.. versionadded:: 3.16
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgs3dsymbolwidget.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
Qgs3DSymbolDialog( const QgsAbstract3DSymbol *symbol, QWidget *parent /TransferThis/ = 0 );
|
||||
%Docstring
|
||||
Constructor for Qgs3DSymbolDialog, initially showing the specified ``symbol``.
|
||||
%End
|
||||
|
||||
QgsAbstract3DSymbol *symbol() const /Factory/;
|
||||
%Docstring
|
||||
Returns a new instance of the symbol defined by the dialog.
|
||||
|
||||
Caller takes ownership of the returned symbol.
|
||||
%End
|
||||
|
||||
QDialogButtonBox *buttonBox() const;
|
||||
%Docstring
|
||||
Returns a reference to the dialog's button box.
|
||||
%End
|
||||
|
||||
};
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
|
||||
@ -14,7 +14,47 @@
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgs3dsymbolwidget.h"
|
||||
#include "qgsapplication.h"
|
||||
#include "qgs3dsymbolregistry.h"
|
||||
#include "qgsabstract3dsymbol.h"
|
||||
#include "qgsgui.h"
|
||||
#include <QVBoxLayout>
|
||||
#include <QDialogButtonBox>
|
||||
|
||||
Qgs3DSymbolWidget::Qgs3DSymbolWidget( QWidget *parent )
|
||||
: QWidget( parent )
|
||||
{}
|
||||
|
||||
Qgs3DSymbolDialog::Qgs3DSymbolDialog( const QgsAbstract3DSymbol *symbol, QWidget *parent )
|
||||
: QDialog( parent )
|
||||
{
|
||||
Q_ASSERT( symbol );
|
||||
|
||||
QgsGui::enableAutoGeometryRestore( this );
|
||||
|
||||
QVBoxLayout *vLayout = new QVBoxLayout();
|
||||
|
||||
if ( Qgs3DSymbolAbstractMetadata *metadata = QgsApplication::symbol3DRegistry()->symbolMetadata( symbol->type() ) )
|
||||
{
|
||||
mWidget = metadata->createSymbolWidget( nullptr );
|
||||
vLayout->addWidget( mWidget );
|
||||
mWidget->setSymbol( symbol, nullptr );
|
||||
}
|
||||
|
||||
mButtonBox = new QDialogButtonBox( QDialogButtonBox::Cancel | QDialogButtonBox::Ok, Qt::Horizontal );
|
||||
connect( mButtonBox, &QDialogButtonBox::accepted, this, &QDialog::accept );
|
||||
connect( mButtonBox, &QDialogButtonBox::rejected, this, &QDialog::reject );
|
||||
vLayout->addWidget( mButtonBox );
|
||||
setLayout( vLayout );
|
||||
setWindowTitle( tr( "3D Symbol" ) );
|
||||
}
|
||||
|
||||
QgsAbstract3DSymbol *Qgs3DSymbolDialog::symbol() const
|
||||
{
|
||||
return mWidget ? mWidget->symbol() : nullptr;
|
||||
}
|
||||
|
||||
QDialogButtonBox *Qgs3DSymbolDialog::buttonBox() const
|
||||
{
|
||||
return mButtonBox;
|
||||
}
|
||||
|
||||
@ -17,11 +17,13 @@
|
||||
#define QGS3DSYMBOLWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QDialog>
|
||||
#include "qgis_gui.h"
|
||||
#include "qgis_sip.h"
|
||||
|
||||
class QgsAbstract3DSymbol;
|
||||
class QgsVectorLayer;
|
||||
class QDialogButtonBox;
|
||||
|
||||
/**
|
||||
* \ingroup gui
|
||||
@ -53,4 +55,41 @@ class GUI_EXPORT Qgs3DSymbolWidget : public QWidget
|
||||
virtual QgsAbstract3DSymbol *symbol() = 0 SIP_FACTORY;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* \ingroup gui
|
||||
* \brief A dialog for configuring a 3D symbol.
|
||||
* \since QGIS 3.16
|
||||
*/
|
||||
class GUI_EXPORT Qgs3DSymbolDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for Qgs3DSymbolDialog, initially showing the specified \a symbol.
|
||||
*/
|
||||
Qgs3DSymbolDialog( const QgsAbstract3DSymbol *symbol, QWidget *parent SIP_TRANSFERTHIS = nullptr );
|
||||
|
||||
/**
|
||||
* Returns a new instance of the symbol defined by the dialog.
|
||||
*
|
||||
* Caller takes ownership of the returned symbol.
|
||||
*/
|
||||
QgsAbstract3DSymbol *symbol() const SIP_FACTORY;
|
||||
|
||||
/**
|
||||
* Returns a reference to the dialog's button box.
|
||||
*/
|
||||
QDialogButtonBox *buttonBox() const;
|
||||
|
||||
private:
|
||||
|
||||
Qgs3DSymbolWidget *mWidget = nullptr;
|
||||
QDialogButtonBox *mButtonBox = nullptr;
|
||||
|
||||
};
|
||||
|
||||
#endif // QGS3DSYMBOLWIDGET_H
|
||||
|
||||
@ -35,6 +35,8 @@
|
||||
#include "qgslabelinggui.h"
|
||||
#include "qgslegendpatchshapewidget.h"
|
||||
#include "qgsabstract3dsymbol.h"
|
||||
#include "qgs3dsymbolregistry.h"
|
||||
#include "qgs3dsymbolwidget.h"
|
||||
#include <QAction>
|
||||
#include <QFile>
|
||||
#include <QFileDialog>
|
||||
@ -332,6 +334,7 @@ QgsStyleManagerDialog::QgsStyleManagerDialog( QgsStyle *style, QWidget *parent,
|
||||
mMenuBtnAddItemColorRamp = new QMenu( this );
|
||||
mMenuBtnAddItemLabelSettings = new QMenu( this );
|
||||
mMenuBtnAddItemLegendPatchShape = new QMenu( this );
|
||||
mMenuBtnAddItemSymbol3D = new QMenu( this );
|
||||
|
||||
QAction *item = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "mIconPointLayer.svg" ) ), tr( "Marker…" ), this );
|
||||
connect( item, &QAction::triggered, this, [ = ]( bool ) { addSymbol( QgsSymbol::Marker ); } );
|
||||
@ -382,6 +385,20 @@ QgsStyleManagerDialog::QgsStyleManagerDialog( QgsStyle *style, QWidget *parent,
|
||||
mMenuBtnAddItemAll->addAction( item );
|
||||
mMenuBtnAddItemLegendPatchShape->addAction( item );
|
||||
|
||||
mMenuBtnAddItemAll->addSeparator();
|
||||
item = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "3d.svg" ) ), tr( "3D Point Symbol…" ), this );
|
||||
connect( item, &QAction::triggered, this, [ = ]( bool ) { addSymbol3D( QStringLiteral( "point" ) ); } );
|
||||
mMenuBtnAddItemAll->addAction( item );
|
||||
mMenuBtnAddItemSymbol3D->addAction( item );
|
||||
item = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "3d.svg" ) ), tr( "3D Line Symbol…" ), this );
|
||||
connect( item, &QAction::triggered, this, [ = ]( bool ) { addSymbol3D( QStringLiteral( "line" ) ); } );
|
||||
mMenuBtnAddItemAll->addAction( item );
|
||||
mMenuBtnAddItemSymbol3D->addAction( item );
|
||||
item = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "3d.svg" ) ), tr( "3D Polygon Symbol…" ), this );
|
||||
connect( item, &QAction::triggered, this, [ = ]( bool ) { addSymbol3D( QStringLiteral( "polygon" ) ); } );
|
||||
mMenuBtnAddItemAll->addAction( item );
|
||||
mMenuBtnAddItemSymbol3D->addAction( item );
|
||||
|
||||
connect( mMenuBtnAddItemColorRamp, &QMenu::triggered,
|
||||
this, static_cast<bool ( QgsStyleManagerDialog::* )( QAction * )>( &QgsStyleManagerDialog::addColorRamp ) );
|
||||
}
|
||||
@ -501,23 +518,30 @@ void QgsStyleManagerDialog::populateTypes()
|
||||
void QgsStyleManagerDialog::tabItemType_currentChanged( int )
|
||||
{
|
||||
// when in Color Ramp tab, add menu to add item button and hide "Export symbols as PNG/SVG"
|
||||
const bool isSymbol = currentItemType() != 3 && currentItemType() != 4 && currentItemType() != 5 && currentItemType() != 6;
|
||||
const bool isSymbol = currentItemType() != 3 && currentItemType() != 4 && currentItemType() != 5 && currentItemType() != 6 && currentItemType() != 7;
|
||||
const bool isColorRamp = currentItemType() == 3;
|
||||
const bool isTextFormat = currentItemType() == 4;
|
||||
const bool isLabelSettings = currentItemType() == 5;
|
||||
const bool isLegendPatchShape = currentItemType() == 6;
|
||||
const bool isSymbol3D = currentItemType() == 7;
|
||||
searchBox->setPlaceholderText( isSymbol ? tr( "Filter symbols…" ) :
|
||||
isColorRamp ? tr( "Filter color ramps…" ) :
|
||||
isTextFormat ? tr( "Filter text symbols…" ) :
|
||||
isLabelSettings ? tr( "Filter label settings…" ) : tr( "Filter legend patch shapes…" ) );
|
||||
isLabelSettings ? tr( "Filter label settings…" ) :
|
||||
isLegendPatchShape ? tr( "Filter legend patch shapes…" ) : tr( "Filter 3D symbols…" ) );
|
||||
|
||||
if ( !mReadOnly && isColorRamp ) // color ramp tab
|
||||
{
|
||||
btnAddItem->setMenu( mMenuBtnAddItemColorRamp );
|
||||
}
|
||||
if ( !mReadOnly && !isSymbol && !isColorRamp && !isTextFormat && !isLabelSettings ) // legend patch shape tab
|
||||
if ( !mReadOnly && isLegendPatchShape ) // legend patch shape tab
|
||||
{
|
||||
btnAddItem->setMenu( mMenuBtnAddItemLegendPatchShape );
|
||||
}
|
||||
else if ( !mReadOnly && isSymbol3D ) // legend patch shape tab
|
||||
{
|
||||
btnAddItem->setMenu( mMenuBtnAddItemSymbol3D );
|
||||
}
|
||||
else if ( !mReadOnly && isLabelSettings ) // label settings tab
|
||||
{
|
||||
btnAddItem->setMenu( mMenuBtnAddItemLabelSettings );
|
||||
@ -538,7 +562,7 @@ void QgsStyleManagerDialog::tabItemType_currentChanged( int )
|
||||
actnExportAsPNG->setVisible( isSymbol );
|
||||
actnExportAsSVG->setVisible( isSymbol );
|
||||
|
||||
mModel->setEntityFilter( isSymbol ? QgsStyle::SymbolEntity : ( isColorRamp ? QgsStyle::ColorrampEntity : isTextFormat ? QgsStyle::TextFormatEntity : isLabelSettings ? QgsStyle::LabelSettingsEntity : QgsStyle::LegendPatchShapeEntity ) );
|
||||
mModel->setEntityFilter( isSymbol ? QgsStyle::SymbolEntity : ( isColorRamp ? QgsStyle::ColorrampEntity : isTextFormat ? QgsStyle::TextFormatEntity : isLabelSettings ? QgsStyle::LabelSettingsEntity : isLegendPatchShape ? QgsStyle::LegendPatchShapeEntity : QgsStyle::Symbol3DEntity ) );
|
||||
mModel->setEntityFilterEnabled( !allTypesSelected() );
|
||||
mModel->setSymbolTypeFilterEnabled( isSymbol && !allTypesSelected() );
|
||||
if ( isSymbol && !allTypesSelected() )
|
||||
@ -701,6 +725,8 @@ int QgsStyleManagerDialog::selectedItemType()
|
||||
return 5;
|
||||
else if ( entity == QgsStyle::LegendPatchShapeEntity )
|
||||
return 6;
|
||||
else if ( entity == QgsStyle::Symbol3DEntity )
|
||||
return 7;
|
||||
|
||||
return mModel->data( index, QgsStyleModel::SymbolTypeRole ).toInt();
|
||||
}
|
||||
@ -742,6 +768,7 @@ int QgsStyleManagerDialog::copyItems( const QList<QgsStyleManagerDialog::ItemDet
|
||||
const QStringList favoriteTextFormats = src->symbolsOfFavorite( QgsStyle::TextFormatEntity );
|
||||
const QStringList favoriteLabelSettings = src->symbolsOfFavorite( QgsStyle::LabelSettingsEntity );
|
||||
const QStringList favoriteLegendPatchShapes = src->symbolsOfFavorite( QgsStyle::LegendPatchShapeEntity );
|
||||
const QStringList favorite3dSymbols = src->symbolsOfFavorite( QgsStyle::Symbol3DEntity );
|
||||
|
||||
for ( auto &details : items )
|
||||
{
|
||||
@ -1025,7 +1052,7 @@ int QgsStyleManagerDialog::copyItems( const QList<QgsStyleManagerDialog::ItemDet
|
||||
const bool hasDuplicateName = dst->symbol3DNames().contains( details.name );
|
||||
bool overwriteThis = false;
|
||||
if ( isImport )
|
||||
addItemToFavorites = favoriteSymbols.contains( details.name );
|
||||
addItemToFavorites = favorite3dSymbols.contains( details.name );
|
||||
|
||||
if ( hasDuplicateName && prompt )
|
||||
{
|
||||
@ -1172,6 +1199,8 @@ int QgsStyleManagerDialog::currentItemType()
|
||||
return 5;
|
||||
case 7:
|
||||
return 6;
|
||||
case 8:
|
||||
return 7;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -1211,6 +1240,11 @@ void QgsStyleManagerDialog::addItem()
|
||||
// actually never hit, because we present a submenu when adding legend patches
|
||||
// changed = addLegendPatchShape();
|
||||
}
|
||||
else if ( currentItemType() == 7 )
|
||||
{
|
||||
// actually never hit, because we present a submenu when adding 3d symbols
|
||||
// changed = addSymbol3D();
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_ASSERT( false && "not implemented" );
|
||||
@ -1526,6 +1560,10 @@ void QgsStyleManagerDialog::editItem()
|
||||
{
|
||||
editLegendPatchShape();
|
||||
}
|
||||
else if ( selectedItemType() == 7 )
|
||||
{
|
||||
editSymbol3D();
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_ASSERT( false && "not implemented" );
|
||||
@ -1847,6 +1885,104 @@ bool QgsStyleManagerDialog::editLegendPatchShape()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QgsStyleManagerDialog::addSymbol3D( const QString &type )
|
||||
{
|
||||
std::unique_ptr< QgsAbstract3DSymbol > symbol( QgsApplication::symbol3DRegistry()->createSymbol( type ) );
|
||||
if ( !symbol )
|
||||
return false;
|
||||
|
||||
Qgs3DSymbolDialog dialog( symbol.get(), this );
|
||||
if ( mReadOnly )
|
||||
dialog.buttonBox()->button( QDialogButtonBox::Ok )->setEnabled( false );
|
||||
|
||||
if ( !dialog.exec() )
|
||||
return false;
|
||||
|
||||
symbol.reset( dialog.symbol() );
|
||||
if ( !symbol )
|
||||
return false;
|
||||
|
||||
QgsStyleSaveDialog saveDlg( this, QgsStyle::Symbol3DEntity );
|
||||
if ( !saveDlg.exec() )
|
||||
return false;
|
||||
QString name = saveDlg.name();
|
||||
|
||||
// request valid/unique name
|
||||
bool nameInvalid = true;
|
||||
while ( nameInvalid )
|
||||
{
|
||||
// validate name
|
||||
if ( name.isEmpty() )
|
||||
{
|
||||
QMessageBox::warning( this, tr( "Save 3D Symbol" ),
|
||||
tr( "Cannot save 3d symbols without a name. Enter a name." ) );
|
||||
}
|
||||
else if ( mStyle->symbol3DNames().contains( name ) )
|
||||
{
|
||||
int res = QMessageBox::warning( this, tr( "Save 3D Symbol" ),
|
||||
tr( "A 3D symbol with the name '%1' already exists. Overwrite?" )
|
||||
.arg( name ),
|
||||
QMessageBox::Yes | QMessageBox::No );
|
||||
if ( res == QMessageBox::Yes )
|
||||
{
|
||||
mStyle->removeEntityByName( QgsStyle::Symbol3DEntity, name );
|
||||
nameInvalid = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// valid name
|
||||
nameInvalid = false;
|
||||
}
|
||||
if ( nameInvalid )
|
||||
{
|
||||
bool ok;
|
||||
name = QInputDialog::getText( this, tr( "3D Symbol Name" ),
|
||||
tr( "Please enter a name for the new 3D symbol:" ),
|
||||
QLineEdit::Normal, name, &ok );
|
||||
if ( !ok )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QStringList symbolTags = saveDlg.tags().split( ',' );
|
||||
|
||||
// add new shape to style and re-populate the list
|
||||
QgsAbstract3DSymbol *newSymbol = symbol.get();
|
||||
mStyle->addSymbol3D( name, symbol.release() );
|
||||
mStyle->saveSymbol3D( name, newSymbol, saveDlg.isFavorite(), symbolTags );
|
||||
|
||||
mModified = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QgsStyleManagerDialog::editSymbol3D()
|
||||
{
|
||||
const QString symbolName = currentItemName();
|
||||
if ( symbolName.isEmpty() )
|
||||
return false;
|
||||
|
||||
std::unique_ptr< QgsAbstract3DSymbol > symbol( mStyle->symbol3D( symbolName ) );
|
||||
if ( !symbol )
|
||||
return false;
|
||||
|
||||
// let the user edit the symbol and update list when done
|
||||
Qgs3DSymbolDialog dlg( symbol.get(), this );
|
||||
if ( !dlg.exec() )
|
||||
return false;
|
||||
|
||||
symbol.reset( dlg.symbol() );
|
||||
if ( !symbol )
|
||||
return false;
|
||||
|
||||
// by adding symbol to style with the same name the old effectively gets overwritten
|
||||
mStyle->addSymbol3D( symbolName, symbol.release(), true );
|
||||
mModified = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void QgsStyleManagerDialog::removeItem()
|
||||
{
|
||||
const QList< ItemDetails > items = selectedItems();
|
||||
@ -1901,6 +2037,14 @@ void QgsStyleManagerDialog::removeItem()
|
||||
QMessageBox::No ) )
|
||||
return;
|
||||
}
|
||||
else if ( currentItemType() == 7 )
|
||||
{
|
||||
if ( QMessageBox::Yes != QMessageBox::question( this, tr( "Remove 3D Symbols" ),
|
||||
QString( tr( "Do you really want to remove %n 3D symbols?", nullptr, items.count() ) ),
|
||||
QMessageBox::Yes,
|
||||
QMessageBox::No ) )
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
QgsTemporaryCursorOverride override( Qt::WaitCursor );
|
||||
|
||||
@ -397,6 +397,9 @@ class GUI_EXPORT QgsStyleManagerDialog : public QDialog, private Ui::QgsStyleMan
|
||||
//! Menu for the "Add item" toolbutton when in legend patch shape mode
|
||||
QMenu *mMenuBtnAddItemLegendPatchShape = nullptr;
|
||||
|
||||
//! Menu for the "Add item" toolbutton when in 3d symbol mode
|
||||
QMenu *mMenuBtnAddItemSymbol3D = nullptr;
|
||||
|
||||
QAction *mActionCopyToDefault = nullptr;
|
||||
|
||||
QAction *mActionCopyItem = nullptr;
|
||||
@ -418,6 +421,9 @@ class GUI_EXPORT QgsStyleManagerDialog : public QDialog, private Ui::QgsStyleMan
|
||||
bool addLegendPatchShape( QgsSymbol::SymbolType type );
|
||||
bool editLegendPatchShape();
|
||||
|
||||
bool addSymbol3D( const QString &type );
|
||||
bool editSymbol3D();
|
||||
|
||||
friend class QgsStyleExportImportDialog;
|
||||
};
|
||||
|
||||
|
||||
@ -382,6 +382,15 @@
|
||||
<string>Legend Patch Shapes</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab3DSymbols">
|
||||
<attribute name="icon">
|
||||
<iconset resource="../../images/images.qrc">
|
||||
<normaloff>:/images/themes/default/3d.svg</normaloff>:/images/themes/default/3d.svg</iconset>
|
||||
</attribute>
|
||||
<attribute name="title">
|
||||
<string>3D Symbols</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@ -669,8 +678,6 @@
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="../../images/images.qrc"/>
|
||||
<include location="../../images/images.qrc"/>
|
||||
<include location="../../images/images.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user