From 2e7942ef1678e8f366efa0758c224966b14bd466 Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Sat, 13 Jul 2024 23:32:36 -0400 Subject: [PATCH] AbstractControlSP, ButtonParamControlSP, OptionalControlSP --- selfdrive/ui/qt/widgets/controls.cc | 45 --- selfdrive/ui/qt/widgets/controls.h | 254 +-------------- .../qt/offroad/custom_offsets_settings.cc | 8 +- .../qt/offroad/custom_offsets_settings.h | 4 +- .../sunnypilot/qt/offroad/display_settings.cc | 18 +- .../sunnypilot/qt/offroad/display_settings.h | 8 +- .../qt/offroad/lane_change_settings.cc | 8 +- .../qt/offroad/lane_change_settings.h | 4 +- .../ui/sunnypilot/qt/offroad/mads_settings.cc | 4 +- .../ui/sunnypilot/qt/offroad/mads_settings.h | 2 +- .../sunnypilot/qt/offroad/sp_priv_settings.cc | 4 +- .../sunnypilot/qt/offroad/sp_priv_settings.h | 3 +- .../offroad/speed_limit_control_settings.cc | 12 +- .../qt/offroad/speed_limit_control_settings.h | 6 +- .../qt/offroad/speed_limit_policy_settings.cc | 4 +- .../qt/offroad/speed_limit_policy_settings.h | 4 +- .../offroad/speed_limit_warning_settings.cc | 14 +- .../qt/offroad/speed_limit_warning_settings.h | 6 +- .../qt/offroad/sunnypilot_settings.cc | 12 +- .../qt/offroad/sunnypilot_settings.h | 6 +- .../sunnypilot/qt/offroad/visuals_settings.cc | 6 +- .../sunnypilot/qt/offroad/visuals_settings.h | 6 +- .../sunnypilot/qt/widgets/sp_priv_controls.cc | 48 +++ .../sunnypilot/qt/widgets/sp_priv_controls.h | 304 ++++++++++++++++++ 24 files changed, 432 insertions(+), 358 deletions(-) diff --git a/selfdrive/ui/qt/widgets/controls.cc b/selfdrive/ui/qt/widgets/controls.cc index f97cb40e13..3b95fe3184 100644 --- a/selfdrive/ui/qt/widgets/controls.cc +++ b/selfdrive/ui/qt/widgets/controls.cc @@ -62,51 +62,6 @@ void AbstractControl::hideEvent(QHideEvent *e) { } } -SPAbstractControl::SPAbstractControl(const QString &title, const QString &desc, const QString &icon, QWidget *parent) : QFrame(parent) { - QVBoxLayout *main_layout = new QVBoxLayout(this); - main_layout->setMargin(0); - - hlayout = new QHBoxLayout; - hlayout->setMargin(0); - hlayout->setSpacing(0); - - // title - if (!title.isEmpty()) { - title_label = new QPushButton(title); - title_label->setFixedHeight(120); - title_label->setStyleSheet("font-size: 50px; font-weight: 450; text-align: left; border: none;"); - main_layout->addWidget(title_label, 1); - - connect(title_label, &QPushButton::clicked, [=]() { - if (!description->isVisible()) { - emit showDescriptionEvent(); - } - - if (!description->text().isEmpty()) { - description->setVisible(!description->isVisible()); - } - }); - } else { - main_layout->addSpacing(20); - } - - main_layout->addLayout(hlayout); - main_layout->addSpacing(2); - - // description - description = new QLabel(desc); - description->setContentsMargins(0, 20, 40, 20); - description->setStyleSheet("font-size: 40px; color: grey"); - description->setWordWrap(true); - description->setVisible(false); - main_layout->addWidget(description); - - main_layout->addStretch(); -} - -void SPAbstractControl::hideEvent(QHideEvent *e) { -} - // controls ButtonControl::ButtonControl(const QString &title, const QString &text, const QString &desc, QWidget *parent) : AbstractControl(title, desc, "", parent) { diff --git a/selfdrive/ui/qt/widgets/controls.h b/selfdrive/ui/qt/widgets/controls.h index c6a1b73552..4c5f08e1ae 100644 --- a/selfdrive/ui/qt/widgets/controls.h +++ b/selfdrive/ui/qt/widgets/controls.h @@ -208,71 +208,29 @@ private: bool store_confirm = false; }; -class SPAbstractControl : public QFrame { - Q_OBJECT - -public: - void setDescription(const QString &desc) { - if (description) description->setText(desc); - } - - void setTitle(const QString &title) { - title_label->setText(title); - } - - const QString getDescription() { - return description->text(); - } - -public slots: - void showDescription() { - description->setVisible(true); - } - - void hideDescription() { - description->setVisible(false); - } - -signals: - void showDescriptionEvent(); - -protected: - SPAbstractControl(const QString &title, const QString &desc = "", const QString &icon = "", QWidget *parent = nullptr); - void hideEvent(QHideEvent *e) override; - - QHBoxLayout *hlayout; - QPushButton *title_label; - -private: - QLabel *description = nullptr; -}; - -class ButtonParamControl : public SPAbstractControl { +class ButtonParamControl : public AbstractControl { Q_OBJECT public: ButtonParamControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, - const std::vector &button_texts, const int minimum_button_width = 300) : SPAbstractControl(title, desc, icon), button_texts(button_texts) { + const std::vector &button_texts, const int minimum_button_width = 225) : AbstractControl(title, desc, icon) { const QString style = R"( QPushButton { - border-radius: 20px; - font-size: 50px; - font-weight: 450; - height:150px; + border-radius: 50px; + font-size: 40px; + font-weight: 500; + height:100px; padding: 0 25 0 25; - color: #FFFFFF; + color: #E4E4E4; + background-color: #393939; } QPushButton:pressed { background-color: #4a4a4a; } QPushButton:checked:enabled { - background-color: #696868; + background-color: #33Ab4C; } QPushButton:disabled { - color: #33FFFFFF; - } - QPushButton:checked:disabled { - background-color: #121212; - color: #33FFFFFF; + color: #33E4E4E4; } )"; key = param.toStdString(); @@ -286,16 +244,12 @@ public: button->setChecked(i == value); button->setStyleSheet(style); button->setMinimumWidth(minimum_button_width); - if (i == 0) hlayout->addSpacing(2); hlayout->addWidget(button); button_group->addButton(button, i); } - hlayout->setAlignment(Qt::AlignLeft); - QObject::connect(button_group, QOverload::of(&QButtonGroup::buttonClicked), [=](int id) { params.put(key, std::to_string(id)); - emit buttonToggled(id); }); } @@ -303,9 +257,6 @@ public: for (auto btn : button_group->buttons()) { btn->setEnabled(enable); } - button_group_enabled = enable; - - update(); } void setCheckedButton(int id) { @@ -314,14 +265,6 @@ public: void refresh() { int value = atoi(params.get(key).c_str()); - - if (value >= button_texts.size()) { - value = button_texts.size() - 1; - } - if (value < 0) { - value = 0; - } - button_group->button(value)->setChecked(true); } @@ -329,53 +272,10 @@ public: refresh(); } - void setButton(QString param) { - key = param.toStdString(); - int value = atoi(params.get(key).c_str()); - for (int i = 0; i < button_group->buttons().size(); i++) { - button_group->buttons()[i]->setChecked(i == value); - } - } - - void setDisabledSelectedButton(std::string val) { - int value = atoi(val.c_str()); - for (int i = 0; i < button_group->buttons().size(); i++) { - button_group->buttons()[i]->setEnabled(i != value); - } - } - -protected: - void paintEvent(QPaintEvent *event) override { - QPainter p(this); - p.setRenderHint(QPainter::Antialiasing); - - // Calculate the total width and height for the background rectangle - int w = 0; - int h = 150; - - for (int i = 0; i < hlayout->count(); ++i) { - QPushButton *button = qobject_cast(hlayout->itemAt(i)->widget()); - if (button) { - w += button->width(); - } - } - - // Draw the rectangle - QRect rect(0 + 2, h - 24, w, h); - p.setPen(QPen(QColor(button_group_enabled ? "#696868" : "#121212"), 3)); - p.drawRoundedRect(rect, 20, 20); - } - -signals: - void buttonToggled(int btn_id); - private: std::string key; Params params; QButtonGroup *button_group; - std::vector button_texts; - - bool button_group_enabled = true; }; class ListWidget : public QWidget { @@ -439,140 +339,6 @@ public: } }; -class SPOptionControl : public SPAbstractControl { - Q_OBJECT - -private: - struct MinMaxValue { - int min_value; - int max_value; - }; - -public: - SPOptionControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, - const MinMaxValue &range, const int per_value_change = 1) : _title(title), SPAbstractControl(title, desc, icon) { - const QString style = R"( - QPushButton { - border-radius: 20px; - font-size: 60px; - font-weight: 500; - width: 150px; - height: 150px; - padding: -3 25 3 25; - color: #FFFFFF; - font-weight: bold; - } - QPushButton:pressed { - color: #5C5C5C; - } - QPushButton:disabled { - color: #5C5C5C; - } - )"; - - label.setStyleSheet(label_enabled_style); - label.setFixedWidth(300); - label.setAlignment(Qt::AlignCenter); - - const std::vector button_texts{"-", "+"}; - - key = param.toStdString(); - value = atoi(params.get(key).c_str()); - - button_group = new QButtonGroup(this); - button_group->setExclusive(true); - for (int i = 0; i < button_texts.size(); i++) { - QPushButton *button = new QPushButton(button_texts[i], this); - button->setStyleSheet(style + ((i == 0) ? "QPushButton { text-align: left; }" : - "QPushButton { text-align: right; }")); - hlayout->addWidget(button, 0, ((i == 0) ? Qt::AlignLeft : Qt::AlignRight) | Qt::AlignVCenter); - if (i == 0) { - hlayout->addWidget(&label, 0, Qt::AlignCenter); - } - button_group->addButton(button, i); - - QObject::connect(button, &QPushButton::clicked, [=]() { - int change_value = (i == 0) ? -per_value_change : per_value_change; - key = param.toStdString(); - value = atoi(params.get(key).c_str()); - value += change_value; - value = std::clamp(value, range.min_value, range.max_value); - params.put(key, QString::number(value).toStdString()); - - button_group->button(0)->setEnabled(!(value <= range.min_value)); - button_group->button(1)->setEnabled(!(value >= range.max_value)); - - updateLabels(); - - if (request_update) { - emit updateOtherToggles(); - } - }); - } - - hlayout->setAlignment(Qt::AlignLeft); - } - - void setUpdateOtherToggles(bool _update) { - request_update = _update; - } - - inline void setLabel(const QString &text) { label.setText(text); } - - void setEnabled(bool enabled) { - for (auto btn : button_group->buttons()) { - btn->setEnabled(enabled); - } - label.setEnabled(enabled); - label.setStyleSheet(enabled ? label_enabled_style : label_disabled_style); - button_enabled = enabled; - - update(); - } - -protected: - void paintEvent(QPaintEvent *event) override { - QPainter p(this); - p.setRenderHint(QPainter::Antialiasing); - - // Calculate the total width and height for the background rectangle - int w = 0; - int h = 150; - - for (int i = 0; i < hlayout->count(); ++i) { - QWidget *widget = qobject_cast(hlayout->itemAt(i)->widget()); - if (widget) { - w += widget->width(); - } - } - - // Draw the rectangle - QRect rect(0, !_title.isEmpty() ? (h - 24) : 20, w, h); - p.setBrush(QColor(button_enabled ? "#b24a4a4a" : "#121212")); // Background color - p.setPen(QPen(Qt::NoPen)); - p.drawRoundedRect(rect, 20, 20); - } - -signals: - void updateLabels(); - void updateOtherToggles(); - -private: - std::string key; - int value; - QButtonGroup *button_group; - QLabel label; - Params params; - std::map option_label = {}; - bool request_update = false; - QString _title = ""; - - const QString label_enabled_style = "font-size: 50px; font-weight: 450; color: #FFFFFF;"; - const QString label_disabled_style = "font-size: 50px; font-weight: 450; color: #5C5C5C;"; - - bool button_enabled = true; -}; - class SubPanelButton : public QPushButton { Q_OBJECT diff --git a/selfdrive/ui/sunnypilot/qt/offroad/custom_offsets_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/custom_offsets_settings.cc index 689f42bb11..73c6e8cf1a 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/custom_offsets_settings.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/custom_offsets_settings.cc @@ -14,13 +14,13 @@ CustomOffsetsSettings::CustomOffsetsSettings(QWidget* parent) : QWidget(parent) // Controls: Camera Offset (cm) camera_offset = new CameraOffset(); - connect(camera_offset, &SPOptionControl::updateLabels, camera_offset, &CameraOffset::refresh); + connect(camera_offset, &OptionControlSP::updateLabels, camera_offset, &CameraOffset::refresh); camera_offset->showDescription(); list->addItem(camera_offset); // Controls: Path Offset (cm) path_offset = new PathOffset(); - connect(path_offset, &SPOptionControl::updateLabels, path_offset, &PathOffset::refresh); + connect(path_offset, &OptionControlSP::updateLabels, path_offset, &PathOffset::refresh); path_offset->showDescription(); list->addItem(path_offset); @@ -28,7 +28,7 @@ CustomOffsetsSettings::CustomOffsetsSettings(QWidget* parent) : QWidget(parent) } // Camera Offset Value -CameraOffset::CameraOffset() : SPOptionControl ( +CameraOffset::CameraOffset() : OptionControlSP ( "CameraOffset", tr("Camera Offset - Laneful Only"), tr("Hack to trick vehicle to be left or right biased in its lane. Decreasing the value will make the car keep more left, increasing will make it keep more right. Changes take effect immediately. Default: +4 cm"), @@ -48,7 +48,7 @@ void CameraOffset::refresh() { } // Path Offset Value -PathOffset::PathOffset() : SPOptionControl ( +PathOffset::PathOffset() : OptionControlSP ( "PathOffset", tr("Path Offset"), tr("Hack to trick the model path to be left or right biased of the lane. Decreasing the value will shift the model more left, increasing will shift the model more right. Changes take effect immediately."), diff --git a/selfdrive/ui/sunnypilot/qt/offroad/custom_offsets_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/custom_offsets_settings.h index 0b693ffc0c..5ddac07340 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/custom_offsets_settings.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/custom_offsets_settings.h @@ -3,7 +3,7 @@ #include "selfdrive/ui/sunnypilot/qt/widgets/sp_priv_controls.h" #include "selfdrive/ui/qt/widgets/scrollview.h" -class CameraOffset : public SPOptionControl { +class CameraOffset : public OptionControlSP { Q_OBJECT public: @@ -15,7 +15,7 @@ private: Params params; }; -class PathOffset : public SPOptionControl { +class PathOffset : public OptionControlSP { Q_OBJECT public: diff --git a/selfdrive/ui/sunnypilot/qt/offroad/display_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/display_settings.cc index cceb2ef7e9..2a6d44bd34 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/display_settings.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/display_settings.cc @@ -18,24 +18,24 @@ DisplayPanel::DisplayPanel(QWidget *parent) : ListWidget(parent, false) { // General: Max Time Offroad (Shutdown timer) auto max_time_offroad = new MaxTimeOffroad(); - connect(max_time_offroad, &SPOptionControl::updateLabels, max_time_offroad, &MaxTimeOffroad::refresh); + connect(max_time_offroad, &OptionControlSP::updateLabels, max_time_offroad, &MaxTimeOffroad::refresh); addItem(max_time_offroad); // General: Onroad Screen Off (Auto Onroad Screen Timer) onroad_screen_off = new OnroadScreenOff(); onroad_screen_off->setUpdateOtherToggles(true); - connect(onroad_screen_off, &SPOptionControl::updateLabels, onroad_screen_off, &OnroadScreenOff::refresh); - connect(onroad_screen_off, &SPOptionControl::updateOtherToggles, this, &DisplayPanel::updateToggles); + connect(onroad_screen_off, &OptionControlSP::updateLabels, onroad_screen_off, &OnroadScreenOff::refresh); + connect(onroad_screen_off, &OptionControlSP::updateOtherToggles, this, &DisplayPanel::updateToggles); addItem(onroad_screen_off); // General: Onroad Screen Off Brightness onroad_screen_off_brightness = new OnroadScreenOffBrightness(); - connect(onroad_screen_off_brightness, &SPOptionControl::updateLabels, onroad_screen_off_brightness, &OnroadScreenOffBrightness::refresh); + connect(onroad_screen_off_brightness, &OptionControlSP::updateLabels, onroad_screen_off_brightness, &OnroadScreenOffBrightness::refresh); addItem(onroad_screen_off_brightness); // General: Brightness Control (Global) auto brightness_control = new BrightnessControl(); - connect(brightness_control, &SPOptionControl::updateLabels, brightness_control, &BrightnessControl::refresh); + connect(brightness_control, &OptionControlSP::updateLabels, brightness_control, &BrightnessControl::refresh); for (auto &[param, title, desc, icon] : toggle_defs) { auto toggle = new ParamControlSP(param, title, desc, icon, this); @@ -65,7 +65,7 @@ void DisplayPanel::updateToggles() { } // Max Time Offroad (Shutdown timer) -MaxTimeOffroad::MaxTimeOffroad() : SPOptionControl ( +MaxTimeOffroad::MaxTimeOffroad() : OptionControlSP ( "MaxTimeOffroad", tr("Max Time Offroad"), tr("Device is automatically turned off after a set time when the engine is turned off (off-road) after driving (on-road)."), @@ -110,7 +110,7 @@ void MaxTimeOffroad::refresh() { } // Onroad Screen Off (Auto Onroad Screen Timer) -OnroadScreenOff::OnroadScreenOff() : SPOptionControl ( +OnroadScreenOff::OnroadScreenOff() : OptionControlSP ( "OnroadScreenOff", tr("Driving Screen Off Timer"), tr("Turn off the device screen or reduce brightness to protect the screen after driving starts. It automatically brightens or turns on when a touch or event occurs."), @@ -136,7 +136,7 @@ void OnroadScreenOff::refresh() { } // Onroad Screen Off Brightness -OnroadScreenOffBrightness::OnroadScreenOffBrightness() : SPOptionControl ( +OnroadScreenOffBrightness::OnroadScreenOffBrightness() : OptionControlSP ( "OnroadScreenOffBrightness", tr("Driving Screen Off Brightness (%)"), tr("When using the Driving Screen Off feature, the brightness is reduced according to the automatic brightness ratio."), @@ -157,7 +157,7 @@ void OnroadScreenOffBrightness::refresh() { } // Brightness Control (Global) -BrightnessControl::BrightnessControl() : SPOptionControl ( +BrightnessControl::BrightnessControl() : OptionControlSP ( "BrightnessControl", tr("Brightness"), tr("Manually adjusts the global brightness of the screen."), diff --git a/selfdrive/ui/sunnypilot/qt/offroad/display_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/display_settings.h index ee1e6b6308..41aac101bc 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/display_settings.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/display_settings.h @@ -2,7 +2,7 @@ #include "selfdrive/ui/sunnypilot/qt/widgets/sp_priv_controls.h" -class OnroadScreenOff : public SPOptionControl { +class OnroadScreenOff : public OptionControlSP { Q_OBJECT public: @@ -14,7 +14,7 @@ private: Params params; }; -class OnroadScreenOffBrightness : public SPOptionControl { +class OnroadScreenOffBrightness : public OptionControlSP { Q_OBJECT public: @@ -26,7 +26,7 @@ private: Params params; }; -class MaxTimeOffroad : public SPOptionControl { +class MaxTimeOffroad : public OptionControlSP { Q_OBJECT public: @@ -38,7 +38,7 @@ private: Params params; }; -class BrightnessControl : public SPOptionControl { +class BrightnessControl : public OptionControlSP { Q_OBJECT public: diff --git a/selfdrive/ui/sunnypilot/qt/offroad/lane_change_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/lane_change_settings.cc index 684568c57d..10fcf2e1c6 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/lane_change_settings.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/lane_change_settings.cc @@ -37,14 +37,14 @@ LaneChangeSettings::LaneChangeSettings(QWidget* parent) : QWidget(parent) { auto_lane_change_timer = new AutoLaneChangeTimer(); auto_lane_change_timer->setUpdateOtherToggles(true); auto_lane_change_timer->showDescription(); - connect(auto_lane_change_timer, &SPOptionControl::updateLabels, auto_lane_change_timer, &AutoLaneChangeTimer::refresh); + connect(auto_lane_change_timer, &OptionControlSP::updateLabels, auto_lane_change_timer, &AutoLaneChangeTimer::refresh); connect(auto_lane_change_timer, &AutoLaneChangeTimer::updateOtherToggles, this, &LaneChangeSettings::updateToggles); list->addItem(auto_lane_change_timer); // Pause Lateral Below Speed w/ Blinker pause_lateral_speed = new PauseLateralSpeed(); pause_lateral_speed->showDescription(); - connect(pause_lateral_speed, &SPOptionControl::updateLabels, pause_lateral_speed, &PauseLateralSpeed::refresh); + connect(pause_lateral_speed, &OptionControlSP::updateLabels, pause_lateral_speed, &PauseLateralSpeed::refresh); for (auto &[param, title, desc, icon] : toggle_defs) { auto toggle = new ParamControlSP(param, title, desc, icon, this); @@ -97,7 +97,7 @@ void LaneChangeSettings::updateToggles() { } // Auto Lane Change Timer (ALCT) -AutoLaneChangeTimer::AutoLaneChangeTimer() : SPOptionControl ( +AutoLaneChangeTimer::AutoLaneChangeTimer() : OptionControlSP ( "AutoLaneChangeTimer", tr("Auto Lane Change by Blinker"), tr("Set a timer to delay the auto lane change operation when the blinker is used. No nudge on the steering wheel is required to auto lane change if a timer is set. Default is Nudge.\nPlease use caution when using this feature. Only use the blinker when traffic and road conditions permit."), @@ -127,7 +127,7 @@ void AutoLaneChangeTimer::refresh() { } } -PauseLateralSpeed::PauseLateralSpeed() : SPOptionControl ( +PauseLateralSpeed::PauseLateralSpeed() : OptionControlSP ( "PauseLateralSpeed", "", tr("Pause lateral actuation with blinker when traveling below the desired speed selected. Default is 20 MPH or 32 km/h."), diff --git a/selfdrive/ui/sunnypilot/qt/offroad/lane_change_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/lane_change_settings.h index 6c2d0d5708..49d15fc02e 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/lane_change_settings.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/lane_change_settings.h @@ -4,7 +4,7 @@ #include "selfdrive/ui/sunnypilot/qt/widgets/sp_priv_controls.h" #include "selfdrive/ui/qt/widgets/scrollview.h" -class AutoLaneChangeTimer : public SPOptionControl { +class AutoLaneChangeTimer : public OptionControlSP { Q_OBJECT public: @@ -19,7 +19,7 @@ private: Params params; }; -class PauseLateralSpeed : public SPOptionControl { +class PauseLateralSpeed : public OptionControlSP { Q_OBJECT public: diff --git a/selfdrive/ui/sunnypilot/qt/offroad/mads_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/mads_settings.cc index 678b495d19..3b64fac1cf 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/mads_settings.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/mads_settings.cc @@ -32,7 +32,7 @@ MadsSettings::MadsSettings(QWidget* parent) : QWidget(parent) { // Disengage Lateral on Brake (DLOB) std::vector dlob_settings_texts{tr("Remain Active"), tr("Pause Steering")}; - dlob_settings = new ButtonParamControl( + dlob_settings = new ButtonParamControlSP( "DisengageLateralOnBrake", tr("Steering Mode After Braking"), tr("Choose how Automatic Lane Centering (ALC) behaves after the brake pedal is manually pressed in sunnypilot.\n\nRemain Active: ALC will remain active even after the brake pedal is pressed.\nPause Steering: ALC will be paused after the brake pedal is manually pressed."), @@ -54,7 +54,7 @@ MadsSettings::MadsSettings(QWidget* parent) : QWidget(parent) { } // trigger offroadTransition when going onroad/offroad - connect(uiState(), &UIState::offroadTransition, dlob_settings, &ButtonParamControl::setEnabled); + connect(uiState(), &UIState::offroadTransition, dlob_settings, &ButtonParamControlSP::setEnabled); main_layout->addWidget(new ScrollView(list, this)); } diff --git a/selfdrive/ui/sunnypilot/qt/offroad/mads_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/mads_settings.h index afdf0caeed..1e01d41182 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/mads_settings.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/mads_settings.h @@ -21,5 +21,5 @@ private: Params params; std::map toggles; - ButtonParamControl *dlob_settings; + ButtonParamControlSP *dlob_settings; }; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/sp_priv_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/sp_priv_settings.cc index 26fff880a6..ad4d666db0 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/sp_priv_settings.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/sp_priv_settings.cc @@ -100,7 +100,7 @@ TogglesPanelSP::TogglesPanelSP(SettingsWindow *parent) : TogglesPanel(parent) { std::vector longi_button_texts{tr("Aggressive"), tr("Moderate"), tr("Standard"), tr("Relaxed")}; - long_personality_setting = new ButtonParamControl("LongitudinalPersonality", tr("Driving Personality"), + long_personality_setting = new ButtonParamControlSP("LongitudinalPersonality", tr("Driving Personality"), tr("Standard is recommended. In moderate/aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. " "In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with " "your steering wheel distance button."), @@ -111,7 +111,7 @@ TogglesPanelSP::TogglesPanelSP(SettingsWindow *parent) : TogglesPanel(parent) { // accel controller std::vector accel_personality_texts{tr("Sport"), tr("Normal"), tr("Eco"), tr("Stock")}; - accel_personality_setting = new ButtonParamControl("AccelPersonality", tr("Acceleration Personality"), + accel_personality_setting = new ButtonParamControlSP("AccelPersonality", tr("Acceleration Personality"), tr("Normal is recommended. In sport mode, sunnypilot will provide aggressive acceleration for a dynamic driving experience. " "In eco mode, sunnypilot will apply smoother and more relaxed acceleration. On supported cars, you can cycle through these " "acceleration personality within Onroad Settings on the driving screen."), diff --git a/selfdrive/ui/sunnypilot/qt/offroad/sp_priv_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/sp_priv_settings.h index f99b0ce075..718aeaa1a4 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/sp_priv_settings.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/sp_priv_settings.h @@ -14,7 +14,8 @@ private slots: private: std::map toggles; - ButtonParamControl *accel_personality_setting; + ButtonParamControlSP *long_personality_setting; + ButtonParamControlSP *accel_personality_setting; ParamWatcher *param_watcher; void updateToggles() override; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/speed_limit_control_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/speed_limit_control_settings.cc index 13b1b715d4..e4c5b7e711 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/speed_limit_control_settings.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/speed_limit_control_settings.cc @@ -13,7 +13,7 @@ SlcSettings::SlcSettings(QWidget* parent) : QWidget(parent) { ListWidget *list = new ListWidget(this, false); std::vector speed_limit_engage_texts{tr("Auto"), tr("User Confirm")}; - speed_limit_engage_settings = new ButtonParamControl( + speed_limit_engage_settings = new ButtonParamControlSP( "SpeedLimitEngageType", tr("Engage Mode"), "", "../assets/offroad/icon_blank.png", @@ -24,7 +24,7 @@ SlcSettings::SlcSettings(QWidget* parent) : QWidget(parent) { list->addItem(speed_limit_engage_settings); std::vector speed_limit_offset_settings_texts{tr("Default"), tr("Fixed"), tr("Percentage")}; - speed_limit_offset_settings = new ButtonParamControl( + speed_limit_offset_settings = new ButtonParamControlSP( "SpeedLimitOffsetType", tr("Limit Offset"), tr("Set speed limit slightly higher than actual speed limit for a more natural drive."), "../assets/offroad/icon_blank.png", speed_limit_offset_settings_texts, @@ -33,11 +33,11 @@ SlcSettings::SlcSettings(QWidget* parent) : QWidget(parent) { list->addItem(speed_limit_offset_settings); slvo = new SpeedLimitValueOffset(); - connect(slvo, &SPOptionControl::updateLabels, slvo, &SpeedLimitValueOffset::refresh); + connect(slvo, &OptionControlSP::updateLabels, slvo, &SpeedLimitValueOffset::refresh); list->addItem(slvo); - connect(speed_limit_offset_settings, &ButtonParamControl::buttonToggled, this, &SlcSettings::updateToggles); - connect(speed_limit_offset_settings, &ButtonParamControl::buttonToggled, slvo, &SpeedLimitValueOffset::refresh); + connect(speed_limit_offset_settings, &ButtonParamControlSP::buttonToggled, this, &SlcSettings::updateToggles); + connect(speed_limit_offset_settings, &ButtonParamControlSP::buttonToggled, slvo, &SpeedLimitValueOffset::refresh); param_watcher = new ParamWatcher(this); @@ -101,7 +101,7 @@ void SlcSettings::updateToggles() { } // Speed Limit Control Custom Offset -SpeedLimitValueOffset::SpeedLimitValueOffset() : SPOptionControl ( +SpeedLimitValueOffset::SpeedLimitValueOffset() : OptionControlSP ( "SpeedLimitValueOffset", "", "", diff --git a/selfdrive/ui/sunnypilot/qt/offroad/speed_limit_control_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/speed_limit_control_settings.h index 3e66956d0c..b3a77f649c 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/speed_limit_control_settings.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/speed_limit_control_settings.h @@ -5,7 +5,7 @@ #include "selfdrive/ui/qt/widgets/scrollview.h" #include "selfdrive/ui/qt/util.h" -class SpeedLimitValueOffset : public SPOptionControl { +class SpeedLimitValueOffset : public OptionControlSP { Q_OBJECT public: @@ -36,8 +36,8 @@ private: std::map toggles; SpeedLimitValueOffset *slvo; - ButtonParamControl *speed_limit_offset_settings; - ButtonParamControl *speed_limit_engage_settings; + ButtonParamControlSP *speed_limit_offset_settings; + ButtonParamControlSP *speed_limit_engage_settings; ParamWatcher *param_watcher; QString slcDescriptionBuilder(QString param, std::vector descriptions) { diff --git a/selfdrive/ui/sunnypilot/qt/offroad/speed_limit_policy_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/speed_limit_policy_settings.cc index f93b14d62d..bc5ec30e73 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/speed_limit_policy_settings.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/speed_limit_policy_settings.cc @@ -12,7 +12,7 @@ SpeedLimitPolicySettings::SpeedLimitPolicySettings(QWidget* parent) : QWidget(pa ListWidget *list = new ListWidget(this, false); - speed_limit_policy = new ButtonParamControl( + speed_limit_policy = new ButtonParamControlSP( "SpeedLimitControlPolicy", tr("Speed Limit Source Policy"), "", @@ -21,7 +21,7 @@ SpeedLimitPolicySettings::SpeedLimitPolicySettings(QWidget* parent) : QWidget(pa 250 ); speed_limit_policy->showDescription(); - connect(speed_limit_policy, &ButtonParamControl::buttonToggled, this, &SpeedLimitPolicySettings::updateToggles); + connect(speed_limit_policy, &ButtonParamControlSP::buttonToggled, this, &SpeedLimitPolicySettings::updateToggles); list->addItem(speed_limit_policy); param_watcher = new ParamWatcher(this); diff --git a/selfdrive/ui/sunnypilot/qt/offroad/speed_limit_policy_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/speed_limit_policy_settings.h index 5b7ef66a68..78d780db0b 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/speed_limit_policy_settings.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/speed_limit_policy_settings.h @@ -1,7 +1,7 @@ #pragma once #include "selfdrive/ui/ui.h" -#include "selfdrive/ui/qt/widgets/controls.h" +#include "selfdrive/ui/sunnypilot/qt/widgets/sp_priv_controls.h" #include "selfdrive/ui/qt/widgets/scrollview.h" #include "selfdrive/ui/qt/util.h" @@ -23,7 +23,7 @@ public slots: private: Params params; - ButtonParamControl *speed_limit_policy; + ButtonParamControlSP *speed_limit_policy; ParamWatcher *param_watcher; QString speedLimitPolicyDescriptionBuilder(QString param, std::vector descriptions) { diff --git a/selfdrive/ui/sunnypilot/qt/offroad/speed_limit_warning_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/speed_limit_warning_settings.cc index 7b7c9676ac..71566b8368 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/speed_limit_warning_settings.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/speed_limit_warning_settings.cc @@ -13,7 +13,7 @@ SpeedLimitWarningSettings::SpeedLimitWarningSettings(QWidget* parent) : QWidget( ListWidget *list = new ListWidget(this, false); std::vector speed_limit_warning_texts{tr("Off"), tr("Display"), tr("Chime")}; - speed_limit_warning_settings = new ButtonParamControl( + speed_limit_warning_settings = new ButtonParamControlSP( "SpeedLimitWarningType", tr("Speed Limit Warning"), "", "../assets/offroad/icon_blank.png", @@ -32,7 +32,7 @@ SpeedLimitWarningSettings::SpeedLimitWarningSettings(QWidget* parent) : QWidget( list->addItem(speed_limit_warning_flash); std::vector speed_limit_warning_offset_settings_texts{tr("Default"), tr("Fixed"), tr("Percentage")}; - speed_limit_warning_offset_settings = new ButtonParamControl( + speed_limit_warning_offset_settings = new ButtonParamControlSP( "SpeedLimitWarningOffsetType", tr("Warning Offset"), tr("Select the desired offset to warn the driver when the vehicle is driving faster than the speed limit."), "../assets/offroad/icon_blank.png", @@ -42,13 +42,13 @@ SpeedLimitWarningSettings::SpeedLimitWarningSettings(QWidget* parent) : QWidget( list->addItem(speed_limit_warning_offset_settings); slwvo = new SpeedLimitWarningValueOffset(); - connect(slwvo, &SPOptionControl::updateLabels, slwvo, &SpeedLimitWarningValueOffset::refresh); + connect(slwvo, &OptionControlSP::updateLabels, slwvo, &SpeedLimitWarningValueOffset::refresh); list->addItem(slwvo); - connect(speed_limit_warning_settings, &ButtonParamControl::buttonToggled, this, &SpeedLimitWarningSettings::updateToggles); + connect(speed_limit_warning_settings, &ButtonParamControlSP::buttonToggled, this, &SpeedLimitWarningSettings::updateToggles); - connect(speed_limit_warning_offset_settings, &ButtonParamControl::buttonToggled, this, &SpeedLimitWarningSettings::updateToggles); - connect(speed_limit_warning_offset_settings, &ButtonParamControl::buttonToggled, slwvo, &SpeedLimitWarningValueOffset::refresh); + connect(speed_limit_warning_offset_settings, &ButtonParamControlSP::buttonToggled, this, &SpeedLimitWarningSettings::updateToggles); + connect(speed_limit_warning_offset_settings, &ButtonParamControlSP::buttonToggled, slwvo, &SpeedLimitWarningValueOffset::refresh); param_watcher = new ParamWatcher(this); @@ -86,7 +86,7 @@ void SpeedLimitWarningSettings::updateToggles() { } // Speed Limit Control Custom Offset -SpeedLimitWarningValueOffset::SpeedLimitWarningValueOffset() : SPOptionControl ( +SpeedLimitWarningValueOffset::SpeedLimitWarningValueOffset() : OptionControlSP ( "SpeedLimitWarningValueOffset", "", "", diff --git a/selfdrive/ui/sunnypilot/qt/offroad/speed_limit_warning_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/speed_limit_warning_settings.h index 1a7d3c2144..6a17cf45b2 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/speed_limit_warning_settings.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/speed_limit_warning_settings.h @@ -5,7 +5,7 @@ #include "selfdrive/ui/qt/widgets/scrollview.h" #include "selfdrive/ui/qt/util.h" -class SpeedLimitWarningValueOffset : public SPOptionControl { +class SpeedLimitWarningValueOffset : public OptionControlSP { Q_OBJECT public: @@ -36,9 +36,9 @@ private: std::map toggles; SpeedLimitWarningValueOffset *slwvo; - ButtonParamControl *speed_limit_warning_offset_settings; + ButtonParamControlSP *speed_limit_warning_offset_settings; ParamControlSP *speed_limit_warning_flash; - ButtonParamControl *speed_limit_warning_settings; + ButtonParamControlSP *speed_limit_warning_settings; ParamWatcher *param_watcher; QString speedLimitWarningDescriptionBuilder(QString param, std::vector descriptions) { diff --git a/selfdrive/ui/sunnypilot/qt/offroad/sunnypilot_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/sunnypilot_settings.cc index 5240aa1949..ef7c26f8db 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/sunnypilot_settings.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/sunnypilot_settings.cc @@ -235,14 +235,14 @@ SunnypilotPanel::SunnypilotPanel(QWidget *parent) : QFrame(parent) { // Controls: Torque - FRICTION friction = new TorqueFriction(); - connect(friction, &SPOptionControl::updateLabels, friction, &TorqueFriction::refresh); + connect(friction, &OptionControlSP::updateLabels, friction, &TorqueFriction::refresh); // Controls: Torque - LAT_ACCEL_FACTOR lat_accel_factor = new TorqueMaxLatAccel(); - connect(lat_accel_factor, &SPOptionControl::updateLabels, lat_accel_factor, &TorqueMaxLatAccel::refresh); + connect(lat_accel_factor, &OptionControlSP::updateLabels, lat_accel_factor, &TorqueMaxLatAccel::refresh); std::vector dlp_settings_texts{tr("Laneful"), tr("Laneless"), tr("Auto")}; - dlp_settings = new ButtonParamControl( + dlp_settings = new ButtonParamControlSP( "DynamicLaneProfile", tr("Dynamic Lane Profile"), "", "../assets/offroad/icon_blank.png", dlp_settings_texts, @@ -567,7 +567,7 @@ void SunnypilotPanel::updateToggles() { } // toggle names to update when CustomTorqueLateral is flipped - std::vector customTorqueGroup{friction, lat_accel_factor}; + std::vector customTorqueGroup{friction, lat_accel_factor}; for (const auto& customTorqueControl : customTorqueGroup) { customTorqueControl->setVisible(!(nnff_toggle->isToggled() || !custom_torque_lateral->isToggled())); customTorqueControl->setEnabled(!(nnff_toggle->isToggled() || !custom_torque_lateral->isToggled())); @@ -581,7 +581,7 @@ void SunnypilotPanel::updateToggles() { dlp_settings->setDescription((model_use_lateral_planner ? "" : dlp_incompatible_desc + "

") + dlp_description); } -TorqueFriction::TorqueFriction() : SPOptionControl ( +TorqueFriction::TorqueFriction() : OptionControlSP ( "TorqueFriction", tr("FRICTION"), tr("Adjust Friction for the Torque Lateral Controller. Live: Override self-tune values; Offline: Override self-tune offline values at car restart."), @@ -597,7 +597,7 @@ void TorqueFriction::refresh() { setLabel(QString::number(torqueFrictionVal)); } -TorqueMaxLatAccel::TorqueMaxLatAccel() : SPOptionControl ( +TorqueMaxLatAccel::TorqueMaxLatAccel() : OptionControlSP ( "TorqueMaxLatAccel", tr("LAT_ACCEL_FACTOR"), tr("Adjust Max Lateral Acceleration for the Torque Lateral Controller. Live: Override self-tune values; Offline: Override self-tune offline values at car restart."), diff --git a/selfdrive/ui/sunnypilot/qt/offroad/sunnypilot_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/sunnypilot_settings.h index 363ca8473e..550b3fa9be 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/sunnypilot_settings.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/sunnypilot_settings.h @@ -12,7 +12,7 @@ #include "selfdrive/ui/sunnypilot/qt/widgets/sp_priv_controls.h" #include "selfdrive/ui/qt/widgets/scrollview.h" -class TorqueFriction : public SPOptionControl { +class TorqueFriction : public OptionControlSP { Q_OBJECT public: @@ -24,7 +24,7 @@ private: Params params; }; -class TorqueMaxLatAccel : public SPOptionControl { +class TorqueMaxLatAccel : public OptionControlSP { Q_OBJECT public: @@ -65,7 +65,7 @@ private: TorqueFriction *friction; TorqueMaxLatAccel *lat_accel_factor; - ButtonParamControl *dlp_settings; + ButtonParamControlSP *dlp_settings; ScrollView *scrollView = nullptr; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/visuals_settings.cc b/selfdrive/ui/sunnypilot/qt/offroad/visuals_settings.cc index 1c535bf126..3ccd7e148f 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/visuals_settings.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/visuals_settings.cc @@ -73,7 +73,7 @@ VisualsPanel::VisualsPanel(QWidget *parent) : ListWidget(parent) { // Visuals: Developer UI Info (Dev UI) std::vector dev_ui_settings_texts{tr("Off"), tr("5 Metrics"), tr("10 Metrics")}; - dev_ui_settings = new ButtonParamControl( + dev_ui_settings = new ButtonParamControlSP( "DevUIInfo", tr("Developer UI"), tr("Display real-time parameters and metrics from various sources."), "../assets/offroad/icon_blank.png", dev_ui_settings_texts, @@ -83,7 +83,7 @@ VisualsPanel::VisualsPanel(QWidget *parent) : ListWidget(parent) { // Visuals: Display Metrics above Chevron std::vector chevron_info_settings_texts{tr("Off"), tr("Distance"), tr("Speed"), tr("Distance\nSpeed")}; - chevron_info_settings = new ButtonParamControl( + chevron_info_settings = new ButtonParamControlSP( "ChevronInfo", tr("Display Metrics Below Chevron"), tr("Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control)."), "../assets/offroad/icon_blank.png", chevron_info_settings_texts, @@ -107,7 +107,7 @@ VisualsPanel::VisualsPanel(QWidget *parent) : ListWidget(parent) { } std::vector sidebar_temp_texts{tr("Off"), tr("RAM"), tr("CPU"), tr("GPU"), tr("Max")}; - sidebar_temp_setting = new ButtonParamControl( + sidebar_temp_setting = new ButtonParamControlSP( "SidebarTemperatureOptions", tr("Display Temperature on Sidebar"), "", "../assets/offroad/icon_blank.png", sidebar_temp_texts, diff --git a/selfdrive/ui/sunnypilot/qt/offroad/visuals_settings.h b/selfdrive/ui/sunnypilot/qt/offroad/visuals_settings.h index 38367912c4..5b20af11da 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/visuals_settings.h +++ b/selfdrive/ui/sunnypilot/qt/offroad/visuals_settings.h @@ -13,7 +13,7 @@ private: Params params; std::map toggles; - ButtonParamControl *dev_ui_settings; - ButtonParamControl *chevron_info_settings; - ButtonParamControl *sidebar_temp_setting; + ButtonParamControlSP *dev_ui_settings; + ButtonParamControlSP *chevron_info_settings; + ButtonParamControlSP *sidebar_temp_setting; }; diff --git a/selfdrive/ui/sunnypilot/qt/widgets/sp_priv_controls.cc b/selfdrive/ui/sunnypilot/qt/widgets/sp_priv_controls.cc index 620e007096..8b2eeac65b 100644 --- a/selfdrive/ui/sunnypilot/qt/widgets/sp_priv_controls.cc +++ b/selfdrive/ui/sunnypilot/qt/widgets/sp_priv_controls.cc @@ -12,6 +12,54 @@ QFrame *horizontal_line(QWidget *parent) { return line; } +AbstractControlSP::AbstractControlSP(const QString &title, const QString &desc, const QString &icon, QWidget *parent) : QFrame(parent) { + QVBoxLayout *main_layout = new QVBoxLayout(this); + main_layout->setMargin(0); + + hlayout = new QHBoxLayout; + hlayout->setMargin(0); + hlayout->setSpacing(0); + + // title + if (!title.isEmpty()) { + title_label = new QPushButton(title); + title_label->setFixedHeight(120); + title_label->setStyleSheet("font-size: 50px; font-weight: 450; text-align: left; border: none;"); + main_layout->addWidget(title_label, 1); + + connect(title_label, &QPushButton::clicked, [=]() { + if (!description->isVisible()) { + emit showDescriptionEvent(); + } + + if (!description->text().isEmpty()) { + description->setVisible(!description->isVisible()); + } + }); + } else { + main_layout->addSpacing(20); + } + + main_layout->addLayout(hlayout); + main_layout->addSpacing(2); + + // description + description = new QLabel(desc); + description->setContentsMargins(0, 20, 40, 20); + description->setStyleSheet("font-size: 40px; color: grey"); + description->setWordWrap(true); + description->setVisible(false); + main_layout->addWidget(description); + + main_layout->addStretch(); +} + +void AbstractControlSP::hideEvent(QHideEvent *e) { + if (description != nullptr) { + description->hide(); + } +} + ParamControlSP::ParamControlSP(const QString ¶m, const QString &title, const QString &desc, const QString &icon, QWidget *parent) : ParamControl(param, title, desc, icon, parent) { diff --git a/selfdrive/ui/sunnypilot/qt/widgets/sp_priv_controls.h b/selfdrive/ui/sunnypilot/qt/widgets/sp_priv_controls.h index 55a37fa36d..fccd04cd40 100644 --- a/selfdrive/ui/sunnypilot/qt/widgets/sp_priv_controls.h +++ b/selfdrive/ui/sunnypilot/qt/widgets/sp_priv_controls.h @@ -12,3 +12,307 @@ public: bool isToggled() { return params.getBool(key); } }; + +class AbstractControlSP : public QFrame { + Q_OBJECT + +public: + void setDescription(const QString &desc) { + if (description) description->setText(desc); + } + + void setTitle(const QString &title) { + title_label->setText(title); + } + + const QString getDescription() { + return description->text(); + } + + public slots: + void showDescription() { + description->setVisible(true); + } + + void hideDescription() { + description->setVisible(false); + } + + signals: + void showDescriptionEvent(); + +protected: + AbstractControlSP(const QString &title, const QString &desc = "", const QString &icon = "", QWidget *parent = nullptr); + void hideEvent(QHideEvent *e) override; + + QHBoxLayout *hlayout; + QPushButton *title_label; + +private: + QLabel *description = nullptr; +}; + +class ButtonParamControlSP : public AbstractControlSP { + Q_OBJECT +public: + ButtonParamControlSP(const QString ¶m, const QString &title, const QString &desc, const QString &icon, + const std::vector &button_texts, const int minimum_button_width = 300) : AbstractControlSP(title, desc, icon), button_texts(button_texts) { + const QString style = R"( + QPushButton { + border-radius: 20px; + font-size: 50px; + font-weight: 450; + height:150px; + padding: 0 25 0 25; + color: #FFFFFF; + } + QPushButton:pressed { + background-color: #4a4a4a; + } + QPushButton:checked:enabled { + background-color: #696868; + } + QPushButton:disabled { + color: #33FFFFFF; + } + QPushButton:checked:disabled { + background-color: #121212; + color: #33FFFFFF; + } + )"; + key = param.toStdString(); + int value = atoi(params.get(key).c_str()); + + button_group = new QButtonGroup(this); + button_group->setExclusive(true); + for (int i = 0; i < button_texts.size(); i++) { + QPushButton *button = new QPushButton(button_texts[i], this); + button->setCheckable(true); + button->setChecked(i == value); + button->setStyleSheet(style); + button->setMinimumWidth(minimum_button_width); + if (i == 0) hlayout->addSpacing(2); + hlayout->addWidget(button); + button_group->addButton(button, i); + } + + hlayout->setAlignment(Qt::AlignLeft); + + QObject::connect(button_group, QOverload::of(&QButtonGroup::buttonClicked), [=](int id) { + params.put(key, std::to_string(id)); + emit buttonToggled(id); + }); + } + + void setEnabled(bool enable) { + for (auto btn : button_group->buttons()) { + btn->setEnabled(enable); + } + button_group_enabled = enable; + + update(); + } + + void setCheckedButton(int id) { + button_group->button(id)->setChecked(true); + } + + void refresh() { + int value = atoi(params.get(key).c_str()); + + if (value >= button_texts.size()) { + value = button_texts.size() - 1; + } + if (value < 0) { + value = 0; + } + + button_group->button(value)->setChecked(true); + } + + void showEvent(QShowEvent *event) override { + refresh(); + } + + void setButton(QString param) { + key = param.toStdString(); + int value = atoi(params.get(key).c_str()); + for (int i = 0; i < button_group->buttons().size(); i++) { + button_group->buttons()[i]->setChecked(i == value); + } + } + + void setDisabledSelectedButton(std::string val) { + int value = atoi(val.c_str()); + for (int i = 0; i < button_group->buttons().size(); i++) { + button_group->buttons()[i]->setEnabled(i != value); + } + } + +protected: + void paintEvent(QPaintEvent *event) override { + QPainter p(this); + p.setRenderHint(QPainter::Antialiasing); + + // Calculate the total width and height for the background rectangle + int w = 0; + int h = 150; + + for (int i = 0; i < hlayout->count(); ++i) { + QPushButton *button = qobject_cast(hlayout->itemAt(i)->widget()); + if (button) { + w += button->width(); + } + } + + // Draw the rectangle + QRect rect(0 + 2, h - 24, w, h); + p.setPen(QPen(QColor(button_group_enabled ? "#696868" : "#121212"), 3)); + p.drawRoundedRect(rect, 20, 20); + } + +signals: + void buttonToggled(int btn_id); + +private: + std::string key; + Params params; + QButtonGroup *button_group; + std::vector button_texts; + + bool button_group_enabled = true; +}; + +class OptionControlSP : public AbstractControlSP { + Q_OBJECT + +private: + struct MinMaxValue { + int min_value; + int max_value; + }; + +public: + OptionControlSP(const QString ¶m, const QString &title, const QString &desc, const QString &icon, + const MinMaxValue &range, const int per_value_change = 1) : _title(title), AbstractControlSP(title, desc, icon) { + const QString style = R"( + QPushButton { + border-radius: 20px; + font-size: 60px; + font-weight: 500; + width: 150px; + height: 150px; + padding: -3 25 3 25; + color: #FFFFFF; + font-weight: bold; + } + QPushButton:pressed { + color: #5C5C5C; + } + QPushButton:disabled { + color: #5C5C5C; + } + )"; + + label.setStyleSheet(label_enabled_style); + label.setFixedWidth(300); + label.setAlignment(Qt::AlignCenter); + + const std::vector button_texts{"-", "+"}; + + key = param.toStdString(); + value = atoi(params.get(key).c_str()); + + button_group = new QButtonGroup(this); + button_group->setExclusive(true); + for (int i = 0; i < button_texts.size(); i++) { + QPushButton *button = new QPushButton(button_texts[i], this); + button->setStyleSheet(style + ((i == 0) ? "QPushButton { text-align: left; }" : + "QPushButton { text-align: right; }")); + hlayout->addWidget(button, 0, ((i == 0) ? Qt::AlignLeft : Qt::AlignRight) | Qt::AlignVCenter); + if (i == 0) { + hlayout->addWidget(&label, 0, Qt::AlignCenter); + } + button_group->addButton(button, i); + + QObject::connect(button, &QPushButton::clicked, [=]() { + int change_value = (i == 0) ? -per_value_change : per_value_change; + key = param.toStdString(); + value = atoi(params.get(key).c_str()); + value += change_value; + value = std::clamp(value, range.min_value, range.max_value); + params.put(key, QString::number(value).toStdString()); + + button_group->button(0)->setEnabled(!(value <= range.min_value)); + button_group->button(1)->setEnabled(!(value >= range.max_value)); + + updateLabels(); + + if (request_update) { + emit updateOtherToggles(); + } + }); + } + + hlayout->setAlignment(Qt::AlignLeft); + } + + void setUpdateOtherToggles(bool _update) { + request_update = _update; + } + + inline void setLabel(const QString &text) { label.setText(text); } + + void setEnabled(bool enabled) { + for (auto btn : button_group->buttons()) { + btn->setEnabled(enabled); + } + label.setEnabled(enabled); + label.setStyleSheet(enabled ? label_enabled_style : label_disabled_style); + button_enabled = enabled; + + update(); + } + +protected: + void paintEvent(QPaintEvent *event) override { + QPainter p(this); + p.setRenderHint(QPainter::Antialiasing); + + // Calculate the total width and height for the background rectangle + int w = 0; + int h = 150; + + for (int i = 0; i < hlayout->count(); ++i) { + QWidget *widget = qobject_cast(hlayout->itemAt(i)->widget()); + if (widget) { + w += widget->width(); + } + } + + // Draw the rectangle + QRect rect(0, !_title.isEmpty() ? (h - 24) : 20, w, h); + p.setBrush(QColor(button_enabled ? "#b24a4a4a" : "#121212")); // Background color + p.setPen(QPen(Qt::NoPen)); + p.drawRoundedRect(rect, 20, 20); + } + +signals: + void updateLabels(); + void updateOtherToggles(); + +private: + std::string key; + int value; + QButtonGroup *button_group; + QLabel label; + Params params; + std::map option_label = {}; + bool request_update = false; + QString _title = ""; + + const QString label_enabled_style = "font-size: 50px; font-weight: 450; color: #FFFFFF;"; + const QString label_disabled_style = "font-size: 50px; font-weight: 450; color: #5C5C5C;"; + + bool button_enabled = true; +};