Currently job artifacts in CI/CD pipelines on LRZ GitLab never expire. Starting from Wed 26.1.2022 the default expiration time will be 30 days (GitLab default). Currently existing artifacts in already completed jobs will not be affected by the change. The latest artifacts for all jobs in the latest successful pipelines will be kept. More information: https://gitlab.lrz.de/help/user/admin_area/settings/continuous_integration.html#default-artifacts-expiration

datacontainerinspectorwidget.cpp 22.7 KB
Newer Older
1
2
// ================================================================================================
// 
schultezub's avatar
schultezub committed
3
// This file is part of the CAMPVis Software Framework.
4
// 
5
// If not explicitly stated otherwise: Copyright (C) 2012-2013, all rights reserved,
schultezub's avatar
schultezub committed
6
//      Christian Schulte zu Berge <christian.szb@in.tum.de>
7
//      Chair for Computer Aided Medical Procedures
8
9
//      Technische Universität München
//      Boltzmannstr. 3, 85748 Garching b. München, Germany
10
// 
schultezub's avatar
schultezub committed
11
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
12
// 
13
14
15
16
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 
// except in compliance with the License. You may obtain a copy of the License at
// 
// http://www.apache.org/licenses/LICENSE-2.0
17
// 
18
19
20
21
// Unless required by applicable law or agreed to in writing, software distributed under the 
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
// either express or implied. See the License for the specific language governing permissions 
// and limitations under the License.
22
23
24
25
26
27
// 
// ================================================================================================

#include "datacontainerinspectorwidget.h"

#include "tgt/assert.h"
28
#include "tgt/logmanager.h"
29
#include "tgt/filesystem.h"
30
31
32
#include "tgt/shadermanager.h"
#include "tgt/textureunit.h"

33
34
35
36
37
38
39
40
#ifdef CAMPVIS_HAS_MODULE_DEVIL
#include <IL/il.h>
#include <IL/ilu.h>
#endif

#include "core/tools/job.h"
#include "core/tools/opengljobprocessor.h"

41
#include "core/datastructures/abstractdata.h"
42
#include "core/datastructures/datacontainer.h"
43
#include "core/datastructures/facegeometry.h"
44
#include "core/datastructures/geometrydata.h"
45
#include "core/datastructures/imagerepresentationgl.h"
46
#include "core/datastructures/renderdata.h"
47

48
49
50
51
#ifdef CAMPVIS_HAS_MODULE_COLUMBIA
#include "modules/columbia/datastructures/fiberdata.h"
#endif

52
#include "application/gui/datacontainertreewidget.h"
53
#include "application/gui/qtdatahandle.h"
54
#include "application/gui/datacontainerfileloaderwidget.h"
55
#include "modules/io/processors/genericimagereader.h"
56

57
#include <QFileDialog>
58
#include <QScrollArea>
59

schultezub's avatar
schultezub committed
60
namespace campvis {
61

62
63
    const std::string DataContainerInspectorWidget::loggerCat_ = "CAMPVis.application.DataContainerInspectorWidget";

64
65
    DataContainerInspectorWidget::DataContainerInspectorWidget(QWidget* parent) 
        : QWidget(parent)
66
        , _inited(false)
67
68
69
        , _dataContainer(0)
        , _dctWidget(0)
        , _canvas(0)
70
        , _pcWidget(0)
71
72
73
        , _mainLayout(0)
        , _infoWidget(0)
        , _infoWidgetLayout(0)
74
        , _lblName(0)
75
        , _lblNumChannels(0)
76
77
78
79
80
81
82
83
84
85
86
        , _lblLocalMemoryFootprint(0)
        , _lblVideoMemoryFootprint(0)
        , _lblTimestamp(0)
        , _lblSize(0)
        , _lblBounds(0)
        , _colorWidget(0)
        , _colorWidgetLayout(0)
        , _lblColorVal(0)
        , _colorValWidget(0)
        , _btnLoadFile(0)
        , _btnSaveToFile(0)
87
        , _propEditorWid(0)
88
89
90
91
92
    {
        setupGUI();
    }

    DataContainerInspectorWidget::~DataContainerInspectorWidget() {
93
94
95
        if (_dataContainer != 0) {
            _dataContainer->s_dataAdded.disconnect(this);
        }
96
97
98
99
    }

    void DataContainerInspectorWidget::setDataContainer(DataContainer* dataContainer) {
        if (_dataContainer != 0) {
100
            _dataContainer->s_dataAdded.disconnect(this);
101
102
103
104
        }

        _dataContainer = dataContainer;
        _dctWidget->update(dataContainer);
105
        updateInfoWidget();
106

107
        if (_dataContainer != 0) {
108
            _dataContainer->s_dataAdded.connect(this, &DataContainerInspectorWidget::onDataContainerDataAdded);
109
110
111
        }
    }

112
113
114
115
    DataContainer* DataContainerInspectorWidget::getDataContainer() {
        return _dataContainer;
    }

116
    void DataContainerInspectorWidget::onDataContainerDataAdded(const std::string& key, const DataHandle& dh) {
117
118
        // copy QtDataHandle because signal will be handled by a different thread an indefinite amount of time later:
        emit dataContainerChanged(QString::fromStdString(key), QtDataHandle(dh));
119
120
121
    }

    QSize DataContainerInspectorWidget::sizeHint() const {
122
        return QSize(800, 600);
123
124
    }

125

126
    void DataContainerInspectorWidget::setupGUI() {
schultezub's avatar
schultezub committed
127
128
        setWindowTitle(tr("DataContainer Inspector"));

129
        _mainLayout = new QGridLayout();
130
131
132
        _mainLayout->setSpacing(4);
        setLayout(_mainLayout);

133
        // left column
134
        _dctWidget = new DataContainerTreeWidget(this);
135
136
        _dctWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
        _dctWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
137
        _dctWidget->setMinimumWidth(256);
138
        _mainLayout->addWidget(_dctWidget, 0, 0);
139

140
141
142
143
144
145
146
147
148
149
150
151
152
        _btnLoadFile = new QPushButton(tr("Load File"), _infoWidget);
        _mainLayout->addWidget(_btnLoadFile, 1, 0);

#ifdef CAMPVIS_HAS_MODULE_DEVIL
        _btnSaveToFile = new QPushButton(tr("Save to File"), _infoWidget);
        _btnSaveToFile->setDisabled(true);
        _mainLayout->addWidget(_btnSaveToFile, 2, 0);

        connect(_btnSaveToFile, SIGNAL(clicked()), this, SLOT(onBtnSaveToFileClicked()));
#endif


        // right column
153
        _infoWidget = new QWidget(this);
154
        _infoWidgetLayout = new QGridLayout();
155
156
157
158
        _infoWidgetLayout->setSpacing(4);
        _infoWidget->setLayout(_infoWidgetLayout);

        _lblName = new QLabel(QString("Name: "), _infoWidget);
159
        _infoWidgetLayout->addWidget(_lblName, 0, 0);
160

161
162
        _lblTimestamp = new QLabel("Timestamp: ", _infoWidget);
        _infoWidgetLayout->addWidget(_lblTimestamp, 0, 1);
163

164
165
        _lblNumChannels = new QLabel("Number of Channels: ", _infoWidget);
        _infoWidgetLayout->addWidget(_lblNumChannels, 1, 0);
166

167
168
        _lblLocalMemoryFootprint = new QLabel(QString("Local Memory: "), _infoWidget);
        _infoWidgetLayout->addWidget(_lblLocalMemoryFootprint, 1, 1);
169

170
        _lblSize = new QLabel(tr("Size: "), _infoWidget);
171
172
        _infoWidgetLayout->addWidget(_lblSize, 2, 0);

173
174
175
        _lblVideoMemoryFootprint = new QLabel(QString("Video Memory: "), _infoWidget);
        _infoWidgetLayout->addWidget(_lblVideoMemoryFootprint, 2, 1);

176
177
        _lblBounds = new QLabel(tr("World Bounds:"), _infoWidget);
        _infoWidgetLayout->addWidget(_lblBounds, 3, 0, 1, 2);
178

179
180
181
182
183
184
185
        _colorWidget = new QWidget(this);
        _lblColorVal = new QLabel(tr("Color: n/a"), _colorWidget);
        
        _colorValWidget = new QWidget(_colorWidget);
        _colorValWidget->setAutoFillBackground(true);
        _colorValWidget->setFixedSize(16, 16);
        
186
187
188
        _colorValWidgetPalette = QPalette(palette());
        _colorValWidgetPalette.setColor(QPalette::Background, Qt::gray);
        _colorValWidget->setPalette(_colorValWidgetPalette);
189
190
191
192
193
194
195
196
197
        
        _colorWidgetLayout = new QHBoxLayout();
        _colorWidgetLayout->setSpacing(0);
        _colorWidgetLayout->setMargin(0);
        _colorWidget->setLayout(_colorWidgetLayout);
        
        _colorWidgetLayout->addWidget(_lblColorVal);
        _colorWidgetLayout->addWidget(_colorValWidget);

198
        _infoWidgetLayout->addWidget(_colorWidget, 4, 0, 1, 2);
199

200
        _canvas = new DataContainerInspectorCanvas(_infoWidget);
201
        _canvas->setMinimumSize(QSize(100, 100));
202
        _infoWidgetLayout->addWidget(_canvas, 5, 0, 1, 2);
203
        _infoWidgetLayout->setRowStretch(5, 2);
204

205
206
207
208
        QScrollArea* _pipelinePropertiesScrollArea = new QScrollArea(_infoWidget);
        _pipelinePropertiesScrollArea->setWidgetResizable(true);
        _pipelinePropertiesScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
        _pipelinePropertiesScrollArea->setFrameStyle(QScrollArea::NoFrame);
209
        _pipelinePropertiesScrollArea->setMinimumHeight(224);
210
211

        _pcWidget = new PropertyCollectionWidget(_pipelinePropertiesScrollArea);
212
        _pcWidget->updatePropCollection(_canvas, _dataContainer);
213
214
215
        _pipelinePropertiesScrollArea->setWidget(_pcWidget);

        _infoWidgetLayout->addWidget(_pipelinePropertiesScrollArea, 6, 0, 1, 2);
216

217
        _mainLayout->addWidget(_infoWidget, 0, 1, 3, 1);
218

219
        qRegisterMetaType<QtDataHandle>("QtDataHandle");
220
        qRegisterMetaType<tgt::vec4>("tgt_vec4");
221
222
223
224
225
226
        connect(
            _dctWidget->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), 
            this, SLOT(onDCTWidgetSelectionModelSelectionChanged(const QItemSelection&, const QItemSelection&)));
        connect(
            this, SIGNAL(dataContainerChanged(const QString&, QtDataHandle)),
            _canvas, SLOT(onDataContainerChanged(const QString&, QtDataHandle)));
227
228
229
230
231
232
        connect(
            _canvas, SIGNAL(s_colorChanged(const tgt::vec4&)),
            this, SLOT(onColorChanged(const tgt::vec4&)));
        connect(
            _canvas, SIGNAL(s_depthChanged(float)),
            this, SLOT(onDepthChanged(float)));
233
        connect(
234
235
            this, SIGNAL(dataContainerChanged(const QString&, QtDataHandle)),
            _dctWidget->getTreeModel(), SLOT(onDataContainerChanged(const QString&, QtDataHandle)));
236
        connect(
237
238
            _btnLoadFile, SIGNAL(clicked()),
            this, SLOT(onBtnLoadFileClicked()));
239
240
241
    }

    void DataContainerInspectorWidget::updateInfoWidget() {
242
243
244
        if (!_inited)
            return;

245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
        // get the selection from the tree widget
        const QModelIndexList& indices = _dctWidget->selectionModel()->selectedRows();
        std::vector< std::pair<QString, QtDataHandle> > handles;
        float _localFootprint = 0.f;
        float _videoFootprint = 0.f;

        // iterate through the indices of the selection
        for (QModelIndexList::const_iterator index = indices.begin(); index != indices.end(); ++index) {
            if (! index->isValid())
                continue;
            // get DataHandle and Handle name
            QVariant item = index->data(Qt::UserRole);
            QtDataHandle handle = item.value<QtDataHandle>();
            QModelIndex idxName = index->sibling(index->row(), 0);

            // only consider non-empty DataHandles
            if (handle.getData() != 0) {
                handles.push_back(std::make_pair(idxName.data(Qt::DisplayRole).toString(), handle));
                _localFootprint += handle.getData()->getLocalMemoryFootprint();
                _videoFootprint += handle.getData()->getVideoMemoryFootprint();
            }
schultezub's avatar
schultezub committed
266
        }
267

268
269
270
271
        // update labels
        if (handles.size() == 1) {
            _lblName->setText("Name: " + handles.front().first);
            _lblTimestamp->setText("Timestamp: " + QString::number(handles.front().second.getTimestamp()));
272

273
            if (const ImageData* tester = dynamic_cast<const ImageData*>(handles.front().second.getData())) {
274
                _canvas->p_transferFunction.setImageHandle(handles.front().second);
275
276
277

                _lblNumChannels->setText(tr("Number of Channels: ") + QString::number(tester->getNumChannels()));

278
279
280
281
282
283
284
285
                std::ostringstream ss;

                ss << tester->getSize();
                _lblSize->setText(tr("Size: ") + QString::fromStdString(ss.str()));

                ss.str("");
                ss << tester->getWorldBounds();
                _lblBounds->setText(tr("World Bounds: ") + QString::fromStdString(ss.str())); 
286

287
288
289
290
291
292
                _canvas->p_currentSlice.setVisible(tester->getDimensionality() == 3);
                _canvas->p_transferFunction.setVisible(true);
                _canvas->p_renderRChannel.setVisible(true);
                _canvas->p_renderGChannel.setVisible(true);
                _canvas->p_renderBChannel.setVisible(true);
                _canvas->p_renderAChannel.setVisible(true);
293
                _canvas->p_geometryRendererProperties.setVisible(false);
294
295
296
            }
            else if (const GeometryData* tester = dynamic_cast<const GeometryData*>(handles.front().second.getData())) {
                _lblSize->setText(tr("Size: n/a"));
297
                _lblNumChannels->setText(tr("Number of Channels: n/a"));
298

299
                std::ostringstream ss;
300
                ss << tester->getWorldBounds();
301
                _lblBounds->setText(tr("World Bounds: ") + QString::fromStdString(ss.str()));
302
303
304
305
306
307
308

                _canvas->p_currentSlice.setVisible(false);
                _canvas->p_transferFunction.setVisible(false);
                _canvas->p_renderRChannel.setVisible(false);
                _canvas->p_renderGChannel.setVisible(false);
                _canvas->p_renderBChannel.setVisible(false);
                _canvas->p_renderAChannel.setVisible(false);
309
                _canvas->p_geometryRendererProperties.setVisible(true);
310
            }
311
312
313
            else if (const RenderData* tester = dynamic_cast<const RenderData*>(handles.front().second.getData())) {
                const ImageData* id = tester->getNumColorTextures() > 0 ? tester->getColorTexture() : tester->getDepthTexture();
                if (id != 0) {
314
315
                    _lblNumChannels->setText(tr("Number of Channels: ") + QString::number(id->getNumChannels()));

316
317
318
319
320
321
322
323
324
                    std::ostringstream ss;
                    ss << id->getSize();
                    _lblSize->setText(tr("Size: ") + QString::fromStdString(ss.str()));

                    ss.str("");
                    ss << id->getWorldBounds();
                    _lblBounds->setText(tr("World Bounds: ") + QString::fromStdString(ss.str())); 
                }
                else {
325
                    _lblNumChannels->setText(tr("Number of Channels: n/a"));
326
327
328
                    _lblSize->setText(tr("Size: n/a"));
                    _lblBounds->setText(tr("World Bounds: n/a")); 
                }
329
330
331
332
333
334
335

                _canvas->p_currentSlice.setVisible(false);
                _canvas->p_transferFunction.setVisible(true);
                _canvas->p_renderRChannel.setVisible(true);
                _canvas->p_renderGChannel.setVisible(true);
                _canvas->p_renderBChannel.setVisible(true);
                _canvas->p_renderAChannel.setVisible(true);
336
                _canvas->p_geometryRendererProperties.setVisible(false);
337
            }
338
339
#ifdef CAMPVIS_HAS_MODULE_COLUMBIA
            else if (const FiberData* tester = dynamic_cast<const FiberData*>(handles.front().second.getData())) {
340
                _lblNumChannels->setText(tr("Number of Channels: n/a"));
341
342
343
344
345
346
347
348
349
350
                std::ostringstream ss;
                ss << "Size: " << tester->numFibers() << " Fibers with " << tester->numSegments() << " Segments.";
                _lblSize->setText(QString::fromStdString(ss.str()));

                ss.str("");
                ss << tester->getWorldBounds();
                _lblBounds->setText(tr("World Bounds: ") + QString::fromStdString(ss.str())); 
            }
#endif
            else {
351
                _lblNumChannels->setText(tr("Number of Channels: n/a"));
352
                _lblSize->setText(tr("Size: n/a"));
353
354
                _lblBounds->setText(tr("World Bounds: n/a")); 
            }
355
356
357
358
        }
        else {
            _lblName->setText(QString::number(handles.size()) + " DataHandles selected");
            _lblTimestamp->setText("Timestamp: n/a");
359

360
            _canvas->p_transferFunction.setImageHandle(DataHandle(0));
361
        }
362
363
        _lblLocalMemoryFootprint->setText("Local Memory: " + humanizeBytes(_localFootprint));
        _lblVideoMemoryFootprint->setText("Video Memory: " + humanizeBytes(_videoFootprint));
364
365

        // update DataHandles for the DataContainerInspectorCanvas
366
        _canvas->setDataHandles(handles);
367
368
    }

369
370
371
372
373
    QString DataContainerInspectorWidget::humanizeBytes(size_t numBytes) const {
        QString units[5] = { tr(" Bytes"), tr(" KB"), tr(" MB"), tr(" GB"), tr(" TB") };
        size_t index = 0;
        size_t remainder = 0;

374
        while (numBytes > 1024 && index < 4) {
375
376
377
378
379
380
381
382
383
384
385
            remainder = numBytes % 1024;
            numBytes /= 1024;
            ++index;
        }

        if (remainder != 0)
            return QString::number(numBytes) + "." + QString::number(remainder) + units[index];
        else
            return QString::number(numBytes) + units[index];
    }

386
387
    void DataContainerInspectorWidget::init() {
        if (_canvas != 0)
388
            _canvas->init();
389
390

        _inited = true;
391
392
393
    }

    void DataContainerInspectorWidget::deinit() {
394
        _inited = false;
395
396
        if (_canvas != 0)
            _canvas->deinit();
schultezub's avatar
schultezub committed
397

398
        _pcWidget->updatePropCollection(0, 0);
399
400
401
402
403
404

        if (_dataContainer != 0) {
            _dataContainer->s_dataAdded.disconnect(this);
        }

        _dataContainer = 0;
405
        _dctWidget->update(0);
406
407
408

        if(_propEditorWid != nullptr)
            _propEditorWid->deinit();
409
410
    }

411
412
    void DataContainerInspectorWidget::onDCTWidgetSelectionModelSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected) {
        updateInfoWidget();
413
414
415
416
417
418
419
420
421
422
423
424

        // get the selection from the tree widget
        const QModelIndexList& indices = _dctWidget->selectionModel()->selectedRows();

        // iterate through the indices of the selection
        for (QModelIndexList::const_iterator index = indices.begin(); index != indices.end(); ++index) {
            if (index->isValid()) {
                _btnSaveToFile->setDisabled(false);
                return;
            }
        }
        _btnSaveToFile->setDisabled(true);
425
426
    }

427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
    void DataContainerInspectorWidget::onBtnSaveToFileClicked() {
        // get the selection from the tree widget
        const QModelIndexList& indices = _dctWidget->selectionModel()->selectedRows();

        // iterate through the indices of the selection
        for (QModelIndexList::const_iterator index = indices.begin(); index != indices.end(); ++index) {
            if (! index->isValid())
                continue;

            // get DataHandle and Handle name
            QVariant item = index->data(Qt::UserRole);
            DataHandle handle = item.value<QtDataHandle>();
            QModelIndex idxName = index->sibling(index->row(), 0);

            // only consider non-empty DataHandles that are ImageData and have render target representations
            if (handle.getData() != 0) {
443
444
445
446
447
448
449
450
451
452
453
454
455
                if (dynamic_cast<const ImageData*>(handle.getData()) || dynamic_cast<const RenderData*>(handle.getData())) {
                    QString dialogCaption = "Export " + idxName.data(Qt::DisplayRole).toString() + " as Image";
                    QString directory = tr("");
                    const QString fileFilter = tr("*.png;;PNG images (*.png)");

                    QString filename = QFileDialog::getSaveFileName(this, dialogCaption, directory, fileFilter);

                    if (! filename.isEmpty()) {
                        // Texture access needs OpenGL context - dispatch method call:
                        GLJobProc.enqueueJob(
                            _canvas, 
                            makeJobOnHeap(&DataContainerInspectorWidget::saveToFile, handle, filename.toStdString()), 
                            OpenGLJobProcessor::SerialJob);
456
457
458
459
460
461
462
463
464
465
466
467
468
                    }
                }
            }
        }
    }

    void DataContainerInspectorWidget::saveToFile(DataHandle handle, std::string filename) {
#ifdef CAMPVIS_HAS_MODULE_DEVIL
        if (tgt::FileSystem::fileExtension(filename).empty()) {
            LERRORC("CAMPVis.application.DataContainerInspectorWidget", "Filename has no extension");
            return;
        }

469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
        // get the ImageData object (either directly or from the RenderData)
        const ImageData* id = 0;
        if (const RenderData* tester = dynamic_cast<const RenderData*>(handle.getData())) {
            id = tester->getColorTexture(0);
        }
        else if (const ImageData* tester = dynamic_cast<const ImageData*>(handle.getData())) {
            id = tester;
        }
        else {
            LERROR("Could not extract image to save.");
            return;
        }

        // extract the data
        WeaklyTypedPointer wtp(WeaklyTypedPointer::UINT8, 1, 0);
        const ImageRepresentationGL* repGL = id->getRepresentation<ImageRepresentationGL>(false);
        if (repGL != 0) // if it's a GL texture, download it (we do not want to use the automatic conversion method here)
            wtp = repGL->getWeaklyTypedPointer();
        else {
            const ImageRepresentationLocal* repLocal = id->getRepresentation<ImageRepresentationLocal>(true);
            if (repLocal != 0)
                wtp = repLocal->getWeaklyTypedPointer();
        }

        if (wtp._pointer == 0) {
            LERROR("Could not extract image to save.");
            return;
        }
497
498
499
500
501
502
503
504


        // create Devil image from image data and write it to file
        ILuint img;
        ilGenImages(1, &img);
        ilBindImage(img);

        // put pixels into IL-Image
505
506
        tgt::ivec2 size = id->getSize().xy();
        ilTexImage(size.x, size.y, 1, static_cast<ILubyte>(wtp._numChannels), wtp.getIlFormat(), wtp.getIlDataType(), wtp._pointer);
507
508
509
510
511
512
513
514
515
516
517
518
519
520
        ilEnable(IL_FILE_OVERWRITE);
        ilResetWrite();
        ILboolean success = ilSaveImage(filename.c_str());
        ilDeleteImages(1, &img);

        if (!success) {
            LERRORC("CAMPVis.application.DataContainerInspectorWidget", "Could not save image to file: " << ilGetError());
        }
#else
        return;
#endif

    }

521
    void DataContainerInspectorWidget::onBtnLoadFileClicked() {
522
523
524
        // delete previous PropertyEditor, then create a new one
        // the final one will be deleted with deinit()
        if(nullptr != _propEditorWid)
525
            _propEditorWid->deinit();
526

527
        _propEditorWid = new DataContainerFileLoaderWidget(this, nullptr);
528
529
        _propEditorWid->setVisible(true);
        
530
531
    }

532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
    void DataContainerInspectorWidget::onColorChanged(const tgt::vec4& color) {
        _lblColorVal->setText(QString("Color: [%1, %2, %3, %4]").arg(QString::number(color.r), QString::number(color.g), QString::number(color.b), QString::number(color.a)));

        tgt::ivec4 clamped(tgt::clamp(color * 255.f, 0.f, 255.f));
        _colorValWidgetPalette.setColor(QPalette::Background, QColor(clamped.r, clamped.g, clamped.b, clamped.a));
        _colorValWidget->setPalette(_colorValWidgetPalette);
    }

    void DataContainerInspectorWidget::onDepthChanged(float depth) {
        _lblColorVal->setText(QString("Depth: %1").arg(QString::number(depth)));

        tgt::ivec4 clamped(tgt::clamp(depth * 255.f, 0.f, 255.f));
        _colorValWidgetPalette.setColor(QPalette::Background, QColor(clamped.r, clamped.g, clamped.b, clamped.a));
        _colorValWidget->setPalette(_colorValWidgetPalette);
    }

548
}