FridgeGrid is a tool intended to help planning cycle exact code for effects on old school hardware. Think of it as a combination of grid paper and fridge magnets in digital form with save and load functions. https://xayax.net/tools/fridgegrid/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

DragWidget.cpp 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. /*
  2. * src/fridgegrid/MainWindow.cpp
  3. * written by Sven Oliver Moll
  4. *
  5. * distributed under the terms of the GNU General Public License (GPL)
  6. * available at http://www.gnu.org/licenses/gpl.html
  7. */
  8. /* class declaration */
  9. #include "DragWidget.hpp"
  10. /* system headers */
  11. /* Qt headers */
  12. #include <QAction>
  13. #include <QApplication>
  14. #include <QDomDocument>
  15. #include <QDrag>
  16. #include <QDragEnterEvent>
  17. #include <QDragMoveEvent>
  18. #include <QDropEvent>
  19. #include <QFileDialog>
  20. #include <QFileInfo>
  21. #include <QMessageBox>
  22. #include <QMimeData>
  23. #include <QPainter>
  24. #include <QSettings>
  25. #include <QTextStream>
  26. #include <QTextEdit>
  27. //#include <QSize>
  28. /* local library headers */
  29. /* local headers */
  30. #include "DragLabel.hpp"
  31. DragWidget::DragWidget( QWidget *parent )
  32. : QWidget( parent )
  33. , mpTextEdit( 0 )
  34. , mGridStyle( "Default", QSize(15,15),
  35. QFont("ErbosDraco Nova Open NBP", 6), QPoint( 2, 1 ), true )
  36. {
  37. setMinimumSize( 400, 200 );
  38. setAcceptDrops( true );
  39. }
  40. DragWidget::~DragWidget()
  41. {
  42. }
  43. QSize DragWidget::gridSize()
  44. {
  45. return mGridStyle.gridSize();
  46. }
  47. void DragWidget::setTextEdit( QTextEdit *textEdit )
  48. {
  49. mpTextEdit = textEdit;
  50. }
  51. void DragWidget::updateLabelPos( const QSize &newSize )
  52. {
  53. QMap<DragLabel*,QPoint> sizemap;
  54. QList<DragLabel*> labels( findChildren<DragLabel*>() );
  55. foreach( DragLabel *label, labels )
  56. {
  57. sizemap.insert( label, pos2grid( label->pos() ) );
  58. }
  59. mGridStyle.setGridSize( newSize );
  60. foreach( DragLabel *label, labels )
  61. {
  62. place( label, grid2pos( sizemap.value(label) ) );
  63. label->draw();
  64. }
  65. update();
  66. }
  67. QPoint DragWidget::grid2pos( const QPoint &pos )
  68. {
  69. return QPoint( pos.x() / mGridStyle.gridSize().width(),
  70. pos.y() / mGridStyle.gridSize().height() );
  71. }
  72. QPoint DragWidget::pos2grid( const QPoint &grid )
  73. {
  74. return QPoint( grid.x() * mGridStyle.gridSize().width(),
  75. grid.y() * mGridStyle.gridSize().height() );
  76. }
  77. void DragWidget::dragEnterEvent( QDragEnterEvent *event )
  78. {
  79. if( event->mimeData()->hasFormat("application/x-fridgemagnet") )
  80. {
  81. if( children().contains( event->source() ) )
  82. {
  83. event->setDropAction( Qt::MoveAction );
  84. event->accept();
  85. }
  86. else
  87. {
  88. event->acceptProposedAction();
  89. }
  90. }
  91. else if( event->mimeData()->hasText() )
  92. {
  93. event->acceptProposedAction();
  94. }
  95. else
  96. {
  97. event->ignore();
  98. }
  99. }
  100. void DragWidget::dragMoveEvent( QDragMoveEvent *event )
  101. {
  102. if( event->mimeData()->hasFormat("application/x-fridgemagnet") )
  103. {
  104. if( children().contains(event->source()) )
  105. {
  106. event->setDropAction(Qt::MoveAction);
  107. event->accept();
  108. }
  109. else
  110. {
  111. event->acceptProposedAction();
  112. }
  113. }
  114. else if( event->mimeData()->hasText() )
  115. {
  116. event->acceptProposedAction();
  117. }
  118. else
  119. {
  120. event->ignore();
  121. }
  122. }
  123. void DragWidget::dropEvent( QDropEvent *event )
  124. {
  125. if( event->mimeData()->hasFormat("application/x-fridgemagnet") )
  126. {
  127. const QMimeData *mime = event->mimeData();
  128. QByteArray itemData( mime->data("application/x-fridgemagnet") );
  129. QDataStream dataStream( &itemData, QIODevice::ReadOnly );
  130. QPoint offset;
  131. QByteArray data;
  132. dataStream >> offset >> data;
  133. DragLabel *newLabel = new DragLabel( data, this );
  134. place( newLabel, event->pos() - offset );
  135. newLabel->show();
  136. newLabel->setAttribute( Qt::WA_DeleteOnClose );
  137. if( event->source() == this )
  138. {
  139. event->setDropAction( Qt::MoveAction );
  140. event->accept();
  141. }
  142. else
  143. {
  144. event->acceptProposedAction();
  145. }
  146. }
  147. else if( event->mimeData()->hasText() )
  148. {
  149. QStringList pieces = event->mimeData()->text().split( '\n', QString::SkipEmptyParts );
  150. QPoint position = event->pos();
  151. foreach( const QString &piece, pieces )
  152. {
  153. DragLabel *newLabel = new DragLabel( this );
  154. newLabel->setText( piece );
  155. if( event->mimeData()->hasColor() )
  156. {
  157. QColor color = qvariant_cast<QColor>( event->mimeData()->colorData() );
  158. newLabel->setColor( color );
  159. }
  160. place( newLabel, position );
  161. newLabel->show();
  162. newLabel->setAttribute( Qt::WA_DeleteOnClose );
  163. position += QPoint( newLabel->width(), 0 );
  164. }
  165. event->acceptProposedAction();
  166. }
  167. else
  168. {
  169. event->ignore();
  170. }
  171. }
  172. void DragWidget::mousePressEvent( QMouseEvent *event )
  173. {
  174. if( event->button() != Qt::LeftButton )
  175. {
  176. return;
  177. }
  178. DragLabel *child = static_cast<DragLabel*>( childAt(event->pos()) );
  179. if( !child )
  180. {
  181. return;
  182. }
  183. QPoint hotSpot = event->pos() - child->pos();
  184. QByteArray itemData;
  185. QDataStream dataStream(&itemData, QIODevice::WriteOnly);
  186. dataStream << hotSpot << child->toByteArray();
  187. QMimeData *mimeData = new QMimeData;
  188. mimeData->setData( "application/x-fridgemagnet", itemData );
  189. mimeData->setText( child->labelText() );
  190. mimeData->setColorData( child->color() );
  191. QDrag *drag = new QDrag( this );
  192. drag->setMimeData( mimeData );
  193. drag->setPixmap( *(child->pixmap()) );
  194. drag->setHotSpot( hotSpot );
  195. child->hide();
  196. if( drag->exec( Qt::MoveAction | Qt::CopyAction, Qt::CopyAction ) == Qt::MoveAction )
  197. {
  198. child->close();
  199. }
  200. else
  201. {
  202. child->show();
  203. }
  204. }
  205. void DragWidget::mouseDoubleClickEvent( QMouseEvent *event )
  206. {
  207. if( event->button() != Qt::LeftButton )
  208. {
  209. return;
  210. }
  211. DragLabel *child = static_cast<DragLabel*>( childAt(event->pos()) );
  212. if( !child )
  213. {
  214. return;
  215. }
  216. child->parameterMenu( event->globalPos() );
  217. }
  218. void DragWidget::paintEvent( QPaintEvent *event )
  219. {
  220. Q_UNUSED( event );
  221. QPainter painter( this );
  222. painter.setRenderHint( QPainter::Antialiasing );
  223. painter.setBrush( Qt::black );
  224. for( int i = mGridStyle.gridSize().width() - 1; i < size().width() ; i += mGridStyle.gridSize().width() )
  225. {
  226. painter.drawLine( i, 0, i, size().height() - 1 );
  227. }
  228. for( int i = mGridStyle.gridSize().height() - 1; i < size().height() ; i += mGridStyle.gridSize().height() )
  229. {
  230. painter.drawLine( 0, i, size().width() - 1, i );
  231. }
  232. painter.end();
  233. }
  234. void DragWidget::place( QWidget *w, int x, int y )
  235. {
  236. if( (x % mGridStyle.gridSize().width()) > (mGridStyle.gridSize().width() / 2) )
  237. {
  238. x += mGridStyle.gridSize().width();
  239. }
  240. if( (y % mGridStyle.gridSize().height()) > (mGridStyle.gridSize().height() / 2) )
  241. {
  242. y += mGridStyle.gridSize().height();
  243. }
  244. x -= (x % mGridStyle.gridSize().width());
  245. y -= (y % mGridStyle.gridSize().height());
  246. w->move( x + 1, y + 1 );
  247. }
  248. void DragWidget::place( QWidget *w, const QPoint &p )
  249. {
  250. place( w, p.x(), p.y() );
  251. }
  252. void DragWidget::exportPng()
  253. {
  254. QSettings settings;
  255. QFileInfo lastFilename( settings.value( "ExportFilename" ).toString() );
  256. QString fileName = QFileDialog::getSaveFileName( this, QCoreApplication::applicationName(),
  257. lastFilename.absoluteFilePath(), "*.png" );
  258. if( fileName.isEmpty() )
  259. {
  260. return;
  261. }
  262. settings.setValue( "ExportFilename", fileName );
  263. grab().save( fileName );
  264. }
  265. void DragWidget::save()
  266. {
  267. QSettings settings;
  268. QFileInfo lastFilename( settings.value( "Filename" ).toString() );
  269. QString fileName = QFileDialog::getSaveFileName( this, QCoreApplication::applicationName(),
  270. lastFilename.absoluteFilePath(), "*.xml" );
  271. if( fileName.isEmpty() )
  272. {
  273. return;
  274. }
  275. settings.setValue( "Filename", fileName );
  276. QDomDocument domDoc;
  277. QDomElement domRoot = domDoc.createElement( "FridgeGrid" );
  278. domDoc.appendChild(domRoot);
  279. QDomElement comment = domDoc.createElement( "comment" );
  280. if( mpTextEdit )
  281. {
  282. comment.setAttribute( "text", mpTextEdit->toPlainText() );
  283. }
  284. domRoot.appendChild( comment );
  285. QDomElement elements = domDoc.createElement( "elements" );
  286. domRoot.appendChild( elements );
  287. QList<DragLabel*> labels( findChildren<DragLabel*>() );
  288. foreach( DragLabel *label, labels )
  289. {
  290. QDomElement domElement = domDoc.createElement("element");
  291. label->writeDomAttributes( &domElement );
  292. elements.appendChild(domElement);
  293. }
  294. QFile file( fileName );
  295. const int indentSize = 2;
  296. file.open( QIODevice::WriteOnly );
  297. QTextStream out( &file );
  298. domDoc.save( out, indentSize );
  299. file.close();
  300. }
  301. void DragWidget::load( const QString &templateFileName )
  302. {
  303. QSettings settings;
  304. QString fileName( templateFileName );
  305. QFileInfo lastFilename( settings.value("Filename").toString() );
  306. if( fileName.isEmpty() )
  307. {
  308. fileName = QFileDialog::getOpenFileName( this, QCoreApplication::applicationName(),
  309. lastFilename.absolutePath(), "*.xml" );
  310. if( fileName.isEmpty() )
  311. {
  312. return;
  313. }
  314. }
  315. // an internal filename should not be saved to registry
  316. if( fileName.startsWith( ':' ) )
  317. {
  318. settings.remove( "Filename" );
  319. }
  320. else
  321. {
  322. settings.setValue( "Filename", fileName );
  323. }
  324. QFile file( fileName );
  325. file.open( QIODevice::ReadOnly );
  326. QString errorStr;
  327. int errorLine;
  328. int errorColumn;
  329. QDomDocument domDoc;
  330. if( !domDoc.setContent( &file, true, &errorStr, &errorLine, &errorColumn ) )
  331. {
  332. QMessageBox::information( window(), QApplication::applicationName(),
  333. tr("Parse error at line %1, column %2:\n%3")
  334. .arg(errorLine)
  335. .arg(errorColumn)
  336. .arg(errorStr) );
  337. //return false;
  338. }
  339. QDomElement domRoot = domDoc.documentElement();
  340. if( domRoot.tagName() != "FridgeGrid" )
  341. {
  342. QMessageBox::information( window(), QApplication::applicationName(),
  343. tr("The file is not a FridgeGrid file.") );
  344. //return false;
  345. }
  346. #if 0
  347. else if (root.hasAttribute("version")
  348. && root.attribute("version") != "1.0")
  349. {
  350. QMessageBox::information( window(), QApplication::applicationName(),
  351. tr("The file is not a FridgeGrid version 1.0 "
  352. "file.") );
  353. return false;
  354. }
  355. #endif
  356. QList<DragLabel*> labels( findChildren<DragLabel*>() );
  357. foreach( DragLabel *label, labels )
  358. {
  359. label->deleteLater();
  360. }
  361. QDomElement comment = domRoot.firstChildElement( "comment" );
  362. if( mpTextEdit )
  363. {
  364. mpTextEdit->setPlainText( comment.attribute("text") );
  365. }
  366. QDomElement elements = domRoot.firstChildElement( "elements" );
  367. QDomNodeList elementList = elements.elementsByTagName( "element" );
  368. for( int i = 0; i < elementList.size(); ++i )
  369. {
  370. const QDomElement &domElement = elementList.at(i).toElement();
  371. DragLabel *newLabel = new DragLabel( this );
  372. QPoint pos( newLabel->readDomAttributes( &domElement ) );
  373. if( pos.isNull() )
  374. {
  375. delete newLabel;
  376. }
  377. else
  378. {
  379. place( newLabel, pos );
  380. newLabel->show();
  381. newLabel->setAttribute(Qt::WA_DeleteOnClose);
  382. }
  383. }
  384. }
  385. void DragWidget::newElement( const QByteArray &d, const QPoint &p )
  386. {
  387. DragLabel *wordLabel = 0;
  388. if( d.isNull() )
  389. {
  390. wordLabel = new DragLabel( this );
  391. }
  392. else
  393. {
  394. wordLabel = new DragLabel( d, this );
  395. }
  396. place( wordLabel, p.x(), p.y() );
  397. wordLabel->show();
  398. wordLabel->setAttribute( Qt::WA_DeleteOnClose );
  399. }
  400. QVariant DragWidget::getData()
  401. {
  402. QVariantList list;
  403. QList<DragLabel*> labels( findChildren<DragLabel*>() );
  404. foreach( DragLabel *label, labels )
  405. {
  406. QVariantMap map;
  407. map.insert( "pos", pos2grid( label->pos() ) );
  408. map.insert( "data", label->toByteArray() );
  409. list.append( map );
  410. }
  411. return list;
  412. }
  413. void DragWidget::setData( const QVariant &data )
  414. {
  415. QVariantList list( data.toList() );
  416. QVariant element;
  417. QList<DragLabel*> labels( findChildren<DragLabel*>() );
  418. foreach( DragLabel *label, labels )
  419. {
  420. label->deleteLater();
  421. }
  422. foreach( element, list )
  423. {
  424. QVariantMap map( element.toMap() );
  425. DragLabel *newLabel = new DragLabel( this );
  426. QPoint pos( grid2pos( map.value( "pos" ).toPoint() ) );
  427. newLabel->setFromByteArray( map.value( "data" ).toByteArray() );
  428. if( pos.isNull() )
  429. {
  430. delete newLabel;
  431. }
  432. else
  433. {
  434. place( newLabel, pos );
  435. newLabel->show();
  436. newLabel->setAttribute( Qt::WA_DeleteOnClose );
  437. }
  438. }
  439. }
  440. GridStyle DragWidget::gridStyle() const
  441. {
  442. return mGridStyle;
  443. }
  444. void DragWidget::setGridStyle(const GridStyle &gridStyle)
  445. {
  446. mGridStyle = gridStyle;
  447. }