lenmus / lomse

A C++ library for rendering, editing and playing back music scores.
MIT License
117 stars 28 forks source link

Positioning the viewport at start of a system #380

Closed cecilios closed 1 year ago

cecilios commented 1 year ago

@npiegdon In discussion #377 it was mentioned the posibility of positioning the vierport at start of a system using system number.

Currently, all methods related to the viewport uses physical units (pixels), e.g. to move the viewport:

Interactor::new_viewport(Pixels x, Pixels y, bool fForceRedraw=true)

When it was decided to use pixels instead of logical units, the point was that the viewport management was mainly related to scrolling.

Deciding the shift amount for an scroll operation once the window width/heigh is known, is just deciding how many scroll steps are convenient for a smooth and fast enough scrolling of a whole window, and dividing the window width/heigh by the chosen number of steps. As applications normally use physical units (pixels) for managing the window (e.g. mouse click points, window size) it was considered simpler and more convenient to manage the viewport also in physical units (pixels). Thus, in current API all methods related to the viewports use pixels. Also, methods related to this, such as determining the total width/heigh of the View for properly positioning scrollbars and their sizes, also provides measurements in pixels, e.g.:

Interactor::get_view_size(Pixels* xWidth, Pixels* yHeight)

After studying the possibility of using logical coordinates as an option, a simple way would be by converting logical units to pixels before invoking viewport related methods, e.g. by using:

void Interactor::model_point_to_device(double* x, double* y, int iPage)
UPoint Interactor::screen_point_to_model_point(Pixels x, Pixels y)

For instance, to position the viewport at start of system iSystem:

GraphicModel* pGM = pInteractor->get_graphic_model();
GmoBoxSystem* pBoxSystem = pGM->get_system_box(iSystem);    //iSystem=0..n-1
LUnits yPos = pBoxSystem->get_origin().y;   //LUnits are relative to page origin
double x(0.0);      //x = 0, place viewport at paper left border
double y(yPos);     //place the viewport at system top. Perhpas some margin should be added
int iPage = 0;      //FreeFlowView only has one page, iPage=0
pInteractor->model_point_to_device(&x, &y, iPage);
pInteractor->new_viewport(Pixels(x), Pixels(y));   

The gain in creating a new method is minimal, just one additional invokation to lomse, but as the API is oriented to pixes surely some other methods that currently use pixels will have to be duplicated. Therefore, it seems more convenient not to duplicate methods and keep the API in pixels, since the cost for those who want to use logical units is only one additional call to perform the units conversion.

Let me know if this is acceptable and solves your needs.

npiegdon commented 1 year ago

Yeah, this looks good. I'm happy using either coordinate system, whichever is most convenient and makes the most sense for the library.

Regarding //iSystem=0..n-1, how would I find out the value of n?

cecilios commented 1 year ago

Regarding //iSystem=0..n-1, how would I find out the value of n?

I have added a new method for this. Please see PR #381

cecilios commented 1 year ago

I am closing this issue as it appears to be resolved. If you believe things are still unresolved please let me know and I can reopen if needed.