1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
|
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rosegarden
A MIDI and audio sequencer and musical notation editor.
This program is Copyright 2000-2008
Guillaume Laurent <glaurent@telegraph-road.org>,
Chris Cannam <cannam@all-day-breakfast.com>,
Richard Bown <richard.bown@ferventsoftware.com>
The moral rights of Guillaume Laurent, Chris Cannam, and Richard
Bown to claim authorship of this work have been asserted.
Other copyrights also apply to some parts of this work. Please
see the AUTHORS file and individual file headers for details.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version. See the file
COPYING included with this distribution for more information.
*/
#ifndef _RG_LINEDSTAFF_H_
#define _RG_LINEDSTAFF_H_
#include "base/Event.h"
#include "base/FastVector.h"
#include "base/Staff.h"
#include "base/ViewElement.h"
#include <tqrect.h>
#include <utility>
#include <vector>
class TQCanvasLine;
class TQCanvasItem;
class TQCanvas;
class isFirstBarInRow;
class barNo;
namespace Rosegarden
{
class BarLine;
class TimeSignature;
class SnapGrid;
class Segment;
class HorizontalLayoutEngine;
class Event;
/**
* LinedStaff is a base class for implementations of Staff that
* display the contents of a Segment on a set of horizontal lines
* with optional vertical bar lines.
* Likely subclasses include the notation and piano-roll staffs.
*
* In general, this class handles x coordinates in floating-point,
* but y-coordinates as integers because of the requirement that
* staff lines be a precise integral distance apart.
*/
class LinedStaff : public Staff
{
public:
typedef std::pair<double, int> LinedStaffCoords;
enum PageMode {
LinearMode = 0,
ContinuousPageMode,
MultiPageMode
};
enum BarStyle {
PlainBar = 0,
DoubleBar,
HeavyDoubleBar,
RepeatEndBar,
RepeatStartBar,
RepeatBothBar,
NoVisibleBar
};
protected:
/**
* Create a new LinedStaff for the given Segment, with a
* linear layout.
*
* \a id is an arbitrary id for the staff in its view,
* not used within the LinedStaff implementation but
* queryable via getId
*
* \a resolution is the number of blank pixels between
* staff lines
*
* \a lineThickness is the number of pixels thick a
* staff line should be
*/
LinedStaff(TQCanvas *, Segment *, SnapGrid *,
int id, int resolution, int lineThickness);
/**
* Create a new LinedStaff for the given Segment, with a
* page layout.
*
* \a id is an arbitrary id for the staff in its view,
* not used within the LinedStaff implementation but
* queryable via getId
*
* \a resolution is the number of blank pixels between
* staff lines
*
* \a lineThickness is the number of pixels thick a
* staff line should be
*
* \a pageWidth is the width of a page, to determine
* when to break lines for page layout
*
* \a rowsPerPage is the number of rows to a page, or zero
* for a single continuous page
*
* \a rowSpacing is the distance in pixels between
* the tops of consecutive rows on this staff
*/
LinedStaff(TQCanvas *, Segment *, SnapGrid *,
int id, int resolution, int lineThickness,
double pageWidth, int rowsPerPage, int rowSpacing);
/**
* Create a new LinedStaff for the given Segment, with
* either page or linear layout.
*/
LinedStaff(TQCanvas *, Segment *, SnapGrid *,
int id, int resolution, int lineThickness, PageMode pageMode,
double pageWidth, int rowsPerPage, int rowSpacing);
public:
virtual ~LinedStaff();
protected:
// Methods required to define the type of staff this is
/**
* Returns the number of visible staff lines
*/
virtual int getLineCount() const = 0;
/**
* Returns the number of invisible staff lines
* to leave space for above (and below) the visible staff
*/
virtual int getLegerLineCount() const = 0;
/**
* Returns the height-on-staff value for
* the bottom visible staff line (a shorthand means for
* referring to staff lines)
*/
virtual int getBottomLineHeight() const = 0;
/**
* Returns the difference between the height-on-
* staff value of one visible staff line and the next one
* above it
*/
virtual int getHeightPerLine() const = 0;
/**
* Returns the height-on-staff value for the top visible
* staff line. This is deliberately not virtual.
*/
int getTopLineHeight() const {
return getBottomLineHeight() +
(getLineCount() - 1) * getHeightPerLine();
}
/**
* Returns true if elements fill the spaces between lines,
* false if elements can fall on lines. If true, the lines
* will be displaced vertically by half a line spacing.
*/
virtual bool elementsInSpaces() const {
return false;
}
/**
* Returns true if the staff should draw a faint vertical line at
* each beat, in between the (darker) bar lines.
*/
virtual bool showBeatLines() const {
return false;
}
/**
* Returns the number of bars between bar-line numbers, or zero if
* bar lines should not be numbered. For example, if this
* function returns 5, every 5th bar (starting at bar 5) will be
* numbered.
*/
virtual int showBarNumbersEvery() const {
return 0;
}
/**
* Returns the bar line / repeat style for the start of the given bar.
*/
virtual BarStyle getBarStyle(int /* barNo */) const {
return PlainBar;
}
/**
* Returns the distance the opening (repeat) bar is inset from the
* nominal barline position. This is to accommodate the situation
* where a repeat bar has to appear after the clef and key.
*/
virtual double getBarInset(int /* barNo */, bool /* isFirstBarInRow */) const {
return 0;
}
protected:
/// Subclass may wish to expose this
virtual void setResolution(int resolution);
/// Subclass may wish to expose this
virtual void setLineThickness(int lineThickness);
/// Subclass may wish to expose this
virtual void setPageMode(PageMode pageMode);
/// Subclass may wish to expose this
virtual void setPageWidth(double pageWidth);
/// Subclass may wish to expose this
virtual void setRowsPerPage(int rowsPerPage);
/// Subclass may wish to expose this
virtual void setRowSpacing(int rowSpacing);
/// Subclass may wish to expose this. Default is zero
virtual void setConnectingLineLength(int length);
public:
/**
* Return the id of the staff. This is only useful to external
* agents, it isn't used by the LinedStaff itself.
*/
virtual int getId() const;
/**
* Set the canvas x-coordinate of the left-hand end of the staff.
* This does not move any canvas items that have already been
* created; it should be called before the sizeStaff/positionElements
* procedure begins.
*/
virtual void setX(double x);
/**
* Get the canvas x-coordinate of the left-hand end of the staff.
*/
virtual double getX() const;
/**
* Set the canvas y-coordinate of the top of the first staff row.
* This does not move any canvas items that have already been
* created; it should be called before the sizeStaff/positionElements
* procedure begins.
*/
virtual void setY(int y);
/**
* Get the canvas y-coordinate of the top of the first staff row.
*/
virtual int getY() const;
/**
* Set the canvas width of the margin to left and right of the
* staff on each page (used only in MultiPageMode). Each staff
* row will still be pageWidth wide (that is, the margin is in
* addition to the pageWidth, not included in it). This does not
* move any canvas items that have already been created; it should
* be called before the sizeStaff/positionElements procedure
* begins.
*/
virtual void setMargin(double m);
/**
* Get the canvas width of the left and right margins.
*/
virtual double getMargin() const;
/**
* Set the canvas height of the area at the top of the first page
* reserved for the composition title and composer's name (used
* only in MultiPageMode).
*/
virtual void setTitleHeight(int h);
/**
* Get the canvas height of the title area.
*/
virtual int getTitleHeight() const;
/**
* Returns the width of the entire staff after layout. Call
* this only after you've done the full sizeStaff/positionElements
* procedure.
*/
virtual double getTotalWidth() const;
/**
* Returns the height of the entire staff after layout. Call
* this only after you've done the full sizeStaff/positionElements
* procedure. If there are multiple rows, this will be the
* height of all rows, including any space between rows that
* is used to display other staffs.
*/
virtual int getTotalHeight() const;
/**
* Returns the total number of pages used by the staff.
*/
int getPageCount() const {
if (m_pageMode != MultiPageMode) return 1;
else return 1 + (getRowForLayoutX(m_endLayoutX) / getRowsPerPage());
}
/**
* Returns the difference between the y coordinates of
* neighbouring visible staff lines. Deliberately non-virtual
*/
int getLineSpacing() const {
return m_resolution + m_lineThickness;
}
/**
* Returns the total height of a single staff row, including ruler
*/
virtual int getHeightOfRow() const;
/**
* Returns true if the given canvas coordinates fall within
* (any of the rows of) this staff. False if they fall in the
* gap between two rows.
*/
virtual bool containsCanvasCoords(double canvasX, int canvasY) const;
/**
* Returns the canvas y coordinate of the specified line on the
* staff. baseX/baseY are a canvas coordinates somewhere on the
* correct row, or -1 for the default row.
*/
virtual int getCanvasYForHeight(int height, double baseX = -1, int baseY = -1) const;
/**
* Returns the y coordinate of the specified line on the
* staff, relative to the top of the row.
*/
virtual int getLayoutYForHeight(int height) const;
/**
* Returns the height-on-staff value nearest to the given
* canvas coordinates.
*/
virtual int getHeightAtCanvasCoords(double x, int y) const;
/**
* Return the full width, height and origin of the bar containing
* the given canvas cooordinates.
*/
virtual TQRect getBarExtents(double x, int y) const;
/**
* Set whether this is the current staff or not. A staff that is
* current will differ visually from non-current staffs.
*
* The owner of the staffs should normally ensure that one staff
* is current (the default is non-current, even if there only is
* one staff) and that only one staff is current at once.
*/
virtual void setCurrent(bool current);
/**
* Move the playback pointer to the layout-X coordinate
* corresponding to the given time, and show it.
*/
virtual void setPointerPosition
(HorizontalLayoutEngine&, timeT);
/**
* Move the playback pointer to the layout-X coordinate
* corresponding to the given canvas coordinates, and show it.
*/
virtual void setPointerPosition(double x, int y);
/**
* Move the playback pointer to the given layout-X
* coordinate, and show it.
*/
virtual void setPointerPosition(double x);
/**
* Returns the layout-X coordinate corresponding to the current
* position of the playback pointer.
*/
virtual double getLayoutXOfPointer() const;
/**
* Returns the canvas coordinates of the top of the playback
* pointer.
*/
virtual void getPointerPosition(double &x, int &y) const;
/**
* Hide the playback pointer.
*/
virtual void hidePointer();
/**
* Move the insertion cursor to the layout-X coordinate
* corresponding to the given time, and show it.
*/
virtual void setInsertCursorPosition(HorizontalLayoutEngine&, timeT);
/**
* Move the insertion cursor to the layout-X coordinate
* corresponding to the given canvas coordinates, and show it.
*/
virtual void setInsertCursorPosition(double x, int y);
/**
* Returns the layout-X coordinate corresponding to the current
* position of the insertion cursor. Returns -1 if this staff
* is not current or there is some other problem.
*/
virtual double getLayoutXOfInsertCursor() const;
/**
* Return the time of the insert cursor.
*/
virtual timeT getInsertCursorTime(HorizontalLayoutEngine&) const;
/**
* Return the canvas coordinates of the top of the insert
* cursor.
*/
virtual void getInsertCursorPosition(double &x, int &y) const;
/**
* Hide the insert cursor.
*/
virtual void hideInsertCursor();
/**
* Query the given horizontal layout object (which is assumed to
* have just completed its layout procedure) to determine the
* required extents of the staff and the positions of the bars,
* and create the bars and staff lines accordingly. It may be
* called either before or after renderElements and/or
* positionElements.
*
* No bars or staff lines will appear unless this method has
* been called.
*/
virtual void sizeStaff(HorizontalLayoutEngine& layout);
/**
* Generate or re-generate sprites for all the elements between
* from and to. See subclasses for specific detailed comments.
*
* A very simplistic staff subclass may choose not to
* implement this (the default implementation is empty) and to
* do all the rendering work in positionElements. If rendering
* elements is slow, however, it makes sense to do it here
* because this method may be called less often.
*/
virtual void renderElements(ViewElementList::iterator from,
ViewElementList::iterator to);
/**
* Call renderElements(from, to) on the whole staff.
*/
virtual void renderAllElements();
/**
* Assign suitable coordinates to the elements on the staff
* between the start and end times, based entirely on the layout
* X and Y coordinates they were given by the horizontal and
* vertical layout processes.
*
* The implementation is free to render any elements it
* chooses in this method as well.
*/
virtual void positionElements(timeT from,
timeT to) = 0;
/**
* Call positionElements(from, to) on the whole staff.
*/
virtual void positionAllElements();
/* Some optional methods for the subclass. */
/**
* Return an iterator pointing to the nearest view element to the
* given canvas coordinates.
*
* If notesAndRestsOnly is true, do not return any view element
* other than a note or rest.
*
* If the closest view element is further away than
* proximityThreshold pixels in either x or y axis, return end().
* If proximityThreshold is less than zero, treat it as infinite.
*
* Also return the clef and key in force at these coordinates.
*
* The default implementation should suit for subclasses that only
* show a single element per layout X coordinate.
*/
virtual ViewElementList::iterator getClosestElementToCanvasCoords
(double x, int y,
Event *&clef, Event *&key,
bool notesAndRestsOnly = false, int proximityThreshold = 10) {
LinedStaffCoords layoutCoords = getLayoutCoordsForCanvasCoords(x, y);
return getClosestElementToLayoutX
(layoutCoords.first, clef, key,
notesAndRestsOnly, proximityThreshold);
}
/**
* Return an iterator pointing to the nearest view element to the
* given layout x-coordinate.
*
* If notesAndRestsOnly is true, do not return any view element
* other than a note or rest.
*
* If the closest view element is further away than
* proximityThreshold pixels in either x or y axis, return end().
* If proximityThreshold is less than zero, treat it as infinite.
*
* Also return the clef and key in force at these coordinates.
*
* The subclass may decide whether to implement this method or not
* based on the semantics and intended usage of the class.
*/
virtual ViewElementList::iterator getClosestElementToLayoutX
(double x,
Event *&clef, Event *&key,
bool notesAndRestsOnly = false, int proximityThreshold = 10) {
return getViewElementList()->end();
}
/**
* Return an iterator pointing to the element "under" the given
* canvas coordinates.
*
* Return end() if there is no such element.
*
* Also return the clef and key in force at these coordinates.
*
*
* The default implementation should suit for subclasses that only
* show a single element per layout X coordinate.
*/
virtual ViewElementList::iterator getElementUnderCanvasCoords
(double x, int y, Event *&clef, Event *&key) {
LinedStaffCoords layoutCoords = getLayoutCoordsForCanvasCoords(x, y);
return getElementUnderLayoutX(layoutCoords.first, clef, key);
}
/**
* Return an iterator pointing to the element "under" the given
* canvas coordinates.
*
* Return end() if there is no such element.
*
* Also return the clef and key in force at these coordinates.
*
* The subclass may decide whether to implement this method or not
* based on the semantics and intended usage of the class.
*/
virtual ViewElementList::iterator getElementUnderLayoutX
(double x, Event *&clef, Event *&key) {
return getViewElementList()->end();
}
// The default implementation of the following is empty. The
// subclass is presumed to know what the staff's name is and
// where to put it; this is simply called at some point during
// the staff-drawing process.
virtual void drawStaffName();
public:
// This should not really be public -- it should be one of the
// protected methods below -- but we have some code that needs
// it and hasn't been supplied with a proper way to do without.
// Please try to avoid calling this method.
//!!! fix NotationView::doDeferredCursorMove
// This should not really be public -- it should be one of the
// protected methods below -- but we have some code that needs
// it and hasn't been supplied with a proper way to do without.
// Please try to avoid calling this method.
//!!! fix NotationView::getStaffForCanvasCoords
LinedStaffCoords
getLayoutCoordsForCanvasCoords(double x, int y) const;
// This should not really be public -- it should be one of the
// protected methods below -- but we have some code that needs
// it and hasn't been supplied with a proper way to do without.
// Please try to avoid calling this method.
//!!! fix NotationView::scrollToTime
LinedStaffCoords
getCanvasCoordsForLayoutCoords(double x, int y) const;//!!!
// This should not really be public -- it should be one of the
// protected methods below -- but we have some code that needs
// it and hasn't been supplied with a proper way to do without.
// Please try to avoid calling this method.
//!!! fix NotationView::print etc
int getRowSpacing() { return m_rowSpacing; }
protected:
// Methods that the subclass may (indeed, should) use to convert
// between the layout coordinates of elements and their canvas
// coordinates. These are deliberately not virtual.
// Note that even linear-layout staffs have multiple rows; their
// rows all have the same y coordinate but increasing x
// coordinates, instead of the other way around. (The only reason
// for this is that it seems to be more efficient from the TQCanvas
// perspective to create and manipulate many relatively short
// canvas lines rather than a smaller number of very long ones.)
int getTopLineOffset() const {
return getLineSpacing() * getLegerLineCount();
}
int getBarLineHeight() const {
return getLineSpacing() * (getLineCount() - 1) + m_lineThickness;
}
int getRowForLayoutX(double x) const {
return (int)(x / m_pageWidth);
}
int getRowForCanvasCoords(double x, int y) const;
int getCanvasYForTopOfStaff(int row = -1) const;
int getCanvasYForTopLine(int row = -1) const {
return getCanvasYForTopOfStaff(row) + getTopLineOffset();
}
double getCanvasXForLeftOfRow(int row) const;
double getCanvasXForRightOfRow(int row) const {
return getCanvasXForLeftOfRow(row) + m_pageWidth;
}
LinedStaffCoords
getCanvasOffsetsForLayoutCoords(double x, int y) const {
LinedStaffCoords cc = getCanvasCoordsForLayoutCoords(x, y);
return LinedStaffCoords(cc.first - x, cc.second - y);
}
double getCanvasXForLayoutX(double x) const;
int getRowsPerPage() const {
return m_rowsPerPage;
}
protected:
// Actual implementation methods. The default implementation
// shows staff lines, connecting lines (where appropriate) and bar
// lines, but does not show time signatures. To see time
// signatures, override the deleteTimeSignatures and
// insertTimeSignature methods. For repeated clefs and keys at
// the start of each row, override deleteRepeatedClefsAndKeys
// and insertRepeatedClefAndKey, but note that your layout class
// will need to allot the space for them separately.
virtual void resizeStaffLines();
virtual void clearStaffLineRow(int row);
virtual void resizeStaffLineRow(int row, double offset, double length);
virtual void deleteBars();
virtual void insertBar(double layoutX, double width, bool isCorrect,
const TimeSignature &,
int barNo, bool showBarNo);
// The default implementations of the following two are empty.
virtual void deleteTimeSignatures();
virtual void insertTimeSignature(double layoutX,
const TimeSignature &);
// The default implementations of the following two are empty.
virtual void deleteRepeatedClefsAndKeys();
virtual void insertRepeatedClefAndKey(double layoutX, int barNo);
void initCursors();
protected:
//--------------- Data members ---------------------------------
TQCanvas *m_canvas;
SnapGrid *m_snapGrid;
int m_id;
double m_x;
int m_y;
double m_margin;
int m_titleHeight;
int m_resolution;
int m_lineThickness;
PageMode m_pageMode;
double m_pageWidth;
int m_rowsPerPage;
int m_rowSpacing;
int m_connectingLineLength;
double m_startLayoutX;
double m_endLayoutX;
bool m_current;
typedef std::vector<TQCanvasItem *> ItemList;
typedef std::vector<ItemList> ItemMatrix;
ItemMatrix m_staffLines;
ItemList m_staffConnectingLines;
typedef std::pair<double, TQCanvasItem *> LineRec; // layout-x, line
typedef FastVector<LineRec> LineRecList;
typedef FastVector<BarLine *> BarLineList;//!!! should be multiset I reckon
static bool compareBars(const BarLine *, const BarLine *);
static bool compareBarToLayoutX(const BarLine *, int);
BarLineList m_barLines;
LineRecList m_beatLines;
LineRecList m_barConnectingLines;
ItemList m_barNumbers;
TQCanvasLine *m_pointer;
TQCanvasLine *m_insertCursor;
timeT m_insertCursorTime;
bool m_insertCursorTimeValid;
};
}
#endif
|