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 > Once we have this we need an instance to store our variable and provide a reference to that We make it because it may be useful to use the same ExprVarRef from multiple expressions !For if you have expressions that all have access to the same variables
Definition tutorial.txt:129
</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