00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include <iostream>
00016 #include <algorithm>
00017
00018 #include <QtGui/QColorDialog>
00019 #include <QtGui/QDoubleValidator>
00020 #include <QtGui/QGraphicsSceneMouseEvent>
00021 #include <QtGui/QHBoxLayout>
00022 #include <QtGui/QLabel>
00023 #include <QtGui/QVBoxLayout>
00024 #include <QtGui/QResizeEvent>
00025 #include <QtGui/QPushButton>
00026 #include <QtGui/QDialogButtonBox>
00027
00028 #include <SeExprBuiltins.h>
00029 #ifdef SEEXPR_USE_QDGUI
00030 # include <qdgui/QdColorPickerDialog.h>
00031 #endif
00032
00033 #include "SeExprEdColorCurve.h"
00034
00035 CCurveScene::CCurveScene() : _curve(new T_CURVE),_width(320), _height(170), _color(SeVec3d(.5)), _interp(T_CURVE::kMonotoneSpline),
00036 _selectedItem(-1), _pixmapDirty(true), _baseRectW(0), _baseRect(0), _lmb(false)
00037 {
00038 rebuildCurve();
00039 resize(_width, _height);
00040 }
00041
00042 CCurveScene::~CCurveScene()
00043 {
00044 delete _curve;
00045 }
00046
00047
00048 void CCurveScene::resize(const int width, const int height)
00049 {
00050
00051 _width = width-16;
00052 _height = height-16;
00053 setSceneRect(-9, -2, width, height);
00054 drawRect();
00055 drawPoints();
00056 _pixmap = QPixmap(_width, _height);
00057 _pixmapDirty = true;
00058 }
00059
00060 void CCurveScene::rebuildCurve()
00061 {
00062 delete _curve;
00063 _curve=new T_CURVE;
00064 for(unsigned int i=0;i<_cvs.size();i++)
00065 _curve->addPoint(_cvs[i]._pos,_cvs[i]._val,_cvs[i]._interp);
00066 _curve->preparePoints();
00067 }
00068
00069 void CCurveScene::addPoint(double x, const SeVec3d y, const T_INTERP interp, const bool select)
00070 {
00071 x=SeExpr::clamp(x,0,1);
00072
00073 _cvs.push_back(T_CURVE::CV(x,y,T_INTERP(interp)));
00074 int newIndex=_cvs.size()-1;
00075
00076 rebuildCurve();
00077
00078 if(select){
00079 _selectedItem = newIndex;
00080 emit cvSelected(x, y, interp);
00081 }
00082 _pixmapDirty = true;
00083 _baseRectW->update();
00084 drawPoints();
00085 }
00086
00087 void CCurveScene::removePoint(const int index)
00088 {
00089 _cvs.erase(_cvs.begin()+index);
00090 _selectedItem = -1;
00091 rebuildCurve();
00092
00093 _pixmapDirty = true;
00094 _baseRectW->update();
00095 drawPoints();
00096 emitCurveChanged();
00097 }
00098
00099 void CCurveScene::removeAll()
00100 {
00101 _cvs.clear();
00102 }
00103
00104
00105 void CCurveScene::keyPressEvent(QKeyEvent *event)
00106 {
00107 if (((event->key() == Qt::Key_Backspace) ||
00108 (event->key() == Qt::Key_Delete)) && (_selectedItem >= 0)) {
00109
00110 removePoint(_selectedItem);
00111 }
00112 }
00113
00114 void CCurveScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
00115 {
00116 _lmb = true;
00117 QPointF pos = mouseEvent->scenePos();
00118
00119 QList<QGraphicsItem *> itemList = items(pos);
00120 if (itemList.empty()) {
00121 _selectedItem = -1;
00122 emit cvSelected(-1, SeVec3d(0.0), _interp);
00123 drawPoints();
00124 } else if (itemList[0]->zValue() == 2) {
00125
00126 const int numCircle = _circleObjects.size();
00127 for (int i = 0; i < numCircle; i++ ) {
00128 QGraphicsItem *obj = _circleObjects[i];
00129 if (obj == itemList[0]) {
00130 _selectedItem = i;
00131 _color = _cvs[i]._val;
00132 _interp = _cvs[i]._interp;
00133 emit cvSelected(_cvs[i]._pos, _cvs[i]._val, _cvs[i]._interp);
00134 }
00135 }
00136 drawPoints();
00137 } else {
00138
00139 double myx=pos.x()/_width;
00140 T_INTERP interpFromNearby=_curve->getLowerBoundCV(SeExpr::clamp(myx,0,1))._interp;
00141 if(interpFromNearby==T_CURVE::kNone) interpFromNearby=T_CURVE::kMonotoneSpline;
00142 addPoint(pos.x()/_width, _color, interpFromNearby);
00143 emitCurveChanged();
00144 }
00145 }
00146
00147 void CCurveScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
00148 {
00149 if (_lmb) {
00150 QPointF point = mouseEvent->scenePos();
00151 if (_selectedItem >= 0) {
00152
00153 double pos = SeExpr::clamp(point.x()/_width,0,1);
00154 _cvs[_selectedItem]._pos=pos;
00155 rebuildCurve();
00156 _pixmapDirty = true;
00157 _baseRectW->update();
00158 emit cvSelected(pos, _cvs[_selectedItem]._val, _cvs[_selectedItem]._interp);
00159 drawPoints();
00160 emitCurveChanged();
00161 }
00162 }
00163 }
00164
00165 void CCurveScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
00166 {
00167 Q_UNUSED(mouseEvent);
00168 _lmb = false;
00169 }
00170
00171
00172 void CCurveScene::interpChanged(const int interp)
00173 {
00174 _interp = (T_INTERP) interp;
00175 if (_selectedItem >= 0) {
00176 _cvs[_selectedItem]._interp = _interp;
00177 rebuildCurve();
00178 _pixmapDirty = true;
00179 _baseRectW->update();
00180 emitCurveChanged();
00181 }
00182 }
00183
00184
00185 void CCurveScene::selPosChanged(double pos)
00186 {
00187 if (_selectedItem >= 0) {
00188 pos=SeExpr::clamp(pos,0,1);
00189 _cvs[_selectedItem]._pos = pos;
00190 rebuildCurve();
00191 _pixmapDirty = true;
00192 _baseRectW->update();
00193 drawPoints();
00194 emitCurveChanged();
00195 }
00196 }
00197
00198
00199 void CCurveScene::selValChanged(const SeVec3d& val)
00200 {
00201 _color = val;
00202 if (_selectedItem >= 0) {
00203 _cvs[_selectedItem]._val = val;
00204 rebuildCurve();
00205 _pixmapDirty = true;
00206 _baseRectW->update();
00207 drawPoints();
00208 emitCurveChanged();
00209 }
00210 }
00211
00212
00213
00214 void CCurveScene::emitCurveChanged()
00215 {
00216 emit curveChanged();
00217 }
00218
00219 QPixmap& CCurveScene::getPixmap()
00220 {
00221 if (_pixmapDirty) {
00222 QByteArray buf;
00223 buf.append(QString("P6\n%1 %2\n255\n").arg(_width).arg(_height));
00224 buf.append(getCPixmap());
00225 _pixmap.loadFromData(buf, "PPM");
00226 _pixmapDirty = false;
00227 }
00228 return _pixmap;
00229 }
00230
00231
00232 QByteArray CCurveScene::getCPixmap()
00233 {
00234
00235 const int len = 3 * _width * _height;
00236 QByteArray pixmap(len, 127);
00237
00238 double paramInc = 1.0 / (_width - 2);
00239 double param = 0.5 * paramInc;
00240
00241 char* ptr = pixmap.data();
00242 *ptr++ = 0;
00243 *ptr++ = 0;
00244 *ptr++ = 0;
00245 for (int i = 1; i < _width - 1; i++) {
00246 SeVec3d color = _curve->getValue(param);
00247 *ptr++ = char(std::min(std::max(0.0, 255 * color[0]), 255.0) + 0.5);
00248 *ptr++ = char(std::min(std::max(0.0, 255 * color[1]), 255.0) + 0.5);
00249 *ptr++ = char(std::min(std::max(0.0, 255 * color[2]), 255.0) + 0.5);
00250 param += paramInc;
00251 }
00252
00253 *ptr++ = 0;
00254 *ptr++ = 0;
00255 *ptr++ = 0;
00256
00257 for (int i = 1; i < _height-1; i++) {
00258 memcpy(pixmap.data()+(i * _width * 3), pixmap.data()+((i - 1) * _width * 3), _width * 3);
00259 }
00260
00261
00262 memset(pixmap.data(), 0, _width * 3);
00263 memset(pixmap.data()+((_height - 1) * _width * 3), 0, _width * 3);
00264
00265 return pixmap;
00266 }
00267
00268
00269
00270 void CCurveScene::drawRect()
00271 {
00272 if (_baseRectW == 0) {
00273 _baseRectW = new SeExprEdCBoxWidget(this);
00274 }
00275 if (_baseRect == 0) {
00276 _baseRect = addWidget(_baseRectW);
00277 }
00278 _baseRect->widget()->setFixedSize(_width, _height);
00279 _baseRect->widget()->update();
00280 _baseRect->setZValue(0);
00281 }
00282
00283
00284
00285 void CCurveScene::drawPoints()
00286 {
00287 while (_circleObjects.size()) {
00288 delete _circleObjects[0];
00289 _circleObjects.erase(_circleObjects.begin());
00290 }
00291 const int numCV = _cvs.size();
00292 for (int i = 0; i < numCV; i++) {
00293 const T_CURVE::CV& pt = _cvs[i];
00294 QPen pen;
00295 if (i == _selectedItem) {
00296 pen = QPen(QColor(255,170,0),1.0);
00297 } else {
00298 pen = QPen(Qt::black,1.0);
00299 }
00300 _circleObjects.push_back(addEllipse(pt._pos*_width-4, _height+3, 8, 8, pen, QBrush(QColor(int(255 * pt._val[0] +0.5), int(255 * pt._val[1] + 0.5), int(255 * pt._val[2] + 0.5)))));
00301 QGraphicsEllipseItem *circle = _circleObjects.back();
00302 circle->setFlag(QGraphicsItem::ItemIsMovable, true);
00303 circle->setZValue(2);
00304 }
00305 }
00306
00307
00308 void SeExprEdCBoxWidget::paintEvent(QPaintEvent* event)
00309 {
00310 Q_UNUSED(event);
00311 QPainter p(this);
00312 p.drawPixmap(0, 0, _curveScene->getPixmap());
00313 }
00314
00315 void SeExprEdCSwatchFrame::paintEvent(QPaintEvent* event)
00316 {
00317 Q_UNUSED(event);
00318 QPainter p(this);
00319 p.fillRect(contentsRect(),_color);
00320 }
00321
00322
00323 SeExprEdCSwatchFrame::SeExprEdCSwatchFrame(SeVec3d value, QWidget* parent) : QFrame(parent), _value(value)
00324 {
00325 _color = QColor(int(255 * _value[0] + 0.5), int(255 * _value[1] + 0.5), int(255 * _value[2] + 0.5));
00326 }
00327
00328
00329 void SeExprEdCSwatchFrame::setValue(const SeVec3d &value)
00330 {
00331 _color = QColor(int(255 * value[0] + 0.5), int(255 * value[1] + 0.5), int(255 * value[2] + 0.5));
00332
00333 _value = value;
00334 repaint();
00335 }
00336
00337 SeVec3d SeExprEdCSwatchFrame::getValue() const
00338 {
00339 return _value;
00340 }
00341
00342
00343 void SeExprEdCSwatchFrame::mousePressEvent(QMouseEvent* event)
00344 {
00345 Q_UNUSED(event);
00346 #ifdef SEEXPR_USE_QDGUI
00347 QColor color = QdColorPickerDialog::chooseColorFromDialog(_color,this);
00348 #else
00349 QColor color = QColorDialog::getColor(_color);
00350 #endif
00351 if (color.isValid()) {
00352 _value[0] = color.red() / 255.0;
00353 _value[1] = color.green() / 255.0;
00354 _value[2] = color.blue() / 255.0;
00355 setPalette(QPalette(color));
00356 _color = color;
00357 emit selValChangedSignal(_value);
00358 emit swatchChanged(color);
00359 }
00360 }
00361
00362
00363 SeExprEdColorCurve::SeExprEdColorCurve(QWidget* parent, QString pLabel, QString vLabel, QString iLabel,
00364 bool expandable) :
00365 QWidget(parent), _scene(0), _selPosEdit(0), _selValEdit(0), _interpComboBox(0)
00366 {
00367 Q_UNUSED(iLabel);
00368 QHBoxLayout *mainLayout = new QHBoxLayout();
00369 mainLayout->setSpacing(2);
00370 mainLayout->setMargin(5);
00371
00372 QWidget *edits = new QWidget;
00373 QVBoxLayout *editsLayout = new QVBoxLayout;
00374 editsLayout->setAlignment(Qt::AlignTop);
00375 editsLayout->setSpacing(0);
00376 editsLayout->setMargin(0);
00377 edits->setLayout(editsLayout);
00378
00379 QWidget *selPos = new QWidget;
00380 QHBoxLayout *selPosLayout = new QHBoxLayout;
00381 selPosLayout->setSpacing(1);
00382 selPosLayout->setMargin(1);
00383 selPos->setLayout(selPosLayout);
00384 _selPosEdit = new QLineEdit;
00385 QDoubleValidator *posValidator = new QDoubleValidator(0.0,1.0,6,_selPosEdit);
00386 _selPosEdit->setValidator(posValidator);
00387 _selPosEdit->setFixedWidth(38);
00388 _selPosEdit->setFixedHeight(20);
00389 selPosLayout->addStretch(50);
00390 QLabel *posLabel;
00391 if (pLabel.isEmpty()) {
00392 posLabel = new QLabel("Selected Position: ");
00393 } else {
00394 posLabel = new QLabel(pLabel);
00395 }
00396 selPosLayout->addWidget(posLabel);
00397 selPosLayout->addWidget(_selPosEdit);
00398
00399 QWidget *selVal = new QWidget;
00400 QBoxLayout *selValLayout = new QHBoxLayout;
00401 selValLayout->setSpacing(1);
00402 selValLayout->setMargin(1);
00403 selVal->setLayout(selValLayout);
00404 _selValEdit = new SeExprEdCSwatchFrame(SeVec3d(.5));
00405 _selValEdit->setFixedWidth(38);
00406 _selValEdit->setFixedHeight(20);
00407 selValLayout->addStretch(50);
00408 QLabel *valLabel;
00409 if (vLabel.isEmpty()) {
00410 valLabel = new QLabel("Selected Color: ");
00411 } else {
00412 valLabel = new QLabel(vLabel);
00413 }
00414 selValLayout->addWidget(valLabel);
00415 selValLayout->addWidget(_selValEdit);
00416
00417 _interpComboBox = new QComboBox;
00418 _interpComboBox->addItem("None");
00419 _interpComboBox->addItem("Linear");
00420 _interpComboBox->addItem("Smooth");
00421 _interpComboBox->addItem("Spline");
00422 _interpComboBox->addItem("MSpline");
00423 _interpComboBox->setCurrentIndex(4);
00424 _interpComboBox->setFixedWidth(70);
00425 _interpComboBox->setFixedHeight(20);
00426
00427 editsLayout->addWidget(selPos);
00428 editsLayout->addWidget(selVal);
00429 editsLayout->addWidget(_interpComboBox);
00430
00431 QFrame *curveFrame = new QFrame;
00432 curveFrame->setFrameShape(QFrame::Panel);
00433 curveFrame->setFrameShadow(QFrame::Sunken);
00434 curveFrame->setLineWidth(1);
00435 QHBoxLayout *curveFrameLayout = new QHBoxLayout;
00436 curveFrameLayout->setMargin(0);
00437 CurveGraphicsView *curveView = new CurveGraphicsView;
00438 curveView->setFrameShape(QFrame::Panel);
00439 curveView->setFrameShadow(QFrame::Sunken);
00440 curveView->setLineWidth(1);
00441 curveView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
00442 curveView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
00443 _scene = new CCurveScene;
00444 curveView->setScene(_scene);
00445 curveView->setTransform(QTransform().scale(1, -1));
00446 curveView->setRenderHints(QPainter::Antialiasing);
00447 curveFrameLayout->addWidget(curveView);
00448 curveFrame->setLayout(curveFrameLayout);
00449
00450 mainLayout->addWidget(edits);
00451 mainLayout->addWidget(curveFrame);
00452 if(expandable){
00453 QPushButton* expandButton=new QPushButton(">");
00454 expandButton->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Expanding);
00455 expandButton->setFixedWidth(15);
00456 mainLayout->addWidget(expandButton);
00457
00458 connect(expandButton, SIGNAL(clicked()), this, SLOT(openDetail()));
00459 }
00460 mainLayout->setStretchFactor(curveFrame,100);
00461 setLayout(mainLayout);
00462
00463
00464
00465
00466 connect(_scene, SIGNAL(cvSelected(double, SeVec3d, T_INTERP)), this, SLOT(cvSelectedSlot(double, SeVec3d, T_INTERP)));
00467
00468 connect(_interpComboBox, SIGNAL(activated(int)), _scene, SLOT(interpChanged(int)));
00469
00470 connect(_selPosEdit, SIGNAL(returnPressed()), this, SLOT(selPosChanged()));
00471 connect(this, SIGNAL(selPosChangedSignal(double)), _scene, SLOT(selPosChanged(double)));
00472
00473 connect(_selValEdit, SIGNAL(selValChangedSignal(SeVec3d)), _scene, SLOT(selValChanged(SeVec3d)));
00474 connect(_selValEdit, SIGNAL(swatchChanged(QColor)), this, SLOT(internalSwatchChanged(QColor)));
00475
00476 connect(curveView, SIGNAL(resizeSignal(int, int)), _scene, SLOT(resize(int, int)));
00477 }
00478
00479
00480
00481 void SeExprEdColorCurve::cvSelectedSlot(const double pos, const SeVec3d val, const T_INTERP interp)
00482 {
00483 QString posStr;
00484 if (pos >= 0.0) {
00485 posStr.setNum(pos, 'f', 3);
00486 _selPosEdit->setText(posStr);
00487 _selValEdit->setValue(val);
00488 emit swatchChanged(QColor::fromRgbF(val[0],val[1],val[2],1));
00489 _interpComboBox->setCurrentIndex(interp);
00490 }
00491 }
00492
00493
00494 void SeExprEdColorCurve::selPosChanged()
00495 {
00496 double pos = SeExpr::clamp(QString(_selPosEdit->text()).toFloat(),0,1);
00497 _selPosEdit->setText(QString("%1").arg(pos, 0, 'f', 3));
00498 emit selPosChangedSignal(pos);
00499 }
00500
00501 void SeExprEdColorCurve::addPoint(const double x, const SeVec3d y, const T_INTERP interp, const bool select)
00502 {
00503 _scene->addPoint(x, y, interp, select);
00504 }
00505
00506 void SeExprEdColorCurve::setSwatchColor(QColor color)
00507 {
00508 SeVec3d newColor(color.redF(),color.greenF(),color.blueF());
00509 _scene->selValChanged(newColor);
00510 _selValEdit->setValue(newColor);
00511 }
00512
00513 QColor SeExprEdColorCurve::getSwatchColor()
00514 {
00515 SeVec3d val=_selValEdit->getValue();
00516 return QColor::fromRgbF(val[0],val[1],val[2],1);
00517 }
00518
00519 void SeExprEdColorCurve::internalSwatchChanged(QColor color)
00520 {
00521 emit swatchChanged(color);
00522 }
00523
00524 void SeExprEdColorCurve::openDetail()
00525 {
00526 QDialog* dialog=new QDialog();
00527 dialog->setMinimumWidth(1024);
00528 dialog->setMinimumHeight(400);
00529 SeExprEdColorCurve* curve=new SeExprEdColorCurve(0,"","","",false);
00530
00531
00532 const std::vector<T_CURVE::CV >& data=_scene->_cvs;
00533 typedef std::vector<T_CURVE::CV >::const_iterator ITERATOR;
00534 for(ITERATOR i=data.begin();i!=data.end();++i)
00535 curve->addPoint(i->_pos,i->_val,i->_interp);
00536
00537 QVBoxLayout* layout=new QVBoxLayout();
00538 dialog->setLayout(layout);
00539 layout->addWidget(curve);
00540
00541 dialog->setLayout(layout);
00542 layout->addWidget(curve);
00543 QDialogButtonBox* buttonbar=new QDialogButtonBox();
00544 buttonbar->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
00545 connect(buttonbar,SIGNAL(accepted()),dialog,SLOT(accept()));
00546 connect(buttonbar,SIGNAL(rejected()),dialog,SLOT(reject()));
00547 layout->addWidget(buttonbar);
00548
00549 if(dialog->exec()==QDialog::Accepted){
00550
00551 _scene->removeAll();
00552 const std::vector<T_CURVE::CV >& dataNew=curve->_scene->_cvs;
00553 typedef std::vector<T_CURVE::CV >::const_iterator ITERATOR;
00554 for(ITERATOR i=dataNew.begin();i!=dataNew.end();++i)
00555 addPoint(i->_pos,i->_val,i->_interp);
00556 _scene->emitCurveChanged();
00557 }
00558 }
00559