From 4cf0ddbbf8f04e4283a2f407b01b8bec2e83e6f8 Mon Sep 17 00:00:00 2001 From: erysdren Date: Wed, 11 Mar 2026 22:57:31 -0500 Subject: [PATCH 1/2] surfacedialog: wip --- radiant/surfacedialog.cpp | 244 ++++++++++++++++++++++++++++++++++++-- radiant/surfacedialog.h | 3 +- radiant/texwindow.cpp | 16 ++- 3 files changed, 249 insertions(+), 14 deletions(-) diff --git a/radiant/surfacedialog.cpp b/radiant/surfacedialog.cpp index f7ece4e7..9828c839 100644 --- a/radiant/surfacedialog.cpp +++ b/radiant/surfacedialog.cpp @@ -43,6 +43,8 @@ #include #include #include +#include +#include #include "signal/isignal.h" #include "math/vector.h" @@ -72,8 +74,153 @@ #include "commands.h" #include "stream/stringstream.h" #include "grid.h" +#include "groupdialog.h" #include "textureentry.h" +//====== +// erysdren: copied from dialog.cpp +namespace { +template< + typename Type_, + typename Other_, + void( *Import ) ( Type_&, Other_ ), + void( *Export ) ( Type_&, const Callback& ) + > +class ImportExport +{ +public: + typedef Type_ Type; + typedef Other_ Other; + + typedef ReferenceCaller ImportCaller; + typedef ReferenceCaller&), Export> ExportCaller; +}; + +typedef ImportExport BoolImportExport; +typedef ImportExport IntImportExport; +typedef ImportExport SizeImportExport; +typedef ImportExport FloatImportExport; +typedef ImportExport StringImportExport; + +void BoolToggleImport( QCheckBox& widget, bool value ){ + widget.setChecked( value ); +} +void BoolToggleExport( QCheckBox& widget, const BoolImportCallback& importCallback ){ + importCallback( widget.isChecked() ); +} +typedef ImportExport BoolToggleImportExport; + + +void IntRadioImport( QButtonGroup& widget, int index ){ + widget.button( index )->setChecked( true ); +} +void IntRadioExport( QButtonGroup& widget, const IntImportCallback& importCallback ){ + importCallback( widget.checkedId() ); +} +typedef ImportExport IntRadioImportExport; + + +void TextEntryImport( QLineEdit& widget, const char* text ){ + widget.setText( text ); +} +void TextEntryExport( QLineEdit& widget, const StringImportCallback& importCallback ){ + importCallback( widget.text().toLatin1().constData() ); +} +typedef ImportExport TextEntryImportExport; + + +void FloatSpinnerImport( QDoubleSpinBox& widget, float value ){ + widget.setValue( value ); +} +void FloatSpinnerExport( QDoubleSpinBox& widget, const FloatImportCallback& importCallback ){ + importCallback( widget.value() ); +} +typedef ImportExport FloatSpinnerImportExport; + + +void IntSpinnerImport( QSpinBox& widget, int value ){ + widget.setValue( value ); +} +void IntSpinnerExport( QSpinBox& widget, const IntImportCallback& importCallback ){ + importCallback( widget.value() ); +} +typedef ImportExport IntSpinnerImportExport; + + +void IntSliderImport( QSlider& widget, int value ){ + widget.setValue( value ); +} +void IntSliderExport( QSlider& widget, const IntImportCallback& importCallback ){ + importCallback( widget.value() ); +} +typedef ImportExport IntSliderImportExport; + +// QSlider operates on int values only, so using 10x range for floats +void FloatSliderImport( QSlider& widget, float value ){ + widget.setValue( value * 10.0 ); +} +void FloatSliderExport( QSlider& widget, const FloatImportCallback& importCallback ){ + importCallback( widget.value() / 10.0 ); +} +typedef ImportExport FloatSliderImportExport; + + +void IntComboImport( QComboBox& widget, int value ){ + widget.setCurrentIndex( value ); +} +void IntComboExport( QComboBox& widget, const IntImportCallback& importCallback ){ + importCallback( widget.currentIndex() ); +} +typedef ImportExport IntComboImportExport; + +template +class CallbackDialogData final : public DLG_DATA +{ +public: + typedef Callback ImportCallback; + typedef Callback ExportCallback; + +private: + ImportCallback m_importWidget; + ExportCallback m_exportWidget; + ImportCallback m_importViewer; + ExportCallback m_exportViewer; + +public: + CallbackDialogData( const ImportCallback& importWidget, const ExportCallback& exportWidget, const ImportCallback& importViewer, const ExportCallback& exportViewer ) + : m_importWidget( importWidget ), m_exportWidget( exportWidget ), m_importViewer( importViewer ), m_exportViewer( exportViewer ){ + } + void release() override{ + delete this; + } + void importData() const override { + m_exportViewer( m_importWidget ); + } + void exportData() const override { + m_exportWidget( m_importViewer ); + } +}; + +template +class AddData +{ + DialogDataList& m_data; +public: + AddData( DialogDataList& data ) : m_data( data ){ + } + void apply( typename Widget::Type& widget, typename Viewer::Type& viewer ) const { + m_data.push_back( + new CallbackDialogData( + typename Widget::ImportCaller( widget ), + typename Widget::ExportCaller( widget ), + typename Viewer::ImportCaller( viewer ), + typename Viewer::ExportCaller( viewer ) + ) + ); + } +}; +} +//====== class Increment { @@ -96,9 +243,13 @@ class Increment void SurfaceInspector_GridChange(); -class SurfaceInspector : public Dialog +class SurfaceInspector { - void BuildDialog() override; + QWidget* m_window{}; + + DialogDataList m_data; + + QWidget* BuildDialog(); NonModalEntry *m_textureEntry; @@ -133,12 +284,20 @@ class SurfaceInspector : public Dialog m_fitHorizontal = 1; } - void constructWindow( QWidget* main_window ){ - Create( main_window ); + ~SurfaceInspector(){ + for ( auto *data : m_data ) + { + data->release(); + } + } + + QWidget* constructWindow( QWidget* main_window ){ + m_window = new QWidget; AddGridChangeCallback( FreeCaller() ); + return BuildDialog(); } void destroyWindow(){ - Destroy(); + // Destroy(); } bool visible() const { return GetWidget()->isVisible(); @@ -149,6 +308,27 @@ class SurfaceInspector : public Dialog } } + QWidget* GetWidget(){ + return m_window; + } + const QWidget* GetWidget() const { + return m_window; + } + + void exportData(){ + for ( const auto *data : m_data ) + { + data->exportData(); + } + } + + void importData(){ + for ( const auto *data : m_data ) + { + data->importData(); + } + } + void Update(); typedef MemberCaller UpdateCaller; void ApplyShader(); @@ -171,8 +351,35 @@ class SurfaceInspector : public Dialog void ApplyFlags(); typedef MemberCaller ApplyFlagsCaller; + + void AddDialogData( QCheckBox& widget, bool& data ){ + AddData( m_data ).apply( widget, data ); + } + void AddDialogData( QButtonGroup& widget, int& data ){ + AddData( m_data ).apply( widget, data ); + } + void AddDialogData( QLineEdit& widget, CopiedString& data ){ + AddData( m_data ).apply( widget, data ); + } + void AddDialogData( QDoubleSpinBox& widget, float& data ){ + AddData( m_data ).apply( widget, data ); + } + void AddDialogData( QSpinBox& widget, int& data ){ + AddData( m_data ).apply( widget, data ); + } + void AddDialogData( QSlider& widget, int& data ){ + AddData( m_data ).apply( widget, data ); + } + void AddDialogData( QSlider& widget, float& data ){ + AddData( m_data ).apply( widget, data ); + } + void AddDialogData( QComboBox& widget, int& data ){ + AddData( m_data ).apply( widget, data ); + } }; +QWidget* g_page_surface; + namespace { SurfaceInspector* g_SurfaceInspector; @@ -183,8 +390,14 @@ inline SurfaceInspector& getSurfaceInspector(){ } } -void SurfaceInspector_constructWindow( QWidget* main_window ){ - getSurfaceInspector().constructWindow( main_window ); +void SurfaceInspector_toggleShow(){ + GroupDialog_showPage( g_page_surface ); + getSurfaceInspector().Update(); + getSurfaceInspector().importData(); +} + +QWidget* SurfaceInspector_constructWindow( QWidget* main_window ){ + return getSurfaceInspector().constructWindow( main_window ); } void SurfaceInspector_destroyWindow(){ getSurfaceInspector().destroyWindow(); @@ -338,6 +551,7 @@ static void OnBtnMatchGrid(){ DoSnapTToGrid( hscale, vscale ); } +#if 0 // DoSurface will always try to show the surface inspector // or update it because something new has been selected // Shamus: It does get called when the SI is hidden, but not when you select something new. ;-) @@ -356,6 +570,7 @@ void SurfaceInspector_toggleShown(){ DoSurface(); } } +#endif #include "camwindow.h" @@ -640,10 +855,10 @@ g_pressedKeysFilter; // ============================================================================= // SurfaceInspector class -void SurfaceInspector::BuildDialog(){ +QWidget* SurfaceInspector::BuildDialog(){ GetWidget()->setWindowTitle( "Surface Inspector" ); - g_guiSettings.addWindow( GetWidget(), "SurfaceInspector/geometry", 99, 99 ); + // g_guiSettings.addWindow( GetWidget(), "SurfaceInspector/geometry", 99, 99 ); GetWidget()->installEventFilter( &g_pressedKeysFilter ); @@ -868,11 +1083,13 @@ void SurfaceInspector::BuildDialog(){ box->addWidget( container ); auto *grid = new QGridLayout( container ); - // QObject::connect( frame, &QGroupBox::clicked, container, &QWidget::setVisible ); + QObject::connect( frame, &QGroupBox::clicked, container, &QWidget::setVisible ); +#if 0 QObject::connect( frame, &QGroupBox::clicked, [container, wnd = GetWidget()]( bool checked ){ container->setVisible( checked ); QTimer::singleShot( 0, [wnd](){ wnd->adjustSize(); wnd->resize( 99, 99 ); } ); } ); +#endif container->setVisible( false ); { QCheckBox** p = m_surfaceFlags; @@ -901,10 +1118,13 @@ void SurfaceInspector::BuildDialog(){ box->addWidget( container ); auto *grid = new QGridLayout( container ); + QObject::connect( frame, &QGroupBox::clicked, container, &QWidget::setVisible ); +#if 0 QObject::connect( frame, &QGroupBox::clicked, [container, wnd = GetWidget()]( bool checked ){ container->setVisible( checked ); QTimer::singleShot( 0, [wnd](){ wnd->adjustSize(); wnd->resize( 99, 99 ); } ); } ); +#endif container->setVisible( false ); { QCheckBox** p = m_contentFlags; @@ -943,6 +1163,8 @@ void SurfaceInspector::BuildDialog(){ } vbox->addStretch( 1 ); } + + return GetWidget(); } /* @@ -1791,7 +2013,7 @@ void SurfaceInspector_registerCommands(){ GlobalCommands_insert( "TextureProjectAxial", makeCallbackF( SurfaceInspector_ProjectTexture_eProjectAxial ) ); GlobalCommands_insert( "TextureProjectOrtho", makeCallbackF( SurfaceInspector_ProjectTexture_eProjectOrtho ) ); GlobalCommands_insert( "TextureProjectCam", makeCallbackF( SurfaceInspector_ProjectTexture_eProjectCam ) ); - GlobalCommands_insert( "SurfaceInspector", makeCallbackF( SurfaceInspector_toggleShown ), QKeySequence( "S" ) ); + GlobalCommands_insert( "SurfaceInspector", makeCallbackF( SurfaceInspector_toggleShow ), QKeySequence( "S" ) ); // GlobalCommands_insert( "FaceCopyTexture", makeCallbackF( SelectedFaces_copyTexture ) ); // GlobalCommands_insert( "FacePasteTexture", makeCallbackF( SelectedFaces_pasteTexture ) ); diff --git a/radiant/surfacedialog.h b/radiant/surfacedialog.h index db4f0a40..6fc3e931 100644 --- a/radiant/surfacedialog.h +++ b/radiant/surfacedialog.h @@ -21,11 +21,10 @@ #pragma once - void SurfaceInspector_Construct(); void SurfaceInspector_Destroy(); -void SurfaceInspector_constructWindow( class QWidget* widget ); +class QWidget* SurfaceInspector_constructWindow( class QWidget* widget ); void SurfaceInspector_destroyWindow(); bool SelectedFaces_empty(); diff --git a/radiant/texwindow.cpp b/radiant/texwindow.cpp index e84f0254..58ad2c65 100644 --- a/radiant/texwindow.cpp +++ b/radiant/texwindow.cpp @@ -86,6 +86,8 @@ #include "preferences.h" #include "commands.h" +#include "surfacedialog.h" + bool string_equal_start( const char* string, StringRange start ){ return string_equal_n( string, start.data(), start.size() ); } @@ -160,6 +162,7 @@ class TextureBrowser CopiedString m_shader; // current shader QWidget* m_parent; + QWidget* m_surfacedialog; QOpenGLWidget* m_gl_widget; QScrollBar* m_texture_scroll; QTabWidget* m_tabs; @@ -1767,11 +1770,14 @@ QWidget* TextureBrowser_constructWindow( QWidget* toplevel ){ g_TexBro.m_parent = toplevel; + g_TexBro.m_surfacedialog = SurfaceInspector_constructWindow( toplevel ); + auto *splitter = new QSplitter; auto *containerWidgetLeft = new QWidget; // Adding a QLayout to a QSplitter is not supported, use proxy widget auto *containerWidgetRight = new QWidget; // Adding a QLayout to a QSplitter is not supported, use proxy widget splitter->addWidget( containerWidgetLeft ); splitter->addWidget( containerWidgetRight ); + splitter->setChildrenCollapsible( false ); auto *vbox = new QVBoxLayout( containerWidgetLeft ); auto *hbox = new QHBoxLayout( containerWidgetRight ); @@ -1780,6 +1786,13 @@ QWidget* TextureBrowser_constructWindow( QWidget* toplevel ){ hbox->setSpacing( 0 ); vbox->setSpacing( 0 ); + auto* splitter2 = new QSplitter; + splitter2->setOrientation(Qt::Vertical); + splitter2->addWidget( g_TexBro.m_surfacedialog ); + splitter2->addWidget( splitter ); + splitter2->setChildrenCollapsible( false ); + splitter2->setStretchFactor( 0, 0 ); // consistent treeview side sizing on resizes + splitter2->setStretchFactor( 1, 1 ); { // menu bar auto *toolbar = new QToolBar; @@ -1881,7 +1894,8 @@ QWidget* TextureBrowser_constructWindow( QWidget* toplevel ){ splitter->setStretchFactor( 0, 0 ); // consistent treeview side sizing on resizes splitter->setStretchFactor( 1, 1 ); g_guiSettings.addSplitter( splitter, "TextureBrowser/splitter", { 100, 800 } ); - return splitter; + g_guiSettings.addSplitter( splitter2, "TextureBrowser/splitter2", { 800, 800 } ); + return splitter2; } void TextureBrowser_destroyWindow(){ From 33fc6cf319363ce54b143e8e55669c9c2c874d95 Mon Sep 17 00:00:00 2001 From: erysdren Date: Wed, 11 Mar 2026 23:16:18 -0500 Subject: [PATCH 2/2] surfacedialog: wip --- radiant/surfacedialog.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/radiant/surfacedialog.cpp b/radiant/surfacedialog.cpp index 9828c839..19968bf2 100644 --- a/radiant/surfacedialog.cpp +++ b/radiant/surfacedialog.cpp @@ -303,9 +303,7 @@ class SurfaceInspector return GetWidget()->isVisible(); } void queueDraw(){ - if ( visible() ) { - m_idleDraw.queueDraw(); - } + m_idleDraw.queueDraw(); } QWidget* GetWidget(){ @@ -378,8 +376,6 @@ class SurfaceInspector } }; -QWidget* g_page_surface; - namespace { SurfaceInspector* g_SurfaceInspector; @@ -391,7 +387,6 @@ inline SurfaceInspector& getSurfaceInspector(){ } void SurfaceInspector_toggleShow(){ - GroupDialog_showPage( g_page_surface ); getSurfaceInspector().Update(); getSurfaceInspector().importData(); } @@ -858,7 +853,7 @@ g_pressedKeysFilter; QWidget* SurfaceInspector::BuildDialog(){ GetWidget()->setWindowTitle( "Surface Inspector" ); - // g_guiSettings.addWindow( GetWidget(), "SurfaceInspector/geometry", 99, 99 ); + g_guiSettings.addWindow( GetWidget(), "SurfaceInspector/geometry", 99, 99 ); GetWidget()->installEventFilter( &g_pressedKeysFilter );