diff --git a/selfdrive/assets/icons/blinkL_off.png b/selfdrive/assets/icons/blinkL_off.png
new file mode 100644
index 0000000000..1a36ecb6a4
Binary files /dev/null and b/selfdrive/assets/icons/blinkL_off.png differ
diff --git a/selfdrive/assets/icons/blinkL_on.png b/selfdrive/assets/icons/blinkL_on.png
new file mode 100644
index 0000000000..437a8e39c5
Binary files /dev/null and b/selfdrive/assets/icons/blinkL_on.png differ
diff --git a/selfdrive/assets/icons/blinkR_off.png b/selfdrive/assets/icons/blinkR_off.png
new file mode 100644
index 0000000000..2cce35764f
Binary files /dev/null and b/selfdrive/assets/icons/blinkR_off.png differ
diff --git a/selfdrive/assets/icons/blinkR_on.png b/selfdrive/assets/icons/blinkR_on.png
new file mode 100644
index 0000000000..d019dcc6d7
Binary files /dev/null and b/selfdrive/assets/icons/blinkR_on.png differ
diff --git a/selfdrive/assets/icons/indicatorC_alert.png b/selfdrive/assets/icons/indicatorC_alert.png
new file mode 100644
index 0000000000..d36f17a558
Binary files /dev/null and b/selfdrive/assets/icons/indicatorC_alert.png differ
diff --git a/selfdrive/assets/icons/indicatorC_off.png b/selfdrive/assets/icons/indicatorC_off.png
new file mode 100644
index 0000000000..4528c62591
Binary files /dev/null and b/selfdrive/assets/icons/indicatorC_off.png differ
diff --git a/selfdrive/assets/icons/indicatorC_on.png b/selfdrive/assets/icons/indicatorC_on.png
new file mode 100644
index 0000000000..1c5c164301
Binary files /dev/null and b/selfdrive/assets/icons/indicatorC_on.png differ
diff --git a/selfdrive/assets/icons/indicatorC_warn.png b/selfdrive/assets/icons/indicatorC_warn.png
new file mode 100644
index 0000000000..03bc07157b
Binary files /dev/null and b/selfdrive/assets/icons/indicatorC_warn.png differ
diff --git a/selfdrive/assets/icons/indicator_off.png b/selfdrive/assets/icons/indicator_off.png
new file mode 100644
index 0000000000..6dea0f81a4
Binary files /dev/null and b/selfdrive/assets/icons/indicator_off.png differ
diff --git a/selfdrive/assets/icons/indicator_on.png b/selfdrive/assets/icons/indicator_on.png
new file mode 100644
index 0000000000..ef021fb7aa
Binary files /dev/null and b/selfdrive/assets/icons/indicator_on.png differ
diff --git a/selfdrive/assets/images/arrow.svg b/selfdrive/assets/images/arrow.svg
new file mode 100644
index 0000000000..659fe5d516
--- /dev/null
+++ b/selfdrive/assets/images/arrow.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript
index 1695e60cd5..8109a793c0 100644
--- a/selfdrive/ui/SConscript
+++ b/selfdrive/ui/SConscript
@@ -27,11 +27,12 @@ Export('widgets')
qt_libs = [widgets, qt_util] + base_libs
qt_src = ["main.cc", "ui.cc", "qt/sidebar.cc", "qt/body.cc",
- "qt/window.cc", "qt/home.cc", "qt/offroad/settings.cc",
+ "qt/window.cc", "qt/home.cc", "qt/offroad/settings.cc", "qt/offroad/customGUI.cc",
"qt/offroad/software_settings.cc", "qt/offroad/developer_panel.cc", "qt/offroad/onboarding.cc",
"qt/offroad/driverview.cc", "qt/offroad/experimental_mode.cc",
"qt/onroad/onroad_home.cc", "qt/onroad/annotated_camera.cc", "qt/onroad/model.cc",
- "qt/onroad/buttons.cc", "qt/onroad/alerts.cc", "qt/onroad/driver_monitoring.cc", "qt/onroad/hud.cc"]
+ "qt/onroad/buttons.cc", "qt/onroad/alerts.cc", "qt/onroad/driver_monitoring.cc", "qt/onroad/hud.cc",
+ "qt/offroad/custom_widgets/acceleration.cc", "qt/offroad/custom_widgets/steering.cc", "qt/offroad/custom_widgets/status.cc"]
# build translation files
with open(File("translations/languages.json").abspath) as f:
diff --git a/selfdrive/ui/qt/offroad/customGUI.cc b/selfdrive/ui/qt/offroad/customGUI.cc
new file mode 100644
index 0000000000..1b654922c8
--- /dev/null
+++ b/selfdrive/ui/qt/offroad/customGUI.cc
@@ -0,0 +1,170 @@
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include "common/watchdog.h"
+#include "common/util.h"
+#include "selfdrive/ui/qt/network/networking.h"
+#include "selfdrive/ui/qt/offroad/settings.h"
+#include "selfdrive/ui/qt/qt_window.h"
+#include "selfdrive/ui/qt/widgets/prime.h"
+#include "selfdrive/ui/qt/widgets/scrollview.h"
+#include "selfdrive/ui/qt/offroad/developer_panel.h"
+#include "selfdrive/ui/qt/offroad/customGUI.h"
+#include "cereal/gen/cpp/car.capnp.h"
+
+// Bring custom window to the front
+void CustomWindow::showEvent(QShowEvent *event) {
+ setCurrentPanel(0);
+}
+
+void CustomWindow::setCurrentPanel(int index, const QString ¶m) {}
+
+CustomWindow::CustomWindow(QWidget *parent) : QFrame(parent) {
+ // Connect custom GUI update to parent uiState update function
+ QObject::connect(uiState(), &UIState::uiUpdate, this, &CustomWindow::updateState);
+
+ // Close btn returns to settings page
+ QPushButton *close_btn = new QPushButton(tr("×"));
+ close_btn->setStyleSheet(R"(
+ QPushButton {
+ font-size: 140px;
+ padding-bottom: 20px;
+ border-radius: 75px;
+ background-color: #555555;
+ font-weight: 400;
+ }
+ QPushButton:pressed {
+ background-color: #3B3B3B;
+ }
+ )");
+ close_btn->setFixedSize(150, 150);
+
+ // Status control buttons to hide/show indicator groups
+ QPushButton *blink_btn = new QPushButton(tr("Blinker"));
+ blink_btn->setStyleSheet(R"(
+ QPushButton {
+ font-size: 25px;
+ padding-bottom: 20px;
+ border-radius: 25px;
+ background-color: #555555;
+ }
+ QPushButton:pressed {
+ background-color: #3B3B3B;
+ }
+ )");
+ blink_btn->setFixedSize(125, 125);
+
+ QPushButton *car_btn = new QPushButton(tr("Car"));
+ car_btn->setStyleSheet(R"(
+ QPushButton {
+ font-size: 30px;
+ padding-bottom: 20px;
+ border-radius: 25px;
+ background-color: #555555;
+ }
+ QPushButton:pressed {
+ background-color: #3B3B3B;
+ }
+ )");
+ car_btn->setFixedSize(125, 125);
+
+ QPushButton *steer_btn = new QPushButton(tr("Steer"));
+ steer_btn->setStyleSheet(R"(
+ QPushButton {
+ font-size: 30px;
+ padding-bottom: 20px;
+ border-radius: 25px;
+ background-color: #555555;
+ }
+ QPushButton:pressed {
+ background-color: #3B3B3B;
+ }
+ )");
+ steer_btn->setFixedSize(125, 125);
+
+ QPushButton *drive_btn = new QPushButton(tr("Drive"));
+ drive_btn->setStyleSheet(R"(
+ QPushButton {
+ font-size: 30px;
+ padding-bottom: 20px;
+ border-radius: 25px;
+ background-color: #555555;
+ }
+ QPushButton:pressed {
+ background-color: #3B3B3B;
+ }
+ )");
+ drive_btn->setFixedSize(125, 125);
+
+ // main settings layout, sidebar + main panel
+ QHBoxLayout *main_layout = new QHBoxLayout(this);
+ main_layout->setSpacing(40);
+ QVBoxLayout *sidebar = new QVBoxLayout();
+ QVBoxLayout *primary = new QVBoxLayout();
+ QVBoxLayout *speed_bar = new QVBoxLayout();
+
+ sidebar->addWidget(close_btn);
+ sidebar->addWidget(blink_btn);
+ sidebar->addWidget(car_btn);
+ sidebar->addWidget(steer_btn);
+ sidebar->addWidget(drive_btn);
+
+ ss = new SteeringSlider(this);
+ lW = new BlinkerStatus(this);
+
+ carStat = new CarStatus(this);
+ steerStat = new SteerStatus(this);
+ driveStat = new DriveStatus(this);
+
+ primary->addWidget(lW);
+ primary->addWidget(carStat);
+ primary->addWidget(steerStat);
+ primary->addWidget(driveStat);
+ primary->addWidget(ss);
+
+ accW = new AccelerationW(this);
+ spW = new SpeedStatus(this, 0);
+ speed_bar->addWidget(spW);
+ speed_bar->addWidget(accW);
+
+ // Connect buttons to visibility functions + settings close
+ QObject::connect(blink_btn, &QPushButton::clicked, [&](){
+ lW->setVisible(!lW->isVisible());
+ });
+ QObject::connect(steer_btn, &QPushButton::clicked, [&](){
+ steerStat->setVisible(!steerStat->isVisible());
+ });
+ QObject::connect(car_btn, &QPushButton::clicked, [&](){
+ carStat->setVisible(!carStat->isVisible());
+ });
+ QObject::connect(drive_btn, &QPushButton::clicked, [&](){
+ driveStat->setVisible(!driveStat->isVisible());
+ });
+ QObject::connect(close_btn, &QPushButton::clicked, this, &CustomWindow::closeCustom);
+ main_layout->addLayout(sidebar);
+ main_layout->addLayout(primary);
+ main_layout->addLayout(speed_bar);
+ setStyleSheet(R"(
+ CustomWindow {
+ background-color: black;
+ }
+ )");
+}
+
+// Update contents of custom window
+// Inherits from ui
+void CustomWindow::updateState(const UIState &s) {
+ const SubMaster &sm = *(s.sm);
+ lW->update(sm);
+ spW->update(sm);
+ carStat->update(sm);
+ steerStat->update(sm);
+ driveStat->update(sm);
+}
+
+
diff --git a/selfdrive/ui/qt/offroad/customGUI.h b/selfdrive/ui/qt/offroad/customGUI.h
new file mode 100644
index 0000000000..41b43b97f8
--- /dev/null
+++ b/selfdrive/ui/qt/offroad/customGUI.h
@@ -0,0 +1,46 @@
+#pragma once
+
+#include