1
//---------------------------------------------------------------------------------------
2
// LenMus Phonascus: The teacher of music
3
// Copyright (c) 2002-2012 LenMus project
5
// This program is free software; you can redistribute it and/or modify it under the
6
// terms of the GNU General Public License as published by the Free Software Foundation,
7
// either version 3 of the License, or (at your option) any later version.
9
// This program is distributed in the hope that it will be useful, but WITHOUT ANY
10
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
11
// PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
// You should have received a copy of the GNU General Public License along with this
14
// program. If not, see <http://www.gnu.org/licenses/>.
16
// For any comment, suggestion or feature request, please contact the manager of
17
// the project at cecilios@users.sourceforge.net
19
//---------------------------------------------------------------------------------------
22
#include "lenmus_document_canvas.h"
23
#include "lenmus_standard_header.h"
25
#include "lenmus_canvas.h"
26
#include "lenmus_string.h"
27
#include "lenmus_midi_server.h"
28
#include "lenmus_dyncontrol.h"
29
#include "lenmus_standard_header.h"
30
#include "lenmus_status_reporter.h"
31
#include "lenmus_dlg_debug.h"
34
#include <lomse_shapes.h>
35
#include <lomse_ldp_exporter.h>
36
#include <lomse_lmd_exporter.h>
37
#include <lomse_score_player.h>
38
#include <lomse_midi_table.h>
39
#include <lomse_player_gui.h>
42
#include <wx/filename.h>
52
//=======================================================================================
53
// DocumentWindow implementation
54
//=======================================================================================
56
BEGIN_EVENT_TABLE(DocumentWindow, wxWindow)
57
EVT_SIZE(DocumentWindow::on_size)
58
EVT_MOUSE_EVENTS(DocumentWindow::on_mouse_event)
59
EVT_KEY_DOWN(DocumentWindow::on_key_event)
60
EVT_PAINT(DocumentWindow::on_paint)
61
EVT_SCROLLWIN(DocumentWindow::on_scroll)
62
LM_EVT_SCORE_HIGHLIGHT(DocumentWindow::on_visual_highlight)
63
EVT_ERASE_BACKGROUND(DocumentWindow::on_erase_background)
64
LM_EVT_END_OF_PLAYBACK(DocumentWindow::on_end_of_playback)
67
DocumentWindow::DocumentWindow(wxWindow* parent, ApplicationScope& appScope,
69
: wxWindow(parent, wxNewId(), wxDefaultPosition, wxDefaultSize,
70
wxVSCROLL | wxHSCROLL | wxALWAYS_SHOW_SB |
71
wxFULL_REPAINT_ON_RESIZE, _T("DocumentWindow") )
72
, m_appScope(appScope)
79
, m_zoomMode(k_zoom_fit_width)
80
, m_fIgnoreOnSize(false)
83
Hide(); //keep hidden until necessary, to avoid useless repaints
86
//---------------------------------------------------------------------------------------
87
DocumentWindow::~DocumentWindow()
89
ScorePlayer* pPlayer = m_appScope.get_score_player();
92
//delete the presenter. This will also delete the Document
94
//TO_FIX: delete presenter deletes all interactors and the document. But here we are
95
//just atempting to delete one view, not the document and all its views.
98
delete_rendering_buffer();
101
//---------------------------------------------------------------------------------------
102
void DocumentWindow::wrapper_play_score(void* pThis, SpEventInfo pEvent)
104
//wxLogMessage(_T("callback: wrapper_play_score"));
105
static_cast<DocumentWindow*>(pThis)->on_play_score(pEvent);
108
//---------------------------------------------------------------------------------------
109
void DocumentWindow::on_play_score(SpEventInfo pEvent)
111
switch (pEvent->get_event_type())
113
case k_do_play_score_event:
117
case k_pause_score_event:
121
case k_stop_playback_event:
128
//---------------------------------------------------------------------------------------
129
void DocumentWindow::play_score(SpEventInfo pEvent)
131
SpEventPlayScore pEv = boost::static_pointer_cast<EventPlayScore>(pEvent);
132
ImoScore* pScore = pEv->get_score();
133
ScorePlayer* pPlayer = m_appScope.get_score_player();
134
PlayerGui* pPlayerGui = pEv->get_player();
136
pPlayer->load_score(pScore, pEv->get_player());
138
//initialize with default options
139
bool fVisualTracking = true;
140
long nMM = pPlayerGui->get_metronome_mm();
142
pPlayer->play(fVisualTracking, nMM, m_pInteractor);
145
//---------------------------------------------------------------------------------------
146
void DocumentWindow::play_stop()
148
ScorePlayer* pPlayer = m_appScope.get_score_player();
152
//---------------------------------------------------------------------------------------
153
void DocumentWindow::play_pause()
155
ScorePlayer* pPlayer = m_appScope.get_score_player();
159
//---------------------------------------------------------------------------------------
160
void DocumentWindow::wrapper_update_window(void* pThis, SpEventInfo pEvent)
162
//wxLogMessage(_T("callback: wrapper_update_window"));
163
static_cast<DocumentWindow*>(pThis)->update_window();
166
//---------------------------------------------------------------------------------------
167
void DocumentWindow::update_window()
169
// Invoking update_window() results in just putting immediately the content
170
// of the currently rendered buffer to the window without neither calling
171
// any lomse methods nor generating any events (i.e. window on_paint)
173
//wxLogMessage(_T("update_window %0x"), this);
176
copy_buffer_on_dc(dc);
179
//---------------------------------------------------------------------------------------
180
void DocumentWindow::copy_buffer_on_dc(wxDC& dc)
182
//wxLogMessage(_T("copy_buffer_on_dc %0x"), this);
183
if (!m_buffer || !m_buffer->IsOk())
186
wxBitmap bitmap(*m_buffer);
187
dc.DrawBitmap(bitmap, 0, 0, false /* don't use mask */);
189
//DEBUG: info about rendering time -------------------------------------
190
double renderTime = m_pInteractor->gmodel_rendering_time();
191
double buildTime = m_pInteractor->gmodel_build_time();
192
wxString msg = wxString::Format(_T("Build time=%.3f, render time=%.3f ms, ticks per second=%d "),
193
buildTime, renderTime, CLOCKS_PER_SEC );
194
StatusReporter* pStatus = m_appScope.get_status_reporter();
195
pStatus->report_status(msg);
196
//END DEBUG ------------------------------------------------------------
201
//---------------------------------------------------------------------------------------
202
void DocumentWindow::on_visual_highlight(lmScoreHighlightEvent& event)
204
SpEventScoreHighlight pEv = event.get_lomse_event();
205
Interactor* pInteractor = get_interactor();
206
pInteractor->on_visual_highlight(pEv);
209
//---------------------------------------------------------------------------------------
210
void DocumentWindow::on_end_of_playback(lmEndOfPlaybackEvent& event)
212
wxLogMessage(_T("[DocumentWindow::on_end_of_playback]"));
213
SpEventPlayScore pEv = event.get_lomse_event();
214
Interactor* pInteractor = get_interactor();
215
pInteractor->send_end_of_play_event(pEv->get_score(), pEv->get_player());
218
//---------------------------------------------------------------------------------------
219
void DocumentWindow::display_document(LdpReader& reader, int viewType,
222
//wxLogMessage(_T("display_document %0x"), this);
225
ostringstream& reporter = m_appScope.get_lomse_reporter();
226
reporter.str(std::string()); //remove any previous content
230
::wxSetCursor(*wxHOURGLASS_CURSOR);
232
m_pPresenter = m_lomse.open_document(viewType, reader, reporter);
233
set_zoom_mode(k_zoom_fit_width);
234
do_display(reporter);
236
catch(std::exception& e)
238
wxMessageBox( to_wx_string(e.what()) );
242
//---------------------------------------------------------------------------------------
243
void DocumentWindow::display_document(const string& filename, int viewType)
245
wxString sF = to_wx_string(filename);
246
wxLogMessage(_T("display_document %s"), sF.c_str());
249
ostringstream& reporter = m_appScope.get_lomse_reporter();
250
reporter.str(std::string()); //remove any previous content
254
::wxSetCursor(*wxHOURGLASS_CURSOR);
256
m_pPresenter = m_lomse.open_document(viewType, filename, reporter);
258
//use filename (without path) as page title
259
wxFileName oFN( to_wx_string(filename) );
260
m_filename = oFN.GetFullName();
262
set_zoom_mode(k_zoom_fit_width);
263
do_display(reporter);
265
catch(std::exception& e)
267
wxMessageBox( to_wx_string(e.what()) );
271
//---------------------------------------------------------------------------------------
272
void DocumentWindow::display_errors(ostringstream& reporter)
274
if (!reporter.str().empty())
276
wxString msg = to_wx_string( reporter.str() );
277
wxString title = _T("Errors in file ");
279
DlgDebug dlg(this, title, msg, true /*show 'Save' button*/);
282
reporter.str(std::string()); //remove any previous content
285
//---------------------------------------------------------------------------------------
286
void DocumentWindow::do_display(ostringstream& reporter)
288
//wxLogMessage(_T("do_display %0x"), this);
290
//get the pointers to the relevant components
291
m_pDoc = m_pPresenter->get_document();
292
m_pInteractor = m_pPresenter->get_interactor(0);
294
//connect the View with the window buffer
295
m_pInteractor->set_rendering_buffer(&m_rbuf_window);
297
//register to receive desired events
298
m_pInteractor->add_event_handler(k_update_window_event, this, wrapper_update_window);
299
m_pInteractor->add_event_handler(k_do_play_score_event, this, wrapper_play_score);
300
m_pInteractor->add_event_handler(k_pause_score_event, this, wrapper_play_score);
301
m_pInteractor->add_event_handler(k_stop_playback_event, this, wrapper_play_score);
303
//set viewport and scale
304
m_fFirstPaint = true;
305
//create_rendering_buffer();
306
//determine_scroll_space_size();
307
//m_pInteractor->new_viewport(-m_xMargin, -m_yMargin);
308
//adjust_scale_and_scrollbars();
310
//AWARE: after creating a pane and loading content on it, wxAuiNotebook / wxFrame
311
//will issue an on_size() followed by an on_paint. Therefore, do not force a
312
//a repaint here as it will be redundant with the coming events
313
Refresh(false /* don't erase background */);
315
////ensure that the rendering buffer is created
316
//if (m_nBufWidth == 0 || m_nBufHeight == 0)
317
// create_rendering_buffer();
319
display_errors(reporter);
322
//---------------------------------------------------------------------------------------
323
void DocumentWindow::on_size(wxSizeEvent& WXUNUSED(event))
325
//wxLogMessage(_T("on_size %s. Visible=%d"), GetLabel().c_str(), (IsShown() ? 1 : 0) );
327
if (!m_pInteractor) return;
328
if (m_fIgnoreOnSize) return;
330
adjust_scale_and_scrollbars();
333
//---------------------------------------------------------------------------------------
334
void DocumentWindow::on_paint(wxPaintEvent& WXUNUSED(event))
336
//wxLogMessage(_T("on_paint %s. Visible=%d"), GetLabel().c_str(), (IsShown() ? 1 : 0) );
338
//AWARE: According wxWidgets documentation, any paint event handler must always
339
//create a wxPaintDC object, even if not used. Otherwise, under MS Windows,
340
// refreshing for this and other windows will go wrong.
343
if (IsShown() && m_pInteractor)
347
m_fFirstPaint = false;
348
create_rendering_buffer();
349
determine_scroll_space_size();
350
adjust_scale_and_scrollbars();
351
m_pInteractor->new_viewport(-m_xMargin, -m_yMargin);
353
update_rendering_buffer();
354
copy_buffer_on_dc(dc);
355
::wxSetCursor(*wxSTANDARD_CURSOR);
359
//---------------------------------------------------------------------------------------
360
void DocumentWindow::on_mouse_event(wxMouseEvent& event)
362
if (!m_pInteractor) return;
364
wxEventType nEventType = event.GetEventType();
365
wxPoint pos = event.GetPosition();
366
unsigned flags = get_mouse_flags(event);
368
if (nEventType == wxEVT_LEFT_DOWN)
370
flags |= k_mouse_left;
371
m_pInteractor->on_mouse_button_down(pos.x, pos.y, flags);
373
else if (nEventType == wxEVT_LEFT_UP)
375
flags |= k_mouse_left;
376
m_pInteractor->on_mouse_button_up(pos.x, pos.y, flags);
378
else if (nEventType == wxEVT_RIGHT_DOWN)
380
flags |= k_mouse_right;
381
m_pInteractor->on_mouse_button_down(pos.x, pos.y, flags);
383
else if (nEventType == wxEVT_RIGHT_UP)
385
flags |= k_mouse_right;
386
m_pInteractor->on_mouse_button_up(pos.x, pos.y, flags);
388
else if (nEventType == wxEVT_MOUSEWHEEL)
390
if (flags && k_kbd_ctrl)
392
// Ctrl + mouse wheel --> zoom in/out
393
if (event.GetWheelRotation() > 0)
397
Refresh(false /* don't erase background */);
402
if (event.GetWheelRotation() > 0)
409
else if (nEventType == wxEVT_MOTION)
410
m_pInteractor->on_mouse_move(pos.x, pos.y, flags);
413
////---------------------------------------------------------------------------------------
414
//void DocumentWindow::on_hyperlink_event(SpEventInfo pEvent)
416
// SpEventMouse pEv = boost::static_pointer_cast<EventMouse>(pEvent);
417
// ImoLink* pLink = static_cast<ImoLink*>( pEv->get_imo_object() );
418
// string& url = pLink->get_url();
419
// wxString msg = wxString::Format(_T("[DocumentWindow::on_hyperlink_event] link='%s'"),
420
// to_wx_string(url).c_str() );
421
// wxMessageBox(msg);
423
//// //extract filename
424
//// //#LenMusPage/L1_MusicReading_mr1_thm12_E1.lms
425
//// string ebook = "/datos/USR/Desarrollo_wx/lenmus/locale/en/books/GeneralExercises.lmb#zip:";
426
//// string page = "GeneralExercises_ClefsReading.lms";
427
//// display_document(ebook + page, ViewFactory::k_view_vertical_book);
430
//---------------------------------------------------------------------------------------
431
unsigned DocumentWindow::get_mouse_flags(wxMouseEvent& event)
434
if (event.LeftIsDown()) flags |= k_mouse_left;
435
if (event.RightIsDown()) flags |= k_mouse_right;
436
if (event.MiddleDown()) flags |= k_mouse_middle;
437
if (event.ShiftDown()) flags |= k_kbd_shift;
438
if (event.AltDown()) flags |= k_kbd_alt;
439
if (event.ControlDown()) flags |= k_kbd_ctrl;
443
//---------------------------------------------------------------------------------------
444
unsigned DocumentWindow::get_keyboard_flags(wxKeyEvent& event)
447
if (event.ShiftDown()) flags |= k_kbd_shift;
448
if (event.AltDown()) flags |= k_kbd_alt;
449
if (event.ControlDown()) flags |= k_kbd_ctrl;
453
//---------------------------------------------------------------------------------------
454
void DocumentWindow::on_document_updated()
456
if (!m_pInteractor) return;
458
//wxLogMessage(_T("on_document_updated %0x"), this);
459
m_pInteractor->on_document_reloaded();
460
Refresh(false /* don't erase background */);
463
//---------------------------------------------------------------------------------------
464
void DocumentWindow::update_rendering_buffer()
466
//wxLogMessage(_T("update_rendering_buffer %0x"), this);
468
if (m_pInteractor && (m_pInteractor->view_needs_repaint() || !is_buffer_ok()) )
470
create_rendering_buffer();
471
m_pInteractor->redraw_bitmap();
475
//---------------------------------------------------------------------------------------
476
bool DocumentWindow::is_buffer_ok()
478
wxSize size = this->GetClientSize();
479
int width = size.GetWidth();
480
int height = size.GetHeight();
484
&& m_nBufWidth == width
485
&& m_nBufHeight == height;
488
//---------------------------------------------------------------------------------------
489
void DocumentWindow::delete_rendering_buffer()
494
//---------------------------------------------------------------------------------------
495
void DocumentWindow::create_rendering_buffer()
497
//creates a bitmap of specified size and associates it to the rendering
498
//buffer for the view. Any existing buffer is automatically deleted
500
//I will use a wxImage as the rendering buffer. wxImage is platform independent
501
//and its buffer is an array of characters in RGBRGBRGB... format, in the
502
//top-to-bottom, left-to-right order. That is, the first RGB triplet corresponds
503
//to the first pixel of the first row; the second RGB triplet, to the second
504
//pixel of the first row, and so on until the end of the first row,
505
//with second row following after it and so on.
507
#define BYTES_PP 3 // Bytes per pixel
509
wxSize size = this->GetClientSize();
510
int width = size.GetWidth();
511
int height = size.GetHeight();
512
//wxLogMessage(_T("create_rendering_buffer %s, w=%d, h=%d"),
513
// GetLabel().c_str(), width, height);
515
// allocate a LENMUS_NEW rendering buffer
516
delete m_buffer; //delete any previous buffer
518
m_nBufHeight = height;
519
m_buffer = LENMUS_NEW wxImage(width, height);
521
int stride = m_nBufWidth * BYTES_PP; //number of bytes per row
523
m_pdata = m_buffer->GetData();
524
m_rbuf_window.attach(m_pdata, m_nBufWidth, m_nBufHeight, stride);
527
//---------------------------------------------------------------------------------------
528
void DocumentWindow::on_key_event(wxKeyEvent& event)
530
if (!m_pInteractor) return;
532
int nKeyCode = event.GetKeyCode();
533
unsigned flags = get_keyboard_flags(event);
535
//fix ctrol+key codes
536
if (nKeyCode > 0 && nKeyCode < 27)
538
nKeyCode += int('A') - 1;
551
on_key(event.GetX(), event.GetY(), nKeyCode, flags);;
555
//---------------------------------------------------------------------------------------
556
void DocumentWindow::set_debug_draw_box(int boxType)
558
m_pInteractor->reset_boxes_to_draw();
559
m_pInteractor->set_box_to_draw(boxType);
561
Refresh(false /* don't erase background */);
564
//---------------------------------------------------------------------------------------
565
void DocumentWindow::on_key(int x, int y, unsigned key, unsigned flags)
570
m_pInteractor->reset_boxes_to_draw();
571
m_pInteractor->set_rendering_option(k_option_draw_box_doc_page_content, true);
574
m_pInteractor->reset_boxes_to_draw();
575
m_pInteractor->set_rendering_option(k_option_draw_box_container, true);
578
m_pInteractor->reset_boxes_to_draw();
579
m_pInteractor->set_rendering_option(k_option_draw_box_system, true);
582
m_pInteractor->reset_boxes_to_draw();
583
m_pInteractor->set_rendering_option(k_option_draw_box_slice, true);
586
m_pInteractor->reset_boxes_to_draw();
587
m_pInteractor->set_rendering_option(k_option_draw_box_slice_instr, true);
590
m_pInteractor->reset_boxes_to_draw();
591
m_pInteractor->set_rendering_option(k_option_draw_box_inline_flag, true);
594
m_pInteractor->switch_task(TaskFactory::k_task_drag_view);
597
m_pInteractor->switch_task(TaskFactory::k_task_selection);
600
m_pInteractor->reset_boxes_to_draw();
603
if (flags && k_kbd_ctrl)
607
if (flags && k_kbd_ctrl)
614
Refresh(false /* don't erase background */);
617
//---------------------------------------------------------------------------------------
618
void DocumentWindow::zoom_to(double scale)
620
if (!m_pInteractor) return;
622
//set zoom, centered on window center
623
wxSize size = this->GetClientSize();
624
m_pInteractor->set_scale(scale, size.GetWidth()/2, 0);
625
m_zoomMode = k_zoom_user;
629
//---------------------------------------------------------------------------------------
630
void DocumentWindow::zoom_in()
632
if (!m_pInteractor) return;
634
wxSize size = this->GetClientSize();
635
m_pInteractor->zoom_in(size.GetWidth()/2, 0);
636
m_zoomMode = k_zoom_user;
640
//---------------------------------------------------------------------------------------
641
void DocumentWindow::zoom_out()
643
if (!m_pInteractor) return;
645
wxSize size = this->GetClientSize();
646
m_pInteractor->zoom_out(size.GetWidth()/2, 0);
647
m_zoomMode = k_zoom_user;
651
//---------------------------------------------------------------------------------------
652
void DocumentWindow::zoom_fit_width()
654
if (!m_pInteractor) return;
656
//wxLogMessage(_T("zoom_fit_width %0x"), this);
657
wxSize size = this->GetClientSize();
658
m_pInteractor->zoom_fit_width(size.GetWidth());
659
m_zoomMode = k_zoom_fit_width;
663
//---------------------------------------------------------------------------------------
664
void DocumentWindow::zoom_fit_full()
666
if (!m_pInteractor) return;
668
//wxLogMessage(_T("zoom_fit_full %0x"), this);
669
wxSize size = this->GetClientSize();
670
m_pInteractor->zoom_fit_full(size.GetWidth(), size.GetHeight());
671
m_zoomMode = k_zoom_fit_full;
675
//---------------------------------------------------------------------------------------
676
ImoScore* DocumentWindow::get_active_score()
678
return m_pDoc->get_score(0);
681
//---------------------------------------------------------------------------------------
682
void DocumentWindow::open_test_document()
685
m_pPresenter = m_lomse.new_document(ViewFactory::k_view_horizontal_book);
687
//get the pointers to the relevant components
688
m_pDoc = m_pPresenter->get_document();
689
m_pInteractor = m_pPresenter->get_interactor(0);
691
//connect the View with the window buffer
692
m_pInteractor->set_rendering_buffer(&m_rbuf_window);
693
m_pInteractor->add_event_handler(k_update_window_event, this, wrapper_update_window);
695
//Now let's place content on the created document
696
m_pDoc->from_string("(lenmusdoc (vers 0.0) (content (score (vers 1.6) "
697
//"(instrument (musicData (clef G)(clef F3)(clef C1)(clef F4) )) )))" );
700
// "(instrument (name \"Violin\")(musicData (clef G)(clef F4)(clef C1) )) )))" );
702
//"(instrument (musicData )) )))" );
704
//"(instrument (staves 2) (musicData )) )))" );
705
//"(instrument (musicData )) (instrument (musicData )) )))" );
707
// //Staves of different sizes
708
// "(instrument (name \"Violin\")(abbrev \"Vln.\")(staff 1 (staffSpacing 400))(musicData (clef G)(n c4 e.))) "
709
// "(instrument (name \"pilano\")(abbrev \"P\")(staves 2)(musicData (clef G p1)(clef F4 p2))) )))" );
711
// //beamed chord. Simplest case
712
// "(instrument (musicData "
713
// "(clef F)(key C)(time 4 4)"
714
// "(chord (n a3 e (beam 1 begin)) (n d3 e))"
715
// "(chord (n g3 e (beam 1 end)) (n e3 e))"
720
// "(instrument (name \"Violin\")(abbrev \"Vln.\")(musicData "
721
// "(clef F4)(key E)(time 2 4)(n +c3 e.)(barline)"
722
// "(n e2 q)(n e3 q)(barline)"
723
// "(n f2 e (beam 1 +))(n g2 e (beam 1 -))"
724
// "(n f3 e (beam 3 +))(n g3 e (beam 3 -))(barline)"
725
// "(n f2 e. (beam 4 +))(n g2 s (beam 4 -b))"
726
// "(n f3 s (beam 5 +f))(n g3 e. (beam 5 -))(barline)"
727
// "(n g2 e. (beam 2 +))(n e3 s (beam 2 -b))(n g3 q)(barline)"
728
// "(n a2 e (beam 6 +))(n g2 e (beam 6 -))(n a3 q)(barline)"
729
// "(n -b2 q)(n =b3 q)(barline)"
730
// "(n xc3 q)(n ++c4 q)(barline)"
731
// "(n d3 q)(n --d4 q)(barline)"
732
// "(n e3 q)(n e4 q)(barline)"
733
// "(n f3 q)(n f4 q)(barline -)"
735
// "(instrument (name \"pilano\")(abbrev \"P\")(staves 2)(musicData "
736
// "(clef G p1)(clef F4 p2)(key F)(time 12 8)"
737
// "(n c5 e. p1)(barline)"
738
// "(n e4 e p1 (beam 10 +))(n g3 e p2 (beam 10 -))"
739
// "(n e4 e p1 (stem up)(beam 11 +))(n e5 e p1 (stem down)(beam 11 -))(barline)"
740
// "(n e4 s p1 (beam 12 ++))(n f4 s p1 (beam 12 ==))"
741
// "(n g4 s p1 (beam 12 ==))(n a4 s p1 (beam 12 --))"
742
// "(n c5 q p1)(barline)"
743
//// "(chord (n c4 q p1)(n e4 q p1)(n g4 q p1))"
744
//// "(chord (n c4 q p1)(n d4 q p1)(n g4 q p1))"
748
// //beamed chord. Beam determines stem direction
749
// "(instrument (musicData "
750
// "(clef G)(key C)(time 2 4)"
751
// "(chord (n c5 s (beam 2 begin begin))(n e5 s)(n g5 s))"
752
// "(chord (n c5 s (beam 2 continue continue))(n f5 s)(n a5 s))"
753
// "(chord (n d5 s (beam 2 continue continue))(n g5 s)(n b5 s))"
754
// "(chord (n g4 s (beam 2 end end))(n e5 s)(n g5 s))"
759
// "(instrument (musicData "
760
// "(clef G)(key A)(time 2 4)"
761
// "(n c4 e g+ t3/2)(n e4 e)(n d4 e g- t-)"
762
// "(n e5 e g+ t3/2)(n c5 e)(n d5 e g- t-)"
766
// //tuplets-engraving-rule-a-1
767
// "(instrument (musicData "
769
// "(n a4 e g+ t3)(n a4 e)(n a4 e g- t-)"
770
// "(n a4 e g+)(n a4 e g-)"
773
// "(n a4 e g+ t4)(n a4 e)(n a4 e)(n a4 e g- t-)"
778
//tuplets-engraving-rule-d-1
779
// "(instrument (musicData "
781
// "(n e4 h t3)(n e4 h)(n e4 h t-)"
783
// "(n e5 h t3)(n e5 h)(n e5 h t-)"
786
// "(n e4 q t3)(n e4 e t-)"
788
// "(n e5 q t3)(n e5 e t-)"
791
// "(n e4 e g+ t4)(n e4 e g-)"
792
// "(n e4 e g+)(n e4 e g-)"
793
// "(n e4 e g+)(n e4 e g-)"
794
// "(n e4 e g+)(n e4 e g- t-)"
796
// "(n e5 e g+ t4)(n e5 e g-)"
797
// "(n e5 e g+)(n e5 e g-)"
798
// "(n e5 e g+)(n e5 e g-)"
799
// "(n e5 e g+)(n e5 e g- t-)"
805
// //tuplets-engraving-rule-b-1
806
// "(instrument (musicData "
808
// "(n e4 e g+ t3)(n e4 e g-)(r e t-)"
809
// "(r e t3)(n e5 e)(r e t-)"
810
// "(n e5 e t3)(r e)(r e t-)"
811
// "(r e t3)(r e)(n e5 e t-)"
816
"(instrument (musicData "
817
"(clef G)(key C)(time 4 4)"
823
//render the LENMUS_NEW score
824
Refresh(false /* don't erase background */);
827
//---------------------------------------------------------------------------------------
828
void DocumentWindow::get_pages_info(int* pMinPage, int* pMaxPage,
829
int* pSelPageFrom, int* pSelPageTo)
831
//Return the default page range to be printed and the page range the user can
832
//select for printing.
835
GraphicModel* pGModel = m_pInteractor->get_graphic_model();
836
*pMaxPage = pGModel->get_num_pages();
838
*pSelPageTo = *pMaxPage;
841
//---------------------------------------------------------------------------------------
842
void DocumentWindow::do_print(wxDC* pDC, int page, int paperWidthPixels,
843
int paperHeightPixels)
845
pDC->SetBackground(*wxWHITE_BRUSH);
848
//get page size in pixels
849
VSize size = m_pInteractor->get_page_size_in_pixels(page);
850
double vPageWidth( size.width );
851
double vPageHeigh( size.height );
853
//determine view scaling
854
double scaleX = double(paperWidthPixels) / vPageWidth;
855
double scaleY = double(paperHeightPixels) / vPageHeigh;
856
double scale = max(scaleX, scaleY);
858
//determine required buffer size (pixels)
859
float wReq = float(paperWidthPixels);
860
float hReq = float(paperHeightPixels);
862
//determine tile size (pixels)
863
int width = min(1024, paperWidthPixels);
864
int height = min(1024, paperHeightPixels);
866
if (width < 1024 && height < 1024)
869
//From paper viewpoint, for copying a tile into paper, copy origin is
870
//at (B, B) and copy size is (w-2B, h-2B). Initial paper org is at (0,0).
871
//From render viewpoint, initial viewport origin is at (-B, -B) and tiles
872
//size (for advancing viewport origin) is also (w-2B, h-2B).
873
VPoint viewport(0,0);
874
VPoint paperPos(0,0);
875
int tileW = width - 2 * border;
876
int tileH = height - 2 * border;
878
//determine how many tiles to print
879
int rows = int(hReq / float(tileW) + 0.5f);
880
int cols = int(wReq / float(tileH) + 0.5f);
882
//determine last row and last column tile sizes
883
int lastW = paperWidthPixels - tileW * (cols - 1);
884
int lastH = paperHeightPixels - tileH * (rows - 1);
886
//allocate tile buffer
887
RenderingBuffer rbuf_print;
888
wxImage* buffer; //the image to serve as buffer
889
unsigned char* pdata; //ptr to the real bytes buffer
890
#define BYTES_PP 3 // Bytes per pixel
891
buffer = LENMUS_NEW wxImage(width, height); // allocate the rendering buffer
892
int stride = width * BYTES_PP; //number of bytes per row
893
pdata = buffer->GetData();
894
rbuf_print.attach(pdata, width, height, stride);
895
m_pInteractor->set_printing_buffer(&rbuf_print);
897
//loop to print tiles.
899
for (int iRow=0; iRow < rows; ++iRow)
901
for (int iCol=0; iCol < cols; ++iCol)
903
m_pInteractor->on_print_page(page-1, scale, viewport);
906
int tileWidth = (iCol == cols-1 ? lastW : tileW);
907
int tileHeight = (iRow == rows-1 ? lastH : tileH);
910
wxBitmap bitmap = *buffer;
915
memoryDC.SelectObjectAsSource(bitmap);
916
pDC->Blit(paperPos.x, paperPos.y, tileWidth, tileHeight,
917
&memoryDC, border, border);
918
memoryDC.SelectObjectAsSource(wxNullBitmap);
921
pDC->DrawBitmap(bitmap, paperPos.x, paperPos.y, false /* don't use mask */);
924
//to try to save time, instead of blitting, get subimage
925
//Results: it takes the same time and prints a black line at bottom
928
wxRect rect(border, border, tileWidth, tileHeight);
929
wxBitmap bitmap( buffer->GetSubImage(rect) );
931
pDC->DrawBitmap(bitmap, paperPos.x, paperPos.y, false /* don't use mask */);
935
wxBitmap bitmap( *buffer );
937
pDC->DrawBitmap(bitmap, paperPos.x, paperPos.y, false /* don't use mask */);
941
//advance origin by tile size
945
//start LENMUS_NEW row
955
//---------------------------------------------------------------------------------------
956
void DocumentWindow::adjust_scale_and_scrollbars()
958
//wxLogMessage(_T("adjust_scale_and_scrollbars %0x"), this);
960
int zoomMode = get_zoom_mode();
961
if (zoomMode == k_zoom_fit_width)
963
else if (zoomMode == k_zoom_fit_full)
969
//---------------------------------------------------------------------------------------
970
void DocumentWindow::determine_scroll_space_size()
972
//wxLogMessage(_T("determine_scroll_space_size %0x"), this);
974
//total size of the rendered document (whole visual space, all pages)
975
m_pInteractor->get_view_size(&m_xScrollSpaceWidth, &m_yScrollSpaceHeight);
976
m_xMargin = m_xScrollSpaceWidth/40; //2.5% margin, at each side
977
m_yMargin = m_xMargin;
979
//how many pixels per scroll unit?
980
//AWARE: In wxWidgets scrollbars uses scroll units (arbitrary user defined units).
981
//After some experimentation I concluded taht the best approach is to use pixels as
982
//scroll units; otherwise truncation errors create problems. The following variables
983
//are used only to define the increment/decrement when scrolling one line
984
m_xPixelsPerScrollUnit = 8;
985
m_yPixelsPerScrollUnit = 15;
987
//get viewport limits (in pixels)
988
m_xMinViewport = -m_xMargin;
989
m_yMinViewport = -m_yMargin;
992
//---------------------------------------------------------------------------------------
993
void DocumentWindow::adjust_scrollbars()
995
//wxLogMessage(_T("adjust_scrollbars %0x"), this);
997
determine_scroll_space_size();
999
//get size of scroll page (client area size)
1000
m_xScrollPageWidth = m_nBufWidth;
1001
m_yScrollPageHeight = m_nBufHeight;
1003
//get viewport limits (in pixels)
1004
m_xMaxViewport = (m_xScrollSpaceWidth - m_xMargin) - m_xScrollPageWidth;
1005
m_yMaxViewport = (m_yScrollSpaceHeight - m_yMargin) - m_yScrollPageHeight;
1007
//get current viewport position
1008
int xCurPos, yCurPos;
1009
m_pInteractor->get_viewport(&xCurPos, &yCurPos);
1011
//determine thumb size (in scroll units) and position
1012
int xThumbSize = m_xScrollPageWidth;
1013
int xStartThumb = max(0, (m_xMargin + xCurPos));
1014
int yThumbSize = m_yScrollPageHeight;
1015
int yStartThumb = max(0, (m_yMargin + yCurPos));
1017
//scroll space size, in scroll units
1018
m_xMaxScrollUnits = m_xScrollSpaceWidth;
1019
m_yMaxScrollUnits = m_yScrollSpaceHeight;
1022
m_fIgnoreOnSize = true;
1023
SetScrollbar(wxVERTICAL, yStartThumb, yThumbSize, m_yMaxScrollUnits);
1024
SetScrollbar(wxHORIZONTAL, xStartThumb, xThumbSize, m_xMaxScrollUnits);
1025
m_fIgnoreOnSize = false;
1028
//---------------------------------------------------------------------------------------
1029
void DocumentWindow::on_scroll(wxScrollWinEvent& event)
1031
//wxLogMessage(_T("on_scroll %0x"), this);
1034
m_pInteractor->get_viewport(&xPos, &yPos);
1036
wxEventType type = event.GetEventType();
1038
if (event.GetOrientation() == wxVERTICAL)
1040
if (type == wxEVT_SCROLLWIN_TOP)
1041
yPos = m_yMinViewport;
1042
else if (type == wxEVT_SCROLLWIN_BOTTOM)
1043
yPos = m_yMaxViewport;
1044
else if (type == wxEVT_SCROLLWIN_LINEUP)
1045
yPos -= m_yPixelsPerScrollUnit;
1046
else if (type == wxEVT_SCROLLWIN_LINEDOWN)
1047
yPos += m_yPixelsPerScrollUnit;
1048
else if (type == wxEVT_SCROLLWIN_PAGEUP)
1049
yPos -= m_yScrollPageHeight;
1050
else if (type == wxEVT_SCROLLWIN_PAGEDOWN)
1051
yPos += m_yScrollPageHeight;
1052
else if (type == wxEVT_SCROLLWIN_THUMBTRACK
1053
|| type == wxEVT_SCROLLWIN_THUMBRELEASE)
1055
yPos = event.GetPosition() - m_yMargin;
1058
#if (LENMUS_PLATFORM_WIN32 == 1) //---------------------------------------------
1060
//In Windows, up/down buttons remain enabled even when reaching top/bottom
1061
if (yPos < m_yMinViewport)
1062
yPos = m_yMinViewport;
1063
else if (yPos > m_yMaxViewport)
1064
yPos = m_yMaxViewport;
1066
//in Windows the scroll thumb remains at top, so we have to
1067
//reposition it manually
1068
if (type != wxEVT_SCROLLWIN_THUMBTRACK)
1069
SetScrollPos(wxVERTICAL, m_yMargin + yPos);
1071
#endif //-----------------------------------------------------------------------
1073
m_pInteractor->new_viewport(xPos, yPos);
1074
m_pInteractor->force_redraw();
1079
if (type == wxEVT_SCROLLWIN_TOP)
1080
xPos = m_xMinViewport;
1081
else if (type == wxEVT_SCROLLWIN_BOTTOM)
1082
xPos = m_xMaxViewport;
1083
else if (type == wxEVT_SCROLLWIN_LINEUP)
1084
xPos -= m_xPixelsPerScrollUnit;
1085
else if (type == wxEVT_SCROLLWIN_LINEDOWN)
1086
xPos += m_xPixelsPerScrollUnit;
1087
else if (type == wxEVT_SCROLLWIN_PAGEUP)
1088
xPos -= m_xScrollPageWidth;
1089
else if (type == wxEVT_SCROLLWIN_PAGEDOWN)
1090
xPos += m_xScrollPageWidth;
1091
else if (type == wxEVT_SCROLLWIN_THUMBTRACK
1092
|| type == wxEVT_SCROLLWIN_THUMBRELEASE)
1094
xPos = event.GetPosition() - m_xMargin;
1097
#if (LENMUS_PLATFORM_WIN32 == 1) //---------------------------------------------
1099
//In Windows, up/down buttons remain enabled even when reaching top/bottom
1100
if (xPos < m_xMinViewport)
1101
xPos = m_xMinViewport;
1102
else if (xPos > m_xMaxViewport)
1103
xPos = m_xMaxViewport;
1105
//in Windows the scroll thumb remains at top, so we have to
1106
//reposition it manually
1107
if (type != wxEVT_SCROLLWIN_THUMBTRACK)
1108
SetScrollPos(wxHORIZONTAL, m_xMargin + xPos);
1110
#endif //-----------------------------------------------------------------------
1112
m_pInteractor->new_viewport(xPos, yPos);
1113
m_pInteractor->force_redraw();
1116
event.Skip(false); //do not propagate event
1119
//---------------------------------------------------------------------------------------
1120
void DocumentWindow::scroll_line(bool fUp)
1123
m_pInteractor->get_viewport(&xPos, &yPos);
1125
yPos -= m_yPixelsPerScrollUnit;
1127
yPos += m_yPixelsPerScrollUnit;
1129
#if (LENMUS_PLATFORM_WIN32 == 1) //---------------------------------------------
1131
//In Windows, up/down buttons remain enabled even when reaching top/bottom
1132
if (yPos < m_yMinViewport)
1133
yPos = m_yMinViewport;
1134
else if (yPos > m_yMaxViewport)
1135
yPos = m_yMaxViewport;
1137
#endif //-----------------------------------------------------------------------
1139
m_pInteractor->new_viewport(xPos, yPos);
1140
m_pInteractor->force_redraw();
1143
//---------------------------------------------------------------------------------------
1144
void DocumentWindow::debug_display_ldp_source()
1146
LdpExporter exporter;
1147
string source = exporter.get_source( m_pDoc->get_imodoc() );
1148
DlgDebug dlg(this, _T("Generated source code"), to_wx_string(source));
1152
//---------------------------------------------------------------------------------------
1153
void DocumentWindow::debug_display_lmd_source()
1155
LmdExporter exporter;
1156
exporter.set_score_format(LmdExporter::k_format_lmd);
1157
string source = exporter.get_source( m_pDoc->get_imodoc() );
1158
DlgDebug dlg(this, _T("Generated source code"), to_wx_string(source));
1163
} //namespace lenmus