/****************************************************************************** * QSkinny - Copyright (C) The authors * SPDX-License-Identifier: BSD-3-Clause *****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include static QQuickAbstractDialog* createQml( const char* className ) { static QQmlEngine engine( nullptr ); QByteArray qmlCode = "import QtQuick.Dialogs\n"; qmlCode += className; qmlCode += " {}"; auto component = new QQmlComponent( &engine ); component->setData( qmlCode.constData(), QUrl() ); if ( component->status() != QQmlComponent::Ready ) { qWarning() << component->errorString(); delete component; return nullptr; } auto dialog = qobject_cast< QQuickAbstractDialog* >( component->create() ); QObject::connect( dialog, &QObject::destroyed, component, &QObject::deleteLater ); return dialog; } namespace { class ButtonBox : public QskLinearBox { Q_OBJECT public: enum DialogType { ColorDialog, FileDialog, FolderDialog, FontDialog, MessageDialog, }; Q_ENUM( DialogType ) ButtonBox( QQuickItem* parent = nullptr ) : QskLinearBox( Qt::Vertical, parent ) { setDefaultAlignment( Qt::AlignCenter ); setMargins( 10 ); setSpacing( 20 ); const auto metaEnum = QMetaEnum::fromType(); for ( int i = ColorDialog; i <= MessageDialog; i++ ) { auto button = new QskPushButton( metaEnum.key( i ), this ); button->setPreferredWidth( 200 ); button->setSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed ); connect( button, &QskPushButton::clicked, this, [ this, i ]() { openDialog( i ); } ); } setExtraSpacingAt( Qt::BottomEdge ); } private: void openDialog( int dialogType ) { /* Qt/Quick Dialogs implements a thin wrapper to make QPlatformTheme::createPlatformDialogHelper accessible from QML. There is not much value for the QSkinny use case and we could use QPlatformTheme in our QskDialog classes without the wrapper. However Qt/Quick Dialogs also offers a fallback implementation that is used when a dialog type is not supported by the platform. These classes are implemented in QML and we need QmlEngine/QmlComponent to use them. Once we have our own fallback implementation we can drop this QML dependency. */ delete m_dialog; m_dialog = nullptr; if ( qGuiApp->testAttribute( Qt::AA_DontUseNativeDialogs ) ) { const auto metaEnum = QMetaEnum::fromType(); m_dialog = createQml( metaEnum.key( dialogType ) ); if ( m_dialog ) m_dialog->setParentWindow( window() ); } else { switch( dialogType ) { case ColorDialog: m_dialog = new QQuickColorDialog(); break; case FileDialog: m_dialog = new QQuickFileDialog(); break; case FolderDialog: m_dialog = new QQuickFolderDialog(); break; case FontDialog: m_dialog = new QQuickFontDialog(); break; case MessageDialog: m_dialog = new QQuickMessageDialog(); break; } } if ( m_dialog ) { if ( auto messageDialog = qobject_cast< QQuickMessageDialog* >( m_dialog ) ) messageDialog->setText( "The quick brown fox jumps over the lazy dog" ); //m_dialog->setModality( Qt::WindowModal ); m_dialog->open(); } } QQuickAbstractDialog* m_dialog = nullptr; }; class MainView : public QskMainView { public: MainView( QQuickItem* parent = nullptr ) : QskMainView( parent ) { auto header = new QskLinearBox(); header->setExtraSpacingAt( Qt::LeftEdge ); header->setSizePolicy( Qt::Vertical, QskSizePolicy::Fixed ); auto button = new QskCheckBox( "Try Native Dialogs", header ); button->setChecked( true ); connect( button, &QskCheckBox::toggled, []( bool on ) { qGuiApp->setAttribute( Qt::AA_DontUseNativeDialogs, !on ); } ); setHeader( header ); setBody( new ButtonBox() ); } }; } int main( int argc, char* argv[] ) { #ifdef ITEM_STATISTICS QskObjectCounter counter( true ); #endif QGuiApplication app( argc, argv ); SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts ); QskWindow window; window.addItem( new MainView() ); window.resize( 800, 600 ); window.show(); return app.exec(); } #include "main.moc"