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