diff --git a/BionxControl.pro b/BionxControl.pro index a8767eb..e4a31a7 100644 --- a/BionxControl.pro +++ b/BionxControl.pro @@ -26,14 +26,14 @@ windows SOURCES += \ bc.cpp \ + bcdata.cpp \ + bcdatamodel.cpp \ bcitemdelegate.cpp \ bctransmitter.cpp \ - bcvaluemodel.cpp \ + bcvdatamanager.cpp \ lib/can_drv_win.c \ bccandriver.cpp \ bccandrivertinycan.cpp \ - bcvalue.cpp \ - bcvaluemanager.cpp \ main.cpp \ bcmainwindow.cpp @@ -41,12 +41,12 @@ HEADERS += \ bc.h \ bccandriver.h \ bccandrivertinycan.h \ + bcdata.h \ + bcdatamodel.h \ bcitemdelegate.h \ bcmainwindow.h \ bctransmitter.h \ - bcvalue.h \ - bcvaluemanager.h \ - bcvaluemodel.h + bcvdatamanager.h FORMS += \ bcmainwindow.ui diff --git a/bcvalue.cpp b/bcdata.cpp similarity index 71% rename from bcvalue.cpp rename to bcdata.cpp index d39691e..f79e23a 100644 --- a/bcvalue.cpp +++ b/bcdata.cpp @@ -30,14 +30,14 @@ #include -#include +#include -BCValueType::BCValueType() +BCDataType::BCDataType() { } -BCValueType::BCValueType( TypeID ID_, QString unitLabel_, optDouble factor_, optDouble min_, optDouble max_ ) +BCDataType::BCDataType( TypeID ID_, QString unitLabel_, optDouble factor_, optDouble min_, optDouble max_ ) : ID{ID_}, unitLabel{unitLabel_}, factor{factor_}, min{min_}, max{max_} { @@ -46,25 +46,18 @@ BCValueType::BCValueType( TypeID ID_, QString unitLabel_, optDouble factor_, opt ///------------------------------- -/* -BCValue::BCValue() -{ - -} -*/ - -BCValue::BCValue(const BCValueType& valueType_, BCDevice::ID deviceID_, BC::ID registerID_) +BCData::BCData(const BCDataType& valueType_, BCDevice::ID deviceID_, BC::ID registerID_) : valueType{valueType_}, deviceID{deviceID_}, registerID{registerID_} { - + value = "--"; } -void BCValue::readRawValue( const BCAbstractTransmitter& transmitter ) const -{ - -} - -void BCValue::writeRawValue( const BCAbstractTransmitter& transmitter ) const +void BCData::readRawValue( const BCAbstractTransmitter& transmitter ) const +{ + bcdata_t rawValue = transmitter.readRawValue( deviceID, registerID ); +} + +void BCData::writeRawValue( const BCAbstractTransmitter& transmitter ) const { } diff --git a/bcvalue.h b/bcdata.h similarity index 77% rename from bcvalue.h rename to bcdata.h index c35d57b..719b31e 100644 --- a/bcvalue.h +++ b/bcdata.h @@ -28,8 +28,8 @@ ***************************************************************************/ -#ifndef BCVALUE_H -#define BCVALUE_H +#ifndef BCDATA_H +#define BCDATA_H #include #include @@ -68,7 +68,7 @@ public: using optDouble = std::optional; -struct BCValueType +struct BCDataType { Q_GADGET @@ -99,8 +99,8 @@ public: }; Q_ENUM(TypeID) - BCValueType(); - BCValueType( TypeID ID_, QString unitLabel_="", optDouble factor_=std::nullopt, optDouble min_=std::nullopt, optDouble max_= std::nullopt ); + BCDataType(); + BCDataType( TypeID ID_, QString unitLabel_="", optDouble factor_=std::nullopt, optDouble min_=std::nullopt, optDouble max_= std::nullopt ); TypeID ID{TypeID::Invalid}; QString unitLabel; @@ -111,41 +111,40 @@ public: }; // really needed? -using BCValueTypeCRef = std::optional>; +using BCDataTypeCRef = std::optional>; -class BCValue +class BCData { public: - //BCValue(); - BCValue( const BCValueType& valueType_, BCDevice::ID deviceID_, BC::ID registerID_ ); + BCData( const BCDataType& valueType_, BCDevice::ID deviceID_, BC::ID registerID_ ); void readRawValue( const BCAbstractTransmitter& transmitter ) const; void writeRawValue( const BCAbstractTransmitter& transmitter ) const; // void reset() - BCValueTypeCRef valueType; - BCDevice::ID deviceID{BCDevice::ID::Invalid}; - BC::ID registerID{BC::ID::Invalid}; - int rowInModel{-1}; - QString label; - QVariant value; - QVariant defaultValue; + BCDataTypeCRef valueType; + BCDevice::ID deviceID{BCDevice::ID::Invalid}; + BC::ID registerID{BC::ID::Invalid}; + int rowInModel{-1}; + QString label; + QVariant value; + QVariant defaultValue; - bool inSync{false}; - bool readOnly{false}; + bool inSync{false}; + bool readOnly{false}; mutable std::optional rawValue; }; -Q_DECLARE_METATYPE(BCValue*) +Q_DECLARE_METATYPE(BCData*) -struct BCValueParams +struct BCDataParams { QString ID; QString Label; @@ -169,7 +168,7 @@ constexpr auto to_u(E e) noexcept { } */ -using BCValueList = QVector; +using BCDataList = QVector; -#endif // BCVALUE_H +#endif // BCDATA_H diff --git a/bcvaluemodel.cpp b/bcdatamodel.cpp similarity index 72% rename from bcvaluemodel.cpp rename to bcdatamodel.cpp index 855e222..4757d23 100644 --- a/bcvaluemodel.cpp +++ b/bcdatamodel.cpp @@ -28,14 +28,14 @@ ***************************************************************************/ -#include +#include -BCValueModel::BCValueModel(QObject *parent) : QAbstractListModel(parent) {} +BCDataModel::BCDataModel(QObject *parent) : QAbstractListModel(parent) {} -void BCValueModel::addValue(const BCValue &val) +void BCDataModel::addValue(const BCData &val) { int row = _valueList.size(); beginInsertRows(QModelIndex(), row, row); @@ -43,42 +43,42 @@ void BCValueModel::addValue(const BCValue &val) endInsertRows(); } -void BCValueModel::setValueList(const BCValueList& valueList) +void BCDataModel::setValueList(const BCDataList& valueList) { beginResetModel(); _valueList = valueList; endResetModel(); } -BCValueList& BCValueModel::getValueList() +BCDataList& BCDataModel::getValueList() { return _valueList; } -int BCValueModel::rowCount(const QModelIndex &parent) const +int BCDataModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) return 0; return _valueList.size(); } -QVariant BCValueModel::data(const QModelIndex& index, int role) const +QVariant BCDataModel::data(const QModelIndex& index, int role) const { int row = index.row(); if (!index.isValid() || row >= _valueList.size()) return QVariant(); - BCValue& value = const_cast(_valueList.at( row )); - value.rowInModel = row; + BCData& entry = const_cast(_valueList.at( row )); + entry.rowInModel = row; if (role == Qt::DisplayRole || role == Qt::EditRole) - return QVariant::fromValue(value); + return entry.value; return QVariant(); } -Qt::ItemFlags BCValueModel::flags(const QModelIndex &index) const +Qt::ItemFlags BCDataModel::flags(const QModelIndex &index) const { if (!index.isValid()) return Qt::NoItemFlags; @@ -87,11 +87,11 @@ Qt::ItemFlags BCValueModel::flags(const QModelIndex &index) const } -bool BCValueModel::setData(const QModelIndex &index, const QVariant &value, int role) +bool BCDataModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (index.isValid() && role == Qt::EditRole) { - BCValue item = _valueList[index.row()]; + BCData item = _valueList[index.row()]; // Wir erwarten hier nur den Value-Teil (vom Slider/Editor) // Checken ob Int oder Double diff --git a/bcvaluemodel.h b/bcdatamodel.h similarity index 79% rename from bcvaluemodel.h rename to bcdatamodel.h index 2a7a201..cc4191d 100644 --- a/bcvaluemodel.h +++ b/bcdatamodel.h @@ -28,26 +28,25 @@ ***************************************************************************/ -#ifndef BCVALUEMODEL_H -#define BCVALUEMODEL_H +#ifndef BCDATAMODEL_H +#define BCDATAMODEL_H #include -#include +#include -class BCValueModel : public QAbstractListModel +class BCDataModel : public QAbstractListModel { Q_OBJECT public: - explicit BCValueModel(QObject *parent = nullptr); - - void addValue(const BCValue &val); - void setValueList(const BCValueList& valueList); - BCValueList& getValueList(); + explicit BCDataModel(QObject *parent = nullptr); + void addValue(const BCData &val); + void setValueList(const BCDataList& valueList); + BCDataList& getValueList(); int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; @@ -58,8 +57,8 @@ public: private: - BCValueList _valueList; + BCDataList _valueList; }; -#endif // BCVALUEMODEL_H +#endif // BCDATAMODEL_H diff --git a/bcitemdelegate.cpp b/bcitemdelegate.cpp index db4c38d..653832a 100644 --- a/bcitemdelegate.cpp +++ b/bcitemdelegate.cpp @@ -12,7 +12,7 @@ #include #include "bcitemdelegate.h" -#include "bcvalue.h" +#include "bcdata.h" #include "qapplication.h" @@ -27,15 +27,19 @@ BCItemDelegate::BCItemDelegate(QListView *view) QString BCItemDelegate::displayText(const QVariant& dataValue, const QLocale& locale) const { // Wir prüfen, ob im Variant unser Struct steckt - if (dataValue.canConvert()) + if (dataValue.canConvert()) { - BCValue& bc = *dataValue.value(); - //qDebug() << " --- YES: " << bc.label; + BCData& bc = *dataValue.value(); + qDebug() << " --- YES: " << bc.label; // Hier bauen wir den String zusammen, den man sieht, // wenn KEIN Editor offen ist. // Format: "Label: Wert Einheit" return QString("%1: %2 %3").arg(bc.label, bc.value.toString(), "mmX"); } + else + { + qDebug() << " --- Nö!"; + } // Fallback für normale Strings/Zahlen return QStyledItemDelegate::displayText(dataValue, locale); @@ -45,10 +49,10 @@ QString BCItemDelegate::displayText(const QVariant& dataValue, const QLocale& lo QWidget *BCItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { QVariant rawData = index.data(Qt::EditRole); - if (!rawData.canConvert()) + if (!rawData.canConvert()) return QStyledItemDelegate::createEditor(parent, option, index); - const BCValue& bc = *rawData.value(); + const BCData& bc = *rawData.value(); // Nur bei Integern den Slider-Editor bauen if (bc.value.typeId() == QMetaType::Int) @@ -93,7 +97,7 @@ QWidget *BCItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewIte void BCItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { // Daten vom Model in den Editor laden - const BCValue& bc = *index.data(Qt::EditRole).value(); + const BCData& bc = *index.data(Qt::EditRole).value(); QSlider *slider = editor->findChild("slider"); QLabel *lblUnit = editor->findChild("lblUnit"); @@ -330,9 +334,9 @@ QString BCItemDelegate::formatDisplayString(const QModelIndex &index) const QString displayStr; /* - QString label = index.data(BCValueListModel::LabelRole).toString(); - QVariant value = index.data(BCValueListModel::ValueRole); - QString unit = index.data(BCValueListModel::UnitRole).toString(); + QString label = index.data(BCDataListModel::LabelRole).toString(); + QVariant value = index.data(BCDataListModel::ValueRole); + QString unit = index.data(BCDataListModel::UnitRole).toString(); QString valueStr = value.toString(); diff --git a/bcmainwindow.cpp b/bcmainwindow.cpp index 53b8dfc..c467ad6 100644 --- a/bcmainwindow.cpp +++ b/bcmainwindow.cpp @@ -62,9 +62,9 @@ BCMainWindow::BCMainWindow(QWidget *parent) // besser: model::emit dataChanged // also: emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole, ValueRole}); - connect( &_valueManager, &BCValueManager::valueTouched, _delegate, &BCItemDelegate::onHighlightRow ); + connect( &_valueManager, &BCDataManager::valueTouched, _delegate, &BCItemDelegate::onHighlightRow ); connect( _connectButton, &QPushButton::clicked, transmitter, &BCTransmitter::onToggleConnectionState ); - connect( _syncButton, &QPushButton::clicked, &_valueManager, &BCValueManager::onSyncFromDevice ); + connect( _syncButton, &QPushButton::clicked, &_valueManager, &BCDataManager::onSyncFromDevice ); } diff --git a/bcmainwindow.h b/bcmainwindow.h index 6452ed7..33e2269 100644 --- a/bcmainwindow.h +++ b/bcmainwindow.h @@ -33,7 +33,7 @@ #include #include -#include +#include class AnimatedDelegate; @@ -53,7 +53,7 @@ public slots: protected: - BCValueManager _valueManager; + BCDataManager _valueManager; AnimatedDelegate* _delegate; diff --git a/bctransmitter.cpp b/bctransmitter.cpp index af3b994..d5af8a2 100644 --- a/bctransmitter.cpp +++ b/bctransmitter.cpp @@ -50,7 +50,7 @@ void BCTransmitter::onToggleConnectionState( bool connect ) } -void BCTransmitter::enqueueValueOp(BC::OpID opID, const BCValue* value) +void BCTransmitter::enqueueValueOp(BC::OpID opID, const BCData* value) { QMutexLocker locker(&_mutex); _valueQueue.enqueue( value ); @@ -83,7 +83,7 @@ void BCTransmitter::processValueOp( BC::OpID opID ) while (true) { - const BCValue* currentValue{}; + const BCData* currentValue{}; { QMutexLocker locker(&_mutex); if (_valueQueue.isEmpty()) diff --git a/bctransmitter.h b/bctransmitter.h index dd3be8c..423dcf2 100644 --- a/bctransmitter.h +++ b/bctransmitter.h @@ -6,9 +6,10 @@ #include #include -#include +#include #include +// template ... class BCTransmitter : public QObject, public BCAbstractTransmitter { Q_OBJECT @@ -23,7 +24,7 @@ public: public slots: void onToggleConnectionState( bool connect ); - void enqueueValueOp(BC::OpID opID, const BCValue* value ); + void enqueueValueOp(BC::OpID opID, const BCData* value ); void processValueOp(BC::OpID opID); signals: @@ -33,9 +34,9 @@ signals: private: - using BCValueQueue = QQueue; + using BCDataQueue = QQueue; - BCValueQueue _valueQueue; + BCDataQueue _valueQueue; QMutex _mutex; std::atomic _isBusy{ false }; diff --git a/bcvaluemanager.cpp b/bcvdatamanager.cpp similarity index 73% rename from bcvaluemanager.cpp rename to bcvdatamanager.cpp index 522f4a4..43e3a95 100644 --- a/bcvaluemanager.cpp +++ b/bcvdatamanager.cpp @@ -37,28 +37,28 @@ #include #include -#include +#include using namespace Qt::StringLiterals; -BCValueManager::BCValueManager(QObject *parent) +BCDataManager::BCDataManager(QObject *parent) : QObject(parent) { createValueTypes(); - //qRegisterMetaType("BCValue*"); - qRegisterMetaType(); + //qRegisterMetaType("BCData*"); + qRegisterMetaType(); _transmitter.moveToThread(&_worker); - connect(this, &BCValueManager::sendValueCommand, &_transmitter, &BCTransmitter::enqueueValueOp); + connect(this, &BCDataManager::sendValueCommand, &_transmitter, &BCTransmitter::enqueueValueOp); // B) Ergebnisse empfangen (Runner -> Manager) - //connect(&_transmitter, &BCTransmitter::commandFinished, this, &BCValueManager::onCommandFinished); - //connect(&_transmitter, &BCTransmitter::messageLogged, this, &BCValueManager::onRunnerMessage); + //connect(&_transmitter, &BCTransmitter::commandFinished, this, &BCDataManager::onCommandFinished); + //connect(&_transmitter, &BCTransmitter::messageLogged, this, &BCDataManager::onRunnerMessage); // C) Aufräumen: Wenn Thread endet, lösche den Runner connect(&_worker, &QThread::finished, &_transmitter, &QObject::deleteLater); @@ -67,7 +67,7 @@ BCValueManager::BCValueManager(QObject *parent) _worker.start(); } -BCValueManager::~BCValueManager() +BCDataManager::~BCDataManager() { // nothing to do here for now, // our models are autokilled. @@ -77,7 +77,7 @@ BCValueManager::~BCValueManager() } -void BCValueManager::createValueTypes() +void BCDataManager::createValueTypes() { /* Invalid = 0x0, @@ -96,44 +96,44 @@ void BCValueManager::createValueTypes() "Date" */ - //_valueTypes.insert( { BCValueType::TypeID::Invalid, "Invalid" } ); + //_valueTypes.insert( { BCDataType::TypeID::Invalid, "Invalid" } ); - _valueTypes.insert( "Invalid", { BCValueType::TypeID::Invalid, "Invalid" } ); - _valueTypes.insert( "Text", { BCValueType::TypeID::Text } ); - _valueTypes.insert( "Number", { BCValueType::TypeID::Number } ); + _valueTypes.insert( "Invalid", { BCDataType::TypeID::Invalid, "Invalid" } ); + _valueTypes.insert( "Text", { BCDataType::TypeID::Text } ); + _valueTypes.insert( "Number", { BCDataType::TypeID::Number } ); - _valueTypes.insert( "Byte", { BCValueType::TypeID::Byte } ); - _valueTypes.insert( "Word", { BCValueType::TypeID::Word } ); - _valueTypes.insert( "Quad", { BCValueType::TypeID::Quad } ); + _valueTypes.insert( "Byte", { BCDataType::TypeID::Byte } ); + _valueTypes.insert( "Word", { BCDataType::TypeID::Word } ); + _valueTypes.insert( "Quad", { BCDataType::TypeID::Quad } ); - _valueTypes.insert( "Float", { BCValueType::TypeID::Float, "", 1.5625} ); - _valueTypes.insert( "Percent",{ BCValueType::TypeID::Percent, "%", 1.5625 } ); - _valueTypes.insert( "KWh", { BCValueType::TypeID::KWh, "kwh", 1.5625 } ); - _valueTypes.insert( "Watt", { BCValueType::TypeID::Watt, "w", 1.5625 } ); - _valueTypes.insert( "Km", { BCValueType::TypeID::Km, "km", 1.5625 } ); - _valueTypes.insert( "Kmh", { BCValueType::TypeID::Kmh, "km/h", 0.1 } ); - _valueTypes.insert( "Mm", { BCValueType::TypeID::Mm, "mm", 1.5625 } ); - _valueTypes.insert( "Sec", { BCValueType::TypeID::Sec, "s", 1.5625 } ); - _valueTypes.insert( "SoC", { BCValueType::TypeID::SoC, "%", 1.5625 } ); - _valueTypes.insert( "Odo", { BCValueType::TypeID::Odo, "km", 1.5625 } ); - _valueTypes.insert( "Assist", { BCValueType::TypeID::Assist, "", 0 ,4 } ); - _valueTypes.insert( "Assist", { BCValueType::TypeID::AssistFac, "%" } ); - _valueTypes.insert( "Date", { BCValueType::TypeID::Date } ); + _valueTypes.insert( "Float", { BCDataType::TypeID::Float, "", 1.5625} ); + _valueTypes.insert( "Percent",{ BCDataType::TypeID::Percent, "%", 1.5625 } ); + _valueTypes.insert( "KWh", { BCDataType::TypeID::KWh, "kwh", 1.5625 } ); + _valueTypes.insert( "Watt", { BCDataType::TypeID::Watt, "w", 1.5625 } ); + _valueTypes.insert( "Km", { BCDataType::TypeID::Km, "km", 1.5625 } ); + _valueTypes.insert( "Kmh", { BCDataType::TypeID::Kmh, "km/h", 0.1 } ); + _valueTypes.insert( "Mm", { BCDataType::TypeID::Mm, "mm", 1.5625 } ); + _valueTypes.insert( "Sec", { BCDataType::TypeID::Sec, "s", 1.5625 } ); + _valueTypes.insert( "SoC", { BCDataType::TypeID::SoC, "%", 1.5625 } ); + _valueTypes.insert( "Odo", { BCDataType::TypeID::Odo, "km", 1.5625 } ); + _valueTypes.insert( "Assist", { BCDataType::TypeID::Assist, "", 0 ,4 } ); + _valueTypes.insert( "Assist", { BCDataType::TypeID::AssistFac, "%" } ); + _valueTypes.insert( "Date", { BCDataType::TypeID::Date } ); } -void BCValueManager::onCommandFinished(int id, bool success) +void BCDataManager::onCommandFinished(int id, bool success) { qDebug() << "[Manager] Command" << id << "finished. Success:" << success; } -void BCValueManager::onRunnerMessage(const QString &msg) +void BCDataManager::onRunnerMessage(const QString &msg) { qDebug() << "[Worker says]:" << msg; } -void BCValueManager::onSyncFromDevice() +void BCDataManager::onSyncFromDevice() { qDebug() << " ---Syncing"; if( _currentDeviceID != BCDevice::ID::Invalid ) @@ -141,12 +141,12 @@ void BCValueManager::onSyncFromDevice() if( _valueModels.contains(_currentDeviceID) ) { - BCValueModel* model = _valueModels[_currentDeviceID]; - BCValueList& currentList = model->getValueList(); + BCDataModel* model = _valueModels[_currentDeviceID]; + BCDataList& currentList = model->getValueList(); - //BCValue& value = currentList[4]; + //BCData& value = currentList[4]; - for( const BCValue& value : currentList ) + for( const BCData& value : currentList ) { qDebug() << " --- value: " << value.label; @@ -169,19 +169,19 @@ void BCValueManager::onSyncFromDevice() } } -std::optional BCValueManager::getModel(BCDevice::ID deviceID ) +std::optional BCDataManager::getModel(BCDevice::ID deviceID ) { if( _valueModels.contains( deviceID) ) return _valueModels[deviceID]; return std::nullopt; } -BCTransmitter* BCValueManager::getTransmitter() +BCTransmitter* BCDataManager::getTransmitter() { return &_transmitter; }; -void BCValueManager::loadBikeData() +void BCDataManager::loadBikeData() { auto printAttrs = [](const QXmlStreamReader& xml) { @@ -231,11 +231,11 @@ void BCValueManager::loadBikeData() qDebug() << " --- Device: " << _xml.name() << ": " << deviceType << " : " << deviceID; _currentDeviceID = BCDevice::ID( deviceID.value() ); - BCValueList parsedValues; + BCDataList parsedValues; loadDeviceData( parsedValues ); if( parsedValues.count() ) { - BCValueModel* valueModel = new BCValueModel( this ); + BCDataModel* valueModel = new BCDataModel( this ); valueModel->setValueList(parsedValues); _valueModels.insert( _currentDeviceID, valueModel ); } @@ -261,7 +261,7 @@ void BCValueManager::loadBikeData() } -void BCValueManager::loadDeviceData( BCValueList& parsedValues ) +void BCDataManager::loadDeviceData( BCDataList& parsedValues ) { auto printAttrs = [](const QXmlStreamReader& xml) { @@ -285,7 +285,7 @@ void BCValueManager::loadDeviceData( BCValueList& parsedValues ) //qDebug() << " --- found: " << _xml.name() << " : " << _xml.attributes().value(BCTags::ID); QString id = _xml.attributes().value(BCTags::ID).toString(); - BCValueParams params + BCDataParams params { .ID = id, .Label = _xml.attributes().value(BCTags::Label).toString(), @@ -294,10 +294,10 @@ void BCValueManager::loadDeviceData( BCValueList& parsedValues ) }; // __fix! können ungültige werte erzeugt werden ? - //BCValue newValue = BCValue::makeValue( _currentDeviceID, params ); + //BCData newValue = BCData::makeValue( _currentDeviceID, params ); //if(newValue) // parsedValues.push_back( newValue ); - std::optional newValue = makeValue( _currentDeviceID, params ); + std::optional newValue = makeValue( _currentDeviceID, params ); if(newValue) parsedValues.push_back( *newValue ); } @@ -307,7 +307,7 @@ void BCValueManager::loadDeviceData( BCValueList& parsedValues ) } } -std::optional BCValueManager::makeValue( BCDevice::ID deviceID, const BCValueParams& params ) +std::optional BCDataManager::makeValue( BCDevice::ID deviceID, const BCDataParams& params ) { /* @@ -332,7 +332,7 @@ std::optional BCValueManager::makeValue( BCDevice::ID deviceID, const B */ - std::optional newValue; + std::optional newValue; std::optional IDVal = s_bcValueEnum.keyToValue64( params.ID.toLatin1().constData() ); if( IDVal.has_value() ) @@ -340,8 +340,8 @@ std::optional BCValueManager::makeValue( BCDevice::ID deviceID, const B if( _valueTypes.contains( params.UnitType ) ) { - const BCValueType& valueType = _valueTypes[params.UnitType]; - newValue = BCValue( valueType, deviceID, static_cast(IDVal.value()) ); + const BCDataType& valueType = _valueTypes[params.UnitType]; + newValue = BCData( valueType, deviceID, static_cast(IDVal.value()) ); /* setIfExists( params.Factor, newValue.factor ); @@ -361,7 +361,7 @@ std::optional BCValueManager::makeValue( BCDevice::ID deviceID, const B } // --- NEU: Speichern mit QXmlStreamWriter --- -void BCValueManager::saveBikeData() +void BCDataManager::saveBikeData() { /* QString fileName = QFileDialog::getSaveFileName(this, "XML speichern", "", "XML Files (*.xml)"); diff --git a/bcvaluemanager.h b/bcvdatamanager.h similarity index 72% rename from bcvaluemanager.h rename to bcvdatamanager.h index 599f171..dd27965 100644 --- a/bcvaluemanager.h +++ b/bcvdatamanager.h @@ -28,8 +28,8 @@ ***************************************************************************/ -#ifndef BCVALUEMANAGER_H -#define BCVALUEMANAGER_H +#ifndef BCVDATAMANAGER_H +#define BCVDATAMANAGER_H #include #include @@ -37,23 +37,23 @@ #include #include -#include +#include #include -class BCValueManager : public QObject +class BCDataManager : public QObject { Q_OBJECT public: - BCValueManager( QObject* parent = nullptr); - virtual ~BCValueManager(); + BCDataManager( QObject* parent = nullptr); + virtual ~BCDataManager(); - std::optional getModel(BCDevice::ID deviceID ); + std::optional getModel(BCDevice::ID deviceID ); BCTransmitter* getTransmitter(); - std::optional makeValue( BCDevice::ID deviceID, const BCValueParams& params ); + std::optional makeValue( BCDevice::ID deviceID, const BCDataParams& params ); public slots: @@ -64,8 +64,8 @@ public slots: signals: // Internes Signal, um Daten an den Worker Thread zu senden - void sendValueCommand( BC::OpID, const BCValue* cmd); - //void valuedTouched(const BCValue& cmd); + void sendValueCommand( BC::OpID, const BCData* cmd); + //void valuedTouched(const BCData& cmd); void valueTouched(int rowInModel ); private slots: @@ -77,13 +77,13 @@ private slots: protected: void createValueTypes(); - void loadDeviceData( BCValueList& parsedValues ); + void loadDeviceData( BCDataList& parsedValues ); - using BCDeviceModels = QMap; - using BCValueTypes = QMap; + using BCDeviceModels = QMap; + using BCDataTypes = QMap; QXmlStreamReader _xml; - BCValueTypes _valueTypes; + BCDataTypes _valueTypes; BCDeviceModels _valueModels; BCDevice::ID _currentDeviceID{BCDevice::ID::Invalid}; QMetaEnum _bcDeviceEnum{QMetaEnum::fromType()}; @@ -93,4 +93,4 @@ protected: }; -#endif // BCVALUEMANAGER_H +#endif // BCVDATAMANAGER_H diff --git a/doc/material_dummy/.qtcreator/material_dummy.pro.user b/doc/material_dummy/.qtcreator/material_dummy.pro.user new file mode 100644 index 0000000..10e74a3 --- /dev/null +++ b/doc/material_dummy/.qtcreator/material_dummy.pro.user @@ -0,0 +1,198 @@ + + + + + + EnvironmentId + {350f6538-4791-42f9-b43d-6ea1a7b22b7b} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + true + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 0 + 80 + true + true + 1 + 0 + false + true + false + 2 + true + true + 0 + 8 + true + false + 1 + true + true + true + *.md, *.MD, Makefile + false + true + true + + + + ProjectExplorer.Project.PluginSettings + + 0 + + + + ProjectExplorer.Project.Target.0 + + Desktop + true + Desktop Qt 6.10.1 MinGW 64-bit + Desktop Qt 6.10.1 MinGW 64-bit + qt.qt6.6101.win64_mingw_kit + 0 + 0 + 0 + + 0 + C:\syncMePlease\projects.now\material_dummy\build\Desktop_Qt_6_10_1_MinGW_64_bit-Debug + C:/syncMePlease/projects.now/material_dummy/build/Desktop_Qt_6_10_1_MinGW_64_bit-Debug + + + true + QtProjectManager.QMakeBuildStep + false + + + + true + Qt4ProjectManager.MakeStep + + 2 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + clean + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + Debug + Qt4ProjectManager.Qt4BuildConfiguration + 0 + 0 + + + 0 + Deploy + Deploy + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + ProjectExplorer.DefaultDeployConfiguration + + 1 + + true + true + 0 + true + + 2 + + false + -e cpu-cycles --call-graph "dwarf,4096" -F 250 + + ProjectExplorer.CustomExecutableRunConfiguration + + false + + true + true + %{RunConfig:Executable:Path} + + 1 + 2 + + 1 + + + 0 + Deploy + Deploy + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + ProjectExplorer.DefaultDeployConfiguration + + 1 + + true + true + 0 + true + + 2 + + false + -e cpu-cycles --call-graph "dwarf,4096" -F 250 + + ProjectExplorer.CustomExecutableRunConfiguration + + false + + true + true + %{RunConfig:Executable:Path} + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + Version + 22 + + diff --git a/doc/material_dummy/main.cpp b/doc/material_dummy/main.cpp new file mode 100644 index 0000000..03ba1d3 --- /dev/null +++ b/doc/material_dummy/main.cpp @@ -0,0 +1,305 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mainwindow.h" + +// Fluent Design Demo Widget +class FluentWidgetDemo : public QWidget { +public: + FluentWidgetDemo() { + setWindowTitle("Fluent Design System - Windows 11"); + resize(600, 500); + + // Acrylic-like background + setStyleSheet(R"( + QWidget { + background-color: #F3F3F3; + font-family: 'Segoe UI Variable', 'Segoe UI', sans-serif; + } + )"); + + auto* mainLayout = new QVBoxLayout(this); + mainLayout->setSpacing(20); + mainLayout->setContentsMargins(32, 32, 32, 32); + + // Title + auto* title = new QLabel("Fluent Design System"); + title->setStyleSheet(R"( + font-size: 28px; + font-weight: 600; + color: #201F1E; + margin-bottom: 8px; + )"); + mainLayout->addWidget(title); + + auto* subtitle = new QLabel("Windows 11 Style Components"); + subtitle->setStyleSheet("font-size: 14px; color: #605E5C;"); + mainLayout->addWidget(subtitle); + + // Text Input + auto* inputLabel = new QLabel("Text Input"); + inputLabel->setStyleSheet("font-size: 12px; color: #323130; font-weight: 600;"); + mainLayout->addWidget(inputLabel); + + auto* input = new QLineEdit(); + input->setPlaceholderText("Enter text here..."); + applyFluentInput(input); + mainLayout->addWidget(input); + + // Slider Section + auto* sliderLabel = new QLabel("Sliders"); + sliderLabel->setStyleSheet("font-size: 12px; color: #323130; font-weight: 600; margin-top: 8px;"); + mainLayout->addWidget(sliderLabel); + + auto* valueLabel = new QLabel("Volume: 50"); + valueLabel->setStyleSheet("font-size: 14px; color: #605E5C;"); + mainLayout->addWidget(valueLabel); + + auto* hSlider = new QSlider(Qt::Horizontal); + hSlider->setRange(0, 100); + hSlider->setValue(50); + hSlider->setStyle(new FluentSliderStyle()); + hSlider->setMinimumHeight(32); // Genug Platz für Handle + mainLayout->addWidget(hSlider); + + connect(hSlider, &QSlider::valueChanged, [valueLabel](int value) { + valueLabel->setText(QString("Volume: %1").arg(value)); + }); + + // Checkbox + auto* checkLabel = new QLabel("Checkbox"); + checkLabel->setStyleSheet("font-size: 12px; color: #323130; font-weight: 600; margin-top: 8px;"); + mainLayout->addWidget(checkLabel); + + auto* checkbox = new QCheckBox("Enable feature"); + applyFluentCheckbox(checkbox); + mainLayout->addWidget(checkbox); + + // Buttons Section + auto* btnLabel = new QLabel("Buttons"); + btnLabel->setStyleSheet("font-size: 12px; color: #323130; font-weight: 600; margin-top: 8px;"); + mainLayout->addWidget(btnLabel); + + auto* btnLayout = new QHBoxLayout(); + btnLayout->setSpacing(12); + + auto* primaryBtn = new QPushButton("Primary"); + applyFluentButton(primaryBtn, ButtonType::Primary); + btnLayout->addWidget(primaryBtn); + + auto* secondaryBtn = new QPushButton("Secondary"); + applyFluentButton(secondaryBtn, ButtonType::Secondary); + btnLayout->addWidget(secondaryBtn); + + auto* subtleBtn = new QPushButton("Subtle"); + applyFluentButton(subtleBtn, ButtonType::Subtle); + btnLayout->addWidget(subtleBtn); + + btnLayout->addStretch(); + mainLayout->addLayout(btnLayout); + + // Vertical Sliders + auto* vLabel = new QLabel("Equalizer"); + vLabel->setStyleSheet("font-size: 12px; color: #323130; font-weight: 600; margin-top: 8px;"); + mainLayout->addWidget(vLabel); + + auto* vLayout = new QHBoxLayout(); + vLayout->setSpacing(24); + + for (int i = 0; i < 5; ++i) { + auto* vSlider = new QSlider(Qt::Vertical); + vSlider->setRange(0, 100); + vSlider->setValue(20 + i * 15); + vSlider->setStyle(new FluentSliderStyle()); + vSlider->setMinimumHeight(120); + vSlider->setMinimumWidth(32); // Genug Platz für Handle + vLayout->addWidget(vSlider); + } + vLayout->addStretch(); + + mainLayout->addLayout(vLayout); + mainLayout->addStretch(); + } + +private: + enum class ButtonType { + Primary, + Secondary, + Subtle + }; + + void applyFluentButton(QPushButton* btn, ButtonType type) { + QString baseStyle = R"( + QPushButton { + background-color: %1; + color: %2; + border: %3; + border-radius: 4px; + padding: 5px 12px; + font-size: 14px; + min-height: 32px; + } + QPushButton:hover { + background-color: %4; + border: %5; + } + QPushButton:pressed { + background-color: %6; + border: %7; + } + QPushButton:disabled { + background-color: #F3F2F1; + color: #A19F9D; + border: 1px solid #EDEBE9; + } + )"; + + switch (type) { + case ButtonType::Primary: + btn->setStyleSheet(baseStyle + .arg("#0078D4") // bg + .arg("white") // text + .arg("none") // border + .arg("#106EBE") // hover bg + .arg("none") // hover border + .arg("#005A9E") // pressed bg + .arg("none") // pressed border + ); + break; + + case ButtonType::Secondary: + btn->setStyleSheet(baseStyle + .arg("white") // bg + .arg("#201F1E") // text + .arg("1px solid #8A8886") // border + .arg("#F3F2F1") // hover bg + .arg("1px solid #323130") // hover border + .arg("#EDEBE9") // pressed bg + .arg("1px solid #201F1E") // pressed border + ); + break; + + case ButtonType::Subtle: + btn->setStyleSheet(baseStyle + .arg("transparent") // bg + .arg("#201F1E") // text + .arg("none") // border + .arg("#F3F2F1") // hover bg + .arg("none") // hover border + .arg("#EDEBE9") // pressed bg + .arg("none") // pressed border + ); + break; + } + + // Subtle shadow for elevation + if (type == ButtonType::Primary) { + auto* shadow = new QGraphicsDropShadowEffect(); + shadow->setBlurRadius(4); + shadow->setColor(QColor(0, 0, 0, 40)); + shadow->setOffset(0, 1); + btn->setGraphicsEffect(shadow); + } + } + + void applyFluentInput(QLineEdit* input) { + input->setStyleSheet(R"( + QLineEdit { + border: 1px solid #8A8886; + border-radius: 4px; + padding: 6px 10px; + background-color: white; + font-size: 14px; + color: #201F1E; + min-height: 32px; + } + QLineEdit:hover { + border: 1px solid #323130; + } + QLineEdit:focus { + border: 2px solid #0078D4; + padding: 5px 9px; + } + QLineEdit:disabled { + background-color: #F3F2F1; + border: 1px solid #EDEBE9; + color: #A19F9D; + } + )"); + } + + void applyFluentCheckbox(QCheckBox* checkbox) { + checkbox->setStyleSheet(R"( + QCheckBox { + spacing: 8px; + font-size: 14px; + color: #201F1E; + } + QCheckBox::indicator { + width: 20px; + height: 20px; + border: 1px solid #8A8886; + border-radius: 4px; + background-color: white; + } + QCheckBox::indicator:hover { + border: 1px solid #323130; + background-color: #F3F2F1; + } + QCheckBox::indicator:checked { + background-color: #0078D4; + border: 1px solid #0078D4; + } + QCheckBox::indicator:checked:hover { + background-color: #106EBE; + border: 1px solid #106EBE; + } + QCheckBox::indicator:disabled { + background-color: #F3F2F1; + border: 1px solid #C8C6C4; + } + )"); + } +}; + + + + + + + +//#include "main.moc" // Wichtig für Q_OBJECT in .cpp Datei + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + +// Segoe UI is default on Windows +#ifdef Q_OS_WIN + QFont font("Segoe UI Variable", 10); +#else + QFont font("Segoe UI", 10); +#endif + app.setFont(font); + + TableViewDemo demo; + demo.show(); + + + FluentWidgetDemo fdemo; + fdemo.show(); + return app.exec(); +} + + diff --git a/doc/material_dummy/mainwindow.cpp b/doc/material_dummy/mainwindow.cpp new file mode 100644 index 0000000..139597f --- /dev/null +++ b/doc/material_dummy/mainwindow.cpp @@ -0,0 +1,2 @@ + + diff --git a/doc/material_dummy/mainwindow.h b/doc/material_dummy/mainwindow.h new file mode 100644 index 0000000..3807a76 --- /dev/null +++ b/doc/material_dummy/mainwindow.h @@ -0,0 +1,148 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sliderdelegate.h" + +class TableViewDemo : public QWidget +{ +public: + TableViewDemo() + { + setWindowTitle("QTableView mit QSlider Editor"); + resize(700, 400); + + auto* layout = new QVBoxLayout(this); + + // Model erstellen (3 Spalten, 10 Zeilen) + auto* model = new QStandardItemModel(10, 2, this); + + // Header setzen + model->setHorizontalHeaderLabels({"Name", "Wert"}); + + // Daten einfügen + for (int row = 0; row < 10; ++row) { + auto* nameItem = new QStandardItem(QString("Eintrag %1").arg(row + 1)); + auto* valueItem = new QStandardItem(); + + // Wert-Item editierbar machen + valueItem->setData(row * 10, Qt::EditRole); // Startwert 0-90 + valueItem->setEditable(true); + + // Andere nicht editierbar + nameItem->setEditable(false); + + + model->setItem(row, 0, nameItem); + model->setItem(row, 1, valueItem); + } + + // TableView erstellen + auto* tableView = new QTableView(); + tableView->setModel(model); + + // === SLIDER DELEGATE für Spalte 2 === + //auto* sliderDelegate = new SliderDelegate(this); + //tableView->setItemDelegateForColumn(1, sliderDelegate); + + tableView->setAlternatingRowColors(false); + // === LINIEN ENTFERNEN === + tableView->setShowGrid(false); + + // Header Style + tableView->horizontalHeader()->setStyleSheet(R"( + QHeaderView::section { + background-color: #F5F5F5; + padding: 10px; + border: none; + font-weight: bold; + color: #333; + } + )"); + + + + // Vertikaler Header ausblenden + tableView->verticalHeader()->setVisible(false); + + // Alternating Row Colors + //tableView->setAlternatingRowColors(true); + + // Style für TableView + tableView->setStyleSheet(R"( + QTableView + { + background-color: white; + border: none; + selection-background-color: #E3F2FD; + selection-color: black; + } + QTableView::item + { + padding: 10px; + border: none; + } + QTableView::item:selected { + background-color: #E3F2FD; + border: 1px solid #0078D4; /* Rahmen um JEDE Zelle */ + } + + } + )"); + + + // Spaltenbreite + tableView->setColumnWidth(0, 50); + tableView->setColumnWidth(1, 150); + tableView->horizontalHeader()->setStretchLastSection(true); + + // Row Height für bessere Slider-Darstellung + tableView->verticalHeader()->setDefaultSectionSize(40); + + // Selection + tableView->setSelectionBehavior(QAbstractItemView::SelectRows); + //tableView->setSelectionMode(QAbstractItemView::SingleSelection); + + // Edit Trigger - Klick zum Editieren + tableView->setEditTriggers(QAbstractItemView::DoubleClicked | + QAbstractItemView::SelectedClicked); + + layout->addWidget(tableView); + + // Signal für Änderungen + connect(model, &QStandardItemModel::dataChanged, this, + [](const QModelIndex& topLeft, const QModelIndex& bottomRight) { + if (topLeft.column() ==1) { + int row = topLeft.row(); + int value = topLeft.data(Qt::DisplayRole).toInt(); + qDebug() << "Zeile" << row << "wurde auf" << value << "gesetzt"; + } + }); + } +}; + +#endif // MAINWINDOW_H diff --git a/doc/material_dummy/mainwindow.ui b/doc/material_dummy/mainwindow.ui new file mode 100644 index 0000000..becc91c --- /dev/null +++ b/doc/material_dummy/mainwindow.ui @@ -0,0 +1,31 @@ + + + MainWindow + + + + 0 + 0 + 800 + 600 + + + + MainWindow + + + + + + 0 + 0 + 800 + 18 + + + + + + + + diff --git a/doc/material_dummy/material_dummy.pro b/doc/material_dummy/material_dummy.pro new file mode 100644 index 0000000..28cc06e --- /dev/null +++ b/doc/material_dummy/material_dummy.pro @@ -0,0 +1,25 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++17 + +# You can make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + mainwindow.cpp + +HEADERS += \ + mainwindow.h \ + sliderdelegate.h + +FORMS += \ + mainwindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/doc/material_dummy/sliderdelegate.h b/doc/material_dummy/sliderdelegate.h new file mode 100644 index 0000000..7df834a --- /dev/null +++ b/doc/material_dummy/sliderdelegate.h @@ -0,0 +1,355 @@ +#ifndef SLIDERDELEGATE_H +#define SLIDERDELEGATE_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Custom Delegate für QSlider in Spalte 3 + + +// Fluent Design Slider Style +class FluentSliderStyle : public QProxyStyle +{ +public: + + FluentSliderStyle() + : QProxyStyle() + {} + + // Wichtig: Genug Platz für Handle reservieren + int pixelMetric(PixelMetric metric, const QStyleOption* option = nullptr, const QWidget* widget = nullptr) const override + { + switch (metric) + { + case PM_SliderThickness: + return 32; // Höhe für horizontalen Slider + case PM_SliderLength: + return 20; // Handle-Größe + case PM_SliderControlThickness: + return 20; + case PM_SliderSpaceAvailable: + if (option) + { + if (const QStyleOptionSlider* sliderOpt = qstyleoption_cast(option)) { + if (sliderOpt->orientation == Qt::Horizontal) { + return sliderOpt->rect.width() - 20; + } else { + return sliderOpt->rect.height() - 20; + } + } + } + return QProxyStyle::pixelMetric(metric, option, widget); + + default: + return QProxyStyle::pixelMetric(metric, option, widget); + } + } + + QRect subControlRect(ComplexControl cc, const QStyleOptionComplex* opt,SubControl sc, const QWidget* widget) const override + { + if (cc == CC_Slider) { + if (const QStyleOptionSlider* slider = qstyleoption_cast(opt)) { + QRect rect = slider->rect; + int handleSize = 20; + + if (sc == SC_SliderHandle) { + // Handle Position korrekt berechnen + if (slider->orientation == Qt::Horizontal) { + int range = slider->maximum - slider->minimum; + int pos = slider->sliderPosition - slider->minimum; + int pixelRange = rect.width() - handleSize; + int pixelPos = (range != 0) ? (pos * pixelRange) / range : 0; + + return QRect(rect.x() + pixelPos, + rect.center().y() - handleSize / 2, + handleSize, handleSize); + } else { + int range = slider->maximum - slider->minimum; + int pos = slider->sliderPosition - slider->minimum; + int pixelRange = rect.height() - handleSize; + int pixelPos = (range != 0) ? (pos * pixelRange) / range : 0; + + return QRect(rect.center().x() - handleSize / 2, + rect.bottom() - pixelPos - handleSize, + handleSize, handleSize); + } + } + } + } + return QProxyStyle::subControlRect(cc, opt, sc, widget); + } + + void drawComplexControl(ComplexControl control, const QStyleOptionComplex* option, QPainter* painter, const QWidget* widget) const override + { + if (control == CC_Slider) + { + if (const QStyleOptionSlider* slider = qstyleoption_cast(option)) { + painter->setRenderHint(QPainter::Antialiasing); + + // Fluent Colors + QColor accentColor(0, 120, 212); // #0078D4 + QColor inactiveColor(138, 136, 134); // #8A8886 + QColor bgColor(255, 255, 255); // White background + + if (slider->orientation == Qt::Horizontal) { + drawHorizontalFluentSlider(painter, slider, accentColor, inactiveColor, bgColor); + } else { + drawVerticalFluentSlider(painter, slider, accentColor, inactiveColor, bgColor); + } + return; + } + } + QProxyStyle::drawComplexControl(control, option, painter, widget); + } + +private: + + void drawHorizontalFluentSlider(QPainter* painter, const QStyleOptionSlider* slider, + const QColor& activeColor, const QColor& inactiveColor, + const QColor& bgColor) const { + QRect groove = slider->rect; + QRect handle = subControlRect(CC_Slider, slider, SC_SliderHandle, nullptr); + + int grooveHeight = 4; + // Track sollte im Widget-Zentrum sein, nicht im groove-Zentrum + int grooveY = slider->rect.center().y() - grooveHeight / 2; + + // Full background track + QRect fullTrack(groove.left(), grooveY, groove.width(), grooveHeight); + painter->setPen(Qt::NoPen); + painter->setBrush(inactiveColor.lighter(150)); + painter->drawRoundedRect(fullTrack, grooveHeight / 2, grooveHeight / 2); + + // Active track (filled portion) + int activeWidth = handle.center().x() - groove.left(); + QRect activeTrack(groove.left(), grooveY, activeWidth, grooveHeight); + painter->setBrush(activeColor); + painter->drawRoundedRect(activeTrack, grooveHeight / 2, grooveHeight / 2); + + // Handle (Thumb) - Fluent style is more subtle + int handleSize = 20; + QRect thumbRect(handle.center().x() - handleSize / 2, + handle.center().y() - handleSize / 2, + handleSize, handleSize); + + // Hover effect - subtle glow + if (slider->state & State_MouseOver) { + painter->setBrush(QColor(activeColor.red(), activeColor.green(), + activeColor.blue(), 30)); + int glowSize = 32; + QRect glow(handle.center().x() - glowSize / 2, + handle.center().y() - glowSize / 2, + glowSize, glowSize); + painter->drawEllipse(glow); + } + + // Thumb + painter->setBrush(bgColor); + painter->setPen(QPen(activeColor, 2)); + painter->drawEllipse(thumbRect); + + // Inner circle for pressed state + if (slider->state & State_Sunken) { + int innerSize = 8; + QRect inner(handle.center().x() - innerSize / 2, + handle.center().y() - innerSize / 2, + innerSize, innerSize); + painter->setPen(Qt::NoPen); + painter->setBrush(activeColor); + painter->drawEllipse(inner); + } + } + + void drawVerticalFluentSlider(QPainter* painter, const QStyleOptionSlider* slider, + const QColor& activeColor, const QColor& inactiveColor, + const QColor& bgColor) const { + QRect groove = slider->rect; + QRect handle = subControlRect(CC_Slider, slider, SC_SliderHandle, nullptr); + + int grooveWidth = 4; + // Track sollte im Widget-Zentrum sein + int grooveX = slider->rect.center().x() - grooveWidth / 2; + + // Full background track + QRect fullTrack(grooveX, groove.top(), grooveWidth, groove.height()); + painter->setPen(Qt::NoPen); + painter->setBrush(inactiveColor.lighter(150)); + painter->drawRoundedRect(fullTrack, grooveWidth / 2, grooveWidth / 2); + + // Active track + int activeHeight = groove.bottom() - handle.center().y(); + QRect activeTrack(grooveX, handle.center().y(), grooveWidth, activeHeight); + painter->setBrush(activeColor); + painter->drawRoundedRect(activeTrack, grooveWidth / 2, grooveWidth / 2); + + // Handle + int handleSize = 20; + QRect thumbRect(handle.center().x() - handleSize / 2, + handle.center().y() - handleSize / 2, + handleSize, handleSize); + + if (slider->state & State_MouseOver) { + painter->setBrush(QColor(activeColor.red(), activeColor.green(), + activeColor.blue(), 30)); + int glowSize = 32; + QRect glow(handle.center().x() - glowSize / 2, + handle.center().y() - glowSize / 2, + glowSize, glowSize); + painter->drawEllipse(glow); + } + + painter->setBrush(bgColor); + painter->setPen(QPen(activeColor, 2)); + painter->drawEllipse(thumbRect); + + if (slider->state & State_Sunken) { + int innerSize = 8; + QRect inner(handle.center().x() - innerSize / 2, + handle.center().y() - innerSize / 2, + innerSize, innerSize); + painter->setPen(Qt::NoPen); + painter->setBrush(activeColor); + painter->drawEllipse(inner); + } + } +}; + +class SliderDelegate : public QStyledItemDelegate +{ + Q_OBJECT + +public: + SliderDelegate(QObject* parent = nullptr) + : QStyledItemDelegate(parent) + {} + + // Editor erstellen (QSlider) + QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option,const QModelIndex& index) const override + { + Q_UNUSED(option) + Q_UNUSED(index) + + auto* slider = new QSlider(Qt::Horizontal, parent); + slider->setRange(0, 100); + slider->setSingleStep(1); + slider->setPageStep(10); +slider->setStyle(new FluentSliderStyle()); + // Signal für sofortige Updates + connect(slider, &QSlider::valueChanged, this, [this, slider]() { + // Commit data sofort bei Änderung + emit const_cast(this)->commitData(slider); + }); + + return slider; + } + + // Editor mit aktuellem Wert füllen + void setEditorData(QWidget* editor, const QModelIndex& index) const override { + int value = index.model()->data(index, Qt::EditRole).toInt(); + auto* slider = static_cast(editor); + slider->setValue(value); + } + + // Wert vom Editor ins Model schreiben + void setModelData(QWidget* editor, QAbstractItemModel* model, + const QModelIndex& index) const override { + auto* slider = static_cast(editor); + int value = slider->value(); + model->setData(index, value, Qt::EditRole); + } + + // Editor-Geometrie (wichtig für korrekte Positionierung) + void updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, + const QModelIndex& index) const override { + Q_UNUSED(index) + /* + QRect barRect = option.rect.adjusted(option.rect.width() - 55, + option.rect.height() / 2 - 2, + -8, + -option.rect.height() / 2 + 2); + */ + QRect sliderRect = option.rect.adjusted( + option.rect.width() - 115, // Von rechts: 115px (Breite der Progress Bar) + 0, // Oben: kein Offset + -8, // Rechts: 8px Padding + 0 // Unten: kein Offset + ); + editor->setGeometry(sliderRect); // Slider nur über Progress Bar + //editor->setGeometry(option.rect); + } + + // Anzeige wenn NICHT editiert wird + void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override + { + + if (index.column() == 1) + { // Nur für Wert-Spalte + // Wert holen + int value = index.model()->data(index, Qt::DisplayRole).toInt(); + + // Hintergrund + if (option.state & QStyle::State_Selected) { + painter->fillRect(option.rect, option.palette.highlight()); + } else if (index.row() % 2 == 1) { + painter->fillRect(option.rect, QColor(0xFAFAFA)); + } else { + painter->fillRect(option.rect, Qt::white); + } + + // Text und kleiner Slider-Indikator zeichnen + painter->save(); + painter->setRenderHint(QPainter::Antialiasing); + + QRect textRect = option.rect.adjusted(8, 0, -120, 0); + QRect barRect = option.rect.adjusted(option.rect.width() - 115, + option.rect.height() / 2 - 2, + -8, + -option.rect.height() / 2 + 2); + + // Text + painter->setPen(option.state & QStyle::State_Selected ? + option.palette.highlightedText().color() : Qt::black); + painter->drawText(textRect, Qt::AlignVCenter | Qt::AlignLeft, + QString::number(value)); + + // Mini Progress Bar + painter->setPen(Qt::NoPen); + painter->setBrush(QColor(0xE0E0E0)); + painter->drawRoundedRect(barRect, 2, 2); + + QRect fillRect = barRect; + fillRect.setWidth(barRect.width() * value / 100); + painter->setBrush(QColor(0x0078D4)); + painter->drawRoundedRect(fillRect, 2, 2); + + painter->restore(); + } else { + // Standard-Zeichnung für andere Spalten + QStyledItemDelegate::paint(painter, option, index); + } + } +}; + +#endif // SLIDERDELEGATE_H diff --git a/main.cpp b/main.cpp index 4cbe0da..4bedc79 100644 --- a/main.cpp +++ b/main.cpp @@ -38,21 +38,21 @@ #include #include -#include -#include +#include +#include /* #include void parseString(const QString &inputString) { -QMetaEnum metaEnum = QMetaEnum::fromType(); +QMetaEnum metaEnum = QMetaEnum::fromType(); bool ok = false; // keyToValue parst den String ("x1") und liefert den int-Wert int intVal = metaEnum.keyToValue(inputString.toLatin1().constData(), &ok); if (ok) { - BCValue::ID id = static_cast(intVal); + BCData::ID id = static_cast(intVal); // Erfolg! } else { // Fehler: String existiert nicht im Enum