@@ -175,11 +175,62 @@ void OnroadAlerts::paintEvent(QPaintEvent *event) {
175
175
}
176
176
177
177
178
+ ExperimentalButton::ExperimentalButton (QWidget *parent) : QPushButton(parent) {
179
+ setVisible (false );
180
+ setFixedSize (btn_size, btn_size);
181
+ setCheckable (true );
182
+
183
+ params = Params ();
184
+ engage_img = loadPixmap (" ../assets/img_chffr_wheel.png" , {img_size, img_size});
185
+ experimental_img = loadPixmap (" ../assets/img_experimental.svg" , {img_size, img_size});
186
+
187
+ QObject::connect (this , &QPushButton::toggled, [=](bool checked) {
188
+ params.putBool (" ExperimentalMode" , checked);
189
+ });
190
+ }
191
+
192
+ void ExperimentalButton::updateState (const UIState &s) {
193
+ const SubMaster &sm = *(s.sm );
194
+
195
+ // button is "visible" if engageable or enabled
196
+ const auto cs = sm[" controlsState" ].getControlsState ();
197
+ setVisible (cs.getEngageable () || cs.getEnabled ());
198
+
199
+ // button is "checked" if experimental mode is enabled
200
+ setChecked (sm[" controlsState" ].getControlsState ().getExperimentalMode ());
201
+
202
+ // disable button when experimental mode is not available, or has not been confirmed for the first time
203
+ const auto cp = sm[" carParams" ].getCarParams ();
204
+ const bool experimental_mode_available = cp.getExperimentalLongitudinalAvailable () ? params.getBool (" ExperimentalLongitudinalEnabled" ) : cp.getOpenpilotLongitudinalControl ();
205
+ setEnabled (params.getBool (" ExperimentalModeConfirmed" ) && experimental_mode_available);
206
+ }
207
+
208
+ void ExperimentalButton::paintEvent (QPaintEvent *event) {
209
+ QPainter p (this );
210
+ p.setRenderHint (QPainter::Antialiasing);
211
+
212
+ QPoint center (btn_size / 2 , btn_size / 2 );
213
+ QPixmap img = isChecked () ? experimental_img : engage_img;
214
+
215
+ p.setOpacity (1.0 );
216
+ p.setPen (Qt::NoPen);
217
+ p.setBrush (QColor (0 , 0 , 0 , 166 ));
218
+ p.drawEllipse (center, btn_size / 2 , btn_size / 2 );
219
+ p.setOpacity (isDown () ? 0.8 : 1.0 );
220
+ p.drawPixmap ((btn_size - img_size) / 2 , (btn_size - img_size) / 2 , img);
221
+ }
222
+
223
+
178
224
AnnotatedCameraWidget::AnnotatedCameraWidget (VisionStreamType type, QWidget* parent) : fps_filter(UI_FREQ, 3 , 1 . / UI_FREQ), CameraWidget(" camerad" , type, true , parent) {
179
225
pm = std::make_unique<PubMaster, const std::initializer_list<const char *>>({" uiDebug" });
180
226
181
- engage_img = loadPixmap (" ../assets/img_chffr_wheel.png" , {img_size, img_size});
182
- experimental_img = loadPixmap (" ../assets/img_experimental.svg" , {img_size - 5 , img_size - 5 });
227
+ QVBoxLayout *main_layout = new QVBoxLayout (this );
228
+ main_layout->setMargin (bdr_s);
229
+ main_layout->setSpacing (0 );
230
+
231
+ experimental_btn = new ExperimentalButton (this );
232
+ main_layout->addWidget (experimental_btn, 0 , Qt::AlignTop | Qt::AlignRight);
233
+
183
234
dm_img = loadPixmap (" ../assets/img_driver_face.png" , {img_size, img_size});
184
235
}
185
236
@@ -227,9 +278,11 @@ void AnnotatedCameraWidget::updateState(const UIState &s) {
227
278
setProperty (" hideDM" , cs.getAlertSize () != cereal::ControlsState::AlertSize::NONE);
228
279
setProperty (" status" , s.status );
229
280
230
- // update engageability and DM icons at 2Hz
281
+ // update engageability/experimental mode button
282
+ experimental_btn->updateState (s);
283
+
284
+ // update DM icons at 2Hz
231
285
if (sm.frame % (UI_FREQ / 2 ) == 0 ) {
232
- setProperty (" engageable" , cs.getEngageable () || cs.getEnabled ());
233
286
setProperty (" dmActive" , sm[" driverMonitoringState" ].getDriverMonitoringState ().getIsActiveMode ());
234
287
setProperty (" rightHandDM" , sm[" driverMonitoringState" ].getDriverMonitoringState ().getIsRHD ());
235
288
}
@@ -382,16 +435,9 @@ void AnnotatedCameraWidget::drawHud(QPainter &p) {
382
435
configFont (p, " Inter" , 66 , " Regular" );
383
436
drawText (p, rect ().center ().x (), 290 , speedUnit, 200 );
384
437
385
- // engage-ability icon
386
- if (engageable) {
387
- SubMaster &sm = *(uiState ()->sm );
388
- drawIcon (p, rect ().right () - radius / 2 - bdr_s * 2 , radius / 2 + int (bdr_s * 1.5 ),
389
- sm[" controlsState" ].getControlsState ().getExperimentalMode () ? experimental_img : engage_img, blackColor (166 ), 1.0 );
390
- }
391
-
392
438
// dm icon
393
439
if (!hideDM) {
394
- int dm_icon_x = rightHandDM ? rect ().right () - radius / 2 - (bdr_s * 2 ) : radius / 2 + (bdr_s * 2 );
440
+ int dm_icon_x = rightHandDM ? rect ().right () - btn_size / 2 - (bdr_s * 2 ) : btn_size / 2 + (bdr_s * 2 );
395
441
drawIcon (p, dm_icon_x, rect ().bottom () - footer_h / 2 ,
396
442
dm_img, blackColor (70 ), dmActive ? 1.0 : 0.2 );
397
443
}
@@ -414,7 +460,7 @@ void AnnotatedCameraWidget::drawIcon(QPainter &p, int x, int y, QPixmap &img, QB
414
460
p.setOpacity (1.0 ); // bg dictates opacity of ellipse
415
461
p.setPen (Qt::NoPen);
416
462
p.setBrush (bg);
417
- p.drawEllipse (x - radius / 2 , y - radius / 2 , radius, radius );
463
+ p.drawEllipse (x - btn_size / 2 , y - btn_size / 2 , btn_size, btn_size );
418
464
p.setOpacity (opacity);
419
465
p.drawPixmap (x - img.size ().width () / 2 , y - img.size ().height () / 2 , img);
420
466
}
0 commit comments