2017-04-27 18:30:36 +00:00
// SPDX-License-Identifier: GPL-2.0
2015-07-17 16:09:42 +00:00
# include "qmlprofile.h"
2018-06-08 10:56:23 +00:00
# include "mobile-widgets/qmlmanager.h"
2019-08-05 17:41:15 +00:00
# include "core/errorhelper.h"
2018-05-11 15:25:41 +00:00
# include "core/subsurface-string.h"
2016-04-05 05:02:03 +00:00
# include "core/metrics.h"
2015-07-25 16:10:51 +00:00
# include <QTransform>
2016-03-09 03:33:19 +00:00
# include <QScreen>
2020-02-17 18:45:28 +00:00
# include <QElapsedTimer>
2015-07-17 16:09:42 +00:00
2020-02-24 14:25:52 +00:00
const double fontScale = 0.6 ; // profile looks less cluttered with smaller font
2015-07-17 16:09:42 +00:00
QMLProfile : : QMLProfile ( QQuickItem * parent ) :
2015-12-29 17:50:47 +00:00
QQuickPaintedItem ( parent ) ,
2016-01-28 15:02:20 +00:00
m_devicePixelRatio ( 1.0 ) ,
2018-05-25 21:30:10 +00:00
m_margin ( 0 ) ,
2020-02-17 18:46:31 +00:00
m_xOffset ( 0.0 ) ,
2021-05-31 19:44:37 +00:00
m_yOffset ( 0.0 )
2015-07-17 16:09:42 +00:00
{
2021-05-31 19:44:37 +00:00
createProfileView ( ) ;
2015-12-29 17:51:34 +00:00
setAntialiasing ( true ) ;
2020-02-17 18:46:31 +00:00
setFlags ( QQuickItem : : ItemClipsChildrenToShape | QQuickItem : : ItemHasContents ) ;
2016-03-09 03:33:19 +00:00
connect ( QMLManager : : instance ( ) , & QMLManager : : sendScreenChanged , this , & QMLProfile : : screenChanged ) ;
2020-03-24 22:02:17 +00:00
connect ( this , & QMLProfile : : scaleChanged , this , & QMLProfile : : triggerUpdate ) ;
2020-12-21 12:42:04 +00:00
connect ( & diveListNotifier , & DiveListNotifier : : divesChanged , this , & QMLProfile : : divesChanged ) ;
2016-03-09 03:33:19 +00:00
setDevicePixelRatio ( QMLManager : : instance ( ) - > lastDevicePixelRatio ( ) ) ;
2015-11-12 00:43:13 +00:00
}
2021-05-31 19:44:37 +00:00
void QMLProfile : : createProfileView ( )
{
2021-05-31 20:29:00 +00:00
m_profileWidget . reset ( new ProfileWidget2 ( nullptr , fontScale * m_devicePixelRatio , nullptr ) ) ;
2021-05-31 19:44:37 +00:00
m_profileWidget - > setProfileState ( nullptr , 0 ) ;
m_profileWidget - > setPrintMode ( true ) ;
}
2020-03-24 22:02:17 +00:00
// we need this so we can connect update() to the scaleChanged() signal - which the connect above cannot do
// directly as it chokes on the default parameter for update().
// If the scale changes we may need to change our offsets to ensure that we still only show a subset of
// the profile and not empty space around it, which the paint() method below will take care of, which will
// eventually get called after we call update()
void QMLProfile : : triggerUpdate ( )
{
update ( ) ;
}
2015-07-17 16:09:42 +00:00
void QMLProfile : : paint ( QPainter * painter )
{
2020-02-17 18:45:28 +00:00
QElapsedTimer timer ;
if ( verbose )
timer . start ( ) ;
2016-01-18 20:32:47 +00:00
// let's look at the intended size of the content and scale our scene accordingly
2016-03-09 03:38:03 +00:00
QRect painterRect = painter - > viewport ( ) ;
QRect profileRect = m_profileWidget - > viewport ( ) - > rect ( ) ;
2016-03-11 02:02:36 +00:00
// qDebug() << "profile viewport and painter viewport" << profileRect << painterRect;
2016-01-18 20:32:47 +00:00
qreal sceneSize = 104 ; // that should give us 2% margin all around (100x100 scene)
2016-03-09 03:38:03 +00:00
qreal dprComp = devicePixelRatio ( ) * painterRect . width ( ) / profileRect . width ( ) ;
qreal sx = painterRect . width ( ) / sceneSize / dprComp ;
qreal sy = painterRect . height ( ) / sceneSize / dprComp ;
// next figure out the weird magic by which we need to shift the painter so the profile is shown
2017-04-03 19:49:14 +00:00
double dpr = devicePixelRatio ( ) ;
double magicValues [ ] = { 0.0 , 0.1 , 0.25 , 0.33 , 0.375 , 0.40 , 0.42 } ;
qreal magicShiftFactor = 0.0 ;
2017-04-16 15:26:40 +00:00
if ( dpr < 1.3 ) {
2017-04-03 19:49:14 +00:00
magicShiftFactor = magicValues [ 0 ] ;
} else if ( dpr > 6.0 ) {
magicShiftFactor = magicValues [ 6 ] ;
} else if ( IS_FP_SAME ( dpr , rint ( dpr ) ) ) {
magicShiftFactor = magicValues [ lrint ( dpr ) ] ;
} else {
int lower = ( int ) dpr ;
magicShiftFactor = ( magicValues [ lower ] * ( lower + 1 - dpr ) + magicValues [ lower + 1 ] * ( dpr - lower ) ) ;
2017-04-16 15:26:40 +00:00
if ( dpr < 1.45 )
magicShiftFactor - = 0.03 ;
2017-04-03 19:49:14 +00:00
}
2016-03-09 03:38:03 +00:00
// now set up the transformations scale the profile and
// shift the painter (taking its existing transformation into account)
QTransform profileTransform = QTransform ( ) ;
2016-01-15 21:55:42 +00:00
profileTransform . scale ( sx , sy ) ;
2020-03-24 22:47:00 +00:00
// this is a bit complex because of the interaction with the Qt widget scaling
// logic. We use the default setup where the scale happens with the center of the
// widget as transformation center.
// The QML code *should* already ensure that we don't shrink the profile, but for
// the math below to work, let's make sure
qreal profileScale = scale ( ) ;
if ( profileScale < 1.0 ) {
profileScale = 1.0 ;
setScale ( profileScale ) ;
}
// When zooming and panning we want to ensure that we always show a subset of the
// profile and not the "empty space" around the profile.
// a bit of math on a piece of paper shows that our offsets need to stay within +/- dx and dy
qreal dx = width ( ) * ( profileScale - 1 ) / ( 2 * dpr * profileScale ) ;
qreal dy = height ( ) * ( profileScale - 1 ) / ( 2 * dpr * profileScale ) ;
m_xOffset = std : : max ( - dx , std : : min ( m_xOffset , dx ) ) ;
m_yOffset = std : : max ( - dy , std : : min ( m_yOffset , dy ) ) ;
2016-03-09 03:38:03 +00:00
QTransform painterTransform = painter - > transform ( ) ;
2020-02-17 18:46:31 +00:00
painterTransform . translate ( dpr * m_xOffset - painterRect . width ( ) * magicShiftFactor , dpr * m_yOffset - painterRect . height ( ) * magicShiftFactor ) ;
2016-03-09 03:38:03 +00:00
2017-06-06 06:22:19 +00:00
# if defined(PROFILE_SCALING_DEBUG)
2016-03-09 03:38:03 +00:00
// some debugging messages to help adjust this in case the magic above is insufficient
2017-06-06 06:22:19 +00:00
qDebug ( ) < < QString ( " dpr %1 profile viewport %2 %3 painter viewport %4 %5 " ) . arg ( dpr ) . arg ( profileRect . width ( ) ) . arg ( profileRect . height ( ) )
. arg ( painterRect . width ( ) ) . arg ( painterRect . height ( ) ) ;
qDebug ( ) < < QString ( " profile matrix %1 %2 %3 %4 %5 %6 %7 %8 %9 " ) . arg ( profileTransform . m11 ( ) ) . arg ( profileTransform . m12 ( ) ) . arg ( profileTransform . m13 ( ) )
. arg ( profileTransform . m21 ( ) ) . arg ( profileTransform . m22 ( ) ) . arg ( profileTransform . m23 ( ) )
. arg ( profileTransform . m31 ( ) ) . arg ( profileTransform . m32 ( ) ) . arg ( profileTransform . m33 ( ) ) ) ;
qDebug ( ) < < QString ( " painter matrix %1 %2 %3 %4 %5 %6 %7 %8 %9 " ) . arg ( painterTransform . m11 ( ) ) . arg ( painterTransform . m12 ( ) ) . arg ( painterTransform . m13 ( ) )
. arg ( painterTransform . m21 ( ) ) . arg ( painterTransform . m22 ( ) ) . arg ( painterTransform . m23 ( ) )
. arg ( painterTransform . m31 ( ) ) . arg ( painterTransform . m32 ( ) ) . arg ( painterTransform . m33 ( ) ) ) ;
2016-03-24 04:22:55 +00:00
qDebug ( ) < < " exist profile transform " < < m_profileWidget - > transform ( ) < < " painter transform " < < painter - > transform ( ) ;
# endif
2016-03-09 03:38:03 +00:00
// apply the transformation
painter - > setTransform ( painterTransform ) ;
2016-01-15 21:55:42 +00:00
m_profileWidget - > setTransform ( profileTransform ) ;
2016-03-09 03:38:03 +00:00
// finally, render the profile
2015-11-12 00:43:13 +00:00
m_profileWidget - > render ( painter ) ;
2020-02-17 18:45:28 +00:00
if ( verbose )
2020-02-17 18:46:31 +00:00
qDebug ( ) < < " finished rendering profile with offset " < < QString : : number ( m_xOffset , ' f ' , 1 ) < < " / " < < QString : : number ( m_yOffset , ' f ' , 1 ) < < " in " < < timer . elapsed ( ) < < " ms " ;
2015-07-17 16:09:42 +00:00
}
2015-12-29 17:50:47 +00:00
void QMLProfile : : setMargin ( int margin )
{
m_margin = margin ;
}
2019-12-23 19:52:41 +00:00
int QMLProfile : : diveId ( ) const
2015-07-17 16:09:42 +00:00
{
return m_diveId ;
}
2020-02-17 18:42:56 +00:00
void QMLProfile : : updateProfile ( )
2015-07-17 16:09:42 +00:00
{
2020-02-17 18:42:56 +00:00
struct dive * d = get_dive_by_uniq_id ( m_diveId ) ;
2015-12-01 23:22:38 +00:00
if ( ! d )
return ;
2017-03-18 22:49:56 +00:00
if ( verbose )
2020-02-17 18:46:31 +00:00
qDebug ( ) < < " update profile for dive # " < < d - > number < < " offeset " < < QString : : number ( m_xOffset , ' f ' , 1 ) < < " / " < < QString : : number ( m_yOffset , ' f ' , 1 ) ;
2021-04-09 20:19:59 +00:00
m_profileWidget - > plotDive ( d , dc_number ) ;
2016-01-13 02:05:06 +00:00
}
2020-02-17 18:42:56 +00:00
void QMLProfile : : setDiveId ( int diveId )
{
m_diveId = diveId ;
if ( m_diveId < 0 )
return ;
updateProfile ( ) ;
}
2016-01-13 02:05:06 +00:00
qreal QMLProfile : : devicePixelRatio ( ) const
{
return m_devicePixelRatio ;
}
void QMLProfile : : setDevicePixelRatio ( qreal dpr )
{
if ( dpr ! = m_devicePixelRatio ) {
m_devicePixelRatio = dpr ;
2021-05-31 19:57:39 +00:00
// Recreate the view to redraw the text items with the new scale.
createProfileView ( ) ;
2016-03-28 21:43:40 +00:00
updateDevicePixelRatio ( dpr ) ;
2016-01-13 02:05:06 +00:00
emit devicePixelRatioChanged ( ) ;
}
2015-07-17 16:09:42 +00:00
}
2016-03-09 03:33:19 +00:00
2020-02-17 18:46:31 +00:00
// don't update the profile here, have the user update x and y and then manually trigger an update
void QMLProfile : : setXOffset ( qreal value )
{
if ( IS_FP_SAME ( value , m_xOffset ) )
return ;
m_xOffset = value ;
emit xOffsetChanged ( ) ;
}
// don't update the profile here, have the user update x and y and then manually trigger an update
void QMLProfile : : setYOffset ( qreal value )
{
if ( IS_FP_SAME ( value , m_yOffset ) )
return ;
m_yOffset = value ;
emit yOffsetChanged ( ) ;
}
2016-03-09 03:33:19 +00:00
void QMLProfile : : screenChanged ( QScreen * screen )
{
setDevicePixelRatio ( screen - > devicePixelRatio ( ) ) ;
}
2020-12-21 12:42:04 +00:00
void QMLProfile : : divesChanged ( const QVector < dive * > & dives , DiveField )
{
for ( struct dive * d : dives ) {
if ( d - > id = = m_diveId ) {
qDebug ( ) < < " dive # " < < d - > number < < " changed, trigger profile update " ;
2021-04-09 20:19:59 +00:00
m_profileWidget - > plotDive ( d , dc_number ) ;
2020-12-21 12:42:04 +00:00
triggerUpdate ( ) ;
return ;
}
}
}