]> git.cworth.org Git - apitrace/blob - gui/argumentseditor.cpp
Take GL_SAMPLER_BINDING in consideration.
[apitrace] / gui / argumentseditor.cpp
1 #include "argumentseditor.h"
2
3 #include "apitracecall.h"
4
5 #include <QDebug>
6 #include <QDoubleSpinBox>
7 #include <QItemEditorFactory>
8 #include <QSpinBox>
9
10 #include <limits.h>
11 #include <float.h>
12
13
14 static bool
15 isVariantEditable(const QVariant &var)
16 {
17     if (var.canConvert<ApiArray>()) {
18         ApiArray array = var.value<ApiArray>();
19         QVector<QVariant> vals = array.values();
20         if (vals.isEmpty())
21             return false;
22         else
23             return isVariantEditable(vals.first());
24     }
25     switch (var.userType()) {
26     case QVariant::Bool:
27     case QVariant::Int:
28     case QVariant::UInt:
29     case QVariant::LongLong:
30     case QVariant::ULongLong:
31     case QMetaType::Float:
32     case QVariant::Double:
33     case QVariant::String:
34         return true;
35     default:
36         return false;
37     }
38 }
39
40 static bool
41 isVariantStringArray(const QVariant &var)
42 {
43     if (var.isNull() || var.userType() != QMetaType::type("ApiArray"))
44         return false;
45
46     ApiArray array = var.value<ApiArray>();
47     QVector<QVariant> origValues = array.values();
48     if (origValues.isEmpty() ||
49         origValues.first().userType() != QVariant::String)
50         return false;
51
52     return true;
53 }
54
55
56
57 void setArgumentsItemEditorFactory ()
58 {
59     QItemEditorCreatorBase *booleanComboBoxEditorCreator =
60     new QStandardItemEditorCreator<BooleanComboBoxEditorCreator>();
61     QItemEditorCreatorBase *uIntEditorCreator =
62     new QStandardItemEditorCreator<UIntEditorCreator>();
63     QItemEditorCreatorBase *intEditorCreator =
64     new QStandardItemEditorCreator<IntEditorCreator>();
65     QItemEditorCreatorBase *uLongLongEditorCreator =
66     new QStandardItemEditorCreator<ULongLongEditorCreator>();
67     QItemEditorCreatorBase *longLongEditorCreator =
68     new QStandardItemEditorCreator<LongLongEditorCreator>();
69     QItemEditorCreatorBase *pixmapEditorCreator =
70     new QStandardItemEditorCreator<PixmapEditorCreator>();
71     QItemEditorCreatorBase *floatEditorCreator =
72     new QStandardItemEditorCreator<FloatEditorCreator>();
73     QItemEditorCreatorBase *doubleEditorCreator =
74     new QStandardItemEditorCreator<DoubleEditorCreator>();
75     QItemEditorCreatorBase *stringEditorCreator =
76     new QStandardItemEditorCreator<StringEditorCreator>();
77     QItemEditorCreatorBase *invalidEditorCreator =
78     new QStandardItemEditorCreator<InvalidEditorCreator>();
79
80     QItemEditorFactory *factory =
81         new QItemEditorFactory();
82
83     QVariant::Type typeFloat = static_cast<QVariant::Type> (qMetaTypeId<float>());
84
85     factory->registerEditor(QVariant::Bool, booleanComboBoxEditorCreator);
86     factory->registerEditor(QVariant::UInt, uIntEditorCreator);
87     factory->registerEditor(QVariant::Int, intEditorCreator);
88     factory->registerEditor(QVariant::ULongLong, uLongLongEditorCreator);
89     factory->registerEditor(QVariant::LongLong, longLongEditorCreator);
90     factory->registerEditor(QVariant::Pixmap, pixmapEditorCreator);
91     factory->registerEditor(typeFloat, floatEditorCreator);
92     factory->registerEditor(QVariant::Double, doubleEditorCreator);
93     factory->registerEditor(QVariant::String, stringEditorCreator);
94     factory->registerEditor(QVariant::Invalid, invalidEditorCreator);
95
96     QItemEditorFactory::setDefaultFactory(factory);
97 }
98
99 BooleanComboBox::BooleanComboBox(QWidget *parent)
100     : QComboBox(parent)
101 {
102     addItem(tr("False"));
103     addItem(tr("True"));
104 }
105
106 void BooleanComboBox::setValue(bool value)
107 {
108     setCurrentIndex(value ? 1 : 0);
109 }
110
111 bool BooleanComboBox::value() const
112 {
113     return (currentIndex() == 1);
114 }
115
116 ArgumentsEditor::ArgumentsEditor(QWidget *parent)
117     : QDialog(parent),
118       m_model(new QStandardItemModel()),
119       m_call(0)
120 {
121     init();
122 }
123
124 ArgumentsEditor::~ArgumentsEditor()
125 {
126     delete m_model;
127 }
128
129 void ArgumentsEditor::setCall(ApiTraceCall *call)
130 {
131     m_call = call;
132     setupCall();
133 }
134
135 ApiTraceCall * ArgumentsEditor::call() const
136 {
137     return m_call;
138 }
139
140 void ArgumentsEditor::init()
141 {
142     m_ui.setupUi(this);
143
144     connect(m_ui.selectStringCB, SIGNAL(currentIndexChanged(int)),
145             SLOT(currentSourceChanged(int)));
146     connect(m_ui.glslEdit, SIGNAL(textChanged()),
147             SLOT(sourceChanged()));
148     connect(m_ui.revertButton, SIGNAL(clicked()),
149             SLOT(revert()));
150
151     setArgumentsItemEditorFactory ();
152
153     m_ui.argsTree->setModel(m_model);
154
155 }
156
157 void ArgumentsEditor::setupCall()
158 {
159     m_model->clear();
160
161     QStringList headers;
162     headers.append(tr("Argument"));
163     headers.append(tr("Value"));
164     m_model->setColumnCount(2);
165     m_model->setHorizontalHeaderLabels(headers);
166     m_ui.argsTabWidget->removeTab(
167         m_ui.argsTabWidget->indexOf(m_ui.shaderTab));
168
169     if (!m_call)
170         return;
171
172     m_ui.callLabel->setText(m_call->name());
173     QStandardItem *rootItem = m_model->invisibleRootItem();
174     for (int i = 0; i < m_call->argNames().count(); ++i) {
175         QString argName = m_call->argNames()[i];
176         QVariant val = m_call->arguments()[i];
177         QStandardItem *nameItem = new QStandardItem(argName);
178         nameItem->setFlags(nameItem->flags() ^ Qt::ItemIsEditable);
179         QList<QStandardItem*> topRow;
180         topRow.append(nameItem);
181
182         if (val.canConvert<ApiArray>()) {
183             ApiArray array = val.value<ApiArray>();
184             QVector<QVariant> vals = array.values();
185
186             QVariant firstVal = vals.value(0);
187             if (firstVal.userType() == QVariant::String) {
188                 m_ui.argsTabWidget->addTab(
189                     m_ui.shaderTab, argName);
190                 setupShaderEditor(vals);
191                 delete nameItem;
192                 continue;
193             } else if (isVariantEditable(firstVal)) {
194                 for (int i = 0; i < vals.count(); ++i) {
195                     QList<QStandardItem*> row;
196
197                     QStandardItem *idx = new QStandardItem();
198                     idx->setFlags(idx->flags() ^ Qt::ItemIsEditable);
199                     idx->setText(tr("%1)").arg(i));
200
201                     QStandardItem *col = new QStandardItem();
202                     col->setFlags(col->flags() | Qt::ItemIsEditable);
203                     col->setData(vals[i], Qt::EditRole);
204                     row.append(idx);
205                     row.append(col);
206                     nameItem->appendRow(row);
207                 }
208             } else {
209                 qDebug()<<"\tUnsupported array = "<<firstVal;
210                 delete nameItem;
211                 continue;
212             }
213         } else  if (val.canConvert<ApiPointer>()) {
214             ApiPointer ptr = val.value<ApiPointer>();
215             QStandardItem *item = new QStandardItem();
216             item->setFlags(item->flags() ^ Qt::ItemIsEditable);
217             item->setText(ptr.toString());
218             QIcon icon(":/resources/emblem-locked.png");
219             item->setIcon(icon);
220             item->setToolTip(tr("Argument is read-only"));
221             topRow.append(item);
222         } else if (val.canConvert<ApiEnum>()) {
223             ApiEnum en = val.value<ApiEnum>();
224             QStandardItem *item = new QStandardItem();
225             item->setFlags(item->flags() ^ Qt::ItemIsEditable);
226             item->setText(en.toString());
227             QIcon icon(":/resources/emblem-locked.png");
228             item->setIcon(icon);
229             item->setToolTip(tr("Argument is read-only"));
230             topRow.append(item);
231         } else if (val.canConvert<ApiBitmask>()) {
232             ApiBitmask mask = val.value<ApiBitmask>();
233             QStandardItem *item = new QStandardItem();
234             item->setFlags(item->flags() ^ Qt::ItemIsEditable);
235             item->setText(mask.toString());
236             QIcon icon(":/resources/emblem-locked.png");
237             item->setIcon(icon);
238             item->setToolTip(tr("Argument is read-only"));
239             topRow.append(item);
240         } else if (val.canConvert<ApiStruct>()) {
241             ApiStruct str = val.value<ApiStruct>();
242             QStandardItem *item = new QStandardItem();
243             item->setFlags(item->flags() ^ Qt::ItemIsEditable);
244             item->setText(str.toString());
245             QIcon icon(":/resources/emblem-locked.png");
246             item->setIcon(icon);
247             item->setToolTip(tr("Argument is read-only"));
248             topRow.append(item);
249         } else if (val.userType() == QVariant::ByteArray) {
250             QByteArray ba = val.value<QByteArray>();
251             QStandardItem *item = new QStandardItem();
252             item->setFlags(item->flags() ^ Qt::ItemIsEditable);
253             item->setText(
254                 tr("<binary data, size = %1 bytes>").arg(ba.size()));
255             QIcon icon(":/resources/emblem-locked.png");
256             item->setIcon(icon);
257             item->setToolTip(tr("Argument is read-only"));
258             topRow.append(item);
259         } else {
260             QStandardItem *item
261                 = new QStandardItem();
262
263             if (isVariantEditable(val)) {
264                 item->setFlags(item->flags() | Qt::ItemIsEditable);
265             } else {
266                 QIcon icon(":/resources/emblem-locked.png");
267                 item->setIcon(icon);
268                 item->setFlags(item->flags() ^ Qt::ItemIsEditable);
269                 item->setToolTip(tr("Argument is read-only"));
270             }
271             item->setData(val, Qt::EditRole);
272             topRow.append(item);
273         }
274         rootItem->appendRow(topRow);
275     }
276 }
277
278 void ArgumentsEditor::setupShaderEditor(const QVector<QVariant> &sources)
279 {
280     m_ui.selectStringCB->clear();
281     m_ui.glslEdit->clear();
282     for (int i = 0; i < sources.count(); ++i) {
283         m_ui.selectStringCB->addItem(
284             tr("Shader string: %1").arg(i),
285             sources[i]);
286     }
287     m_ui.selectStringCB->setCurrentIndex(0);
288 }
289
290 void ArgumentsEditor::currentSourceChanged(int idx)
291 {
292     QVariant source = m_ui.selectStringCB->itemData(idx);
293     QString str = source.toString();
294     m_ui.glslEdit->setPlainText(source.toString());
295     m_ui.lengthLabel->setText(
296         tr("%1").arg(str.length()));
297 }
298
299 void ArgumentsEditor::sourceChanged()
300 {
301     QString str = m_ui.glslEdit->toPlainText();
302     m_ui.lengthLabel->setText(
303         tr("%1").arg(str.length()));
304
305     m_ui.selectStringCB->setItemData(
306         m_ui.selectStringCB->currentIndex(),
307         str);
308 }
309
310 void ArgumentsEditor::accept()
311 {
312     QStringList argNames = m_call->argNames();
313     QVector<QVariant> originalValues = m_call->arguments();
314     QVector<QVariant> newValues;
315     bool changed = false;
316     for (int i = 0; i < argNames.count(); ++i) {
317         bool valChanged = false;
318         QString argName = argNames[i];
319         QVariant argValue = originalValues[i];
320         QVariant editorValue = valueForName(argName, argValue, &valChanged);
321
322         newValues.append(editorValue);
323 #if 0
324         qDebug()<<"Arg = "<<argName;
325         qDebug()<<"\toriginal = "<<argValue;
326         qDebug()<<"\teditor   = "<<editorValue;
327         qDebug()<<"\tchanged  = "<<valChanged;
328 #endif
329         if (valChanged)
330             changed = true;
331     }
332     if (changed)
333         m_call->setEditedValues(newValues);
334     QDialog::accept();
335 }
336
337 QVariant ArgumentsEditor::valueForName(const QString &name,
338                                        const QVariant &originalValue,
339                                        bool *changed) const
340 {
341     QVariant val;
342
343     *changed = false;
344
345     //Handle string arrays specially
346     if (isVariantStringArray(originalValue)) {
347         ApiArray array = originalValue.value<ApiArray>();
348         return arrayFromEditor(array, changed);
349     }
350
351     if (!isVariantEditable(originalValue)) {
352         return originalValue;
353     }
354
355     for (int topRow = 0; topRow < m_model->rowCount(); ++topRow) {
356         QModelIndex nameIdx = m_model->index(topRow, 0, QModelIndex());
357         QString argName = nameIdx.data().toString();
358         /* we display shaders in a separate widget so
359          * the ordering might be different */
360         if (argName == name) {
361             if (originalValue.userType() == QMetaType::type("ApiArray")) {
362                 ApiArray array = originalValue.value<ApiArray>();
363                 val = arrayFromIndex(nameIdx, array, changed);
364             } else {
365                 QModelIndex valIdx = m_model->index(topRow, 1, QModelIndex());
366                 val = valIdx.data();
367                 if (val != originalValue)
368                     *changed = true;
369             }
370         }
371     }
372     return val;
373 }
374
375 QVariant ArgumentsEditor::arrayFromIndex(const QModelIndex &parentIndex,
376                                          const ApiArray &origArray,
377                                          bool *changed) const
378 {
379     QVector<QVariant> origValues = origArray.values();
380
381     *changed = false;
382
383     if (origValues.isEmpty())
384         return QVariant::fromValue(ApiArray());
385
386     QVector<QVariant> lst;
387     for (int i = 0; i < origValues.count(); ++i) {
388         QModelIndex valIdx = m_model->index(i, 1, parentIndex);
389         QVariant var = valIdx.data();
390         QVariant origValue = origValues[i];
391         if (var != origValue)
392             *changed = true;
393         //qDebug()<<"\t\tarray "<<i<<") "<<var;
394         lst.append(var);
395     }
396     return QVariant::fromValue(ApiArray(lst));
397 }
398
399 QVariant ArgumentsEditor::arrayFromEditor(const ApiArray &origArray,
400                                           bool *changed) const
401 {
402     QVector<QVariant> vals;
403     QVector<QVariant> origValues = origArray.values();
404
405     Q_ASSERT(isVariantStringArray(QVariant::fromValue(origArray)));
406     *changed = false;
407     //shaders
408     for (int i = 0; i < m_ui.selectStringCB->count(); ++i) {
409         QVariant val = m_ui.selectStringCB->itemData(i);
410         QVariant origValue = origValues[i];
411         if (origValue != val)
412             *changed = true;
413         vals.append(val);
414     }
415     return QVariant::fromValue(ApiArray(vals));
416 }
417
418 void ArgumentsEditor::revert()
419 {
420     m_call->revert();
421     setupCall();
422 }
423
424 #include "argumentseditor.moc"