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.6 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

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

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

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

215
        _mainLayout->addWidget(_infoWidget, 0, 1, 3, 1);
216

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

    void DataContainerInspectorWidget::updateInfoWidget() {
240
241
242
        if (!_inited)
            return;

243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
        // 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
264
        }
265

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

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

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

276
277
278
279
280
281
282
283
                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())); 
284

285
286
287
288
289
290
                _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);
291
                _canvas->p_geometryRendererProperties.setVisible(false);
292
293
294
            }
            else if (const GeometryData* tester = dynamic_cast<const GeometryData*>(handles.front().second.getData())) {
                _lblSize->setText(tr("Size: n/a"));
295
                _lblNumChannels->setText(tr("Number of Channels: n/a"));
296

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

                _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);
307
                _canvas->p_geometryRendererProperties.setVisible(true);
308
            }
309
310
311
            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) {
312
313
                    _lblNumChannels->setText(tr("Number of Channels: ") + QString::number(id->getNumChannels()));

314
315
316
317
318
319
320
321
322
                    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 {
323
                    _lblNumChannels->setText(tr("Number of Channels: n/a"));
324
325
326
                    _lblSize->setText(tr("Size: n/a"));
                    _lblBounds->setText(tr("World Bounds: n/a")); 
                }
327
328
329
330
331
332
333

                _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);
334
                _canvas->p_geometryRendererProperties.setVisible(false);
335
            }
336
337
#ifdef CAMPVIS_HAS_MODULE_COLUMBIA
            else if (const FiberData* tester = dynamic_cast<const FiberData*>(handles.front().second.getData())) {
338
                _lblNumChannels->setText(tr("Number of Channels: n/a"));
339
340
341
342
343
344
345
346
347
348
                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 {
349
                _lblNumChannels->setText(tr("Number of Channels: n/a"));
350
                _lblSize->setText(tr("Size: n/a"));
351
352
                _lblBounds->setText(tr("World Bounds: n/a")); 
            }
353
354
355
356
        }
        else {
            _lblName->setText(QString::number(handles.size()) + " DataHandles selected");
            _lblTimestamp->setText("Timestamp: n/a");
357

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

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

367
368
369
370
371
    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;

372
        while (numBytes > 1024 && index < 4) {
373
374
375
376
377
378
379
380
381
382
383
            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];
    }

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

        _inited = true;
389
390
391
    }

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

396
        _pcWidget->updatePropCollection(0, 0);
397
398
399
400
401
402

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

        _dataContainer = 0;
403
        _dctWidget->update(0);
404
405
406

        if(_propEditorWid != nullptr)
            _propEditorWid->deinit();
407
408
    }

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

        // 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);
423
424
    }

425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
    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) {
441
442
443
444
445
446
447
448
449
450
451
452
453
                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);
454
455
456
457
458
459
460
461
462
463
464
465
466
                    }
                }
            }
        }
    }

    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;
        }

467
468
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
        // 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;
        }
495
496
497
498
499
500
501
502


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

        // put pixels into IL-Image
503
504
        tgt::ivec2 size = id->getSize().xy();
        ilTexImage(size.x, size.y, 1, static_cast<ILubyte>(wtp._numChannels), wtp.getIlFormat(), wtp.getIlDataType(), wtp._pointer);
505
506
507
508
509
510
511
512
513
514
515
516
517
518
        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

    }

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

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

530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
    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);
    }

546
}