1 /*
2 * QGuidoItemContainer.cpp
3 *
4 * Created by Christophe Daudin on 12/05/09.
5 * Copyright 2009 Grame. All rights reserved.
6 *
7 * GNU Lesser General Public License Usage
8 * Alternatively, this file may be used under the terms of the GNU Lesser
9 * General Public License version 2.1 as published by the Free Software
10 * Foundation and appearing in the file LICENSE.LGPL included in the
11 * packaging of this file. Please review the following information to
12 * ensure the GNU Lesser General Public License version 2.1 requirements
13 * will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
14 *
15 *
16 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
17 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18 */
19
20 #include <sstream>
21 #include <QGraphicsSceneMouseEvent>
22 #include <QStyleOptionGraphicsItem>
23
24 #include "QGuidoItemContainer.h"
25 #include "QGuidoGraphicsItem.h"
26 #include "QGuidoImporter.h"
27
28 #include "QItemResizer.h"
29
30 #ifdef USES_GUIDO_AR
31 #include "QGuidoAR.h"
32 #include "QPaletteItem.h"
33 #endif
34
35 #include <assert.h>
36 #include <QtDebug>
37
38 #define PROPORTIONAL_SPRING 1.0f
39 #define PROPORTIONAL_FORCE 1500.0f
40 #define NO_PROPORTIONAL_SPRING 1.1f
41 #define NO_PROPORTIONAL_FORCE 750.0f
42
43 #define DEFAULT_PROPORTIONAL false
44 #define DEFAULT_OPTIMAL_PAGE_FILL true
45 #define DEFAULT_RESIZE_PAGE true
46
47 #define SELECTION_FLAG_SELECTED 2
48 #define SELECTION_FLAG_HIGHLIGHTED 1
49 #define SELECTION_FLAG_IDLE 0
50 #define SELECTION_SWITCH_INVALID_CODE 1
51
52 #define TITLE_BAR_FONT_COLOR Qt::black
53 #define TITLE_BAR_FONT QFont("Lucida Grande")
54 #define TITLE_BAR_FONT_PEN_WIDTH 1.0f
55
56
57 #define ARROW_PEN_WIDTH 2
58
59 #define PAGE_TURNER_ARROW_SIZE 10
60
61 #define PAGE_LABEL_RECT_OUT_WIDTH 5
62 #define PAGE_LABEL_RECT_OUT_HEIGHT 5
63 #define PAGE_LABEL_TEXT_MARGIN 0
64 #define PAGE_LABEL_RECT_RADIUS_FACTOR 0.5f
65
66 #define INVALID_RECT QRect(0,0,100,100)
67
68 #define DOM_GUIDO_ITEM_CURRENT_PAGE "currentPage"
69 #define DOM_GUIDO_ITEM_GRID_WIDTH "gridWidth"
70 #define DOM_GUIDO_ITEM_GRID_HEIGHT "gridHeight"
71
72 #define GMN_CONTAINER_MIME_FLAG "GMNContainerMimeFlag"
73 #define GMN_CONTAINER_MIME_GRID_WIDTH "GMNContainerMimeGridWidth"
74 #define GMN_CONTAINER_MIME_GRID_HEIGHT "GMNContainerMimeGridHeight"
75 #define GMN_CONTAINER_MIME_PAGE_INDEX "gmnContainerMimePageIndex"
76
77 class QPageTurnerItem : public QGraphicsPolygonItem
78 {
79 public:
QPageTurnerItem(bool isNext,const QPolygonF & polygon,QGuidoItemContainer * parent)80 QPageTurnerItem( bool isNext , const QPolygonF& polygon , QGuidoItemContainer * parent )
81 : QGraphicsPolygonItem( polygon , parent )
82 {
83 mParent = parent;
84 mIsNext = isNext;
85
86 setAcceptHoverEvents(true);
87
88 setCursor( Qt::PointingHandCursor );
89 }
90
91 protected:
92
mousePressEvent(QGraphicsSceneMouseEvent * event)93 void mousePressEvent( QGraphicsSceneMouseEvent * event )
94 {
95 if ( mIsNext )
96 mParent->nextPage();
97 else
98 mParent->previousPage();
99
100 event->accept();
101 }
102
103 QGuidoItemContainer * mParent;
104 bool mIsNext;
105
106 };
107
108 QPolygonF getRightArrowPolygon(const QRectF& boundingRect);
109 QPolygonF getLeftArrowPolygon(const QRectF& boundingRect);
110
111
112 //-------------------------------------------------------------------------
113 // Public functions //
114 //-------------------------------------------------------------------------
115 //-------------------------------------------------------------------------
QGuidoItemContainer(QGraphicsItem * parent)116 QGuidoItemContainer::QGuidoItemContainer(QGraphicsItem * parent)
117 : QLanguageItem(parent)
118 {
119 init();
120 }
121
122 //-------------------------------------------------------------------------
QGuidoItemContainer(const QMimeData * mimeData,QGraphicsItem * parent)123 QGuidoItemContainer::QGuidoItemContainer(const QMimeData * mimeData , QGraphicsItem * parent)
124 : QLanguageItem(parent)
125 {
126 QGuidoItemContainer::init(mimeData);
127 }
128
129 //-------------------------------------------------------------------------
QGuidoItemContainer(const QDomElement * domElement,QGraphicsItem * parent)130 QGuidoItemContainer::QGuidoItemContainer(const QDomElement * domElement , QGraphicsItem * parent)
131 : QLanguageItem(parent)
132 {
133 QGuidoItemContainer::init(domElement);
134 }
135
136 //-------------------------------------------------------------------------
QGuidoItemContainer(const QGuidoItemContainer * other,QGraphicsItem * parent)137 QGuidoItemContainer::QGuidoItemContainer(const QGuidoItemContainer * other , QGraphicsItem * parent)
138 : QLanguageItem(parent)
139 {
140 QGuidoItemContainer::init(other);
141 }
142
143 //-------------------------------------------------------------------------
~QGuidoItemContainer()144 QGuidoItemContainer::~QGuidoItemContainer()
145 {
146 #ifdef USES_GUIDO_AR
147 if ( mMidiRef != -1 )
148 {
149 stop();
150 QGuidoAR::midiClose(mMidiRef);
151 mPlayerState = STOPPED;
152 mMidiRef = -1;
153 }
154 #endif
155 }
156
157 //-------------------------------------------------------------------------
exportToPdf(const QString & fileName)158 void QGuidoItemContainer::exportToPdf(const QString& fileName)
159 {
160 QPrinter printer;
161 printer.setFullPage(true);
162 printer.setOutputFileName( fileName );
163 printer.setOutputFormat( QPrinter::PdfFormat );
164 exportToPdf( &printer );
165 }
166
167 //-------------------------------------------------------------------------
saveToDomElement(QDomDocument * doc)168 QDomElement QGuidoItemContainer::saveToDomElement( QDomDocument * doc)
169 {
170 QDomElement element = QLanguageItem::saveToDomElement(doc);
171
172 element.setAttribute( DOM_GUIDO_ITEM_PROPORTIONAL_LAYOUT , mIsProportionalOn );
173 element.setAttribute( DOM_GUIDO_ITEM_OPTIMAL_PAGE_FILL , mIsOptimalPageFillOn );
174 element.setAttribute( DOM_GUIDO_ITEM_RESIZE_PAGE_ON , mGuidoItem->isResizePageToMusicOn() );
175 element.setAttribute( DOM_GUIDO_ITEM_SCALE , mGuidoItem->transform().m11() );
176
177 element.setAttribute( DOM_GUIDO_ITEM_CURRENT_PAGE, mGuidoItem->firstVisiblePage() );
178 element.setAttribute( DOM_GUIDO_ITEM_GRID_WIDTH, mGuidoItem->gridWidth() );
179 element.setAttribute( DOM_GUIDO_ITEM_GRID_HEIGHT, mGuidoItem->gridHeight() );
180
181 return element;
182 }
183
184 //-------------------------------------------------------------------------
recognizes(const QMimeData * mimeData)185 bool QGuidoItemContainer::recognizes( const QMimeData * mimeData )
186 {
187 return mimeData->hasFormat( GMN_CONTAINER_MIME_FLAG );
188 }
189
190 //-------------------------------------------------------------------------
recognizes(const QDomElement * e)191 bool QGuidoItemContainer::recognizes( const QDomElement * e )
192 {
193 return ( QVariant( e->attribute( DOM_GUIDO_ITEM_PROPORTIONAL_LAYOUT, "-1" ) ).toInt() != -1 );
194 }
195
196 //-------------------------------------------------------------------------
setCode(const QString & code)197 bool QGuidoItemContainer::setCode( const QString& code )
198 {
199 // bool oldIsValid = isValid();
200
201 mGuidoItem->setGMNCode(code);
202 if (!isValid() && QGuidoImporter::musicxmlSupported()) { // try to import file as MusicXML file
203 std::stringstream out;
204 if ( QGuidoImporter::musicxmlString2Guido(code.toUtf8().constData(), true, out) )
205 {
206 mGuidoItem->setGMNCode( out.str().c_str() );
207 unlinkFile();
208 }
209 }
210
211 QLanguageItem::codeChanged();
212
213 mPenBrushSwitcher.setActiveSwitch( isValid() ? 0 : SELECTION_SWITCH_INVALID_CODE );
214 updateSelectionItem();
215 mHasToUpdateDragImage = true;
216
217 if ( mResizer )
218 updateResizerColor();
219
220 #ifdef USES_GUIDO_AR
221 stop();
222 mMidiRef = QGuidoAR::getMidiRef( this->code() );
223 #endif
224
225 return isValid();
226 }
227
228 //-------------------------------------------------------------------------
descriptiveNameHasChanged()229 void QGuidoItemContainer::descriptiveNameHasChanged()
230 {
231 updateTitleBar();
232 }
233
234 //-------------------------------------------------------------------------
isEqualTo(QLanguageItem * item) const235 bool QGuidoItemContainer::isEqualTo( QLanguageItem * item ) const
236 {
237 if ( !QLanguageItem::isEqualTo(item) )
238 return false;
239
240 QGuidoItemContainer* otherContainer = dynamic_cast<QGuidoItemContainer*>(item);
241 if ( !otherContainer )
242 return false;
243
244 // if ( mIsOptimalPageFillOn != otherContainer->mIsOptimalPageFillOn )
245 // return false;
246 // if ( mIsProportionalOn != otherContainer->mIsProportionalOn )
247 // return false;
248
249 // if ( mGuidoItem->firstVisiblePage()!= other->mGuidoItem->firstVisiblePage())
250 // return false;
251
252 return true;
253 }
254
255 //-------------------------------------------------------------------------
guidoItem() const256 QGuidoGraphicsItem * QGuidoItemContainer::guidoItem() const
257 {
258 return mGuidoItem;
259 }
260
261 //-------------------------------------------------------------------------
setMinMaxScale(float min,float max)262 void QGuidoItemContainer::setMinMaxScale(float min , float max)
263 {
264 mMinScale = min;
265 mMaxScale = max;
266 }
267
268 //-------------------------------------------------------------------------
269 // Public slots //
270 //-------------------------------------------------------------------------
271
272 //-------------------------------------------------------------------------
resized(const QRectF & newRect)273 void QGuidoItemContainer::resized(const QRectF& newRect)
274 {
275 if ( newRect.toRect() == rect().toRect() )
276 return;
277
278
279 if ( mResizeMode == RESIZE_GRID )
280 {
281 QRectF oldRect = rect();
282 mGuidoItem->setGridWidth( mGuidoItem->gridWidth() * newRect.width() / rect().width() + 0.5f );
283 mGuidoItem->setGridHeight( mGuidoItem->gridHeight() * newRect.height() / rect().height() + 0.5f );
284 guidoGeometryChanged();
285
286 QSizeF dSize( rect().size() - oldRect.size() );
287 moveBy( dSize.width() * ( newRect.x() ? -1 : 0 ) , dSize.height() * ( newRect.y() ? -1 : 0 ) );
288 }
289 else if ( mResizeMode == RESIZE_FORMAT )
290 {
291 QRectF oldRect = rect();
292
293 GuidoPageFormat f = mGuidoItem->guidoPageFormat();
294 f.width = f.width * newRect.width() / rect().width();
295 f.height = f.height * newRect.height() / rect().height();
296 mGuidoItem->setGuidoPageFormat(f);
297
298 //Control if how the page format was actually supported,
299 //and set it to its actual value.
300 if ( rect().toRect() != newRect.toRect() ) //has use int comparison, float isn't reliable
301 {
302 f = mGuidoItem->guidoPageFormat();
303 f.width = f.width * rect().width() / newRect.width();
304 f.height = f.height * rect().height() / newRect.height();
305 mGuidoItem->setGuidoPageFormat(f);
306 }
307
308 QSizeF dSize( rect().size() - oldRect.size() );
309
310 // moveBy( newRect.x() , newRect.y() );
311 moveBy( dSize.width() * ( newRect.x() ? -1 : 0 ) , dSize.height() * ( newRect.y() ? -1 : 0 ) );
312 }
313 else
314 {
315 float xScale = mGuidoItem->transform().m11();
316 float yScale = mGuidoItem->transform().m22();
317
318 float dx = newRect.x();
319 float dy = newRect.y();
320
321 float sx = ( newRect.width() / rect().width() );
322 float sy = ( newRect.height() / rect().height() );
323
324 float boundedSx = sx;
325 float boundedSy = sy;
326
327 if ( mMaxScale )
328 boundedSx = qMin( mMaxScale/xScale , boundedSx );
329 boundedSx = qMax( mMinScale/xScale , boundedSx );
330 if ( mMaxScale )
331 boundedSy = qMin( mMaxScale/yScale , boundedSy );
332 boundedSy = qMax( mMinScale/yScale , boundedSy );
333
334 dx = dx * (boundedSx - 1 ) / ( sx - 1 );
335 dy = dy * (boundedSy - 1 ) / ( sy - 1 );
336
337 moveBy( dx , dy );
338
339 // mGuidoItem->scale( boundedSx , boundedSy );
340 mGuidoItem->setTransform(QTransform::fromScale(boundedSx, boundedSy), true);
341 guidoGeometryChanged();
342
343 Q_EMIT scaleChanged( mGuidoItem->transform().m11() );
344 }
345 mResizeMode = RESIZE_NORMAL;
346 if ( mResizer )
347 mResizer->setKeepAspectRatio(true);
348 }
349
350 //-------------------------------------------------------------------------
351 // Protected slots //
352 //-------------------------------------------------------------------------
353
354 //-------------------------------------------------------------------------
switchOptimalPageFill()355 void QGuidoItemContainer::switchOptimalPageFill()
356 {
357 setOptimalPageFill( !mIsOptimalPageFillOn );
358 }
359
360 //-------------------------------------------------------------------------
switchProportional()361 void QGuidoItemContainer::switchProportional()
362 {
363 setProportional( !mIsProportionalOn );
364 }
365
366 //-------------------------------------------------------------------------
switchResizePage()367 void QGuidoItemContainer::switchResizePage()
368 {
369 setResizePageToMusic( !mGuidoItem->isResizePageToMusicOn() );
370 }
371
372 //-------------------------------------------------------------------------
373 // Protected functions //
374 //-------------------------------------------------------------------------
375
376 /*
377 * This method is called in subclasses constructors.
378 *
379 * Why isn't it called direclty in QGuidoItemContainer constructor ?
380 * -> because subclasses build a specific QGuidoItem, accessed
381 * by the pure virtual QGuidoItemContainer::mGuidoItem,
382 * and used in QGuidoItemContainer::init().
383 * -> this design has pros (one initialisation code for the mGuidoItem)
384 * and cons (subclasses MUST call the baseclass's init function)
385 */
386 //-------------------------------------------------------------------------
init()387 void QGuidoItemContainer::init()
388 {
389 mGuidoItem = new QGuidoGraphicsItem( this );
390
391 #if !linux // bug in Qt 4.4 with the linux cache mode
392 mGuidoItem->setCacheMode( QGraphicsItem::DeviceCoordinateCache );
393 #endif
394
395 #ifdef USES_GUIDO_AR
396 mMidiRef = -1;
397 mPlayerState = STOPPED;
398
399 QLanguageItem::plug( new QPaletteItemDropper( PALETTE_GUIDO_ELEMENT , QList<int>() << PALETTE_GUIDO_ELEMENT , this , this ) );
400 #endif
401
402 connect( mGuidoItem , SIGNAL(geometryHasChanged()), this, SLOT(guidoGeometryChanged()) );
403
404 mIsProportionalOn = DEFAULT_PROPORTIONAL;
405 mIsOptimalPageFillOn = DEFAULT_OPTIMAL_PAGE_FILL;
406 mGuidoItem->setResizePageToMusic( DEFAULT_RESIZE_PAGE );
407
408 setMinMaxScale(0,0);
409
410 mHeadBar = new QTextPathItem( "" , true , TITLE_BAR_FONT_COLOR , TITLE_BAR_FONT , TITLE_BAR_FONT_PEN_WIDTH , this );
411 mHeadBar->setZValue( 1 );
412
413 mSelectionItem = new QGraphicsPathItem(this);
414 mSelectionItem->setZValue(-1);
415
416 setAcceptHoverEvents(true);
417
418 connect( this , SIGNAL(descriptiveNameChanged()) , this, SLOT(descriptiveNameHasChanged()) );
419
420 // Set pens & brushes
421 mPenBrushSwitcher.addFlag( SELECTION_FLAG_SELECTED , 2 , PenBrush(SELECTED_PEN , SELECTED_BRUSH ) );
422 mPenBrushSwitcher.addFlag( SELECTION_FLAG_HIGHLIGHTED , 1 , PenBrush(HIGHLIGHTED_PEN , HIGHLIGHTED_BRUSH ) );
423 mPenBrushSwitcher.addFlag( SELECTION_FLAG_IDLE , 0, PenBrush(STANDARD_PEN , STANDARD_BRUSH ) );
424 mPenBrushSwitcher.setFlag( SELECTION_FLAG_IDLE , true );
425 mPenBrushSwitcher.setSwitchedFlag(SELECTION_FLAG_IDLE, SELECTION_SWITCH_INVALID_CODE, PenBrush(INVALID_PEN, INVALID_STANDARD_BRUSH ) );
426 mPenBrushSwitcher.setSwitchedFlag(SELECTION_FLAG_HIGHLIGHTED, SELECTION_SWITCH_INVALID_CODE, PenBrush(INVALID_PEN, INVALID_HIGHLIGHTED_BRUSH ) );
427 mPenBrushSwitcher.setSwitchedFlag(SELECTION_FLAG_SELECTED, SELECTION_SWITCH_INVALID_CODE, PenBrush(INVALID_PEN, INVALID_BRUSH_SELECTED ) );
428
429 //Imported from QGuidoSPageItemContainer
430 mNextPageTurner = new QPageTurnerItem( true, QPolygonF() , this );
431 mPreviousPageTurner = new QPageTurnerItem( false, QPolygonF() , this );
432
433 mNextPageTurner->setZValue(4);
434 mPreviousPageTurner->setZValue(4);
435
436 mPageLabelItem = new QTextPathItem( "" , true , Qt::black , QFont(FONT_FAMILY , FONT_SIZE) , 1 , this );
437 mPageLabelItem->setZValue(2);
438
439 //Visibility controlled in updatePageItemsVisibility, only for non-storage items.
440 mPageLabelItem->setVisible( false );
441 mNextPageTurner->setVisible(false);
442 mPreviousPageTurner->setVisible(false);
443
444 //Set pen
445 QPen pen = QPen( Qt::black );
446 pen.setJoinStyle( Qt::RoundJoin );
447 pen.setWidth( ARROW_PEN_WIDTH );
448 mNextPageTurner->setBrush( SELECTED_BRUSH );
449 mPreviousPageTurner->setBrush( SELECTED_BRUSH );
450 mNextPageTurner->setPen( pen );
451 mPreviousPageTurner->setPen( pen );
452
453 mPageLabelItem->setPen( SELECTED_PEN );
454 mPageLabelItem->setBrush( SELECTED_BRUSH );
455 updatePageIndexLabel();
456
457 guidoUpdateGeometry( INVALID_RECT );
458
459 mResizeMode = RESIZE_NORMAL;
460 mResizer = 0;
461 }
462
463 //-------------------------------------------------------------------------
init(const QMimeData * mimeData)464 void QGuidoItemContainer::init(const QMimeData * mimeData)
465 {
466 init();
467 loadFromMimeData(mimeData);
468 }
469
470 //-------------------------------------------------------------------------
init(const QDomElement * domElement)471 void QGuidoItemContainer::init(const QDomElement * domElement)
472 {
473 init();
474 loadFromDomElement(domElement);
475 }
476
477 //-------------------------------------------------------------------------
init(const QGuidoItemContainer * other)478 void QGuidoItemContainer::init(const QGuidoItemContainer * other)
479 {
480 init();
481 loadFromOtherContainer(other);
482 }
483
484 //-------------------------------------------------------------------------
loadFromMimeData(const QMimeData * mimeData)485 void QGuidoItemContainer::loadFromMimeData( const QMimeData * mimeData )
486 {
487 load( mimeData );
488
489 if ( mimeData->hasFormat(GMN_CONTAINER_MIME_PROPORTIONAL_ON) )
490 mIsProportionalOn = mimeData->data( GMN_CONTAINER_MIME_PROPORTIONAL_ON ).toInt();
491 else
492 mIsProportionalOn = DEFAULT_PROPORTIONAL;
493
494 if ( mimeData->hasFormat(GMN_CONTAINER_MIME_OPTIMAL_PAGE_FILL_ON) )
495 mIsOptimalPageFillOn = mimeData->data( GMN_CONTAINER_MIME_OPTIMAL_PAGE_FILL_ON ).toInt();
496 else
497 mIsOptimalPageFillOn = DEFAULT_OPTIMAL_PAGE_FILL;
498
499 if ( mimeData->hasFormat(GMN_CONTAINER_MIME_RESIZE_PAGE_ON) )
500 setResizePageToMusic( mimeData->data( GMN_CONTAINER_MIME_RESIZE_PAGE_ON ).toInt() );
501 else
502 setResizePageToMusic( DEFAULT_RESIZE_PAGE );
503
504
505 if ( mimeData->hasFormat( GMN_CONTAINER_MIME_SCALE ) )
506 {
507 float scale = mimeData->data( GMN_CONTAINER_MIME_SCALE ).toDouble();
508 resize( scale , scale );
509 }
510
511 updateLayoutSettings();
512
513 mGuidoItem->setGridWidth( mimeData->data( GMN_CONTAINER_MIME_GRID_WIDTH ).toInt() );
514 mGuidoItem->setGridHeight( mimeData->data( GMN_CONTAINER_MIME_GRID_HEIGHT ).toInt() );
515 setCurrentPage( mimeData->data( GMN_CONTAINER_MIME_PAGE_INDEX ).toInt() );
516 }
517
518 //-------------------------------------------------------------------------
loadFromOtherContainer(const QGuidoItemContainer * otherContainer)519 void QGuidoItemContainer::loadFromOtherContainer( const QGuidoItemContainer * otherContainer )
520 {
521 setResizePageToMusic( otherContainer->mGuidoItem->isResizePageToMusicOn() );
522 load( otherContainer );
523 mIsOptimalPageFillOn = otherContainer->mIsOptimalPageFillOn;
524 mIsProportionalOn = otherContainer->mIsProportionalOn;
525
526 // mGuidoItem->scale( otherContainer->mGuidoItem->transform().m11() , otherContainer->mGuidoItem->transform().m22() );
527 mGuidoItem->setTransform(QTransform::fromScale(otherContainer->mGuidoItem->transform().m11(), otherContainer->mGuidoItem->transform().m22()), true);
528
529 updateLayoutSettings();
530 mGuidoItem->setGridWidth(otherContainer->mGuidoItem->gridWidth());
531 mGuidoItem->setGridHeight(otherContainer->mGuidoItem->gridHeight());
532 setCurrentPage( otherContainer->mGuidoItem->firstVisiblePage());
533 }
534
535 //-------------------------------------------------------------------------
loadFromDomElement(const QDomElement * e)536 void QGuidoItemContainer::loadFromDomElement( const QDomElement * e)
537 {
538 if ( e->tagName() != DOM_LANGUAGE_ITEM )
539 return;
540
541 mIsProportionalOn = QVariant( e->attribute( DOM_GUIDO_ITEM_PROPORTIONAL_LAYOUT, "#DEFAULT_PROPORTIONAL" ) ).toBool();
542 mIsOptimalPageFillOn = QVariant( e->attribute( DOM_GUIDO_ITEM_OPTIMAL_PAGE_FILL, "#DEFAULT_OPTIMAL_PAGE_FILL" ) ).toBool();
543 setResizePageToMusic( QVariant( e->attribute( DOM_GUIDO_ITEM_RESIZE_PAGE_ON, "#DEFAULT_RESIZE_PAGE" ) ).toBool() );
544
545 load( e );
546
547 float scale = QVariant( e->attribute( DOM_GUIDO_ITEM_SCALE, "1" ) ).toDouble();
548 resize( scale , scale );
549
550 updateLayoutSettings();
551
552 int currentPage = QVariant( e->attribute( DOM_GUIDO_ITEM_CURRENT_PAGE, "1" ) ).toInt();
553 int gridWidth = QVariant( e->attribute( DOM_GUIDO_ITEM_GRID_WIDTH, "1" ) ).toInt();
554 int gridHeight = QVariant( e->attribute( DOM_GUIDO_ITEM_GRID_HEIGHT, "1" ) ).toInt();
555 mGuidoItem->setGridWidth(gridWidth);
556 mGuidoItem->setGridHeight(gridHeight);
557 setCurrentPage( currentPage );
558 }
559
560 //-------------------------------------------------------------------------
buildContextMenu()561 QMenu * QGuidoItemContainer::buildContextMenu()
562 {
563 QMenu * menu = QLanguageItem::buildContextMenu();
564
565 QAction * exportAct = new QAction( "Export" , this );
566 connect( exportAct , SIGNAL( triggered() ) , this , SIGNAL( exportItem() ) );
567 menu->addAction( exportAct );
568
569 QMenu * layoutMenu = menu->addMenu( CONTEXT_MENU_LAYOUT );
570 layoutMenu->setObjectName( CONTEXT_MENU_LAYOUT );
571
572 //Layout actions :Proportional layout
573 QString layoutProportionalMsg = QString("Switch ") + ( mIsProportionalOn ? "OFF" : "ON" ) + " Proportionnal layout";
574 QAction * layoutProportionalSwitch = new QAction( layoutProportionalMsg , layoutMenu );
575 connect( layoutProportionalSwitch , SIGNAL(triggered()) , this , SLOT(switchProportional()) );
576 layoutMenu->addAction(layoutProportionalSwitch);
577
578 //Layout actions : Optimal page fill
579 QString layoutOptimalPageFillMsg = QString("Switch ") + ( mIsOptimalPageFillOn ? "OFF" : "ON" ) + " Optimal page fill";
580 QAction * layoutOptimalPageFillSwitch = new QAction( layoutOptimalPageFillMsg , layoutMenu );
581 connect( layoutOptimalPageFillSwitch , SIGNAL(triggered()) , this , SLOT(switchOptimalPageFill()) );
582 layoutMenu->addAction(layoutOptimalPageFillSwitch);
583
584 //Layout actions : Auto-resizePageToMusic
585 QString layoutResizePageMsg = QString("Switch ") + ( mGuidoItem->isResizePageToMusicOn() ? "OFF" : "ON" ) + " Auto Resize-Page";
586 QAction * layoutResizePageSwitch = new QAction( layoutResizePageMsg , layoutMenu );
587 connect( layoutResizePageSwitch , SIGNAL(triggered()) , this , SLOT(switchResizePage()) );
588 layoutMenu->addAction(layoutResizePageSwitch);
589
590 //"Change the current page" actions.
591 QAction * firstPage = new QAction( "First page" , this );
592 QAction * previousPage = new QAction( "Previous page" , this );
593 QAction * nextPage = new QAction( "Next page" , this );
594 QAction * lastPage = new QAction( "Last page" , this );
595
596 connect(firstPage , SIGNAL(triggered()) , this , SLOT(firstPage()) );
597 connect(previousPage , SIGNAL(triggered()) , this , SLOT(previousPage()) );
598 connect(nextPage , SIGNAL(triggered()) , this , SLOT(nextPage()) );
599 connect(lastPage , SIGNAL(triggered()) , this , SLOT(lastPage()) );
600
601 layoutMenu->addAction( newSeparator(this) );
602 layoutMenu->addAction(firstPage);
603 layoutMenu->addAction(previousPage);
604 layoutMenu->addAction(nextPage);
605 layoutMenu->addAction(lastPage);
606
607 /*
608 bool onceOnly = false;
609 for ( int i = 0 ; i < menu->actions().size() ; i++ )
610 {
611 if ( menu->actions()[i]->data().toString() == CONTEXT_MENU_LAYOUT )
612 {
613 if ( !onceOnly )
614 {
615 layoutMenu->addSeparator();
616 onceOnly = true;
617 }
618 // qDebug("QGuidoItemContainer::buildContextMenu() : action removed from menu and added to ");
619 layoutMenu->addAction( menu->actions()[i] );
620 menu->actions()[i]->setParent( layoutMenu );
621 menu->removeAction( menu->actions()[i] );
622 i--;
623 }
624 }
625 */
626
627 return menu;
628 }
629
630 //-------------------------------------------------------------------------
buildDragImage()631 QImage* QGuidoItemContainer::buildDragImage()
632 {
633 return new QImage( itemToImage( mSelectionItem , 1.0f , 0 , true ) );
634 }
635
636 //-------------------------------------------------------------------------
exportToPdf(QPrinter * printer)637 void QGuidoItemContainer::exportToPdf( QPrinter * printer )
638 {
639 int originalPage = mGuidoItem->firstVisiblePage();
640
641 mGuidoItem->setPage(1);
642 QRectF firstPageRect = guidoItem()->boundingRect();
643 printer->setPaperSize( QSizeF( firstPageRect.width() , firstPageRect.height() ) , QPrinter::Millimeter );
644
645 QPainter painter;
646 painter.begin( printer );
647
648 painter.setWindow( firstPageRect.toRect() );
649
650 int pCount = mGuidoItem->pageCount();
651 for ( int page = 1 ; page <= pCount ; page++ )
652 {
653 QRectF rect = guidoItem()->boundingRect();
654
655 QStyleOptionGraphicsItem option;
656 option.exposedRect = rect;
657 mGuidoItem->paint( &painter , &option , 0 );
658
659 if (page != pCount)
660 {
661 mGuidoItem->setPage(page+1);
662 rect = guidoItem()->boundingRect();
663
664 printer->newPage();
665 }
666 }
667 painter.end();
668
669 mGuidoItem->setPage( originalPage );
670 }
671
672 //-------------------------------------------------------------------------
updateLayoutSettings()673 void QGuidoItemContainer::updateLayoutSettings()
674 {
675 GuidoLayoutSettings settings = mGuidoItem->guidoLayoutSettings();
676
677 settings.optimalPageFill = ( mIsOptimalPageFillOn ) ? 1 : 0;
678 settings.force = ( mIsProportionalOn ) ? PROPORTIONAL_FORCE : NO_PROPORTIONAL_FORCE;
679 settings.spring = ( mIsProportionalOn ) ? PROPORTIONAL_SPRING : NO_PROPORTIONAL_SPRING;
680
681 mGuidoItem->setGuidoLayoutSettings( settings );
682 }
683
684 //-------------------------------------------------------------------------
setOptimalPageFill(bool isOptimalPageFillOn)685 void QGuidoItemContainer::setOptimalPageFill(bool isOptimalPageFillOn)
686 {
687 mIsOptimalPageFillOn = isOptimalPageFillOn;
688 updateLayoutSettings();
689 }
690
691 //-------------------------------------------------------------------------
setResizePageToMusic(bool isResizePageOn)692 void QGuidoItemContainer::setResizePageToMusic(bool isResizePageOn)
693 {
694 mGuidoItem->setResizePageToMusic(isResizePageOn);
695 }
696
697 //-------------------------------------------------------------------------
setProportional(bool isProportionalOn)698 void QGuidoItemContainer::setProportional(bool isProportionalOn)
699 {
700 mIsProportionalOn = isProportionalOn;
701 updateLayoutSettings();
702 }
703
704 //-------------------------------------------------------------------------
buildMimeData()705 QMimeData * QGuidoItemContainer::buildMimeData()
706 {
707 QMimeData * data = QLanguageItem::buildMimeData();
708 data->setData( GMN_CONTAINER_MIME_FLAG , 0 );
709 data->setData( GMN_CONTAINER_MIME_PROPORTIONAL_ON , QByteArray::number(mIsProportionalOn) );
710 data->setData( GMN_CONTAINER_MIME_OPTIMAL_PAGE_FILL_ON , QByteArray::number(mIsOptimalPageFillOn) );
711 data->setData( GMN_CONTAINER_MIME_RESIZE_PAGE_ON , QByteArray::number(mGuidoItem->isResizePageToMusicOn()) );
712 data->setData( GMN_CONTAINER_MIME_SCALE , QByteArray::number(mGuidoItem->transform().m11() ) );
713
714 data->setData( GMN_CONTAINER_MIME_PAGE_INDEX , QByteArray::number( mGuidoItem->firstVisiblePage()) );
715 data->setData( GMN_CONTAINER_MIME_GRID_WIDTH , QByteArray::number( mGuidoItem->gridWidth()) );
716 data->setData( GMN_CONTAINER_MIME_GRID_HEIGHT , QByteArray::number( mGuidoItem->gridHeight()) );
717 return data;
718 }
719
720 //-------------------------------------------------------------------------
updateTitleBarVisibility()721 void QGuidoItemContainer::updateTitleBarVisibility()
722 {
723 // mHeadBar->setVisible( ( mPenBrushSwitcher.isFlagOn( SELECTION_FLAG_HIGHLIGHTED ) || isSelected() ) && file().length() && ( mHeadBar->textItem()->boundingRect().height() < rect().height() ) );
724 mHeadBar->setVisible( false );
725 }
726
727 //-------------------------------------------------------------------------
updateTitleBar()728 void QGuidoItemContainer::updateTitleBar()
729 {
730 int barHeight = QFontMetrics( mHeadBar->textItem()->font() ).height();
731
732 QPainterPath path;
733 path.moveTo( 0 , barHeight );
734 path.arcTo( QRect(0,0,ROUNDED_RECT_RADIUS * 2 , ROUNDED_RECT_RADIUS * 2) , 180 , -90 );
735 path.lineTo( rect().width() - ROUNDED_RECT_RADIUS * 2 , 0 );
736 path.arcTo( QRect( path.currentPosition().x() , path.currentPosition().y() ,ROUNDED_RECT_RADIUS * 2 , ROUNDED_RECT_RADIUS * 2) , 90 , -90 );
737 path.lineTo( rect().width() , barHeight );
738 path.closeSubpath();
739
740 mHeadBar->setPath( path );
741
742 updateTitleText();
743 updateTitleBarVisibility();
744 }
745
746 //-------------------------------------------------------------------------
updateTitleText()747 void QGuidoItemContainer::updateTitleText()
748 {
749 if ( !file().length() )
750 return;
751
752 if ( !rect().isValid() )
753 return;
754
755 mHeadBar->setText( getDescriptiveFileName() );
756 }
757
758 //-------------------------------------------------------------------------
updateSyntaxErrorItem()759 void QGuidoItemContainer::updateSyntaxErrorItem()
760 {
761 /*
762 QPainterPath path;
763 path.addRoundedRect( rect() , mRoundedRectRadius , mRoundedRectRadius );
764 mSyntaxErrorItem->setPath( path );
765 */
766 }
767
768 //-------------------------------------------------------------------------
updateSelectionItem()769 void QGuidoItemContainer::updateSelectionItem()
770 {
771 mSelectionItem->setPen( mPenBrushSwitcher.activeObject().mPen );
772 mSelectionItem->setBrush( mPenBrushSwitcher.activeObject().mBrush );
773 mHeadBar->setPen( mPenBrushSwitcher.activeObject().mPen );
774 mHeadBar->setBrush( mPenBrushSwitcher.activeObject().mBrush );
775 }
776
777 //-------------------------------------------------------------------------
setFile(const QString & fileName)778 void QGuidoItemContainer::setFile(const QString& fileName)
779 {
780 QLanguageItem::setFile(fileName);
781 updateTitleText();
782 updateTitleBarVisibility();
783 }
784
785 //-------------------------------------------------------------------------
keyPressEvent(QKeyEvent * event)786 void QGuidoItemContainer::keyPressEvent ( QKeyEvent * event )
787 {
788 if ( mIsStorageModeOn )
789 return;
790
791 QLanguageItem::keyPressEvent( event );
792 int key = event->key();
793 if ( ( key == Qt::Key_PageUp )
794 || ( key == Qt::Key_PageDown )
795 )
796 {
797 int pageIncrement;
798 switch (key)
799 {
800 case Qt::Key_PageUp: pageIncrement = -1; break;
801 case Qt::Key_PageDown: pageIncrement = 1; break;
802 default: pageIncrement = 0; break;
803 }
804 if ( pageIncrement == 1 )
805 nextPage();
806 else
807 previousPage();
808
809 event->accept();
810 }
811 else if ( key == Qt::Key_G )
812 {
813 mResizeMode = RESIZE_GRID;
814 mResizer->setKeepAspectRatio(false);
815 event->accept();
816 }
817 else if ( key == Qt::Key_F )
818 {
819 mResizeMode = RESIZE_FORMAT;
820 mResizer->setKeepAspectRatio(false);
821 event->accept();
822 }
823 else
824 {
825 event->ignore();
826 }
827 }
828
829 //-------------------------------------------------------------------------
setResizer(QItemResizer * resizer)830 void QGuidoItemContainer::setResizer( QItemResizer* resizer )
831 {
832 mResizer = resizer;
833 updateResizerColor();
834 }
835
836 //-------------------------------------------------------------------------
updatePageItemsVisibility()837 void QGuidoItemContainer::updatePageItemsVisibility()
838 {
839 if ( mIsStorageModeOn )
840 return;
841
842 int firstVisiblePage = mGuidoItem->firstVisiblePage();
843 int lastVisiblePage = mGuidoItem->lastVisiblePage();
844 int pageCount = mGuidoItem->pageCount();
845 mNextPageTurner->setVisible ( mGuidoItem->isGMNValid() && isSelected() && ( pageCount > lastVisiblePage ) );
846 mPreviousPageTurner->setVisible ( mGuidoItem->isGMNValid() && isSelected() && ( firstVisiblePage > 1 ) );
847 mPageLabelItem->setVisible ( mGuidoItem->isGMNValid() && isSelected() && !((mGuidoItem->firstVisiblePage()==1) && (mGuidoItem->lastVisiblePage()==mGuidoItem->pageCount())) );
848 }
849
850 //-------------------------------------------------------------------------
updatePageIndexLabel()851 void QGuidoItemContainer::updatePageIndexLabel()
852 {
853 // qDebug() << "updatePageIndexLabel() : " << mGuidoItem->firstVisiblePage() << "-" << mGuidoItem->lastVisiblePage() << "/" << mGuidoItem->pageCount() ;
854
855 //Updates the page index item.
856 QString pageLabel;
857 if ( mGuidoItem->firstVisiblePage() != mGuidoItem->lastVisiblePage() )
858 QTextStream(&pageLabel) << mGuidoItem->firstVisiblePage() << "-" << mGuidoItem->lastVisiblePage() << "/" << mGuidoItem->pageCount() ;
859 else
860 QTextStream(&pageLabel) << mGuidoItem->firstVisiblePage() << "/" << mGuidoItem->pageCount() ;
861
862 QFontMetrics fontMetrics( mPageLabelItem->textItem()->font() );
863 QRect pageLabelRect = fontMetrics.boundingRect( pageLabel );
864 pageLabelRect.moveTo( rect().width() , rect().height() );
865 pageLabelRect.translate( -pageLabelRect.width() + PAGE_LABEL_RECT_OUT_WIDTH , -pageLabelRect.height() + PAGE_LABEL_RECT_OUT_HEIGHT );
866 pageLabelRect.translate(-5,-2);
867 pageLabelRect.setWidth( pageLabelRect.width() + 10 );
868 pageLabelRect.setHeight( pageLabelRect.height() + 4 );
869 QPainterPath pageLabelPath;
870 pageLabelPath.addRoundedRect( pageLabelRect , ROUNDED_RECT_RADIUS , ROUNDED_RECT_RADIUS );
871 if ( mPageLabelItem->path() != pageLabelPath )
872 mPageLabelItem->setPath( pageLabelPath );
873
874 mPageLabelItem->setText(pageLabel);
875 }
876
877 //-------------------------------------------------------------------------
updateResizerColor()878 void QGuidoItemContainer::updateResizerColor()
879 {
880 mResizer->setPen( isValid() ? SELECTED_PEN : INVALID_PEN );
881 mResizer->setBrush( isValid() ? HIGHLIGHTED_BRUSH : INVALID_STANDARD_BRUSH );
882 }
883
884 //-------------------------------------------------------------------------
setCurrentPage(int page)885 void QGuidoItemContainer::setCurrentPage(int page)
886 {
887 mGuidoItem->setPage(page);
888
889 guidoGeometryChanged();
890 }
891
892 //-------------------------------------------------------------------------
firstPage()893 void QGuidoItemContainer::firstPage()
894 {
895 if ( mGuidoItem->firstVisiblePage()!= 1 )
896 setCurrentPage(1);
897 }
898
899 //-------------------------------------------------------------------------
previousPage()900 void QGuidoItemContainer::previousPage()
901 {
902 int currentPage = mGuidoItem->firstVisiblePage();
903 if ( currentPage - 1 >= 1 )
904 setCurrentPage( currentPage - 1 );
905 }
906
907 //-------------------------------------------------------------------------
nextPage()908 void QGuidoItemContainer::nextPage()
909 {
910 int currentPage = mGuidoItem->firstVisiblePage();
911 if ( currentPage + 1 <= mGuidoItem->pageCount() )
912 setCurrentPage( currentPage + 1 );
913 }
914
915 //-------------------------------------------------------------------------
lastPage()916 void QGuidoItemContainer::lastPage()
917 {
918 int currentPage = mGuidoItem->firstVisiblePage();
919 int pageCount = mGuidoItem->pageCount();
920 if ( currentPage != pageCount )
921 setCurrentPage( pageCount );
922 }
923
924 //-------------------------------------------------------------------------
getRightArrowPolygon(const QRectF & boundingRect)925 QPolygonF getRightArrowPolygon(const QRectF& boundingRect)
926 {
927 QVector<QPointF> rightPoints;
928 rightPoints << QPointF(0,0) << QPointF(-PAGE_TURNER_ARROW_SIZE,-PAGE_TURNER_ARROW_SIZE) << QPointF(-PAGE_TURNER_ARROW_SIZE,PAGE_TURNER_ARROW_SIZE);
929 QPolygonF rightPolygon( rightPoints );
930 rightPolygon.translate( boundingRect.width() + PAGE_TURNER_ARROW_SIZE/2 , boundingRect.height() / 2 );
931 return rightPolygon;
932 }
933
934 //-------------------------------------------------------------------------
getLeftArrowPolygon(const QRectF & boundingRect)935 QPolygonF getLeftArrowPolygon(const QRectF& boundingRect)
936 {
937 QVector<QPointF> leftPoints;
938 leftPoints << QPointF(0,0) << QPointF(PAGE_TURNER_ARROW_SIZE,-PAGE_TURNER_ARROW_SIZE) << QPointF(PAGE_TURNER_ARROW_SIZE,PAGE_TURNER_ARROW_SIZE);
939 QPolygonF leftPolygon( leftPoints );
940 leftPolygon.translate( 0 - PAGE_TURNER_ARROW_SIZE/2, boundingRect.height() / 2 );
941 return leftPolygon;
942 }
943
944 //-------------------------------------------------------------------------
itemChange(GraphicsItemChange change,const QVariant & value)945 QVariant QGuidoItemContainer::itemChange( GraphicsItemChange change, const QVariant& value )
946 {
947 QVariant standardResult = QLanguageItem::itemChange( change , value );
948
949 if ( change == QGraphicsItem::ItemSelectedHasChanged )
950 {
951 updateTitleBarVisibility();
952 mPenBrushSwitcher.setFlag( SELECTION_FLAG_SELECTED , value.toBool() );
953 updateSelectionItem();
954 updatePageItemsVisibility();
955 }
956 return standardResult;
957 }
958
959 //-------------------------------------------------------------------------
hoverEnterEvent(QGraphicsSceneHoverEvent * e)960 void QGuidoItemContainer::hoverEnterEvent ( QGraphicsSceneHoverEvent * e )
961 {
962 QLanguageItem::hoverEnterEvent(e);
963
964 mPenBrushSwitcher.setFlag( SELECTION_FLAG_HIGHLIGHTED , true );
965 updateSelectionItem();
966
967 updateTitleBarVisibility();
968 }
969
970 //-------------------------------------------------------------------------
hoverLeaveEvent(QGraphicsSceneHoverEvent * e)971 void QGuidoItemContainer::hoverLeaveEvent ( QGraphicsSceneHoverEvent * e )
972 {
973 QLanguageItem::hoverLeaveEvent(e);
974
975 mPenBrushSwitcher.setFlag( SELECTION_FLAG_HIGHLIGHTED , false );
976 updateSelectionItem();
977 updateTitleBarVisibility();
978 }
979
980 /*
981 * The mGuidoItem geometry has changed, for various reasons (codeChanged, layout, pages alignment, ...)
982 * so the QGuidoItemContainer compute its new size (for now, uses the new size of mGuidoItem)
983 * and call updateGeometry(QRect) with it.
984 *
985 * This method doesn't exists in QLanguageItem.
986 */
987 //-------------------------------------------------------------------------
guidoGeometryChanged()988 void QGuidoItemContainer::guidoGeometryChanged()
989 {
990 // if ( isValid() )
991 // {
992 QRectF itemRect = mGuidoItem->boundingRect();
993 if ( ( itemRect.width() <= 0 ) || ( itemRect.height() <= 0 ) )
994 itemRect = INVALID_RECT;
995
996 QRectF newGeometry = mapFromItem( mGuidoItem , itemRect ).boundingRect();
997 if ( newGeometry != rect() )
998 {
999 guidoUpdateGeometry(newGeometry);
1000 }
1001 //Updates page-turn arrows visibility
1002 updatePageItemsVisibility();
1003
1004 //Updates page label
1005 updatePageIndexLabel();
1006 // }
1007 }
1008
1009 //-------------------------------------------------------------------------
guidoUpdateGeometry(const QRectF & newGeometry)1010 void QGuidoItemContainer::guidoUpdateGeometry(const QRectF& newGeometry)
1011 {
1012 QLanguageItem::updateGeometry( newGeometry );
1013
1014 QPainterPath p;
1015 p.addRoundedRect( newGeometry , ROUNDED_RECT_RADIUS , ROUNDED_RECT_RADIUS );
1016 mSelectionItem->setPath(p);
1017
1018 updateTitleBar();
1019 updateSyntaxErrorItem();
1020
1021 //Updates page-turn arrows positions
1022 mNextPageTurner->setPolygon( getRightArrowPolygon(newGeometry) );
1023 mPreviousPageTurner->setPolygon( getLeftArrowPolygon(newGeometry) );
1024 }
1025
1026 //-------------------------------------------------------------------------
resize(float xScale,float yScale)1027 void QGuidoItemContainer::resize( float xScale , float yScale )
1028 {
1029 resized( QRectF( 0, 0, xScale * rect().width() , yScale * rect().height()) );
1030 }
1031
1032 //------------------------------------------------------------------------
1033 // Guido AR section (palette stuff, guido2midi) //
1034 //------------------------------------------------------------------------
1035
1036 #ifdef USES_GUIDO_AR
1037
1038 //-------------------------------------------------------------------------
play()1039 void QGuidoItemContainer::play()
1040 {
1041
1042 if ( mMidiRef == -1 )
1043 {
1044 stop();
1045 mMidiRef = QGuidoAR::getMidiRef(mGuidoItem->gmnCode());
1046 }
1047
1048 if ( mPlayerState == PAUSED )
1049 QGuidoAR::midiResume(mMidiRef);
1050 else
1051 QGuidoAR::midiPlay(mMidiRef);
1052
1053 mPlayerState = PLAYING;
1054
1055 }
1056
1057 //-------------------------------------------------------------------------
pause()1058 void QGuidoItemContainer::pause()
1059 {
1060
1061 if ( mMidiRef != -1 )
1062 {
1063 QGuidoAR::midiPause(mMidiRef);
1064 mPlayerState = PAUSED;
1065 }
1066
1067 }
1068
1069 //-------------------------------------------------------------------------
stop()1070 void QGuidoItemContainer::stop()
1071 {
1072
1073 if ( mMidiRef != -1 )
1074 {
1075 QGuidoAR::midiStop(mMidiRef);
1076 mPlayerState = STOPPED;
1077 mMidiRef = -1;
1078 }
1079
1080 }
1081
1082 #endif
1083