Skip to content

Commit 17382a0

Browse files
committed
3d: Introduce qgs3dsymbolbutton
1 parent 2c66bb2 commit 17382a0

File tree

3 files changed

+243
-0
lines changed

3 files changed

+243
-0
lines changed

src/app/3d/qgs3dsymbolbutton.cpp

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/***************************************************************************
2+
qgs3dsymbolbutton.cpp
3+
--------------------------------------
4+
Date : January 2026
5+
Copyright : (C) 2026 by Jean Felder
6+
Email : jean dot felder at oslandia dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#include "qgs3dsymbolbutton.h"
17+
18+
#include "qgs3dsymbolutils.h"
19+
#include "qgsvectorlayer3drendererwidget.h"
20+
21+
#include <QDialog>
22+
#include <QDialogButtonBox>
23+
#include <QString>
24+
#include <QVBoxLayout>
25+
26+
#include "moc_qgs3dsymbolbutton.cpp"
27+
28+
using namespace Qt::StringLiterals;
29+
30+
Qgs3DSymbolButton::Qgs3DSymbolButton( QWidget *parent )
31+
: QToolButton( parent )
32+
{
33+
connect( this, &QAbstractButton::clicked, this, &Qgs3DSymbolButton::showSettingsDialog );
34+
}
35+
36+
void Qgs3DSymbolButton::setLayer( QgsVectorLayer *layer )
37+
{
38+
mLayer = layer;
39+
}
40+
41+
void Qgs3DSymbolButton::setDialogTitle( const QString &title )
42+
{
43+
mDialogTitle = title;
44+
}
45+
46+
void Qgs3DSymbolButton::setSymbol( std::unique_ptr<QgsAbstract3DSymbol> symbol )
47+
{
48+
mSymbol = std::move( symbol );
49+
50+
const int fontHeight = static_cast<int>( Qgis::UI_SCALE_FACTOR * fontMetrics().height() * 1.4 );
51+
const QSize size = QToolButton::minimumSizeHint();
52+
53+
int symbolBtnHeight;
54+
if ( mSymbol && mSymbol->type() == "point"_L1 )
55+
{
56+
symbolBtnHeight = std::max( size.height(), 3 * fontHeight );
57+
setMaximumWidth( static_cast<int>( 1.5 * symbolBtnHeight ) );
58+
setMinimumWidth( maximumWidth() );
59+
}
60+
else
61+
{
62+
symbolBtnHeight = fontHeight;
63+
setMaximumWidth( 999999 );
64+
}
65+
66+
setMinimumHeight( symbolBtnHeight );
67+
updatePreview();
68+
}
69+
70+
QgsAbstract3DSymbol *Qgs3DSymbolButton::symbol() const
71+
{
72+
return mSymbol.get();
73+
}
74+
75+
void Qgs3DSymbolButton::resizeEvent( QResizeEvent *event )
76+
{
77+
QToolButton::resizeEvent( event );
78+
updatePreview();
79+
}
80+
81+
void Qgs3DSymbolButton::updatePreview()
82+
{
83+
if ( !mSymbol )
84+
{
85+
return;
86+
}
87+
88+
#ifdef Q_OS_WIN
89+
QSize iconSize = QSize( width() - 10, height() - 6 );
90+
#else
91+
QSize iconSize = QSize( width() - 10, height() - 12 );
92+
#endif
93+
94+
const QIcon symbolIcon = Qgs3DSymbolUtils::vectorSymbolPreviewIcon( mSymbol.get(), iconSize, QgsScreenProperties( screen() ), 0 );
95+
setIcon( symbolIcon );
96+
setIconSize( iconSize );
97+
}
98+
99+
void Qgs3DSymbolButton::updateSymbolFromWidget( QgsSingleSymbol3DRendererWidget *widget )
100+
{
101+
setSymbol( widget->symbol() );
102+
emit changed();
103+
}
104+
105+
void Qgs3DSymbolButton::showSettingsDialog()
106+
{
107+
QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( this );
108+
QgsSingleSymbol3DRendererWidget *widget = new QgsSingleSymbol3DRendererWidget( mLayer, this );
109+
widget->setSymbol( mSymbol.get() );
110+
widget->setPanelTitle( mDialogTitle );
111+
if ( panel && panel->dockMode() )
112+
{
113+
widget->setDockMode( true );
114+
connect( widget, &QgsPanelWidget::widgetChanged, this, [this, widget] { updateSymbolFromWidget( widget ); } );
115+
panel->openPanel( widget );
116+
}
117+
else
118+
{
119+
widget->setDockMode( false );
120+
121+
// Show the dialog version if not in a panel
122+
QDialog *dialog = new QDialog( this );
123+
124+
QgsSettings settings;
125+
const QString key = u"/UI/paneldialog/%1"_s.arg( widget->panelTitle() );
126+
dialog->restoreGeometry( settings.value( key ).toByteArray() );
127+
128+
dialog->setWindowTitle( widget->panelTitle() );
129+
dialog->setLayout( new QVBoxLayout() );
130+
131+
dialog->layout()->addWidget( widget );
132+
133+
QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Cancel | QDialogButtonBox::Ok );
134+
connect( buttonBox, &QDialogButtonBox::accepted, dialog, &QDialog::accept );
135+
connect( buttonBox, &QDialogButtonBox::rejected, dialog, &QDialog::reject );
136+
dialog->layout()->addWidget( buttonBox );
137+
138+
if ( dialog->exec() == QDialog::Accepted )
139+
{
140+
updateSymbolFromWidget( widget );
141+
}
142+
settings.setValue( key, dialog->saveGeometry() );
143+
}
144+
}

src/app/3d/qgs3dsymbolbutton.h

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/***************************************************************************
2+
qgs3dsymbolbutton.h
3+
--------------------------------------
4+
Date : January 2026
5+
Copyright : (C) 2026 by Jean Felder
6+
Email : jean dot felder at oslandia dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#ifndef QGS3DSYMBOLBUTTON_H
17+
#define QGS3DSYMBOLBUTTON_H
18+
19+
#include <memory>
20+
21+
#include "qgsabstract3dsymbol.h"
22+
#include "qgsvectorlayer.h"
23+
24+
#include <QToolButton>
25+
26+
class QgsSingleSymbol3DRendererWidget;
27+
28+
29+
/**
30+
* \class Qgs3DSymbolButton
31+
* \brief A push button widget for selecting and displaying a 3D symbol.
32+
* \since QGIS 4.0
33+
*/
34+
class Qgs3DSymbolButton : public QToolButton
35+
{
36+
Q_OBJECT
37+
38+
public:
39+
/**
40+
* Constructor for Qgs3DSymbolButton
41+
*
42+
* \param parent parent widget
43+
*/
44+
Qgs3DSymbolButton( QWidget *parent );
45+
46+
47+
/**
48+
* Sets the button's symbol.
49+
*
50+
* \param symbol 3D symbol to represent
51+
* \see symbol()
52+
*/
53+
void setSymbol( std::unique_ptr<QgsAbstract3DSymbol> symbol );
54+
55+
/**
56+
* Returns the current symbol defined by the button.
57+
* \see setSymbol()
58+
*/
59+
QgsAbstract3DSymbol *symbol() const;
60+
61+
/**
62+
* Sets a \a layer to associate with the widget. This allows the
63+
* widget to setup layer related settings within the symbol settings dialog.
64+
*
65+
* \param layer layer to associate. Ownership of \a layer is not transferred.
66+
*/
67+
void setLayer( QgsVectorLayer *layer );
68+
69+
/**
70+
* Sets the \a title for the symbol settings dialog window.
71+
*
72+
* \param title dialog title
73+
*/
74+
void setDialogTitle( const QString &title );
75+
76+
signals:
77+
/**
78+
* Emitted when the symbol's settings are changed.
79+
*/
80+
void changed();
81+
82+
protected:
83+
void resizeEvent( QResizeEvent *event ) override;
84+
85+
private slots:
86+
void showSettingsDialog();
87+
void updateSymbolFromWidget( QgsSingleSymbol3DRendererWidget *widget );
88+
89+
private:
90+
void updatePreview();
91+
92+
private:
93+
std::unique_ptr<QgsAbstract3DSymbol> mSymbol = nullptr;
94+
QPointer<QgsVectorLayer> mLayer;
95+
QString mDialogTitle;
96+
};
97+
98+
#endif // QGS3DSYMBOLBUTTON_H

src/app/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,7 @@ if (WITH_3D)
381381
3d/qgsphongmaterialwidget.cpp
382382
3d/qgsphongtexturedmaterialwidget.cpp
383383
3d/qgsrulebased3drendererwidget.cpp
384+
3d/qgs3dsymbolbutton.cpp
384385
3d/qgssimplelinematerialwidget.cpp
385386
3d/qgssymbol3dwidget.cpp
386387
3d/qgstiledscenelayer3drendererwidget.cpp

0 commit comments

Comments
 (0)