diff --git a/SConstruct b/SConstruct index 3dd8e9862a..fc1ddfd66b 100644 --- a/SConstruct +++ b/SConstruct @@ -264,7 +264,7 @@ Export('envCython') # Qt build environment qt_env = env.Clone() -qt_modules = ["Widgets", "Gui", "Core", "Network", "Concurrent", "Multimedia"] +qt_modules = ["Widgets", "Gui", "Core", "Network", "Concurrent", "Multimedia", "Quick", "Qml", "QuickWidgets"] if arch != "aarch64": qt_modules += ["DBus"] @@ -307,6 +307,9 @@ qt_flags = [ "-DQT_NO_DEBUG", "-DQT_WIDGETS_LIB", "-DQT_GUI_LIB", + "-DQT_QUICK_LIB", + "-DQT_QUICKWIDGETS_LIB", + "-DQT_QML_LIB", "-DQT_CORE_LIB" ] qt_env['CXXFLAGS'] += qt_flags diff --git a/selfdrive/ui/qt/offroad/onboarding.cc b/selfdrive/ui/qt/offroad/onboarding.cc index a2018af1a4..edbc10f7a7 100644 --- a/selfdrive/ui/qt/offroad/onboarding.cc +++ b/selfdrive/ui/qt/offroad/onboarding.cc @@ -1,12 +1,13 @@ #include #include +#include #include #include -#include #include #include +#include +#include #include -#include #include "common/params.h" #include "onboarding.hpp" @@ -37,7 +38,7 @@ void TrainingGuide::mouseReleaseEvent(QMouseEvent *e) { } } -TrainingGuide::TrainingGuide(QWidget* parent) { +TrainingGuide::TrainingGuide(QWidget* parent) : QFrame(parent){ image.load("../assets/training/step0.jpg"); } @@ -53,17 +54,24 @@ void TrainingGuide::paintEvent(QPaintEvent *event) { painter.drawImage(rect.topLeft(), image); } +TermsPage::TermsPage(QWidget *parent) : QFrame(parent){ -QWidget* OnboardingWindow::terms_screen() { QVBoxLayout *main_layout = new QVBoxLayout; - main_layout->setContentsMargins(40, 20, 40, 20); + main_layout->setMargin(40); + main_layout->setSpacing(40); + + QQuickWidget *text = new QQuickWidget(QUrl::fromLocalFile("qt/offroad/text_view.qml"), this); + text->setResizeMode(QQuickWidget::SizeRootObjectToView); + text->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + text->setAttribute(Qt::WA_AlwaysStackOnTop); + text->setClearColor(Qt::transparent); + + text->rootContext()->setContextProperty("font_size", 55); + + QString text_view = util::read_file("../assets/offroad/tc.html").c_str(); + text->rootContext()->setContextProperty("text_view", text_view); - QString terms_html = QString::fromStdString(util::read_file("../assets/offroad/tc.html")); - terms_text = new QTextEdit(); - terms_text->setReadOnly(true); - terms_text->setTextInteractionFlags(Qt::NoTextInteraction); - terms_text->setHtml(terms_html); - main_layout->addWidget(terms_text); + main_layout->addWidget(text); // TODO: add decline page QHBoxLayout* buttons = new QHBoxLayout; @@ -72,29 +80,17 @@ QWidget* OnboardingWindow::terms_screen() { buttons->addWidget(new QPushButton("Decline")); buttons->addSpacing(50); - QPushButton *accept_btn = new QPushButton("Scroll to accept"); + accept_btn = new QPushButton("Scroll to accept"); accept_btn->setEnabled(false); buttons->addWidget(accept_btn); QObject::connect(accept_btn, &QPushButton::released, [=]() { - Params().write_db_value("HasAcceptedTerms", current_terms_version); - updateActiveScreen(); + emit acceptedTerms(); }); - // TODO: tune the scrolling - auto sb = terms_text->verticalScrollBar(); - QScroller::grabGesture(terms_text, QScroller::TouchGesture); - terms_text->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - - QObject::connect(sb, &QScrollBar::valueChanged, [sb, accept_btn]() { - if (sb->value() == sb->maximum()){ - accept_btn->setText("Accept"); - accept_btn->setEnabled(true); - } - }); - - QWidget *widget = new QWidget; - widget->setLayout(main_layout); - widget->setStyleSheet(R"( + QObject *obj = (QObject*)text->rootObject(); + QObject::connect(obj, SIGNAL(qmlSignal()), SLOT(enableAccept())); + setLayout(main_layout); + setStyleSheet(R"( * { font-size: 50px; } @@ -104,8 +100,12 @@ QWidget* OnboardingWindow::terms_screen() { background-color: #292929; } )"); +} - return widget; +void TermsPage::enableAccept(){ + accept_btn->setText("Accept"); + accept_btn->setEnabled(true); + return; } void OnboardingWindow::updateActiveScreen() { @@ -126,7 +126,13 @@ OnboardingWindow::OnboardingWindow(QWidget *parent) : QStackedWidget(parent) { current_terms_version = params.get("TermsVersion", false); current_training_version = params.get("TrainingVersion", false); - addWidget(terms_screen()); + TermsPage* terms = new TermsPage(this); + addWidget(terms); + + connect(terms, &TermsPage::acceptedTerms, [=](){ + Params().write_db_value("HasAcceptedTerms", current_terms_version); + updateActiveScreen(); + }); TrainingGuide* tr = new TrainingGuide(this); connect(tr, &TrainingGuide::completedTraining, [=](){ diff --git a/selfdrive/ui/qt/offroad/onboarding.hpp b/selfdrive/ui/qt/offroad/onboarding.hpp index e307bb63a5..998efde3bf 100644 --- a/selfdrive/ui/qt/offroad/onboarding.hpp +++ b/selfdrive/ui/qt/offroad/onboarding.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include "selfdrive/common/params.h" @@ -30,6 +31,23 @@ signals: void completedTraining(); }; + +class TermsPage : public QFrame { + Q_OBJECT + +public: + explicit TermsPage(QWidget *parent = 0); + +private: + QPushButton *accept_btn; + +public slots: + void enableAccept(); + +signals: + void acceptedTerms(); +}; + class OnboardingWindow : public QStackedWidget { Q_OBJECT @@ -41,10 +59,6 @@ private: std::string current_terms_version; std::string current_training_version; - QTextEdit *terms_text; - QWidget *terms_screen(); - QWidget *training_screen(); - signals: void onboardingDone(); diff --git a/selfdrive/ui/qt/offroad/text_view.qml b/selfdrive/ui/qt/offroad/text_view.qml new file mode 100644 index 0000000000..c97a676167 --- /dev/null +++ b/selfdrive/ui/qt/offroad/text_view.qml @@ -0,0 +1,33 @@ +import QtQuick 2.0 + +Item { + id: root + signal qmlSignal() + + Flickable { + id: flickArea + objectName: "flickArea" + anchors.fill: parent + contentHeight: helpText.height + contentWidth: helpText.width + flickableDirection: Flickable.VerticalFlick + flickDeceleration: 7500.0 + maximumFlickVelocity: 10000.0 + pixelAligned: true + + onAtYEndChanged: root.qmlSignal() + + Text { + id: helpText + width: flickArea.width + font.pixelSize: font_size + textFormat: Text.RichText + color: "white" + wrapMode: Text.Wrap + + text: text_view + } + } +} + +