13
13
// You should have received a copy of the GNU General Public License along
14
14
// with Lomse; if not, see <http://www.gnu.org/licenses/>.
16
16
// For any comment, suggestion or feature request, please contact the manager of
17
17
// the project at cecilios@users.sourceforge.net
19
//-------------------------------------------------------------------------------------
19
//---------------------------------------------------------------------------------------
21
21
#include "lomse_score_layouter.h"
23
23
#include "lomse_basic_model.h"
24
#include "lomse_calligrapher.h"
24
25
#include "lomse_gm_basic.h"
27
//#include "lomse_internal_model.h"
28
//#include "lomse_im_note.h"
26
#include "lomse_internal_model.h"
27
#include "lomse_box_system.h"
28
#include "lomse_box_slice.h"
29
#include "lomse_box_slice_instr.h"
30
#include "lomse_shape_staff.h"
31
#include "lomse_instrument_engraver.h"
32
#include "lomse_system_layouter.h"
33
#include "lomse_clef_engraver.h"
34
//-------------------------------------------------------------------------------------
39
//---------------------------------------------------------------------------------------
35
40
// ScoreLayouter implementation
36
//-------------------------------------------------------------------------------------
41
//---------------------------------------------------------------------------------------
38
ScoreLayouter::ScoreLayouter(ImoDocObj* pImo)
39
: ContentLayouter(pImo)
43
ScoreLayouter::ScoreLayouter(ImoDocObj* pImo, GraphicModel* pGModel, TextMeter* pMeter)
44
: ContentLayouter(pImo, pGModel)
45
, m_pTextMeter(pMeter)
46
, m_scoreIt( get_imo_score()->get_staffobjs_table() )
47
// , m_pSysCursor((SystemCursor*)NULL)
50
, m_pCurBoxSystem(NULL)
54
//---------------------------------------------------------------------------------------
43
55
ScoreLayouter::~ScoreLayouter()
47
void ScoreLayouter::do_layout(GmoBox* pContainerBox)
52
void ScoreLayouter::initializations()
54
//m_pGModel = new GraphicModel();
57
//delete_system_cursor();
58
delete_instrument_layouters();
59
delete_system_layouters();
62
//---------------------------------------------------------------------------------------
63
ImoScore* ScoreLayouter::get_imo_score()
65
return dynamic_cast<ImoScore*>(m_pImo);
68
//---------------------------------------------------------------------------------------
69
void ScoreLayouter::prepare_to_start_layout()
71
ContentLayouter::prepare_to_start_layout();
73
create_stub_for_score();
74
create_instrument_engravers();
56
75
// GetScoreRenderizationOptions();
57
76
// PrepareFontsThatMatchesStavesSizes();
58
// DecideSystemsIndentation();
77
decide_systems_indentation();
59
78
// DecideSpaceBeforeProlog();
60
// CreateSystemCursor();
62
//m_nCurrentPageNumber = 0;
64
// m_uLastSystemHeight = 0.0f;
67
// m_pBoxScore = new lmBoxScore(m_pScore);
70
//lmBoxScore* ScoreLayouter::LayoutScore(lmScore* pScore)
72
// //Build the graphical model for a score justifying measures, so that they fit exactly
74
// //This method encapsulates the line breaking algorithm and the spacing algorithm.
75
// //Page filling is not yet implemented.
76
// //This method is only invoked from lmGraphicManager::Layout()
79
// //pScore->Dump(_T("dump.txt"));
87
// //Each loop cycle computes and justifies one system
89
// //Form and add columns until no more space in current system
90
// bool fFirstSystemInPage = AddNewPageIfRequired();
91
// CreateSystemBox(fFirstSystemInPage);
92
// bool fThisIsLastSystem = FillCurrentSystemWithColumns();
94
// //Justify system (distribute space across all columns)
95
// ComputeMeasuresSizesToJustifyCurrentSystem(fThisIsLastSystem);
96
// RepositionStaffObjs();
98
// //Final details for this system
99
// SetCurrentSystemLenght(fThisIsLastSystem);
100
// AddInitialLineJoiningAllStavesInSystem();
101
// UpdateBoxSlicesSizes();
102
// GetSystemHeightAndAdvancePaperCursor();
104
// } while (m_pSysCursor->ThereAreObjects());
107
// if (RequestedToFillScoreWithEmptyStaves())
108
// FillPageWithEmptyStaves();
110
// m_pBoxScore->PopulateLayers(); //reorganize shapes in layers for renderization
112
// return m_pBoxScore;
80
m_nCurrentPageNumber = 0;
82
m_uLastSystemHeight = 0.0f;
86
//---------------------------------------------------------------------------------------
87
void ScoreLayouter::create_stub_for_score()
89
m_pStubScore = new GmoStubScore( get_imo_score() );
90
m_pGModel->add_stub(m_pStubScore);
93
//---------------------------------------------------------------------------------------
94
void ScoreLayouter::create_instrument_engravers()
96
ImoScore* pScore = get_imo_score();
97
for (int iInstr = 0; iInstr < pScore->get_num_instruments(); iInstr++)
99
ImoInstrument* pInstr = pScore->get_instrument(iInstr);
100
m_instrEngravers.push_back( new InstrumentEngraver(pInstr, m_pTextMeter) );
104
//---------------------------------------------------------------------------------------
105
void ScoreLayouter::delete_instrument_layouters()
107
std::vector<InstrumentEngraver*>::iterator it;
108
for (it = m_instrEngravers.begin(); it != m_instrEngravers.end(); ++it)
110
m_instrEngravers.clear();
113
//---------------------------------------------------------------------------------------
114
void ScoreLayouter::delete_system_layouters()
116
std::vector<SystemLayouter*>::iterator it;
117
for (it = m_sysLayouters.begin(); it != m_sysLayouters.end(); ++it)
119
m_sysLayouters.clear();
122
//---------------------------------------------------------------------------------------
123
void ScoreLayouter::decide_systems_indentation()
125
m_uFirstSystemIndent = 0.0f;
126
m_uOtherSystemIndent = 0.0f;
127
std::vector<InstrumentEngraver*>::iterator it;
128
for (it = m_instrEngravers.begin(); it != m_instrEngravers.end(); ++it)
130
(*it)->measure_indents();
131
m_uFirstSystemIndent = max(m_uFirstSystemIndent, (*it)->get_indent_first());
132
m_uOtherSystemIndent = max(m_uOtherSystemIndent, (*it)->get_indent_other());
136
//---------------------------------------------------------------------------------------
137
void ScoreLayouter::layout_in_page(GmoBox* pContainerBox)
139
//AWARE: This method is invoked to layout a page. If there are more pages to
140
//layout, it will be invoked more times. Therefore, this method must not initialize
141
//anything. All initializations must be done in 'prepare_to_start_layout()'.
142
//layout_in_page() method must allways continue layouting from current state.
144
page_initializations(pContainerBox);
145
move_cursor_to_top_left_corner();
146
add_titles_if_first_page();
148
while(more_systems_to_add() && enough_space_in_page())
153
set_layout_is_finished( !more_systems_to_add() );
156
//---------------------------------------------------------------------------------------
157
void ScoreLayouter::page_initializations(GmoBox* pContainerBox)
159
m_pCurBoxPage = dynamic_cast<GmoBoxScorePage*>( pContainerBox );
160
is_first_system_in_page(true);
161
more_systems_to_add(true);
164
//---------------------------------------------------------------------------------------
165
GmoBox* ScoreLayouter::create_pagebox(GmoBox* pParentBox)
167
GmoBox* pBox = new GmoBoxScorePage(m_pStubScore, pParentBox);
168
pBox->set_left( pParentBox->get_left() );
169
pBox->set_top( pParentBox->get_top() );
173
//---------------------------------------------------------------------------------------
174
void ScoreLayouter::add_titles_if_first_page()
179
move_cursor_after_headers();
183
//---------------------------------------------------------------------------------------
184
void ScoreLayouter::add_next_system()
186
create_system_layouter();
187
//create_system_cursor();
189
fill_current_system_with_columns();
190
justify_current_system();
192
if (!more_systems_to_add()) // && m_fStopStaffLinesAtFinalBarline)
193
truncate_current_system();
194
//AddInitialLineJoiningAllStavesInSystem();
195
//UpdateBoxSlicesSizes();
196
set_system_height_and_advance_paper_cursor();
197
is_first_system_in_page(false);
200
////---------------------------------------------------------------------------------------
201
//void ScoreLayouter::create_system_cursor()
203
// delete_system_cursor();
204
// m_pSysCursor = new SystemCursor(m_pScore);
207
////---------------------------------------------------------------------------------------
208
//void ScoreLayouter::delete_system_cursor()
211
// delete m_pSysCursor;
214
//---------------------------------------------------------------------------------------
215
bool ScoreLayouter::enough_space_in_page()
218
// If paper height is smaller than system height it is impossible to fit
219
// one system in a page. We have to split system horizontally (some staves in
220
// one page and the others in next page).
223
//By using m_uLastSystemHeight to determine if there is enough space we are
224
//assuming that next system height will be equal to last finished system.
226
return remaining_height() >= m_uLastSystemHeight;
229
//---------------------------------------------------------------------------------------
230
LUnits ScoreLayouter::remaining_height()
232
return m_pCurBoxPage->get_height() - m_pageCursor.y;
235
//---------------------------------------------------------------------------------------
236
void ScoreLayouter::move_cursor_to_top_left_corner()
238
m_pageCursor.x = m_pCurBoxPage->get_left();
239
m_pageCursor.y = m_pCurBoxPage->get_top();
242
//---------------------------------------------------------------------------------------
243
void ScoreLayouter::add_score_titles()
246
//m_pScore->LayoutAttachedObjects(m_pStubScore->GetCurrentPage(), m_pPaper);
249
//---------------------------------------------------------------------------------------
250
void ScoreLayouter::move_cursor_after_headers()
253
move_cursor_to_top_left_corner();
254
//m_pageCursor.y += m_pScore->GetHeadersHeight();
257
//---------------------------------------------------------------------------------------
258
void ScoreLayouter::create_system_layouter()
260
m_sysLayouters.push_back(
261
new SystemLayouter() ); //m_rSpacingFactor, m_nSpacingMethod, m_nSpacingValue) );
264
//---------------------------------------------------------------------------------------
265
void ScoreLayouter::create_system_box()
267
//m_nColumnsInSystem = 0;
270
m_pCurBoxSystem = m_pCurBoxPage->add_system(m_nCurSystem++);
271
//m_pCurBoxSystem->SetFirstMeasure(m_nAbsColumn);
274
m_pCurBoxSystem->set_origin(m_pageCursor.x, m_pageCursor.y);
277
LUnits left = 500.0f; //pScore->get_system_left_space(iSystem);
278
m_pCurBoxSystem->set_left_margin(left);
281
m_pCurBoxSystem->set_width( m_pCurBoxPage->get_width() );
283
//move x cursor to system left marging
284
m_pageCursor.x += left;
287
//---------------------------------------------------------------------------------------
288
void ScoreLayouter::set_system_height_and_advance_paper_cursor()
291
// //A system has been layouted. Update last system heigh record (without bottom space)
292
// //and advance paper cursor to next system position
294
// //AWARE: In GetSystemDistance() we are using m_nCurSystem instead of
295
// //m_nCurSystem-1. This is to get the system distance between this system
297
// LUnits uSystemBottomSpace = m_pScore->GetSystemDistance(m_nCurSystem, false) / 2.0;
298
// m_pCurBoxSystem->SetBottomSpace(uSystemBottomSpace);
299
m_uLastSystemHeight = m_pCurBoxSystem->get_height();
301
//advance paper in system bottom space
302
m_pageCursor.x = m_pCurBoxPage->get_left();
303
m_pageCursor.y = m_pCurBoxSystem->get_bottom();
306
//---------------------------------------------------------------------------------------
307
void ScoreLayouter::fill_current_system_with_columns()
312
create_column_and_add_it_to_current_system();
314
while(!m_scoreIt.is_end() && !must_terminate_system());
316
more_systems_to_add( !m_scoreIt.is_end() );
319
//---------------------------------------------------------------------------------------
320
void ScoreLayouter::justify_current_system()
322
//ComputeMeasuresSizesToJustifyCurrentSystem(fThisIsLastSystem);
323
//RepositionStaffObjs();
326
//---------------------------------------------------------------------------------------
327
void ScoreLayouter::create_column_and_add_it_to_current_system()
329
//Creates a column and adds it to current system, if enough space.
330
//The column is sized and this space discunted from available line space.
331
//Returns true if either:
332
// - current system is completed,
333
// - there is not enough space tor include this column in current system, or
334
// - if a newSystem tag is found.
335
//If not enough space for adding the column, SystemCursor is repositined again at
336
//start of this column and nothing is added to current system.
338
// //reposition paper vertically at the start of the system. It has been advanced
339
// //when sizing the previous column
340
// m_pageCursor.y = m_uStartOfCurrentSystem;
343
create_column_boxes();
344
must_terminate_system(false);
345
collect_content_for_this_bar();
348
// //if this is the first column compute the space available in
349
// //this system. The method is a little tricky. The total space available
350
// //is (pScore->GetPageRightMargin() - pScore->GetCursorX()). But we have
351
// //to take into account the space that will be used by the prolog. As the
352
// //left position of the first column has taken all this into account,
353
// //it is posible to use that value by just doing:
354
// if (is_first_column_in_system())
356
// m_uFreeSpace = m_pScore->GetRightMarginXPos()
357
// - m_pScore->GetSystemLeftSpace(m_nCurSystem - 1)
358
// - m_sysLayouters[m_nCurSystem-1]->GetStartPositionForColumn(m_nRelColumn);
361
// //check if there is enough space to add this column to current system
362
// if(m_uFreeSpace < m_sysLayouters[m_nCurSystem-1]->GetMinimumSize(m_nRelColumn))
364
// //there is no enough space for this column.
366
// //restore cursors to re-process this column
367
// m_pSysCursor->GoBackPrevPosition();
369
// //if no column added to system, the line width is not enough for drawing
370
// //just one measure or no measures in score (i.e. no time signature).
371
// //We have to split the current column and reprocess it
372
// if (m_nColumnsInSystem == 0)
374
// //determine break time to split this column
375
// SplitColumn(m_uFreeSpace);
378
// //discard measurements for current column
379
// m_sysLayouters[m_nCurSystem-1]->DiscardMeasurementsForColumn(m_nRelColumn);
380
// m_pCurBoxSystem->DeleteLastSlice();
382
// //if at least one column in current system, the system is finished
383
// if (m_nColumnsInSystem > 0)
384
// return true; //terminate system
388
// //there is enough space for this column. Add it to system
389
add_column_to_system();
393
//---------------------------------------------------------------------------------------
394
void ScoreLayouter::add_slice_box()
396
m_pCurSlice = m_pCurBoxSystem->add_slice(m_nAbsColumn);
398
m_pCurSlice->set_left(m_pCurBoxSystem->get_content_left());
399
m_pCurSlice->set_top(m_pCurBoxSystem->get_top());
400
m_pCurSlice->set_width(m_pCurBoxSystem->get_content_width());
402
m_pageCursor.y = m_pCurSlice->get_top();
405
//---------------------------------------------------------------------------------------
406
void ScoreLayouter::create_column_boxes()
408
m_sliceInstrBoxes.clear();
410
ImoScore* pScore = get_imo_score();
412
ImoInstrument* pInstr = NULL;
413
int maxInstr = pScore->get_num_instruments() - 1;
415
for (int iInstr = 0; iInstr <= maxInstr; iInstr++)
417
m_pageCursor.x = m_pCurSlice->get_left(); //align start of all staves
418
pInstr = pScore->get_instrument(iInstr);
419
LUnits uMargin = determine_top_space(iInstr, pInstr);
422
terminate_slice_instr(iInstr-1, uMargin);
424
start_slice_instr(pInstr, iInstr, uMargin);
427
//set last SliceInstr height
428
LUnits uBottomMargin = pInstr->get_staff(0)->get_staff_margin() / 2.0f;
429
terminate_slice_instr(maxInstr, uBottomMargin);
431
//set slice and system height
432
LUnits uTotalHeight = m_pageCursor.y - m_pCurSlice->get_top();
433
m_pCurSlice->set_height(uTotalHeight);
434
if (is_first_column_in_system())
435
m_pCurBoxSystem->set_height(uTotalHeight);
438
void ScoreLayouter::measure_this_bar()
441
// //restore x cursor to paper left margin
442
// m_pageCursor.x = m_pScore->GetPageLeftMargin();
444
// //all measures in column number m_nAbsColumn have been sized. The information is stored in
445
// //object SystemLayouter. Now proced to re-position the StaffObjs so that all StaffObjs
446
// //sounding at the same time will have the same x coordinate.
447
// bool fTrace = m_fDebugMode && (m_nTraceMeasure == 0 || m_nTraceMeasure == m_nAbsColumn);
449
// m_sysLayouters[m_nCurSystem-1]->EndOfSystemMeasurements();
450
// m_sysLayouters[m_nCurSystem-1]->DoColumnSpacing(m_nRelColumn, fTrace);
453
//---------------------------------------------------------------------------------------
454
LUnits ScoreLayouter::determine_top_space(int nInstr, ImoInstrument* pInstr)
458
ImoScore* pScore = get_imo_score();
459
if (is_first_system_in_page())
461
ImoSystemInfo* pInfo = pScore->get_first_system_info();
462
return pInfo->get_top_system_distance();
466
ImoSystemInfo* pInfo = pScore->get_other_system_info();
467
return pInfo->get_system_distance() / 2.0f;
471
return pInstr->get_staff(0)->get_staff_margin() / 2.0f;
474
//---------------------------------------------------------------------------------------
475
void ScoreLayouter::start_slice_instr(ImoInstrument* pInstr, int iInstr, LUnits uTopMargin)
477
m_pCurBSI = m_pCurSlice->add_box_for_instrument(pInstr);
478
m_sliceInstrBoxes.push_back( m_pCurBSI );
479
m_pCurBSI->set_top( m_pageCursor.y );
480
m_pCurBSI->set_left( m_pCurSlice->get_left() );
481
m_pCurBSI->set_width( m_pCurSlice->get_width() );
483
m_pageCursor.y += uTopMargin;
485
if (is_first_column_in_system())
486
add_staff_lines_name_and_bracket(iInstr, uTopMargin);
489
//---------------------------------------------------------------------------------------
490
void ScoreLayouter::terminate_slice_instr(int iInstr, LUnits uBottomMargin)
492
m_pageCursor.y += uBottomMargin;
493
m_pCurBSI->set_height( m_pageCursor.y - m_pCurBSI->get_top() );
496
//---------------------------------------------------------------------------------------
497
void ScoreLayouter::add_staff_lines_name_and_bracket(int iInstr, LUnits uTopMargin)
499
LUnits indent = get_system_indent();
500
InstrumentEngraver* engraver = get_instrument_engraver(iInstr);
501
engraver->add_staff_lines(m_pCurBoxSystem, m_pageCursor.x, m_pageCursor.y, indent);
502
engraver->add_name_abbrev(m_pCurBSI, m_nCurSystem);
503
engraver->add_brace_bracket(m_pCurBSI);
504
m_pageCursor.y = engraver->get_staff_bottom();
507
//---------------------------------------------------------------------------------------
508
InstrumentEngraver* ScoreLayouter::get_instrument_engraver(int iInstr)
510
std::vector<InstrumentEngraver*>::iterator it = m_instrEngravers.begin();
511
for (; it != m_instrEngravers.end() && iInstr > 0; ++it, --iInstr);
515
//---------------------------------------------------------------------------------------
516
void ScoreLayouter::truncate_current_system()
518
//system must be truncated at final barline if requested. Otherwise it must go
519
//to right margin. Set here the applicable lenght.
521
// if (fThisIsLastSystem && m_fStopStaffLinesAtFinalBarline)
523
// //this is the last system and it has been requested to stop staff lines
524
// //in last measure. So, set final x so staff lines go to final bar line
525
// LUnits xFinalPos = 0.0f;
526
// LUnits yFinalPos = 0.0f;
527
// ImoInstrument *pI;
528
// for (pI = m_pScore->GetFirstInstrument(); pI; pI=m_pScore->GetNextInstrument())
530
// LUnits xPos, yPos;
531
// pI->GetVStaff()->GetBarlineOfLastNonEmptyMeasure(&xPos, &yPos);
532
// if (yPos > yFinalPos)
538
// if (xFinalPos > 0.0f)
539
// m_pCurBoxSystem->UpdateXRight( xFinalPos - 1 );
541
// m_pCurBoxSystem->UpdateXRight( m_pScore->GetRightMarginXPos() );
545
//---------------------------------------------------------------------------------------
546
void ScoreLayouter::collect_content_for_this_bar() //ImoInstrument* pInstr, int iInstr)
548
// // Compute the width of the current measure (or remaining part of it) of the lmVStaff
549
// // Input variables:
550
// // pVStaff - lmVStaff to process
551
// // nInstr - instrument number 0..n
552
// // m_pSysCursor is pointing to current position
553
// // m_nRelColumn and m_nAbsColumn have the relative and absolute numbers for current
554
// // column beign measured
555
// // flag is_first_column_in_system() signals if this is the first column of current system
558
// // all measurements are stored in SystemLayouter
559
// // Return bool: true if newSystem tag found in this measure
561
// //add some space at start of measure, if necessary
562
LUnits uSpaceAfterStart = 0.0f;
563
// if (is_first_column_in_system())
565
// //if first measure of system, add some space before prolog
566
// uSpaceAfterStart = m_uSpaceBeforeProlog;
570
// //Not first measure of system. Get the previous barline and add some space if
571
// //the previous barline is visible.
572
// ImoBarline* pBar = m_pSysCursor->GetPreviousBarline(nInstr);
575
// if (pBar->IsVisible())
576
// uSpaceAfterStart = pVStaff->TenthsToLogical(20.0f); // TODO: user options
580
// //ask system formatter to prepare to receive data for this instrument objects in this column
581
LUnits uxStart = m_pageCursor.x;
583
SystemLayouter* pSysLayouter = m_sysLayouters[m_nCurSystem-1];
584
pSysLayouter->start_bar_measurements(m_nRelColumn, uxStart, uSpaceAfterStart);
586
// //The prolog (clef and key signature) must be rendered on each system, but the
587
// //matching StaffObjs only exist in the first system. In the first system the prolog
588
// //is rendered as part as the normal StaffObj rendering process, so there is nothig
589
// //special to do to render the prolog. But for the other systems we must force the
590
// //rendering of the prolog because there are no StaffObjs representing the prolog.
591
bool fProlog = (is_first_column_in_system()); //fProlog -> we are adding prolog objects
592
// if (m_nAbsColumn != 1 && is_first_column_in_system())
594
// AddProlog(m_pCurBSI, false, pVStaff, nInstr);
595
// fProlog = false; //prolog added
598
//Pre-allocate common engravers
599
ClefEngraver clefEngrv;
602
// //loop to process all StaffObjs in this measure
603
bool fNewSystemTagFound = false; //newSystem tag found
604
ImoStaffObj* pSO = NULL;
605
//ScoreIterator sit = m_pSysCursor->get_iterator(iInstr);
606
//// m_scoreIt.ResetFlags();
607
while(!m_scoreIt.is_end() ) //&& !m_scoreIt.change_of_measure())
609
pSO = dynamic_cast<ImoStaffObj*>( (*m_scoreIt)->imo_object() );
610
int iInstr = (*m_scoreIt)->num_instrument();
611
int iStaff = (*m_scoreIt)->staff();
612
LUnits lineSpacing = get_line_spacing(iInstr, iStaff);
614
// if (pSO->IsBarline() || IsHigherTime(pSO->GetTimePos(), m_pSysCursor->GetBreakTime()) )
616
// break; //End of measure: exit loop.
619
// else if (pSO->IsControl())
621
// ESOCtrolType nCtrolType = ((lmSOControl*)pSO)->GetCtrolType();
622
// if(lmNEW_SYSTEM == nCtrolType)
624
// //new system tag found in this measure
625
// fNewSystemTagFound = true;
628
// wxLogMessage(_T("ScoreLayouter::collect_content_for_this_bar] Bad SOControl type"));
633
/*else*/ if (pSO->is_clef())
635
m_pageCursor.x = uxStart;
636
//pSO->Layout(m_pCurBSI, m_pPaper);
637
//GmoShape* pShape = pSO->GetShape();
638
ImoClef* pClef = dynamic_cast<ImoClef*>(pSO);
639
GmoShape* pShape = clefEngrv.create_shape(pClef, m_pCurBSI, m_pageCursor,
641
pSysLayouter->include_object(m_nRelColumn, iInstr, pSO, fProlog,
644
// else if (pSO->IsKeySignature())
646
// m_pageCursor.x =uxStart);
647
// AddKey((lmKeySignature*)pSO, m_pCurBSI, pVStaff, nInstr, fProlog);
650
// else if (pSO->IsTimeSignature())
652
// m_pageCursor.x =uxStart);
653
// AddTime((TimeSignature*)pSO, m_pCurBSI, pVStaff, nInstr, fProlog);
658
// //it is neither clef, key signature nor time signature. Finish prologue
661
// //create this lmStaffObj shape and add to table
662
// m_pageCursor.x =uxStart);
663
// pSO->Layout(m_pCurBSI, m_pPaper);
664
// GmoShape* pShape = pSO->GetShape();
665
// pSysLayouter->IncludeObject(m_nRelColumn, nInstr, pSO, pShape, fProlog);
671
// //The barline lmStaffObj is not included in the loop as it might not exist in the last
672
// //bar of a score. In theses cases, the loop is exited because the end of the score is
673
// //reached. In any case we have to close the line
674
// if (pSO && pSO->IsBarline())
676
// ++sit; //leave cursor pointing to next measure
678
// m_pageCursor.x =uxStart);
679
// pSO->Layout(m_pCurBSI, m_pPaper);
680
// GmoShape* pShape = pSO->GetShape();
681
// pSysLayouter->include_barline_and_terminate_bar_measurements(m_nRelColumn, pSO, uxStart);
685
// // no barline at the end of the measure.
686
pSysLayouter->terminate_bar_measurements_without_barline(m_nRelColumn, uxStart);
688
// //force new system if a break point reached
689
// if (pSO && IsHigherTime(pSO->GetTimePos(), m_pSysCursor->GetBreakTime()))
690
// fNewSystemTagFound = true;
693
must_terminate_system( fNewSystemTagFound );
696
//---------------------------------------------------------------------------------------
697
void ScoreLayouter::add_column_to_system()
699
// //A column has been processed, it has been checked that there is enough space to include it
700
// //in current system and, finally, decided to include it. This method does whatever
701
// //is necessary to include the column and consolidate the situation.
703
// //Add column to current system and discount the space that the measure will take
704
// m_uFreeSpace -= m_sysLayouters[m_nCurSystem-1]->GetMinimumSize(m_nRelColumn);
705
// m_nColumnsInSystem++;
706
// m_pSysCursor->CommitCursors();
707
add_shapes_for_score_objs();
710
// //mark all objects in column as 'non dirty'
711
// m_sysLayouters[m_nCurSystem-1]->ClearDirtyFlags(m_nRelColumn);
713
// //prepare to create a new column
718
//---------------------------------------------------------------------------------------
719
void ScoreLayouter::add_shapes_for_score_objs()
721
m_sysLayouters[m_nCurSystem-1]->add_shapes(m_sliceInstrBoxes);
724
//---------------------------------------------------------------------------------------
725
LUnits ScoreLayouter::get_line_spacing(int iInstr, int iStaff)
727
ImoScore* pScore = get_imo_score();
728
ImoInstrument* pInstr = pScore->get_instrument(iInstr);
729
return pInstr->get_staff(iStaff)->get_line_spacing();
734
////-----------------------------------------------------------------------------------------
735
//// ScoreLayouter implementation OLD CODE TO REVIEW
736
////-----------------------------------------------------------------------------------------
738
//---------------------------------------------------------------------------------------
739
//void ScoreLayouter::DeleteSystemLayouters()
741
// std::vector<SystemLayouter*>::iterator it;
742
// for (it=m_sysLayouters.begin(); it != m_sysLayouters.end(); ++it)
744
// m_sysLayouters.clear();
748
//---------------------------------------------------------------------------------------
749
//void ScoreLayouter::SplitColumn(LUnits uAvailable)
751
// //We have measured a column and it doesn't fit in current system. Split it.
752
// //All information about column to split is stored in the SystemLayouter.
753
// //Parameter uAvailable is the available space in current system
757
// if (m_sysLayouters[m_nCurSystem-1]->GetOptimumBreakPoint(m_nRelColumn, uAvailable, &rTime, &uWidth))
759
// wxString sMsg = _("Program failure: not enough space for drawing just one bar.");
760
// ::wxLogFatalError(sMsg);
763
// m_pSysCursor->SetBreakTime(rTime);
766
//---------------------------------------------------------------------------------------
767
//LUnits ScoreLayouter::AddEmptySystem(int nSystem, GmoBoxSystem* pBoxSystem)
769
// //Add staff lines to received GmoBoxSystem. Returns system height including bottom margin.
770
// //Paper is left positioned at next staff position
772
// LUnits uSystemHeight = - m_pageCursor.y;
774
// // explore all instruments in the score
775
// LUnits xStartPos = m_pageCursor.x;
778
// ImoInstrument* pInstr = m_pScore->GetFirstInstrument();
781
// m_pageCursor.x = xStartPos ); //align start of staves in this system
783
// LUnits yPaperPos = m_pageCursor.y;
785
// lmVStaff* pVStaff = pInstr->GetVStaff();
788
// LUnits uTopMargin;
791
// //First instrument of this system
792
// uTopMargin = pBoxSystem->get_top_space();
797
// //Not first instrument of system. Split distance: half for each instrument
798
// uTopMargin = pVStaff->GetFirstStaff()->GetStaffDistance() / 2.0f;
800
// //advance paper to top limit of current instrument
801
// m_pageCursor.y += uTopMargin;
802
// yPaperPos = m_pageCursor.y;
805
// //Here paper is positioned at top limit of current instrument
807
// //advance paper to top line of first staff (instrument top bounds)
808
// m_pageCursor.y += uTopMargin;
809
// yPaperPos = m_pageCursor.y;
811
// //Add staff lines for current instrument. As final xPos is yet unknown, so I use zero.
812
// //It will be updated when the system is completed
813
// uyBottom = pVStaff->LayoutStaffLines(pBoxSystem, pInstr, xStartPos,
814
// 0.0f, m_pageCursor.y);
816
// //advance paper in height of this lmVStaff
817
// m_pageCursor.y =uyBottom );
819
// //proceed with next instrument
820
// pInstr = m_pScore->GetNextInstrument();
824
// //restore x cursor to paper left margin
825
// m_pageCursor.x = m_pScore->GetPageLeftMargin() );
827
// //set system bottom position
828
// pBoxSystem->SetYBottom(uyBottom);
831
// uSystemHeight += m_pageCursor.y;
832
// return uSystemHeight;
835
//---------------------------------------------------------------------------------------
836
//void ScoreLayouter::RedistributeFreeSpace(LUnits uAvailable, bool fLastSystem)
838
// //Step 3: Justify measures (distribute remainnig space across all measures)
839
// //-------------------------------------------------------------------------------
840
// //Redistributes the space to try to have all columns with equal witdh.
841
// //The system is not justified if this is the last system and there is no barline
842
// //in the last measure.
844
// //on entering in this function:
845
// // - object SystemLayouter stores the minimum size for each column for
846
// // the current system.
847
// // - uAvailable stores the free space remaining at the end of this system
850
// // - the values stored in SystemLayouter are modified to reflect the new size
851
// // for the bar columns, so that the line get justified.
853
// //-------------------------------------------------------------------------------------
855
// if (uAvailable <= 0.0f) return; //no space to distribute
857
// //The system must not be justified if this is the last system and there is no barline
858
// //in the last bar. Check this.
859
// SystemLayouter* pSysFmt = m_sysLayouters[m_nCurSystem-1];
860
// if (fLastSystem && !pSysFmt->ColumnHasBarline(m_nColumnsInSystem-1))
861
// return; //no need to justify
863
// //compute average column size and total occupied
864
// LUnits uTotal = 0.0f;
865
// for (int i = 0; i < m_nColumnsInSystem; i++)
867
// uTotal += pSysFmt->GetMinimumSize(i);
869
// LUnits uAverage = (uTotal + uAvailable) / m_nColumnsInSystem;
871
// //for each column, compute the diference between its size and the average target size
872
// //sum up all the diferences in uDifTotal
873
// std::vector<LUnits> uDif(m_nColumnsInSystem, 0.0f);
874
// LUnits uDifTotal = 0;
875
// int nNumSmallerColumns = 0; //num of columns smaller than average
876
// for (int i = 0; i < m_nColumnsInSystem; i++)
878
// uDif[i] = uAverage - pSysFmt->GetMinimumSize(i);
879
// if (uDif[i] > 0.0f)
881
// uDifTotal += uDif[i];
882
// nNumSmallerColumns++;
886
// //distribute space
887
// if (uDifTotal > uAvailable)
889
// //not enough space to make all equal
890
// LUnits uReduce = (uDifTotal - uAvailable) / nNumSmallerColumns;
891
// for (int i = 0; i < m_nColumnsInSystem; i++)
893
// if (uDif[i] > 0.0f)
895
// uDif[i] -= uReduce;
896
// pSysFmt->IncrementColumnSize(i, uDif[i]);
902
// //enough space to make all columns equal size
903
// for (int i = 0; i < m_nColumnsInSystem; i++)
905
// if (uDif[i] > 0.0f)
907
// pSysFmt->IncrementColumnSize(i, uDif[i]);
915
////=========================================================================================
916
//// Methods to deal with measures
917
////=========================================================================================
918
//---------------------------------------------------------------------------------------
919
//void ScoreLayouter::AddProlog(GmoBoxSliceInstr* pBSI, bool fDrawTimekey, lmVStaff* pVStaff,
922
// // The prolog (clef and key signature) must be rendered on each system,
923
// // but the matching StaffObjs only exist in the first system. Therefore, in the
924
// // normal staffobj rendering process, the prolog would be rendered only in
925
// // the first system.
926
// // So, for the other systems it is necessary to force the rendering
927
// // of the prolog because there are no StaffObjs representing it.
928
// // This method does it.
930
// // To know what clef, key and time signature to draw we take this information from the
931
// // context associated to first note of the measure on each staff. If there are no notes,
932
// // the context is taken from the barline. If, finally, no context is found, no prolog
935
// LUnits uPrologWidth = 0.0f;
936
// lmClef* pClef = (lmClef*)NULL;
937
// lmEClefType nClef = lmE_Undefined;
938
// lmKeySignature* pKey = (lmKeySignature*)NULL;
939
// TimeSignature* pTime = (TimeSignature*)NULL;
941
// //AWARE when this method is invoked the paper position must be at the left marging,
942
// //at the start of a new system.
943
// LUnits xStartPos = m_pageCursor.x; //Save x to align all clefs
944
// LUnits yStartPos = m_pageCursor.y;
946
// //iterate over the collection of lmStaff objects to draw current clef and key signature
948
// lmStaff* pStaff = pVStaff->GetFirstStaff();
949
// LUnits uyOffset = 0.0f;
950
// LUnits xPos = 0.0f;
952
// SystemLayouter* pSysLayouter = m_sysLayouters[m_nCurSystem-1];
953
// lmContext* pContext = (lmContext*)NULL;
954
// for (int nStaff=1; nStaff <= pVStaff->GetNumStaves(); pStaff = pVStaff->GetNextStaff(), nStaff++)
958
// uyOffset += pStaff->GetStaffDistance();
960
// //locate context for first note in this staff
961
// pContext = m_pSysCursor->GetStartOfColumnContext(nInstr, nStaff);
965
// pClef = pContext->GetClef();
966
// pKey = pContext->GetKey();
967
// pTime = pContext->GetTime();
972
// nClef = pClef->GetClefType();
973
// if (pClef->IsVisible())
975
// lmUPoint uPos = lmUPoint(xPos, yStartPos+uyOffset); //absolute position
976
// GmoShape* pShape = pClef->CreateShape(pBSI, m_pPaper, uPos);
977
// pShape->SetShapeLevel(lm_ePrologShape);
978
// xPos += pShape->GetWidth();
979
// pSysLayouter->IncludeObject(m_nRelColumn, nInstr, pClef, pShape, true);
983
// //render key signature
984
// if (pKey && pKey->IsVisible())
986
// lmUPoint uPos = lmUPoint(xPos, yStartPos+uyOffset); //absolute position
987
// GmoShape* pShape = pKey->CreateShape(pBSI, m_pPaper, uPos, nClef, pStaff);
988
// pShape->SetShapeLevel(lm_ePrologShape);
989
// xPos += pShape->GetWidth();
990
// pSysLayouter->IncludeObject(m_nRelColumn, nInstr, pKey, pShape, true, nStaff);
995
// //compute prolog width
996
// uPrologWidth = wxMax(uPrologWidth, xPos - xStartPos);
998
// //compute vertical displacement for next staff
999
// uyOffset += pStaff->GetHeight();
1003
// // update paper cursor position
1004
// m_pageCursor.x =xStartPos + uPrologWidth);
1008
//---------------------------------------------------------------------------------------
1009
//void ScoreLayouter::AddKey(lmKeySignature* pKey, Box* pBox,
1010
// lmVStaff* pVStaff, int nInstr, bool fProlog)
1012
// // This method is responsible for creating the key signature shapes for
1013
// // all staves of this instrument. And also, of adding them to the graphical
1014
// // model and to the Timepos table
1016
// //create the shapes
1017
// pKey->Layout(pBox, m_pPaper);
1019
// //add the shapes to the timepos table
1020
// SystemLayouter* pSysLayouter = m_sysLayouters[m_nCurSystem-1];
1021
// GmoShape* pMainShape = ((lmStaffObj*)pKey)->GetShape(); //cast forced because otherwise the compiler complains
1022
// for (int nStaff=1; nStaff <= pVStaff->GetNumStaves(); nStaff++)
1024
// GmoShape* pShape = pKey->GetShape(nStaff);
1025
// pSysLayouter->IncludeObject(m_nRelColumn, nInstr, pKey, pShape, fProlog, nStaff);
1031
//---------------------------------------------------------------------------------------
1032
//void ScoreLayouter::AddTime(TimeSignature* pTime, Box* pBox,
1033
// lmVStaff* pVStaff, int nInstr, bool fProlog)
1035
// // This method is responsible for creating the time signature shapes for
1036
// // all staves of this instrument. And also, of adding them to the graphical
1037
// // model and to the Timepos table
1039
// //create the shapes
1040
// pTime->Layout(pBox, m_pPaper);
1042
// //add the shapes to the timepos table
1043
// SystemLayouter* pSysLayouter = m_sysLayouters[m_nCurSystem-1];
1044
// GmoShape* pMainShape = ((lmStaffObj*)pTime)->GetShape(); //cast forced because otherwise the compiler complains
1045
// for (int nStaff=1; nStaff <= pVStaff->GetNumStaves(); nStaff++)
1047
// GmoShape* pShape = pTime->GetShape(nStaff);
1048
// pSysLayouter->IncludeObject(m_nRelColumn, nInstr, pTime, pShape, fProlog, nStaff);
1053
//---------------------------------------------------------------------------------------
1054
//void ScoreLayouter::RepositionStaffObjs()
1056
// //SystemLayouter stores the final size that must have each column
1057
// //of this system. This method changes StaffObjs locations so that they are evenly
1058
// //distributed across the the bar.
1060
// //dbg ------------------------------------------------------------------------------
1061
// if (m_fDebugMode) {
1062
// wxLogMessage(_T("Before repositioning objects"));
1063
// wxLogMessage(_T("***************************************\n"));
1064
// wxLogMessage( m_pScore->Dump() );
1066
// //dbg ------------------------------------------------------------------------------
1068
// LUnits uxStartOfMeasure = m_sysLayouters[m_nCurSystem-1]->GetStartPositionForColumn(0);
1069
// for (int i=0; i < m_nColumnsInSystem; i++)
1071
// GmoBoxSlice* pBSlice = (GmoBoxSlice*)m_pCurBoxSystem->GetChildBox(i);
1072
// uxStartOfMeasure = m_sysLayouters[m_nCurSystem-1]->RedistributeSpace(i, uxStartOfMeasure);
1073
// m_sysLayouters[m_nCurSystem-1]->AddTimeGridToBoxSlice(i, pBSlice);
1076
// //dbg ------------------------------------------------------------------------------
1077
// if (m_fDebugMode) {
1078
// wxLogMessage(_T("After repositioning objects"));
1079
// wxLogMessage(_T("***************************************\n"));
1080
// wxLogMessage( m_pScore->Dump() );
1082
// //dbg ------------------------------------------------------------------------------
1086
//---------------------------------------------------------------------------------------
1087
//void ScoreLayouter::GetScoreRenderizationOptions()
1089
// // get options for renderization
1091
// m_fStopStaffLinesAtFinalBarline = m_pScore->GetOptionBool(_T("StaffLines.StopAtFinalBarline"));
1092
// m_fJustifyFinalBarline = m_pScore->GetOptionBool(_T("Score.JustifyFinalBarline"));
1093
// m_rSpacingFactor = (float) m_pScore->GetOptionDouble(_T("Render.SpacingFactor"));
1094
// m_nSpacingMethod = (ESpacingMethod) m_pScore->GetOptionLong(_T("Render.SpacingMethod"));
1095
// m_nSpacingValue = (Tenths) m_pScore->GetOptionLong(_T("Render.SpacingValue"));
1098
//---------------------------------------------------------------------------------------
1099
//void ScoreLayouter::PrepareFontsThatMatchesStavesSizes()
1101
// //for each staff size, setup fonts of right point size for that staff size
1102
// ImoInstrument *pInstr;
1103
// for (pInstr = m_pScore->GetFirstInstrument(); pInstr; pInstr=m_pScore->GetNextInstrument())
1105
// pInstr->GetVStaff()->SetUpFonts(m_pPaper);
1109
//---------------------------------------------------------------------------------------
1110
//void ScoreLayouter::DecideSpaceBeforeProlog()
1112
// //TODO. Now a fixed value of 7.5 tenths is used. User options ?
1114
// Tenths rSpaceBeforeProlog = 7.5f;
1115
// ImoInstrument* pInstr = m_pScore->GetFirstInstrument();
1116
// lmVStaff* pVStaff = pInstr->GetVStaff();
1117
// m_uSpaceBeforeProlog = pVStaff->TenthsToLogical(rSpaceBeforeProlog, 1);
1120
//---------------------------------------------------------------------------------------
1121
//void ScoreLayouter::ComputeMeasuresSizesToJustifyCurrentSystem(bool fThisIsLastSystem)
1123
// //TO ComputeMeasuresSizesToJustifyCurrentSystem divide up the remaining space
1124
// //between all bars, except if current system is the last one and flag
1125
// //"JustifyFinalBarline" is not set or there is no final barline.
1127
// //At this point the number of measures to include in current system has been computed
1128
// //and some data is stored in the following global variables:
1130
// // SystemLayouter - positioning information for columns and
1131
// // minimum size for each column for current system.
1132
// // m_uFreeSpace - free space available on this system
1133
// // m_nColumnsInSystem - the number of measures that fit in this system
1135
// //Now we are going to compute new column sizes and store results
1136
// //in SystemLayouter but changes nothing in the StaffObjs
1138
// if (!fThisIsLastSystem || (fThisIsLastSystem && m_fJustifyFinalBarline))
1139
// RedistributeFreeSpace(m_uFreeSpace, fThisIsLastSystem);
1143
//---------------------------------------------------------------------------------------
1144
//void ScoreLayouter::AddInitialLineJoiningAllStavesInSystem()
1146
// //TODO: In current code, the decision about joining staves depends only on first
1147
// //instrument. This should be changed and the line should go from first visible
1148
// //staff to last visible one.
1150
// //TODO: For empty scores (no staffobj on any instrument) this initial line should
1153
// //Add the shape for the initial barline that joins all staves in a system
1154
// lmVStaff* pVStaff = m_pScore->GetFirstInstrument()->GetVStaff();
1155
// if (m_pScore->GetOptionBool(_T("Staff.DrawLeftBarline")) && !pVStaff->HideStaffLines() )
1157
// LUnits uxPos = m_pCurBoxSystem->get_left() + get_system_indent();
1158
// LUnits uLineThickness = lmToLogicalUnits(0.2, lmMILLIMETERS); // thin line width will be 0.2 mm TODO user options
1159
// GmoShapeSimpleLine* pLine =
1160
// new GmoShapeSimpleLine(pVStaff, uxPos, m_pCurBoxSystem->GetYTopFirstStaff(),
1161
// uxPos, m_pCurBoxSystem->GetYBottom(),
1162
// uLineThickness, 0.0, *wxBLACK, _T("System joining line"),
1163
// lm_eEdgeHorizontal);
1164
// m_pCurBoxSystem->AddShape(pLine, lm_eLayerBarlines);
1168
//---------------------------------------------------------------------------------------
1169
//void ScoreLayouter::UpdateBoxSlicesSizes()
1171
// //update BoxSlices with the final measures sizes, except for last
1172
// //measure, as its length has been already set up
1174
// LUnits xEnd = m_sysLayouters[m_nCurSystem-1]->GetStartPositionForColumn(0);
1175
// for (int iRel=0; iRel < m_nColumnsInSystem; iRel++)
1177
// LUnits xStart = xEnd;
1178
// xEnd = xStart + m_sysLayouters[m_nCurSystem-1]->GetMinimumSize(iRel);
1179
// GmoBoxSlice* pBoxSlice = m_pCurBoxSystem->get_slice(iRel);
1180
// pBoxSlice->UpdateXLeft(xStart);
1181
// if (iRel < m_nColumnsInSystem)
1182
// pBoxSlice->UpdateXRight(xEnd);
1186
//---------------------------------------------------------------------------------------
1187
//bool ScoreLayouter::RequestedToFillScoreWithEmptyStaves()
1189
// return (!m_fStopStaffLinesAtFinalBarline
1190
// && m_pScore->GetOptionBool(_T("Score.FillPageWithEmptyStaves")) );
1193
//---------------------------------------------------------------------------------------
1194
//void ScoreLayouter::FillPageWithEmptyStaves()
1196
// //First system has been always added before arriving here. Fill the remaining
1197
// //page space with empty staves
1199
// //advance vertically the previous system bottom space
1200
// m_pageCursor.y += m_pScore->GetSystemDistance(m_nCurSystem, false) / 2.0 ;
1202
// while (true) //loop is exited when reaching end of page
1204
// //Here Paper is positioned at the start of the new current system.
1206
// bool fFirstSystemInPage = false;
1208
// //TODO ************
1209
// // By using nSystemHeight we are assuming that next system height is going
1210
// // to be equal to last finished system. In this test it is necessary
1211
// // to compute and use next system height
1212
// LUnits nNextSystemHeight = m_uLastSystemHeight;
1213
// LUnits yNew = m_pageCursor.y + nNextSystemHeight;
1214
// if ( yNew > m_pScore->GetMaximumY() )
1215
// break; //exit loop
1217
// //create the system container
1218
// m_uStartOfCurrentSystem = m_pageCursor.y; //save start of system position
1219
// m_pCurBoxSystem =
1220
// m_pCurBoxPage->add_system(m_nCurSystem, m_pageCursor.x,
1221
// m_uStartOfCurrentSystem, fFirstSystemInPage);
1222
// m_pCurBoxSystem->SetFirstMeasure(m_nAbsColumn);
1223
// m_pageCursor.x += m_pCurBoxSystem->get_left_margin();
1224
// m_pCurBoxSystem->SetIndent(get_system_indent());
1227
// m_nRelColumn = 0; //first column of this system
1229
// m_uLastSystemHeight = AddEmptySystem(m_nCurSystem, m_pCurBoxSystem); //Add the staff lines
1231
// //staff lines go to the rigth margin
1232
// m_pCurBoxSystem->UpdateXRight( m_pScore->GetRightMarginXPos() );
1234
// // compute system bottom space
1236
// // In GetSystemDistance() we are using m_nCurSystem instead of m_nCurSystem-1.
1237
// // This is to get the system distance between this system and next one.
1238
// LUnits uSystemBottomSpace = m_pScore->GetSystemDistance(m_nCurSystem, false) / 2.0;
1239
// m_pCurBoxSystem->SetBottomSpace(uSystemBottomSpace);
1241
// //advance paper in system bottom space
1242
// m_pageCursor.y += uSystemBottomSpace;
1244
// //increment loop information
1249
////=========================================================================================
1250
//// methods coded only for Unit Tests
1251
////=========================================================================================
1253
//int ScoreLayouter::GetNumSystemLayouters() { return (int)m_sysLayouters.size(); }
1254
//int ScoreLayouter::GetNumColumns(int iSys) { return m_sysLayouters[iSys]->GetNumColumns(); }
1255
//int ScoreLayouter::GetNumLines(int iSys, int iCol)
1256
// { return m_sysLayouters[iSys]->GetNumLinesInColumn(iCol); }
1258
//SystemLayouter* ScoreLayouter::get_system_layouter(int iSys)
1261
// return m_sysLayouters[iSys];
117
1265
} //namespace lomse