@ -190,20 +190,26 @@ MessageDelegate::Layout MessageDelegate::calcLayout(
L . isVoice = ( contentType = = " audio/opus " ) ;
if ( L . isVoice ) {
L . voiceDuration = index . data ( MsgVoiceDurationRole ) . toString ( ) ;
QFontMetrics fm ( option . font ) ;
int lineH = fm . lineSpacing ( ) ;
L . totalHeight = qMax ( lineH * 2 + kGap * 2 , kAvatar ) + kItemGap ;
L . bubbleWidth = 160 ;
int pbs = 16 ; // play button size
int wh = 25 ; // waveform height
int th = 14 ; // text line height
L . bubbleWidth = 220 ;
int bubbleH = kPadTop + wh + 4 + th + kPadBot ;
L . totalHeight = qMax ( bubbleH , kAvatar ) + kItemGap ;
int contentEdge = L . isOutgoing
? L . viewWidth - ( L . narrow ? kMarginH : ( kMarginH + kAvatar + kGap ) )
: ( L . narrow ? kMarginH : ( kMarginH + kAvatar + kGap ) ) ;
if ( ! L . isOutgoing )
L . bubbleRect = QRect ( contentEdge , 0 , L . bubbleWidth , L . totalHeight - kItemGap ) ;
else
L . bubbleRect = QRect ( contentEdge - L . bubbleWidth , 0 , L . bubbleWidth , L . totalHeight - kItemGap ) ;
L . voicePlayBtnRect = QRect ( L . bubbleRect . left ( ) + kPadH , L . bubbleRect . top ( ) + kPadTop + 4 , 28 , 28 ) ;
L . voiceDurationRect = QRect ( L . bubbleRect . left ( ) + kPadH + 36 , L . bubbleRect . top ( ) + kPadTop + 4 ,
L . bubbleWidth - kPadH * 2 - 36 , 28 ) ;
int bx = L . isOutgoing ? ( contentEdge - L . bubbleWidth ) : contentEdge ;
L . bubbleRect = QRect ( bx , 0 , L . bubbleWidth , bubbleH ) ;
L . voicePlayBtnRect = QRect ( bx + kPadH , kPadTop + 4 , pbs , pbs ) ;
int wx = bx + kPadH + pbs + 4 ;
int ww = L . bubbleWidth - 2 * kPadH - pbs - 4 ;
L . voiceWaveformRect = QRect ( wx , kPadTop + 1 , ww , wh ) ;
L . voiceDurationRect = QRect ( wx , kPadTop + wh + 4 , ww - 40 , th ) ;
L . voiceTimeRect = QRect ( wx + ww - 40 , kPadTop + wh + 4 , 40 , th ) ;
if ( ! L . narrow ) {
int avatarY = L . bubbleRect . bottom ( ) - kAvatar ;
if ( ! L . isOutgoing )
@ -611,14 +617,25 @@ void MessageDelegate::paint(QPainter *painter, const QStyleOptionViewItem &optio
bool isPlaying = st . playing ;
bool isPaused = st . paused ;
/* compute elapsed/frac for progress */
float elapsed = 0 , frac = 0 , durSec = st . durationSec ;
if ( isPaused ) {
elapsed = st . pausedPosSec ;
} else if ( isPlaying ) {
qint64 now = QDateTime : : currentMSecsSinceEpoch ( ) ;
elapsed = ( now - st . startMs ) / 1000.0f ;
if ( elapsed > durSec ) elapsed = durSec ;
}
if ( durSec > 0 ) frac = elapsed / durSec ;
if ( frac < 0 ) frac = 0 ; if ( frac > 1 ) frac = 1 ;
QRectF playR = L . voicePlayBtnRect ;
/* Play/Pause button */
/* Play/Pause icon (small — 10px triangle) */
painter - > setPen ( Qt : : NoPen ) ;
painter - > setBrush ( QColor ( 0x33 , 0x90 , 0xEC ) ) ;
if ( isPlaying | | isPaused ) {
/* Pause icon (two vertical bars) */
qreal bw = playR . width ( ) / 5.0 ;
qreal gap = playR . width ( ) / 8.0 ;
qreal top = playR . center ( ) . y ( ) - playR . height ( ) / 3.0 ;
@ -626,66 +643,63 @@ void MessageDelegate::paint(QPainter *painter, const QStyleOptionViewItem &optio
painter - > drawRoundedRect ( QRectF ( playR . center ( ) . x ( ) - gap - bw , top , bw , bot - top ) , 1 , 1 ) ;
painter - > drawRoundedRect ( QRectF ( playR . center ( ) . x ( ) + gap , top , bw , bot - top ) , 1 , 1 ) ;
} else {
/* Play icon (triangle) */
QPainterPath playPath ;
QPainterPath path ;
qreal cx = playR . center ( ) . x ( ) - playR . width ( ) / 6.0 ;
qreal cy = playR . center ( ) . y ( ) ;
qreal hs = playR . height ( ) / 2.5 ;
playPath . moveTo ( cx , cy - hs ) ;
playPath . lineTo ( cx + hs * 1.5 , cy ) ;
playPath . lineTo ( cx , cy + hs ) ;
playPath . closeSubpath ( ) ;
painter - > drawPath ( playPath ) ;
}
/* Duration text */
painter - > setPen ( option . palette . text ( ) . color ( ) ) ;
painter - > setFont ( option . font ) ;
if ( ! L . voiceDuration . isEmpty ( ) )
painter - > drawText ( L . voiceDurationRect , Qt : : AlignLeft | Qt : : AlignVCenter , L . voiceDuration ) ;
/* Progress bar */
int pbLeft = L . bubbleRect . left ( ) + kPadH ;
int pbWidth = L . bubbleWidth - 2 * kPadH ;
int pbTop = L . voicePlayBtnRect . bottom ( ) + 6 ;
int pbHeight = 3 ;
if ( ( isPlaying | | isPaused ) & & st . durationSec > 0 ) {
float elapsed ;
if ( isPaused ) {
elapsed = st . pausedPosSec ;
} else {
qint64 now = QDateTime : : currentMSecsSinceEpoch ( ) ;
elapsed = ( now - st . startMs ) / 1000.0f ;
if ( elapsed > st . durationSec ) elapsed = st . durationSec ;
}
float frac = elapsed / st . durationSec ;
painter - > setPen ( Qt : : NoPen ) ;
painter - > setBrush ( QColor ( 0x33 , 0x90 , 0xEC , 60 ) ) ;
painter - > drawRoundedRect ( QRect ( pbLeft , pbTop , pbWidth , pbHeight ) , 2 , 2 ) ;
path . moveTo ( cx , cy - hs ) ;
path . lineTo ( cx + hs * 1.5 , cy ) ;
path . lineTo ( cx , cy + hs ) ;
path . closeSubpath ( ) ;
painter - > drawPath ( path ) ;
}
/* Waveform (25px) */
QList < QVariant > wf = index . data ( MsgVoiceWaveformRole ) . toList ( ) ;
int wfN = wf . size ( ) ;
QRect wfR = L . voiceWaveformRect ;
if ( wfN > 0 ) {
float barW = ( float ) wfR . width ( ) / wfN ;
int ph = wfR . height ( ) - 3 ; /* leave 3px for progress bar at bottom */
for ( int i = 0 ; i < wfN ; i + + ) {
float v = wf [ i ] . toFloat ( ) ;
int barH = 1 + ( int ) ( v * ( ph - 1 ) ) ;
int x = wfR . left ( ) + ( int ) ( i * barW ) ;
int y = wfR . top ( ) + ph - barH ;
int bw = qMax ( 2 , ( int ) ( barW * 0.8f ) ) ;
bool before = wfN > 0 & & ( float ) i / wfN < = frac ;
painter - > setBrush ( before ? QColor ( 0x33 , 0x90 , 0xEC ) : QColor ( 0x33 , 0x90 , 0xEC , 45 ) ) ;
painter - > drawRect ( QRect ( x , y , bw , barH ) ) ;
}
}
/* Progress bar (3px, at bottom of waveform area) */
int ph = 3 ;
int pbY = wfR . bottom ( ) - ph ;
painter - > setBrush ( QColor ( 0x44 , 0x44 , 0x44 ) ) ;
painter - > drawRoundedRect ( QRect ( wfR . left ( ) , pbY , wfR . width ( ) , ph ) , 2 , 2 ) ;
if ( frac > 0 ) {
painter - > setBrush ( QColor ( 0x33 , 0x90 , 0xEC ) ) ;
painter - > drawRoundedRect ( QRect ( pbLeft , pbTop , ( int ) ( pbWidth * frac ) , pbHeight ) , 2 , 2 ) ;
/* Position text */
QFont timeFont = option . font ;
timeFont . setPointSize ( timeFont . pointSize ( ) - 2 ) ;
painter - > setFont ( timeFont ) ;
painter - > setPen ( option . palette . text ( ) . color ( ) . lighter ( 150 ) ) ;
int secs = ( int ) elapsed ;
QString posStr = QString ( " %1:%2 " ) . arg ( secs / 60 ) . arg ( secs % 60 , 2 , 10 , QChar ( ' 0 ' ) ) ;
QRect posR ( pbLeft , pbTop + 4 , pbWidth / 2 , 14 ) ;
painter - > drawText ( posR , Qt : : AlignLeft | Qt : : AlignVCenter , posStr ) ;
painter - > drawRoundedRect ( QRect ( wfR . left ( ) , pbY , ( int ) ( wfR . width ( ) * frac ) , ph ) , 2 , 2 ) ;
}
/* Tim e */
/* Duration + elapsed on bottom line */
QFont timeFont = option . font ;
timeFont . setPointSize ( timeFont . pointSize ( ) - 1 ) ;
timeFont . setPointSize ( timeFont . pointSize ( ) - 2 ) ;
painter - > setFont ( timeFont ) ;
painter - > setPen ( option . palette . text ( ) . color ( ) . lighter ( 150 ) ) ;
QString timeStr = index . data ( MsgTimeRole ) . toString ( ) ;
QRect timeR = QRect ( L . bubbleRect . right ( ) - kPadH - 50 , pbTop + 4 , 50 , 16 ) ;
painter - > drawText ( timeR , Qt : : AlignRight | Qt : : AlignVCenter , timeStr ) ;
int eSec = ( int ) elapsed , dSec = ( int ) durSec ;
QString durText = QString ( " %1:%2 / %3:%4 " )
. arg ( eSec / 60 ) . arg ( eSec % 60 , 2 , 10 , QChar ( ' 0 ' ) )
. arg ( dSec / 60 ) . arg ( dSec % 60 , 2 , 10 , QChar ( ' 0 ' ) ) ;
painter - > drawText ( L . voiceDurationRect , Qt : : AlignLeft | Qt : : AlignVCenter , durText ) ;
/* Timestamp */
QFont tsFont = option . font ;
tsFont . setPointSize ( tsFont . pointSize ( ) - 1 ) ;
painter - > setFont ( tsFont ) ;
painter - > drawText ( L . voiceTimeRect , Qt : : AlignRight | Qt : : AlignVCenter ,
index . data ( MsgTimeRole ) . toString ( ) ) ;
painter - > restore ( ) ;
return ;