# include "selfdrive/ui/qt/body.h"
# include <cmath>
# include <algorithm>
# include <QPainter>
BodyWindow : : BodyWindow ( QWidget * parent ) : fuel_filter ( 1.0 , 5. , 1. / UI_FREQ ) , QLabel ( parent ) {
awake = new QMovie ( " ../assets/body/awake.gif " ) ;
awake - > setCacheMode ( QMovie : : CacheAll ) ;
sleep = new QMovie ( " ../assets/body/sleep.gif " ) ;
sleep - > setCacheMode ( QMovie : : CacheAll ) ;
QPalette p ( Qt : : black ) ;
setPalette ( p ) ;
setAutoFillBackground ( true ) ;
setAlignment ( Qt : : AlignCenter ) ;
setAttribute ( Qt : : WA_TransparentForMouseEvents , true ) ;
QObject : : connect ( uiState ( ) , & UIState : : uiUpdate , this , & BodyWindow : : updateState ) ;
}
void BodyWindow : : paintEvent ( QPaintEvent * event ) {
QLabel : : paintEvent ( event ) ;
QPainter p ( this ) ;
p . setRenderHint ( QPainter : : Antialiasing ) ;
p . translate ( width ( ) - 136 , 16 ) ;
// battery outline + detail
const QColor gray = QColor ( " #737373 " ) ;
p . setBrush ( Qt : : NoBrush ) ;
p . setPen ( QPen ( gray , 4 , Qt : : SolidLine , Qt : : RoundCap , Qt : : RoundJoin ) ) ;
p . drawRoundedRect ( 2 , 2 , 78 , 36 , 8 , 8 ) ;
p . setPen ( Qt : : NoPen ) ;
p . setBrush ( gray ) ;
p . drawRoundedRect ( 84 , 12 , 6 , 16 , 4 , 4 ) ;
p . drawRect ( 84 , 12 , 3 , 16 ) ;
// battery level
double fuel = std : : clamp ( fuel_filter . x ( ) , 0.2f , 1.0f ) ;
const int m = 5 ; // manual margin since we can't do an inner border
p . setPen ( Qt : : NoPen ) ;
p . setBrush ( fuel > 0.25 ? QColor ( " #32D74B " ) : QColor ( " #FF453A " ) ) ;
p . drawRoundedRect ( 2 + m , 2 + m , ( 78 - 2 * m ) * fuel , 36 - 2 * m , 4 , 4 ) ;
// charging status
if ( charging ) {
p . setPen ( Qt : : NoPen ) ;
p . setBrush ( Qt : : white ) ;
const QPolygonF charger ( {
QPointF ( 12.31 , 0 ) ,
QPointF ( 12.31 , 16.92 ) ,
QPointF ( 18.46 , 16.92 ) ,
QPointF ( 6.15 , 40 ) ,
QPointF ( 6.15 , 23.08 ) ,
QPointF ( 0 , 23.08 ) ,
} ) ;
p . drawPolygon ( charger . translated ( 98 , 0 ) ) ;
}
}
void BodyWindow : : updateState ( const UIState & s ) {
if ( ! isVisible ( ) ) {
return ;
}
const SubMaster & sm = * ( s . sm ) ;
auto cs = sm [ " carState " ] . getCarState ( ) ;
charging = cs . getCharging ( ) ;
fuel_filter . update ( cs . getFuelGauge ( ) ) ;
// TODO: use carState.standstill when that's fixed
const bool standstill = std : : abs ( cs . getVEgo ( ) ) < 0.01 ;
QMovie * m = standstill ? sleep : awake ;
if ( m ! = movie ( ) ) {
setMovie ( m ) ;
movie ( ) - > start ( ) ;
}
update ( ) ;
}