diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..6c001c8 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,43 @@ +cmake_minimum_required(VERSION 3.16) + +project(comboboxtests VERSION 0.1 LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(Qt6 6.4 REQUIRED COMPONENTS Quick) + +qt_standard_project_setup() + +qt_add_executable(appcomboboxtests + main.cpp + cppdefinedmodel.h cppdefinedmodel.cpp +) + +qt_add_qml_module(appcomboboxtests + URI comboboxtests + VERSION 1.0 + RESOURCES + icons/movinghead.png + icons/nebelmaschine.png + icons/rgbstrahler.png + QML_FILES + Main.qml + IconComboBox.qml + IconChooserDelegateLayout.qml +) + +set_target_properties(appcomboboxtests PROPERTIES + MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com + MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} + MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + MACOSX_BUNDLE TRUE + WIN32_EXECUTABLE TRUE +) + +target_link_libraries(appcomboboxtests + PRIVATE Qt6::Quick +) + +install(TARGETS appcomboboxtests + BUNDLE DESTINATION . + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/IconChooserDelegateLayout.qml b/IconChooserDelegateLayout.qml new file mode 100644 index 0000000..30b3464 --- /dev/null +++ b/IconChooserDelegateLayout.qml @@ -0,0 +1,29 @@ +import QtQuick +import QtQuick.Controls.Material +import QtQuick.Layouts + +RowLayout { + property string text + property string iconSource + property bool isInsideMaterialComboBox: false + + id: layout + + Image { + Layout.topMargin: isInsideMaterialComboBox ? 15 : 9 + Layout.bottomMargin: isInsideMaterialComboBox ? 15 : 9 + Layout.fillHeight: true + source: layout.iconSource + fillMode: Image.PreserveAspectFit + } + Label { + Layout.preferredHeight: layout.height + text: layout.text + verticalAlignment: Label.AlignVCenter + fontSizeMode: Text.VerticalFit + font.pixelSize: 20 + } + Item { + Layout.fillWidth: true + } +} diff --git a/IconComboBox.qml b/IconComboBox.qml new file mode 100644 index 0000000..a3fa56e --- /dev/null +++ b/IconComboBox.qml @@ -0,0 +1,69 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Controls.Material +import Qt.labs.folderlistmodel 2.4 +import comboboxtests 1.0 + +ComboBox { + id: comboBox + + property string iconSourceRole + + delegate: ItemDelegate { + height: 64 + anchors.left: parent.left + anchors.right: parent.right + contentItem: IconChooserDelegateLayout { + anchors.top: parent.top + anchors.bottom: parent.bottom + text: model[comboBox.textRole] + iconSource: model[comboBox.iconSourceRole] + } + } + contentItem: IconChooserDelegateLayout { + text: comboBox.displayText + isInsideMaterialComboBox: true + iconSource: { +// console.log("QAbstractListModel", model instanceof QAbstractListModel); +// console.log("QAbstractItemModel", model instanceof QAbstractItemModel); +// console.log("FolderListModel", model instanceof FolderListModel); +// console.log("DeviceTypesModel", model instanceof CppDefinedModel); +// console.log("QtObject", model instanceof QtObject); + + if (comboBox.currentIndex < 0) + return ''; + if (!comboBox.model) + return ''; + if (!comboBox.iconSourceRole) + return ''; + + // FolderListModel has a different API + if (model instanceof FolderListModel) + return model.get(comboBox.currentIndex, iconSourceRole); + // ListModel has another different API + else if ('get' in model) + { + const data = model.get(comboBox.currentIndex); + console.log(data); + return data[iconSourceRole]; + } + // and I dont know how to access C++ models from QML at all + else if ('roleNames' in model || 'data' in model) + { + if (!('roleNames' in model && 'data' in model)) + throw 'roleNames or data not defined!'; + + const roleNames = model.roleNames(); + console.log('roleNames', roleNames); + + const index = model.index(comboBox.currentIndex, 0); + const data = model.data(index, 99); + console.log('data', data); + + throw 'getting data from model using roleNames and data is not yet implemented.'; + } + else + throw 'unknown model type: ' + typeof model; + } + } +} diff --git a/Main.qml b/Main.qml new file mode 100644 index 0000000..49ced30 --- /dev/null +++ b/Main.qml @@ -0,0 +1,84 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Controls.Material +import QtQuick.Layouts +import QtQuick.Window +import Qt.labs.folderlistmodel 2.4 +import comboboxtests 1.0 + +Window { + width: 640 + height: 480 + visible: true + title: qsTr("Hello World") + + GridLayout { + anchors.fill: parent + + columns: 2 + + // IconComboBox shall support qml ListModels + IconComboBox { + Layout.preferredHeight: 64 + id: listModelComboBox + textRole: 'theText' + valueRole: 'theValue' + iconSourceRole: 'theIconUrl' + model: ListModel { + ListElement { theText: 'text0'; theValue: 'value0'; theIconUrl: 'qrc:/comboboxtests/icons/movinghead.png' } + ListElement { theText: 'text1'; theValue: 'value1'; theIconUrl: 'qrc:/comboboxtests/icons/movinghead.png' } + ListElement { theText: 'text2'; theValue: 'value2'; theIconUrl: 'qrc:/comboboxtests/icons/nebelmaschine.png' } + ListElement { theText: 'text3'; theValue: 'value3'; theIconUrl: 'qrc:/comboboxtests/icons/nebelmaschine.png' } + ListElement { theText: 'text4'; theValue: 'value4'; theIconUrl: 'qrc:/comboboxtests/icons/rgbstrahler.png' } + ListElement { theText: 'text5'; theValue: 'value5'; theIconUrl: 'qrc:/comboboxtests/icons/rgbstrahler.png' } + } + } + Label { + text: qsTr('currentValue: ') + listModelComboBox.currentValue + } + + // IconComboBox shall support qml FolderListModels (to let the user select which icon to use) + IconComboBox { + Layout.preferredHeight: 64 + id: folderListModelComboBox + textRole: "fileBaseName" + valueRole: "fileBaseName" + iconSourceRole: "fileUrl" + model: FolderListModel { + folder: "qrc:/comboboxtests/icons/" + showDirs: false + + function getUrlForIcon(name) { + let myFolder = folder; + if (myFolder.length < 1 || myFolder.charAt(myFolder.length - 1) !== '/') { + myFolder = myFolder + '/'; + } + + return myFolder + name + ".png" + } + } + } + Label { + text: qsTr('currentValue: ') + folderListModelComboBox.currentValue + } + + // IconComboBox shall support C++ QAbstractListModels (access to our internal database) + IconComboBox { + Layout.preferredHeight: 64 + id: cppModelComboBox + textRole: 'theText' + valueRole: 'theValue' + iconSourceRole: 'theIconUrl' + model: CppDefinedModel { + + } + } + Label { + text: qsTr('currentValue: ') + cppModelComboBox.currentValue + } + + Item { + Layout.fillHeight: true + } + } +} diff --git a/cppdefinedmodel.cpp b/cppdefinedmodel.cpp new file mode 100644 index 0000000..6b243f9 --- /dev/null +++ b/cppdefinedmodel.cpp @@ -0,0 +1 @@ +#include "cppdefinedmodel.h" diff --git a/cppdefinedmodel.h b/cppdefinedmodel.h new file mode 100644 index 0000000..798ca71 --- /dev/null +++ b/cppdefinedmodel.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include + +class CppDefinedModel : public QAbstractListModel +{ + Q_OBJECT + QML_ELEMENT + + enum { + TextRole = Qt::UserRole, + ValueRole, + IconUrlRole + }; + +public: + using QAbstractListModel::QAbstractListModel; + + int rowCount(const QModelIndex &parent) const override + { + return 6; + } + QVariant data(const QModelIndex &index, int role) const override + { + switch (role) + { + case TextRole: return QString("name%0").arg(index.row()); + case ValueRole: return QString("value%0").arg(index.row()); + case IconUrlRole: return QString("qrc:/comboboxtests/icons/%0.png") + .arg(std::array{{"movinghead", "nebelmaschine", "rgbstrahler"}}[index.row() / 2 % 3]); + } + return {}; + } + QHash roleNames() const override + { + return {{TextRole, "theText"}, {ValueRole, "theValue"}, {IconUrlRole, "theIconUrl"}}; + } +}; diff --git a/icons/movinghead.png b/icons/movinghead.png new file mode 100644 index 0000000..712d6d6 Binary files /dev/null and b/icons/movinghead.png differ diff --git a/icons/nebelmaschine.png b/icons/nebelmaschine.png new file mode 100644 index 0000000..cf7cf93 Binary files /dev/null and b/icons/nebelmaschine.png differ diff --git a/icons/rgbstrahler.png b/icons/rgbstrahler.png new file mode 100644 index 0000000..1ca0bf8 Binary files /dev/null and b/icons/rgbstrahler.png differ diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..8eea606 --- /dev/null +++ b/main.cpp @@ -0,0 +1,17 @@ +#include +#include + + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + + QQmlApplicationEngine engine; + const QUrl url(u"qrc:/comboboxtests/Main.qml"_qs); + QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed, + &app, []() { qFatal("object creation failed!"); QCoreApplication::exit(-1); }, + Qt::QueuedConnection); + engine.load(url); + + return app.exec(); +}