Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement HalfPageView #248

Merged
merged 5 commits into from
Jul 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion add-sources.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ set(MODULE_FILES

set(MVC_FILES
${LOMSE_SRC_DIR}/mvc/lomse_graphic_view.cpp
${LOMSE_SRC_DIR}/mvc/lomse_half_page_view.cpp
${LOMSE_SRC_DIR}/mvc/lomse_interactor.cpp
${LOMSE_SRC_DIR}/mvc/lomse_presenter.cpp
${LOMSE_SRC_DIR}/mvc/lomse_tasks.cpp
Expand All @@ -186,9 +187,9 @@ set(PARSER_FILES
${LOMSE_SRC_DIR}/parser/lmd/lomse_lmd_analyser.cpp
${LOMSE_SRC_DIR}/parser/lmd/lomse_lmd_compiler.cpp

${LOMSE_SRC_DIR}/parser/mxl/lomse_compressed_mxl_compiler.cpp
${LOMSE_SRC_DIR}/parser/mxl/lomse_mxl_analyser.cpp
${LOMSE_SRC_DIR}/parser/mxl/lomse_mxl_compiler.cpp
${LOMSE_SRC_DIR}/parser/mxl/lomse_compressed_mxl_compiler.cpp

${LOMSE_SRC_DIR}/parser/mnx/lomse_mnx_analyser.cpp
${LOMSE_SRC_DIR}/parser/mnx/lomse_mnx_compiler.cpp
Expand Down
7 changes: 6 additions & 1 deletion include/lomse_box_system.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ class GmoBoxSystem : public GmoBox
vector<GmoShapeStaff*> m_staffShapes;
vector<int> m_firstStaff; //index to first staff for each instrument
TimeGridTable* m_pGridTable;
int m_iPage; //number of score page (0..n-1) in which this system is contained
int m_iPage; //index of score page (0..n-1) in which this system is contained
int m_iSystem; //index of this system in the score (0..n-1)

vector<int> m_iFirstMeasure; //index to first measure, per instrument
vector<int> m_nMeasures; //number of measures in this system, per instrument
Expand Down Expand Up @@ -86,6 +87,7 @@ class GmoBoxSystem : public GmoBox
LUnits get_x_for_barline_at_time(TimeUnits timepos);

//miscellaneous info
inline int get_system_number() { return m_iSystem; }
GmoShapeStaff* get_staff_shape(int absStaff);
GmoShapeStaff* get_staff_shape(int iInstr, int iStaff);
int instr_number_for_staff(int absStaff);
Expand Down Expand Up @@ -133,6 +135,9 @@ class GmoBoxSystem : public GmoBox
friend class SystemLayouter;
inline void add_shift_to_start_measure(LUnits width) { m_dxFirstMeasure += width; }

friend class GmoBoxScorePage;
inline void set_system_number(int iSystem) { m_iSystem = iSystem; }


};

Expand Down
8 changes: 5 additions & 3 deletions include/lomse_gm_basic.h
Original file line number Diff line number Diff line change
Expand Up @@ -568,9 +568,10 @@ class GmoBoxDocPageContent : public GmoBox
class GmoBoxScorePage : public GmoBox
{
protected:
int m_iFirstSystem; //0..n-1
int m_iLastSystem; //0..n-1
int m_iPage; //0..n-1 number of this score page
int m_iFirstSystem; //0..n-1
int m_iLastSystem; //0..n-1
int m_iPage; //0..n-1 number of this score-page
LUnits m_maxSystemHeight; //height of highest system in this page

public:
GmoBoxScorePage(ImoScore* pScore);
Expand All @@ -587,6 +588,7 @@ class GmoBoxScorePage : public GmoBox
}
GmoBoxSystem* get_system(int iSystem); //nSystem = 0..n-1
inline int get_page_number() { return m_iPage; }
LUnits get_max_system_height() { return m_maxSystemHeight; }

//timepos information
TimeUnits end_time();
Expand Down
88 changes: 7 additions & 81 deletions include/lomse_graphic_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ enum EViewType {
k_view_single_system,
k_view_single_page,
k_view_free_flow,
k_view_half_page,
};

///@cond INTERNAL
Expand Down Expand Up @@ -214,7 +215,7 @@ class GraphicView : public View
void use_cursor(DocCursor* pCursor);
void use_selection_set(SelectionSet* pSelectionSet);
void add_visual_effect(VisualEffect* pEffect);
void set_visual_effects_for_mode(int mode);
virtual void on_mode_changed(int mode);

///@} //View settings

Expand Down Expand Up @@ -444,7 +445,7 @@ class GraphicView : public View
protected:
GraphicView(LibraryScope& libraryScope, ScreenDrawer* pDrawer);

void draw_all();
virtual void draw_all();
void draw_graphic_model();
void draw_time_grid();
void generate_paths();
Expand All @@ -469,7 +470,8 @@ class GraphicView : public View
void layout_selection_highlight();
void delete_all_handlers();
void add_handler(int iHandler, GmoObj* pOwnerGmo);
void do_change_viewport(Pixels x, Pixels y);
virtual void do_change_viewport(Pixels x, Pixels y);
void set_visual_effects_for_mode(int mode);

//scrolling and tempo line

Expand Down Expand Up @@ -507,8 +509,8 @@ class GraphicView : public View
void do_change_viewport();


void do_move_tempo_line_and_change_viewport(ImoId scoreId, TimeUnits timepos,
bool fTempoLine, bool fViewport);
virtual void do_move_tempo_line_and_change_viewport(ImoId scoreId, TimeUnits timepos,
bool fTempoLine, bool fViewport);

};

Expand Down Expand Up @@ -770,82 +772,6 @@ class LOMSE_EXPORT FreeFlowView : public SinglePageView
};


//---------------------------------------------------------------------------------------
/** %HalfPageView is a GraphicView for rendering scores.

It has a double behaviour. For displayin the score, it behaves as a SinglePageView,
taht is, the score is displayed as ...

But during playback, the behaviour is different. When playback starts,
The window is split horizontally in two halfs, originating two virtual vertical
windows, one at top and the other at bottom. In top window it is displayed the first
score chunk and the second chunk is displayed in the bottom windows. When playback
enters in the bottom window the top windows is updated with the third chunk. Next,
when the playback enters again in top window, the bottom window is updated with the
next chunk, and so on.

- It allows to solve the problem of repetition marks and jumps: when the window being played has a jump, the other window is updated with the next logical system positioned at right measure instead of with the next chunk. The behaviour for the user is simple: when the user finds a jump he/she will know that it is necessary to jump to the other half window, unless the repetition is over and the music should continue from that point.

- But, as other solutions, it is only useful when system height is not big, in this case when it is smaller than half window.

<b>Margins</b>

The document is displayed on a white paper and the view has no margins, that is, the
default view origin point is (0.0, 0.0). Therefore, document content will be
displayed with the margins defined in the document.


<b>Background color</b>

The white paper is surrounded by the background, that will be visible only when the
user application changes the viewport (e.g., by scrolling right).
In %FreeFlowView the default background color is white and, as with all Views,
the background color can be changed by invoking Interactor::set_view_background().


<b>AutoScroll</b>

When this View is used for rendering a music score, during playback auto-scroll
will be, by default, enabled. This implies that as playback advances the View
will generate EventUpdateViewport events so that measure being played is always
totally visible.
*/
class LOMSE_EXPORT HalfPageView : public GraphicView
{
public:
///@cond INTERNALS
//excluded from public API because the View methods are managed from Interactor

HalfPageView(LibraryScope& libraryScope, ScreenDrawer* pDrawer);
virtual ~HalfPageView() {}

// //overrides for SinglePageView
// int get_layout_constrains() override { return k_use_viewport_width | k_infinite_height; }
//
// //overrides for GraphicView
// bool graphic_model_must_be_updated() override;
// void zoom_in(Pixels x=0, Pixels y=0) override;
// void zoom_out(Pixels x=0, Pixels y=0) override;
// void zoom_fit_full(Pixels width, Pixels height) override;
// void zoom_fit_width(Pixels width) override;
// void set_scale(double scale, Pixels x=0, Pixels y=0) override;

int page_at_screen_point(double x, double y) override;
void set_viewport_for_page_fit_full(Pixels screenWidth) override;
void get_view_size(Pixels* xWidth, Pixels* yHeight) override;
int get_layout_constrains() override { return k_use_paper_width | k_infinite_height; }
bool is_valid_for_this_view(Document* UNUSED(pDoc)) override { return true; }

///@endcond

protected:
void collect_page_bounds() override;

};




} //namespace lomse

#endif //__LOMSE_GRAPHIC_VIEW_H__
171 changes: 171 additions & 0 deletions include/lomse_half_page_view.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
//---------------------------------------------------------------------------------------
// This file is part of the Lomse library.
// Lomse is copyrighted work (c) 2010-2020. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice, this
// list of conditions and the following disclaimer in the documentation and/or
// other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
// DAMAGE.
//
// For any comment, suggestion or feature request, please contact the manager of
// the project at [email protected]
//---------------------------------------------------------------------------------------

#ifndef __LOMSE_HALF_PAGE_VIEW_H__
#define __LOMSE_HALF_PAGE_VIEW_H__

#include "lomse_graphic_view.h"


///@cond INTERNAL
namespace lomse
{
///@endcond


//---------------------------------------------------------------------------------------
/** %HalfPageView is a GraphicView for rendering scores.

This view has a double behaviour. In normal mode (no playback) it behaves as
SinglePageView, that is the score is rendered on a single page as high as necessary
to contain all the score (e.g., an HTML page having a body of fixed size).

But when in playback mode, the bitmap to be rendered in the application window is
split horizontally in two halves, originating two virtual vertical windows, one at
top and the other at bottom. In the top window it is displayed the first score chunk
and the second chunk is displayed in the bottom window. When playback enters in the
bottom window the top window is updated with the third chunk. Next, when the playback
enters again in the top window, the bottom window is updated with the next chunk,
and so on.

When playback is finished (because the end of the score is reached or because the
app stops playback  -- but not when playback is paused --) the display returns
automatically to SinglePageView mode.

This view allows to solve the problem page turning and the problem of repetition
marks and jumps: when the window being played has a jump to a system not visible
in that window, the other window is updated with the next logical system (the one
containing the jump destination) instead of with the next system. The behaviour for
the user is very simple: when the end of the last system in current window is reached
or when user finds a jump to a point that is not displayed in current window, he/she
will know that it is necessary to jump to the other half window.

You should note that when the view is split, only full systems are displayed in
the sub-windows. This is to avoid doubts about were the music continues, that could
appear in cases in which next system is practically fully displayed after current
one. It also makes the display more clear.

The view does not enter in split mode in the following cases:
- when window height is smaller than two times the highest system,
- when window width is lower than system width,
- when the score fits completely in the window height, or
- when the document is not only one score
In these cases, playback behaviour will be that of SinglePageView

When the view is in split mode (during playback) all settings for controlling what
to display and how, are fully controlled by the view. Therefore, the user application
should disable all user controls that could invoke methods to do changes, such as
scroll position, zoom factor or other. Invoking these methods will not cause crashes
but will cause unnecessary interference with what is displayed.

*/
class LOMSE_EXPORT HalfPageView : public SinglePageView
{
public:
///@cond INTERNALS
//excluded from public API because the View methods are managed from Interactor

HalfPageView(LibraryScope& libraryScope, ScreenDrawer* pDrawer);
virtual ~HalfPageView() {}

//overrides for SinglePageView
bool is_valid_for_this_view(Document* pDoc) override;

//overrides for GraphicView
void on_mode_changed(int mode) override;
void change_viewport_if_necessary(ImoId id) override;


protected:
//overrides for GraphicView
void draw_all() override;
void do_change_viewport(Pixels x, Pixels y) override;
void do_move_tempo_line_and_change_viewport(ImoId scoreId, TimeUnits timepos,
bool fTempoLine, bool fViewport) override;

//specific internal methods for this view
void compute_buffer_split();
void decide_split_or_normal_view();
void decide_systems_to_display();
void do_draw_all();
void draw_bottom_window();
void draw_separation_line();
void draw_top_window();
void remove_split();
void send_enable_scroll_event(bool enable);
void set_viewport_for_next(int iNextWindow);
void create_systems_jumps_table();
void determine_how_many_systems_fit_and_effective_window_height(int iWindow, int iSys);


protected:
//data to control split mode
bool m_fPlaybackMode; //true during playback (pause also included)
bool m_fSplitMode; //true when the view must be split
ImoScore* m_pScore; //if the document is only one score; otherwise, nullptr

//temporary data: last processed rendering buffer.
//User app. can change the buffer but the view does not receive notifications.
//Therefore, for detecting a buffer change, we need to save this information
unsigned char* m_buf;
unsigned m_bufWidth;
unsigned m_bufHeight;
int m_bufStride;

//temporary data: split buffer parameters
unsigned m_SplitHeight;
unsigned char* m_BottomBuf;
unsigned char* m_TopBuf;
unsigned m_usedHeight[2]; //real used height by sub-window

//temporary data: for controlling real used heigh
LUnits m_winHeight; //total sub-window height
LUnits m_height[2]; //sub-window occupied height
int m_nSys[2]; //number of systems displayed in each sub-window

//temporary data: viewport origin for each sub-window
Pixels m_vxOrgPlay[2], m_vyOrgPlay[2];

//temporary data, to control display while playback
GmoBoxScorePage* m_pBSP; //score-page, to access systems
int m_iPlayWindow; //index (0=top or 1=bottom) to playback window
int m_curSystem; //current system being played (0..n-1)
int m_iSystem; //index on m_systems: next system to display
std::vector<int> m_systems; //indices to systems to play, in playback order


///@endcond
};




} //namespace lomse

#endif //__LOMSE_HALF_PAGE_VIEW_H__
6 changes: 4 additions & 2 deletions include/lomse_injectors.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class HorizontalBookView;
class SingleSystemView;
class SinglePageView;
class FreeFlowView;
class HalfPageView;
class Interactor;
class Presenter;
class LomseDoorway;
Expand Down Expand Up @@ -289,9 +290,10 @@ class Injector
Document* pDoc);
static SingleSystemView* inject_SingleSystemView(LibraryScope& libraryScope,
Document* pDoc);
static SinglePageView* inject_SinglePageView(LibraryScope& libraryScope,
Document* pDoc);
static SinglePageView* inject_SinglePageView(LibraryScope& libraryScope, Document* pDoc);
static FreeFlowView* inject_FreeFlowView(LibraryScope& libraryScope, Document* pDoc);
static HalfPageView* inject_HalfPageView(LibraryScope& libraryScope, Document* pDoc);

static Interactor* inject_Interactor(LibraryScope& libraryScope,
WpDocument wpDoc, View* pView,
DocCommandExecuter* pExec);
Expand Down
Loading