SeExpr
ExprControlCollection.cpp
Go to the documentation of this file.
1/*
2* Copyright Disney Enterprises, Inc. All rights reserved.
3*
4* Licensed under the Apache License, Version 2.0 (the "License");
5* you may not use this file except in compliance with the License
6* and the following modification to it: Section 6 Trademarks.
7* deleted and replaced with:
8*
9* 6. Trademarks. This License does not grant permission to use the
10* trade names, trademarks, service marks, or product names of the
11* Licensor and its affiliates, except as required for reproducing
12* the content of the NOTICE file.
13*
14* You may obtain a copy of the License at
15* http://www.apache.org/licenses/LICENSE-2.0
16*
17* @file ExprControlCollection.cpp
18* @brief Manages/creates a bunch of ExprControls by using expression text
19* @author aselle
20*/
21#include <QVBoxLayout>
22#include <QHBoxLayout>
23#include <QToolButton>
24#include <QPushButton>
25#include <QRadioButton>
26#include <QFormLayout>
27#include <QDialogButtonBox>
28#include <QColorDialog>
29#include <QLabel>
30#include "ExprEditor.h"
31#include "ExprHighlighter.h"
32#include "ExprCompletionModel.h"
33#include "ExprCurve.h"
34#include "ExprColorCurve.h"
35#include "ExprControl.h"
37#include "EditableExpression.h"
38#include "Editable.h"
39
40ExprControlCollection::ExprControlCollection(QWidget* parent, bool showAddButton)
41 : QWidget(parent), count(0), showAddButton(showAddButton), editableExpression(0) {
42 controlLayout = new QVBoxLayout();
43 controlLayout->setMargin(0);
44 controlLayout->setSpacing(0);
45 controlLayout->insertStretch(-1, 100);
46
47 if (showAddButton) {
48 QPushButton* button = new QPushButton("Add Widget");
49 button->setFocusPolicy(Qt::NoFocus);
50 QHBoxLayout* buttonLayout = new QHBoxLayout();
51 buttonLayout->insertStretch(-1, 100);
52 buttonLayout->addWidget(button, 0);
53 controlLayout->addLayout(buttonLayout);
54 connect(button, SIGNAL(clicked()), SLOT(addControlDialog()));
55 }
56 setLayout(controlLayout);
57}
58
60
61ExprAddDialog::ExprAddDialog(int& count, QWidget* parent) : QDialog(parent) {
62 QVBoxLayout* verticalLayout;
63 verticalLayout = new QVBoxLayout();
64 verticalLayout->setSpacing(3);
65 verticalLayout->setMargin(3);
66 setLayout(verticalLayout);
67 QHBoxLayout* horizontalLayout = new QHBoxLayout();
68
69 horizontalLayout->addWidget(new QLabel("Variable"));
70 // TODO would be nice to unique this over multiple sessions
71 variableName = new QLineEdit(QString("$var%1").arg(count++));
72
73 horizontalLayout->addWidget(variableName);
74 verticalLayout->addLayout(horizontalLayout);
75
76 tabWidget = new QTabWidget();
77
78 // Curve
79 {
80 QWidget* curveTab = new QWidget();
81 QFormLayout* curveLayout = new QFormLayout(curveTab);
82 curveLayout->setWidget(0, QFormLayout::LabelRole, new QLabel("Lookup"));
83 curveLookup = new QLineEdit("$u");
84 curveLayout->setWidget(0, QFormLayout::FieldRole, curveLookup);
85 tabWidget->addTab(curveTab, QString("Curve"));
86 }
87
88 // Color Curve
89 {
90 QWidget* colorCurveTab = new QWidget();
91 QFormLayout* colorCurveLayout = new QFormLayout(colorCurveTab);
92 colorCurveLayout->setWidget(0, QFormLayout::LabelRole, new QLabel("Lookup"));
93 colorCurveLookup = new QLineEdit("$u");
94 colorCurveLayout->setWidget(0, QFormLayout::FieldRole, colorCurveLookup);
95 tabWidget->addTab(colorCurveTab, QString("Color Curve"));
96 }
97
98 // Integer
99 {
100 QWidget* intTab = new QWidget();
101 QFormLayout* intFormLayout = new QFormLayout(intTab);
102 intFormLayout->setWidget(0, QFormLayout::LabelRole, new QLabel("Default"));
103 intFormLayout->setWidget(1, QFormLayout::LabelRole, new QLabel("Min"));
104 intFormLayout->setWidget(2, QFormLayout::LabelRole, new QLabel("Max"));
105 intDefault = new QLineEdit("0");
106 intFormLayout->setWidget(0, QFormLayout::FieldRole, intDefault);
107 intMin = new QLineEdit("0");
108 intFormLayout->setWidget(1, QFormLayout::FieldRole, intMin);
109 intMax = new QLineEdit("10");
110 intFormLayout->setWidget(2, QFormLayout::FieldRole, intMax);
111 tabWidget->addTab(intTab, QString("Int"));
112 }
113
114 // Float
115 {
116 QWidget* floatTab = new QWidget();
117 QFormLayout* floatFormLayout = new QFormLayout(floatTab);
118 floatFormLayout->setWidget(0, QFormLayout::LabelRole, new QLabel("Default"));
119 floatFormLayout->setWidget(1, QFormLayout::LabelRole, new QLabel("Min"));
120 floatFormLayout->setWidget(2, QFormLayout::LabelRole, new QLabel("Max"));
121 floatDefault = new QLineEdit("0");
122 floatFormLayout->setWidget(0, QFormLayout::FieldRole, floatDefault);
123 floatMin = new QLineEdit("0");
124 floatFormLayout->setWidget(1, QFormLayout::FieldRole, floatMin);
125 floatMax = new QLineEdit("1");
126 floatFormLayout->setWidget(2, QFormLayout::FieldRole, floatMax);
127
128 tabWidget->addTab(floatTab, QString("Float"));
129 }
130
131 // Vector
132 {
133 QWidget* vectorTab = new QWidget();
134 QFormLayout* vectorFormLayout = new QFormLayout(vectorTab);
135 vectorFormLayout->setWidget(0, QFormLayout::LabelRole, new QLabel("Default"));
136 vectorFormLayout->setWidget(1, QFormLayout::LabelRole, new QLabel("Min"));
137 vectorFormLayout->setWidget(2, QFormLayout::LabelRole, new QLabel("Max"));
138 vectorDefault0 = new QLineEdit("0");
139 vectorDefault1 = new QLineEdit("0");
140 vectorDefault2 = new QLineEdit("0");
141 QHBoxLayout* compLayout = new QHBoxLayout();
142 compLayout->addWidget(vectorDefault0);
143 compLayout->addWidget(vectorDefault1);
144 compLayout->addWidget(vectorDefault2);
145 vectorFormLayout->setLayout(0, QFormLayout::FieldRole, compLayout);
146 vectorMin = new QLineEdit("0");
147 vectorFormLayout->setWidget(1, QFormLayout::FieldRole, vectorMin);
148 vectorMax = new QLineEdit("1");
149 vectorFormLayout->setWidget(2, QFormLayout::FieldRole, vectorMax);
150
151 tabWidget->addTab(vectorTab, QString("Vector"));
152 }
153
154 // Color
155 {
156 QWidget* colorTab = new QWidget();
157 QFormLayout* colorLayout = new QFormLayout(colorTab);
158 colorWidget = new QPushButton();
159 colorWidget->setFixedWidth(30);
160 colorWidget->setFixedWidth(30);
161 colorLayout->setWidget(0, QFormLayout::LabelRole, new QLabel("Color"));
162 colorLayout->setWidget(0, QFormLayout::FieldRole, colorWidget);
163 color = Qt::red;
164 QPixmap colorPix(30, 30);
165 colorPix.fill(color);
166 colorWidget->setIcon(QIcon(colorPix));
167 tabWidget->addTab(colorTab, QString("Color"));
168
169 connect(colorWidget, SIGNAL(clicked()), this, SLOT(colorChooseClicked()));
170 }
171
172 // Color Swatch
173 {
174 QWidget* swatchTab = new QWidget();
175 QFormLayout* swatchLayout = new QFormLayout(swatchTab);
176 swatchLookup = new QLineEdit("$u");
177 swatchLayout->setWidget(0, QFormLayout::LabelRole, new QLabel("Lookup"));
178 swatchLayout->setWidget(0, QFormLayout::FieldRole, swatchLookup);
179 rainbowPaletteBtn = new QRadioButton("Rainbow");
180 rainbowPaletteBtn->setChecked(true);
181 grayPaletteBtn = new QRadioButton("Shades of Gray");
182 swatchLayout->setWidget(1, QFormLayout::LabelRole, new QLabel("Colors"));
183 swatchLayout->setWidget(1, QFormLayout::FieldRole, rainbowPaletteBtn);
184 swatchLayout->setWidget(2, QFormLayout::LabelRole, new QLabel(""));
185 swatchLayout->setWidget(2, QFormLayout::FieldRole, grayPaletteBtn);
186 tabWidget->addTab(swatchTab, QString("Swatch"));
187 }
188
189 // String literal
190 {
191 QWidget* stringTab = new QWidget();
192 QFormLayout* stringLayout = new QFormLayout(stringTab);
193 stringTypeWidget = new QComboBox();
194 stringTypeWidget->addItem("string");
195 stringTypeWidget->addItem("file");
196 stringTypeWidget->addItem("directory");
197 stringDefaultWidget = new QLineEdit();
198 stringNameWidget = new QLineEdit("str1");
199
200 stringLayout->setWidget(0, QFormLayout::LabelRole, new QLabel("String Name"));
201 stringLayout->setWidget(0, QFormLayout::FieldRole, stringNameWidget);
202 stringLayout->setWidget(1, QFormLayout::LabelRole, new QLabel("String Type"));
203 stringLayout->setWidget(1, QFormLayout::FieldRole, stringTypeWidget);
204 stringLayout->setWidget(2, QFormLayout::LabelRole, new QLabel("String Default"));
205 stringLayout->setWidget(3, QFormLayout::FieldRole, stringDefaultWidget);
206
207 tabWidget->addTab(stringTab, QString("String"));
208 }
209
210 // Anim Curve
211 {
212 QWidget* curveTab = new QWidget();
213 QFormLayout* curveLayout = new QFormLayout(curveTab);
214 curveLayout->setWidget(0, QFormLayout::LabelRole, new QLabel("Lookup"));
215 curveLayout->setWidget(1, QFormLayout::LabelRole, new QLabel("Link"));
216 animCurveLookup = new QLineEdit("$frame");
217 animCurveLink = new QLineEdit("");
218 curveLayout->setWidget(0, QFormLayout::FieldRole, animCurveLookup);
219 curveLayout->setWidget(1, QFormLayout::FieldRole, animCurveLink);
220 tabWidget->addTab(curveTab, QString("AnimCurve"));
221 }
222
223 // DeepWater
224 {
225 QWidget* deepWaterTab = new QWidget();
226 QFormLayout* deepWaterLayout = new QFormLayout(deepWaterTab);
227 deepWaterLayout->setWidget(0, QFormLayout::LabelRole, new QLabel("Lookup"));
228 deepWaterLookup = new QLineEdit("$u");
229 deepWaterLayout->setWidget(0, QFormLayout::FieldRole, deepWaterLookup);
230 tabWidget->addTab(deepWaterTab, QString("Deep Water"));
231 }
232
233 verticalLayout->addWidget(tabWidget);
234
235 QDialogButtonBox* buttonBox = new QDialogButtonBox();
236 buttonBox->setOrientation(Qt::Horizontal);
237 buttonBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok);
238
239 verticalLayout->addWidget(buttonBox);
240
241 QObject::connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
242 QObject::connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
243
244 tabWidget->setCurrentIndex(0);
245}
246
248 color = QColorDialog::getColor(color);
249 if (color.isValid()) {
250 QPixmap colorPix(30, 30);
251 colorPix.fill(color);
252 ((QPushButton*)sender())->setIcon(QIcon(colorPix));
253 }
254}
255
257 if (rainbowPaletteBtn->isChecked())
258 return ("[1,0,0],[1,.6,0],[1,1,0],[0,1,0],[0,1,1],[0,0,1],[.6,.1,.6],[1,0,1],[1,1,1],[0,0,0]");
259 else if (grayPaletteBtn->isChecked())
260 return (
261 "[1,1,1],[.9,.9,.9],[.8,.8,.8],[.7,.7,.7],[.6,.6,.6],[.5,.5,.5],[.4,.4,.4],[.3,.3,.3],[.2,.2,.2],[0,0,0]");
262 else
263 return ("[1,1,1],[.5,.5,.5],[0,0,0]");
264}
265
267 ExprAddDialog* dialog = new ExprAddDialog(count, this);
268 if (dialog->exec()) {
269 QString s;
270 switch (dialog->tabWidget->currentIndex()) {
271 case 0:
272 s = QString("%1 = curve(%2,0,0,4,1,1,4);\n").arg(dialog->variableName->text()).arg(
273 dialog->curveLookup->text());
274 break;
275 case 1:
276 s = QString("%1 = ccurve(%2,0,[0,0,0],4,1,[1,1,1],4);\n").arg(dialog->variableName->text()).arg(
277 dialog->colorCurveLookup->text());
278 break;
279 case 2:
280 s = dialog->variableName->text() + " = " + dialog->intDefault->text() + "; # " +
281 dialog->intMin->text() + "," + dialog->intMax->text() + "\n";
282 break;
283 case 3:
284 s = QString("%1 = %2; # %3, %4\n")
285 .arg(dialog->variableName->text())
286 .arg(dialog->floatDefault->text())
287 .arg(atof(dialog->floatMin->text().toStdString().c_str()), 0, 'f', 3)
288 .arg(atof(dialog->floatMax->text().toStdString().c_str()), 0, 'f', 3);
289 break;
290 case 4:
291 s = QString("%1 = [%2,%3,%4]; # %5, %6\n")
292 .arg(dialog->variableName->text())
293 .arg(dialog->vectorDefault0->text())
294 .arg(dialog->vectorDefault1->text())
295 .arg(dialog->vectorDefault2->text())
296 .arg(atof(dialog->vectorMin->text().toStdString().c_str()), 0, 'f', 3)
297 .arg(atof(dialog->vectorMax->text().toStdString().c_str()), 0, 'f', 3);
298 break;
299 case 5:
300 s = QString("%1 = [%2,%3,%4];\n")
301 .arg(dialog->variableName->text())
302 .arg(dialog->color.redF())
303 .arg(dialog->color.greenF())
304 .arg(dialog->color.blueF());
305 break;
306 case 6:
307 s = QString("%1 = swatch(%2,%3);\n")
308 .arg(dialog->variableName->text())
309 .arg(dialog->swatchLookup->text())
310 .arg(dialog->initSwatch());
311 break;
312 case 7:
313 s = QString("\"%1\" #%2 %3\n")
314 .arg(dialog->stringDefaultWidget->text())
315 .arg(dialog->stringTypeWidget->currentText())
316 .arg(dialog->stringNameWidget->text());
317 break;
318 case 8:
319 s = QString("%1 = animCurve(%2,\"constant\",\"constant\",0,\"%3\");")
320 .arg(dialog->variableName->text())
321 .arg(dialog->animCurveLookup->text())
322 .arg(dialog->animCurveLink->text());
323 break;
324 case 9:
325 s = QString("%1 = deepWater(%2,9,30,0,1,0,5,0,0,[0,0,0],0,0,0);\n")
326 .arg(dialog->variableName->text())
327 .arg(dialog->deepWaterLookup->text());
328 break;
329 }
330 emit insertString(s.toStdString());
331 }
332}
333
334bool ExprControlCollection::rebuildControls(const QString& expressionText, std::vector<QString>& variables) {
335 // parse a new editable expression so we can check if we need to make new controls
336 EditableExpression* newEditable = new EditableExpression;
337 newEditable->setExpr(expressionText.toStdString());
338
339 // check for new variables
340
341 bool newVariables = true;
342 if (editableExpression && editableExpression->getVariables() == newEditable->getVariables()) newVariables = false;
343 if (newVariables) {
344 const std::vector<std::string>& vars = newEditable->getVariables();
345 variables.clear();
346 for (size_t k = 0; k < vars.size(); k++) {
347 variables.push_back(("$" + vars[k]).c_str());
348 }
349 }
350
351 if (newEditable->size() == 0 && !editableExpression) return false;
352
354 // controls match so we only need to update positions (i.e. if the user typed and shifted some controls)
355 editableExpression->updateString(*newEditable);
356 delete newEditable;
357 } else {
358 // controls did not match
359
360 // delete old controls
361 for (unsigned int i = 0; i < _controls.size(); i++) {
362 controlLayout->removeWidget(_controls[i]);
363 delete _controls[i];
364 }
365 _linkedId = -1;
366 _controls.clear();
367
368 // swap to new editable expression
369 delete editableExpression;
370 editableExpression = newEditable;
371
372 // build new controls
373 for (size_t i = 0; i < editableExpression->size(); i++) {
374 Editable* editable = (*editableExpression)[i];
375 ExprControl* widget = 0;
376 // Create control "factory" (but since its only used here...)
377 if (NumberEditable* x = dynamic_cast<NumberEditable*>(editable))
378 widget = new NumberControl(i, x);
379 else if (VectorEditable* x = dynamic_cast<VectorEditable*>(editable))
380 widget = new VectorControl(i, x);
381 else if (StringEditable* x = dynamic_cast<StringEditable*>(editable))
382 widget = new StringControl(i, x);
383 else if (CurveEditable* x = dynamic_cast<CurveEditable*>(editable))
384 widget = new CurveControl(i, x);
385 else if (ColorCurveEditable* x = dynamic_cast<ColorCurveEditable*>(editable))
386 widget = new CCurveControl(i, x);
387 else if (AnimCurveEditable* x = dynamic_cast<AnimCurveEditable*>(editable)) {
388 widget = new AnimCurveControl(i, x);
389 } else if (ColorSwatchEditable* x = dynamic_cast<ColorSwatchEditable*>(editable))
390 widget = new ColorSwatchControl(i, x);
391 else if (DeepWaterEditable* x = dynamic_cast<DeepWaterEditable*>(editable))
392 widget = new DeepWaterControl(i, x);
393 else {
394 std::cerr << "SeExpr editor logic error, cannot find a widget for the given editable" << std::endl;
395 }
396 if (widget) {
397 // successfully made widget
398 int insertPoint = controlLayout->count() - 1;
399 if (showAddButton) insertPoint--;
400 controlLayout->insertWidget(insertPoint, widget);
401 _controls.push_back(widget);
402 connect(widget, SIGNAL(controlChanged(int)), SLOT(singleControlChanged(int)));
403 connect(widget, SIGNAL(linkColorEdited(int, QColor)), SLOT(linkColorEdited(int, QColor)));
404 connect(widget, SIGNAL(linkColorLink(int)), SLOT(linkColorLink(int)));
405 } else {
406 std::cerr << "Expr Editor Logic ERROR did not make widget" << std::endl;
407 }
408 }
409 }
410 return newVariables;
411}
412
414 if (idx < 0 || idx >= (int)_controls.size()) return;
415
416 /* Right now we only launch the anim curve editor.
417 * It would be better to launch them generically. */
418 AnimCurveControl* control = dynamic_cast<AnimCurveControl*>(_controls[idx]);
419 if (!control) return;
420
421 control->editGraphClicked();
422}
423
425 _linkedId = id;
426 for (unsigned int i = 0; i < _controls.size(); i++) {
427 _controls[i]->linkDisconnect(_linkedId);
428 }
429}
430
431void ExprControlCollection::linkColorEdited(int id, QColor color) {
432 if (id == _linkedId) emit linkColorOutput(color);
433}
434
436 // TODO: fix
437 if (_linkedId < 0 || _linkedId >= (int)_controls.size()) return;
438 _controls[_linkedId]->setColor(color);
439}
440
441void ExprControlCollection::updateText(const int id, QString& text) {
442 Q_UNUSED(id);
443 if (editableExpression) text = QString(editableExpression->getEditedExpr().c_str());
444}
445
Control for editing a color ramp curve.
A control for editing color swatches.
Control for editing a normal curve ramp.
Control for displaying a deep water spectrum.
Factors a SeExpr into an editable expression with controls (i.e. value boxes, curve boxes)
size_t size() const
Return the count of editable parameters.
void setExpr(const std::string &expr)
Set's expressions and parses it into "control editable form".
std::string getEditedExpr() const
Return a reconstructed expression using all the editable's current values.
bool controlsMatch(const EditableExpression &other) const
Check if the other editable expression has editables that all match i.e. the controls are same.
void updateString(const EditableExpression &other)
Update the string refered to into the controls (this is only valid if controlsmatch)
const std::vector< std::string > & getVariables() const
Get list of commentsø
This class is the UI for adding widgets.
QLineEdit * animCurveLookup
QLineEdit * vectorDefault0
QLineEdit * animCurveLink
QRadioButton * grayPaletteBtn
QLineEdit * vectorDefault1
QRadioButton * rainbowPaletteBtn
QLineEdit * stringDefaultWidget
ExprAddDialog(int &count, QWidget *parent=0)
QLineEdit * stringNameWidget
QLineEdit * deepWaterLookup
QComboBox * stringTypeWidget
QLineEdit * colorCurveLookup
QLineEdit * vectorDefault2
QPushButton * colorWidget
const char * initSwatch()
void controlChanged(int id)
Notification that a specific control was changed.
bool rebuildControls(const QString &expressionText, std::vector< QString > &variables)
Rebuild the controls given the new expressionText. Return any local variables found.
ExprControlCollection(QWidget *parent=0, bool showAddButton=true)
void insertString(const std::string &controlString)
void singleControlChanged(int id)
Notification when by a control whenever it is edited.
void linkColorOutput(QColor color)
Gives information about when a link color was changed.
void addControlDialog()
When a user clicks "Add Widget" button.
std::vector< ExprControl * > _controls
void linkColorLink(int id)
Notification by a control that a new color link is desired.
void linkColorEdited(int id, QColor color)
Notification by a control that a color is edited (when it is linked)
EditableExpression * editableExpression
void updateText(const int id, QString &text)
Request new text, given taking into account control id's new values.
void linkColorInput(QColor color)
Base class for all controls for Expressions.
Definition ExprControl.h:54
Number slider for either float or int data.
A control for editing strings, filenames, and directories.
A vector or color control (named vector because it edits a SeExpr2::Vec3d literal)
</pre >< h3 > A simple variable reference</h3 > This is not a very interesting subclass of expression until we add some additional variables Variables on some applications may be very dynamic In this we only need x
Definition tutorial.txt:108