00001 #include <QGraphicsSceneMouseEvent>
00002 #include <QDebug>
00003
00004 #include "ThymioButtons.h"
00005
00006 #include "ThymioScene.h"
00007 #include "ThymioScene.moc"
00008
00009 using namespace std;
00010
00011 namespace Aseba
00012 {
00013
00014 ThymioScene::ThymioScene(QObject *parent) :
00015 QGraphicsScene(parent),
00016 prevNewEventButton(false),
00017 prevNewActionButton(false),
00018 lastFocus(-1),
00019 thymioCompiler(),
00020 eventButtonColor(QColor(0,191,255)),
00021 actionButtonColor(QColor(218,112,214)),
00022 sceneModified(false),
00023 scaleFactor(0.5),
00024 newRow(false),
00025 advancedMode(false)
00026 {
00027 ThymioButtonSet *button = new ThymioButtonSet(0, advancedMode);
00028 button->setScale(scaleFactor);
00029 button->setPos(15*scaleFactor, 20*scaleFactor);
00030 buttonSets.push_back(button);
00031 thymioCompiler.addButtonSet(button->getIRButtonSet());
00032
00033 buttonSetHeight = button->boundingRect().height();
00034
00035 addItem(button);
00036 connect(button, SIGNAL(buttonUpdated()), this, SLOT(buttonUpdateDetected()));
00037 connect(this, SIGNAL(selectionChanged()), this, SIGNAL(stateChanged()));
00038 }
00039
00040 ThymioScene::~ThymioScene()
00041 {
00042 clear();
00043 }
00044
00045 QGraphicsItem *ThymioScene::addAction(ThymioButton *item)
00046 {
00047 ThymioButtonSet *button = 0;
00048 prevNewActionButton = false;
00049
00050 if( newRow )
00051 button = createNewButtonSet();
00052 else if( prevNewEventButton )
00053 button = buttonSets.last();
00054 else
00055 {
00056 if( lastFocus >= 0 )
00057 button = buttonSets.at(lastFocus);
00058 else
00059 for(int i=0; i<buttonSets.size(); ++i)
00060 if( buttonSets.at(i)->hasFocus() )
00061 {
00062 button = buttonSets.at(i);
00063 break;
00064 }
00065
00066 if( !button )
00067 {
00068 if(!buttonSets.isEmpty() && !(buttonSets.last()->actionExists()) )
00069 button = buttonSets.last();
00070 else
00071 {
00072 button = createNewButtonSet();
00073 prevNewActionButton = true;
00074 }
00075 }
00076 }
00077
00078 if( item ) button->addActionButton(item);
00079 prevNewEventButton = false;
00080 newRow = false;
00081
00082 if( button->eventExists() )
00083 {
00084 lastFocus = -1;
00085 setFocusItem(0);
00086 }
00087
00088 setSceneRect(QRectF(0, 0, 1030*scaleFactor, (buttonSets.size()+2)*400*scaleFactor));
00089
00090 return button;
00091 }
00092
00093 QGraphicsItem *ThymioScene::addEvent(ThymioButton *item)
00094 {
00095 ThymioButtonSet *button = 0;
00096 prevNewEventButton = false;
00097
00098 if( newRow )
00099 button = createNewButtonSet();
00100 else if( prevNewActionButton )
00101 button = buttonSets.last();
00102 else
00103 {
00104 if( lastFocus >= 0 )
00105 button = buttonSets.at(lastFocus);
00106 else
00107 for(int i=0; i<buttonSets.size(); ++i)
00108 if( buttonSets.at(i)->hasFocus() )
00109 {
00110 button = buttonSets.at(i);
00111 break;
00112 }
00113
00114 if( !button )
00115 {
00116 if(!buttonSets.isEmpty() && !(buttonSets.last()->eventExists()) )
00117 button = buttonSets.last();
00118 else
00119 {
00120 button = createNewButtonSet();
00121 prevNewEventButton = true;
00122 }
00123 }
00124
00125 }
00126
00127 if( item ) button->addEventButton(item);
00128 prevNewActionButton = false;
00129 newRow = false;
00130
00131 if( button->actionExists() )
00132 {
00133 lastFocus = -1;
00134 setFocusItem(0);
00135 }
00136
00137 setSceneRect(QRectF(0, 0, 1030*scaleFactor, (buttonSets.size()+2)*400*scaleFactor));
00138
00139 return button;
00140 }
00141
00142 void ThymioScene::addButtonSet(ThymioButton *event, ThymioButton *action)
00143 {
00144 ThymioButtonSet *button = createNewButtonSet();
00145 if(event) button->addEventButton(event);
00146 if(action) button->addActionButton(action);
00147 lastFocus = -1;
00148 setFocusItem(0);
00149
00150 prevNewEventButton = false;
00151 prevNewActionButton = false;
00152 newRow = false;
00153
00154 setSceneRect(QRectF(0, 0, 1030*scaleFactor, (buttonSets.size()+2)*400*scaleFactor));
00155 }
00156
00157 ThymioButtonSet *ThymioScene::createNewButtonSet()
00158 {
00159 ThymioButtonSet *button = new ThymioButtonSet(buttonSets.size(), advancedMode);
00160 button->setColorScheme(eventButtonColor, actionButtonColor);
00161 button->setScale(scaleFactor);
00162 buttonSets.push_back(button);
00163
00164 addItem(button);
00165
00166 connect(button, SIGNAL(buttonUpdated()), this, SLOT(buttonUpdateDetected()));
00167 thymioCompiler.addButtonSet(button->getIRButtonSet());
00168
00169 return button;
00170 }
00171
00172 bool ThymioScene::isEmpty() const
00173 {
00174 if( buttonSets.isEmpty() )
00175 return true;
00176
00177 if( buttonSets.size() > 1 ||
00178 buttonSets[0]->actionExists() ||
00179 buttonSets[0]->eventExists() )
00180 return false;
00181
00182 return true;
00183 }
00184
00185 void ThymioScene::reset()
00186 {
00187 clear();
00188
00189 ThymioButtonSet *button = createNewButtonSet();
00190 button->setPos(15*scaleFactor, 20*scaleFactor);
00191
00192 setSceneRect(QRectF(0, 0, 1030*scaleFactor, (buttonSets.size()+2)*400*scaleFactor));
00193 }
00194
00195 void ThymioScene::clear()
00196 {
00197 advancedMode = false;
00198 for(ButtonSetItr itr = buttonsBegin(); itr != buttonsEnd(); ++itr)
00199 (*itr)->setAdvanced(false);
00200
00201 for(int i=0; i<buttonSets.size(); i++)
00202 {
00203 disconnect(buttonSets.at(i), SIGNAL(buttonUpdated()), this, SLOT(buttonUpdateDetected()));
00204 removeItem(buttonSets.at(i));
00205 delete(buttonSets.at(i));
00206 }
00207 buttonSets.clear();
00208 thymioCompiler.clear();
00209
00210 sceneModified = false;
00211
00212 lastFocus = -1;
00213 prevNewActionButton = false;
00214 prevNewEventButton = false;
00215 }
00216
00217 void ThymioScene::setColorScheme(QColor eventColor, QColor actionColor)
00218 {
00219 eventButtonColor = eventColor;
00220 actionButtonColor = actionColor;
00221
00222 for(ButtonSetItr itr = buttonsBegin(); itr != buttonsEnd(); ++itr)
00223 (*itr)->setColorScheme(eventColor, actionColor);
00224
00225 update();
00226
00227 sceneModified = true;
00228 }
00229
00230 void ThymioScene::setAdvanced(bool advanced)
00231 {
00232 advancedMode = advanced;
00233 for(ButtonSetItr itr = buttonsBegin(); itr != buttonsEnd(); ++itr)
00234 (*itr)->setAdvanced(advanced);
00235
00236 buttonUpdateDetected();
00237 }
00238
00239 void ThymioScene::removeButton(int row)
00240 {
00241 Q_ASSERT( row < buttonSets.size() );
00242
00243 ThymioButtonSet *button = buttonSets[row];
00244 disconnect(button, SIGNAL(buttonUpdated()), this, SLOT(buttonUpdateDetected()));
00245 buttonSets.removeAt(row);
00246 thymioCompiler.removeButtonSet(row);
00247
00248 removeItem(button);
00249 delete(button);
00250
00251 rearrangeButtons(row);
00252
00253 if( buttonSets.isEmpty() )
00254 {
00255 ThymioButtonSet *button = createNewButtonSet();
00256 button->setPos(advancedMode?5*scaleFactor:15*scaleFactor,20*scaleFactor);
00257 }
00258
00259 prevNewEventButton = false;
00260 prevNewActionButton = false;
00261 lastFocus = -1;
00262
00263 sceneModified = true;
00264
00265 setSceneRect(QRectF(0, 0, 1030*scaleFactor, (buttonSets.size()+2)*400*scaleFactor));
00266
00267 buttonUpdateDetected();
00268 }
00269
00270 void ThymioScene::insertButton(int row)
00271 {
00272 Q_ASSERT( row <= buttonSets.size() );
00273
00274 ThymioButtonSet *button = new ThymioButtonSet(row, advancedMode);
00275 button->setColorScheme(eventButtonColor, actionButtonColor);
00276 button->setScale(scaleFactor);
00277 buttonSets.insert(row, button);
00278 addItem(button);
00279
00280 thymioCompiler.insertButtonSet(row, button->getIRButtonSet());
00281
00282 connect(button, SIGNAL(buttonUpdated()), this, SLOT(buttonUpdateDetected()));
00283
00284 setFocusItem(button);
00285 lastFocus = row;
00286
00287 rearrangeButtons(row+1);
00288
00289 prevNewEventButton = false;
00290 prevNewActionButton = false;
00291
00292 sceneModified = true;
00293
00294 setSceneRect(QRectF(0, 0, 1030*scaleFactor, (buttonSets.size()+2)*400*scaleFactor));
00295
00296 buttonUpdateDetected();
00297 }
00298
00299 void ThymioScene::rearrangeButtons(int row)
00300 {
00301 for(int i=row; i<buttonSets.size(); ++i)
00302 buttonSets.at(i)->setRow(i);
00303 }
00304
00305 void ThymioScene::setScale(qreal scale)
00306 {
00307 scaleFactor = scale*0.5;
00308 for( ButtonSetItr itr = buttonsBegin(); itr != buttonsEnd(); ++itr )
00309 (*itr)->setScale(scaleFactor);
00310
00311 setSceneRect(QRectF(0, 0, 1030*scaleFactor, (buttonSets.size()+2)*400*scaleFactor));
00312 }
00313
00314 QString ThymioScene::getErrorMessage() const
00315 {
00316 switch(thymioCompiler.getErrorCode()) {
00317 case THYMIO_MISSING_EVENT:
00318 return tr("Line %0: Missing event").arg(thymioCompiler.getErrorLine());
00319 break;
00320 case THYMIO_MISSING_ACTION:
00321 return tr("Line %0: Missing action").arg(thymioCompiler.getErrorLine());
00322 break;
00323 case THYMIO_EVENT_MULTISET:
00324 return tr("Line %0: Redeclaration of event").arg(thymioCompiler.getErrorLine());
00325 break;
00326 case THYMIO_INVALID_CODE:
00327 return tr("Line %0: Unknown event/action type").arg(thymioCompiler.getErrorLine());
00328 break;
00329 case THYMIO_NO_ERROR:
00330 return tr("Compilation success");
00331 default:
00332 return tr("Unknown VPL error");
00333 break;
00334 }
00335 }
00336
00337 QList<QString> ThymioScene::getCode() const
00338 {
00339 QList<QString> out;
00340
00341 for(std::vector<std::wstring>::const_iterator itr = thymioCompiler.beginCode();
00342 itr != thymioCompiler.endCode(); ++itr)
00343 out.push_back(QString::fromStdWString(*itr));
00344
00345 return out;
00346 }
00347
00348 int ThymioScene::getFocusItemId() const
00349 {
00350 QGraphicsItem *item = focusItem();
00351
00352 while( item != 0 )
00353 {
00354 if( item->data(0).toString() == "buttonset" )
00355 return thymioCompiler.buttonToCode(item->data(1).toInt());
00356 else
00357 item = item->parentItem();
00358 }
00359
00360 return -1;
00361 }
00362
00363 void ThymioScene::buttonUpdateDetected()
00364 {
00365 sceneModified = true;
00366
00367 thymioCompiler.compile();
00368 thymioCompiler.generateCode();
00369
00370 for(int i=0; i<buttonSets.size(); i++)
00371 buttonSets[i]->setErrorStatus(false);
00372
00373 if( !thymioCompiler.isSuccessful() )
00374 buttonSets[thymioCompiler.getErrorLine()]->setErrorStatus(true);
00375
00376 emit stateChanged();
00377 }
00378
00379 void ThymioScene::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
00380 {
00381 if( event->mimeData()->hasFormat("thymiobutton") &&
00382 ((event->scenePos().y()-20*scaleFactor)/(buttonSetHeight*scaleFactor)) >= buttonSets.size() )
00383 {
00384 setFocusItem(0);
00385 event->accept();
00386 }
00387 else
00388 QGraphicsScene::dragMoveEvent(event);
00389 }
00390
00391 void ThymioScene::dropEvent(QGraphicsSceneDragDropEvent *event)
00392 {
00393 if ( event->mimeData()->hasFormat("thymiobuttonset") )
00394 {
00395 QByteArray buttonData = event->mimeData()->data("thymiobuttonset");
00396 QDataStream dataStream(&buttonData, QIODevice::ReadOnly);
00397
00398 int prevRow, currentRow;
00399 dataStream >> prevRow;
00400
00401 ThymioButtonSet *button = buttonSets.at(prevRow);
00402 buttonSets.removeAt(prevRow);
00403 thymioCompiler.removeButtonSet(prevRow);
00404
00405 qreal currentYPos = event->scenePos().y();
00406 currentRow = (int)((currentYPos-20*scaleFactor)/(buttonSetHeight*scaleFactor));
00407 currentRow = (currentRow < 0 ? 0 : currentRow > buttonSets.size() ? buttonSets.size() : currentRow);
00408
00409 buttonSets.insert(currentRow, button);
00410 thymioCompiler.insertButtonSet(currentRow, button->getIRButtonSet());
00411
00412 rearrangeButtons( prevRow < currentRow ? prevRow : currentRow );
00413
00414 event->setDropAction(Qt::MoveAction);
00415 event->accept();
00416
00417 setFocusItem(button);
00418 lastFocus = currentRow;
00419
00420 buttonUpdateDetected();
00421 }
00422 else if( event->mimeData()->hasFormat("thymiobutton") &&
00423 ((event->scenePos().y()-20*scaleFactor)/(buttonSetHeight*scaleFactor)) >= buttonSets.size() )
00424 {
00425 QByteArray buttonData = event->mimeData()->data("thymiobutton");
00426 QDataStream dataStream(&buttonData, QIODevice::ReadOnly);
00427
00428 int parentID;
00429 dataStream >> parentID;
00430
00431 QString buttonName;
00432 int numButtons;
00433 dataStream >> buttonName >> numButtons;
00434
00435 ThymioButton *button = 0;
00436
00437 if ( buttonName == "button" )
00438 button = new ThymioButtonsEvent(0, advancedMode);
00439 else if ( buttonName == "prox" )
00440 button = new ThymioProxEvent(0, advancedMode);
00441 else if ( buttonName == "proxground" )
00442 button = new ThymioProxGroundEvent(0, advancedMode);
00443 else if ( buttonName == "tap" )
00444 {
00445 button = new ThymioTapEvent(0, advancedMode);
00446 QByteArray rendererData = event->mimeData()->data("thymiorenderer");
00447 QDataStream rendererStream(&rendererData, QIODevice::ReadOnly);
00448 quint64 location;
00449 rendererStream >> location;
00450 QSvgRenderer *tapSvg;
00451 tapSvg = (QSvgRenderer*)location;
00452 button->setSharedRenderer(tapSvg);
00453 }
00454 else if ( buttonName == "clap" )
00455 {
00456 button = new ThymioClapEvent(0, advancedMode);
00457 QByteArray rendererData = event->mimeData()->data("thymiorenderer");
00458 QDataStream rendererStream(&rendererData, QIODevice::ReadOnly);
00459 quint64 location;
00460 rendererStream >> location;
00461 QSvgRenderer *clapSvg;
00462 clapSvg = (QSvgRenderer*)location;
00463 button->setSharedRenderer(clapSvg);
00464 }
00465 else if ( buttonName == "move" )
00466 button = new ThymioMoveAction();
00467 else if ( buttonName == "color" )
00468 button = new ThymioColorAction();
00469 else if ( buttonName == "circle" )
00470 button = new ThymioCircleAction();
00471 else if ( buttonName == "sound" )
00472 button = new ThymioSoundAction();
00473 else if ( buttonName == "memory" )
00474 button = new ThymioMemoryAction();
00475
00476 if( button )
00477 {
00478 event->setDropAction(Qt::MoveAction);
00479 event->accept();
00480
00481 lastFocus = -1;
00482 prevNewActionButton = false;
00483 prevNewEventButton = false;
00484 newRow = true;
00485
00486 if( event->mimeData()->data("thymiotype") == QString("event").toLatin1() )
00487 addEvent(button);
00488 else if( event->mimeData()->data("thymiotype") == QString("action").toLatin1() )
00489 addAction(button);
00490
00491 for( int i=0; i<numButtons; ++i )
00492 {
00493 int status;
00494 dataStream >> status;
00495 button->setClicked(i, status);
00496 }
00497
00498 }
00499 }
00500 else
00501 QGraphicsScene::dropEvent(event);
00502 }
00503
00504 void ThymioScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
00505 {
00506 QGraphicsScene::mousePressEvent(event);
00507 }
00508
00509 void ThymioScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
00510 {
00511 QGraphicsScene::mouseReleaseEvent(event);
00512
00513 if( event->button() == Qt::LeftButton )
00514 {
00515 QGraphicsItem *item = focusItem();
00516 if( item )
00517 {
00518 if( item->data(0) == "remove" )
00519 removeButton((item->parentItem()->data(1)).toInt());
00520 else if( item->data(0) == "add" )
00521 insertButton((item->parentItem()->data(1)).toInt()+1);
00522
00523
00524 }
00525 }
00526
00527 update();
00528 }
00529
00530 };