Qt spinner (#2494)

* move android spinner

* qt spinner

* rotation

* nothing by default

* spin spin

* fix rotate

* style

* spinner for all

* -2

* unused
pull/2498/head
Adeeb Shihadeh 2020-11-06 18:44:04 -08:00 committed by GitHub
parent c6e1beb402
commit 6c86afee16
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 192 additions and 68 deletions

View File

@ -4,17 +4,14 @@ from common.basedir import BASEDIR
class Spinner(): class Spinner():
def __init__(self, noop=False): def __init__(self):
# spinner is currently only implemented for android try:
self.spinner_proc = None self.spinner_proc = subprocess.Popen(["./spinner"],
if not noop: stdin=subprocess.PIPE,
try: cwd=os.path.join(BASEDIR, "selfdrive", "ui"),
self.spinner_proc = subprocess.Popen(["./spinner"], close_fds=True)
stdin=subprocess.PIPE, except OSError:
cwd=os.path.join(BASEDIR, "selfdrive", "ui", "spinner"), self.spinner_proc = None
close_fds=True)
except OSError:
self.spinner_proc = None
def __enter__(self): def __enter__(self):
return self return self

View File

@ -7,8 +7,6 @@ from common.basedir import BASEDIR
class TextWindow: class TextWindow:
def __init__(self, text): def __init__(self, text):
# text window is only implemented for android currently
self.text_proc = None
try: try:
self.text_proc = subprocess.Popen(["./text", text], self.text_proc = subprocess.Popen(["./text", text],
stdin=subprocess.PIPE, stdin=subprocess.PIPE,

View File

@ -219,8 +219,6 @@ selfdrive/common/visionbuf.h
selfdrive/common/visionbuf_ion.c selfdrive/common/visionbuf_ion.c
selfdrive/common/visionimg.cc selfdrive/common/visionimg.cc
selfdrive/common/visionimg.h selfdrive/common/visionimg.h
selfdrive/common/spinner.c
selfdrive/common/spinner.h
selfdrive/common/gpio.cc selfdrive/common/gpio.cc
selfdrive/common/gpio.h selfdrive/common/gpio.h
@ -344,9 +342,11 @@ selfdrive/ui/SConscript
selfdrive/ui/*.cc selfdrive/ui/*.cc
selfdrive/ui/*.hpp selfdrive/ui/*.hpp
selfdrive/ui/ui selfdrive/ui/ui
selfdrive/ui/spinner/Makefile selfdrive/ui/text
selfdrive/ui/spinner/spinner selfdrive/ui/spinner
selfdrive/ui/spinner/spinner.c selfdrive/ui/android/spinner/Makefile
selfdrive/ui/android/spinner/spinner
selfdrive/ui/android/spinner/spinner.c
selfdrive/ui/android/text/Makefile selfdrive/ui/android/text/Makefile
selfdrive/ui/android/text/text selfdrive/ui/android/text/text

View File

@ -8,7 +8,6 @@ from functools import wraps
import cereal.messaging as messaging import cereal.messaging as messaging
from cereal import car from cereal import car
from common.basedir import BASEDIR from common.basedir import BASEDIR
from common.hardware import ANDROID
from common.params import Params from common.params import Params
from common.spinner import Spinner from common.spinner import Spinner
from panda import Panda from panda import Panda
@ -36,7 +35,7 @@ os.environ['BASEDIR'] = BASEDIR
@with_processes(['boardd']) @with_processes(['boardd'])
def test_boardd_loopback(): def test_boardd_loopback():
# wait for boardd to init # wait for boardd to init
spinner = Spinner(noop=(not ANDROID)) spinner = Spinner()
time.sleep(2) time.sleep(2)
# boardd blocks on CarVin and CarParams # boardd blocks on CarVin and CarParams

View File

@ -1,14 +0,0 @@
#ifndef COMMON_SPINNER_H
#define COMMON_SPINNER_H
#ifdef __cplusplus
extern "C" {
#endif
int spin(int argc, char** argv);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -78,7 +78,7 @@ import traceback
from multiprocessing import Process from multiprocessing import Process
# Run scons # Run scons
spinner = Spinner(noop=(__name__ != "__main__" or not ANDROID)) spinner = Spinner()
spinner.update("0") spinner.update("0")
if not prebuilt: if not prebuilt:
@ -138,7 +138,6 @@ if not prebuilt:
cloudlog.error("scons build failed\n" + error_s) cloudlog.error("scons build failed\n" + error_s)
# Show TextWindow # Show TextWindow
no_ui = __name__ != "__main__" or not ANDROID
error_s = "\n \n".join(["\n".join(textwrap.wrap(e, 65)) for e in errors]) error_s = "\n \n".join(["\n".join(textwrap.wrap(e, 65)) for e in errors])
with TextWindow("openpilot failed to build\n \n" + error_s) as t: with TextWindow("openpilot failed to build\n \n" + error_s) as t:
t.wait_for_exit() t.wait_for_exit()

View File

@ -1,2 +1,5 @@
moc_* moc_*
*.moc
qt/text qt/text
qt/spinner

View File

@ -72,5 +72,6 @@ else:
qt_src = ["qt/ui.cc", "qt/window.cc", "qt/qt_sound.cc", "qt/offroad/settings.cc", "qt/offroad/onboarding.cc"] + src qt_src = ["qt/ui.cc", "qt/window.cc", "qt/qt_sound.cc", "qt/offroad/settings.cc", "qt/offroad/onboarding.cc"] + src
qt_env.Program("_ui", qt_src, LIBS=qt_libs + libs) qt_env.Program("_ui", qt_src, LIBS=qt_libs + libs)
# text window # spinner and text window
qt_env.Program("qt/text", ["qt/text.cc"], LIBS=qt_libs + libs) qt_env.Program("qt/text", ["qt/text.cc"], LIBS=qt_libs + libs)
qt_env.Program("qt/spinner", ["qt/spinner.cc"], LIBS=qt_libs + libs)

View File

@ -1,7 +1,9 @@
CC = clang CC = clang
CXX = clang++ CXX = clang++
PHONELIBS = ../../../phonelibs ROOT_DIR = ../../..
PHONELIBS = $(ROOT_DIR)/phonelibs
COMMON = $(ROOT)/selfdrive/common
WARN_FLAGS = -Werror=implicit-function-declaration \ WARN_FLAGS = -Werror=implicit-function-declaration \
-Werror=incompatible-pointer-types \ -Werror=incompatible-pointer-types \
@ -19,10 +21,10 @@ OPENGL_LIBS = -lGLESv3
FRAMEBUFFER_LIBS = -lutils -lgui -lEGL FRAMEBUFFER_LIBS = -lutils -lgui -lEGL
OBJS = spinner.o \ OBJS = spinner.o \
../../common/framebuffer.o \ $(COMMON)/framebuffer.o \
../../common/util.o \ $(COMMON)/util.o \
$(PHONELIBS)/nanovg/nanovg.o \ $(PHONELIBS)/nanovg/nanovg.o \
../../common/spinner.o \ $(COMMON)/spinner.o \
opensans_semibold.o \ opensans_semibold.o \
img_spinner_track.o \ img_spinner_track.o \
img_spinner_comma.o img_spinner_comma.o
@ -41,7 +43,7 @@ spinner: $(OBJS)
$(OPENGL_LIBS) \ $(OPENGL_LIBS) \
-lm -llog -lm -llog
../../common/framebuffer.o: ../../common/framebuffer.cc $(COMMON)/framebuffer.o: $(COMMON)/framebuffer.cc
@echo "[ CXX ] $@" @echo "[ CXX ] $@"
$(CXX) $(CXXFLAGS) -MMD \ $(CXX) $(CXXFLAGS) -MMD \
-I$(PHONELIBS)/android_frameworks_native/include \ -I$(PHONELIBS)/android_frameworks_native/include \
@ -49,15 +51,15 @@ spinner: $(OBJS)
-I$(PHONELIBS)/android_hardware_libhardware/include \ -I$(PHONELIBS)/android_hardware_libhardware/include \
-c -o '$@' '$<' -c -o '$@' '$<'
opensans_semibold.o: ../../assets/fonts/opensans_semibold.ttf opensans_semibold.o: $(ROOT_DIR)/selfdrive/assets/fonts/opensans_semibold.ttf
@echo "[ bin2o ] $@" @echo "[ bin2o ] $@"
cd '$(dir $<)' && ld -r -b binary '$(notdir $<)' -o '$(abspath $@)' cd '$(dir $<)' && ld -r -b binary '$(notdir $<)' -o '$(abspath $@)'
img_spinner_track.o: ../../assets/img_spinner_track.png img_spinner_track.o: $(ROOT_DIR)/selfdrive/assets/img_spinner_track.png
@echo "[ bin2o ] $@" @echo "[ bin2o ] $@"
cd '$(dir $<)' && ld -r -b binary '$(notdir $<)' -o '$(abspath $@)' cd '$(dir $<)' && ld -r -b binary '$(notdir $<)' -o '$(abspath $@)'
img_spinner_comma.o: ../../assets/img_spinner_comma.png img_spinner_comma.o: $(ROOT_DIR)/selfdrive/assets/img_spinner_comma.png
@echo "[ bin2o ] $@" @echo "[ bin2o ] $@"
cd '$(dir $<)' && ld -r -b binary '$(notdir $<)' -o '$(abspath $@)' cd '$(dir $<)' && ld -r -b binary '$(notdir $<)' -o '$(abspath $@)'

View File

@ -42,8 +42,7 @@ bool stdin_input_available() {
return (FD_ISSET(0, &fds)); return (FD_ISSET(0, &fds));
} }
int spin(int argc, char** argv) { int main(int argc, char** argv) {
int err;
bool draw_progress = false; bool draw_progress = false;
float progress_val = 0.0; float progress_val = 0.0;

View File

@ -0,0 +1,126 @@
#include <stdio.h>
#include <string>
#include <iostream>
#include <QString>
#include <QGridLayout>
#include <QApplication>
#include <QDesktopWidget>
#ifdef QCOM2
#include <qpa/qplatformnativeinterface.h>
#include <QPlatformSurfaceEvent>
#include <wayland-client-protocol.h>
#endif
#include "spinner.hpp"
Spinner::Spinner(QWidget *parent) {
QGridLayout *main_layout = new QGridLayout();
main_layout->setSpacing(0);
main_layout->setMargin(50);
const int img_size = 500;
comma = new QLabel();
comma->setPixmap(QPixmap("../assets/img_spinner_comma.png").scaled(img_size, img_size, Qt::KeepAspectRatio));
comma->setFixedSize(img_size, img_size);
main_layout->addWidget(comma, 0, 0, Qt::AlignHCenter | Qt::AlignVCenter);
track_img = QPixmap("../assets/img_spinner_track.png").scaled(img_size, img_size, Qt::KeepAspectRatio);
track = new QLabel();
track->setPixmap(track_img);
track->setFixedSize(img_size, img_size);
main_layout->addWidget(track, 0, 0, Qt::AlignHCenter | Qt::AlignVCenter);
text = new QLabel("building boardd");
text->setVisible(false);
text->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
main_layout->addWidget(text, 1, 0, Qt::AlignHCenter);
progress_bar = new QProgressBar();
progress_bar->setMinimum(5);
progress_bar->setMaximum(100);
progress_bar->setTextVisible(false);
progress_bar->setVisible(false);
progress_bar->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
main_layout->addWidget(progress_bar, 1, 0, Qt::AlignHCenter);
setLayout(main_layout);
setStyleSheet(R"(
Spinner {
background-color: black;
}
QLabel {
color: white;
font-size: 80px;
}
QProgressBar {
background-color: #373737;
border: none;
margin: 100px;
height: 50px;
width: 1000px;
}
QProgressBar::chunk {
background-color: white;
}
)");
rotate_timer = new QTimer(this);
rotate_timer->start(1000/30.);
QObject::connect(rotate_timer, SIGNAL(timeout()), this, SLOT(rotate()));
notifier = new QSocketNotifier(fileno(stdin), QSocketNotifier::Read);
QObject::connect(notifier, SIGNAL(activated(int)), this, SLOT(update(int)));
};
void Spinner::rotate() {
transform.rotate(5);
QPixmap r = track_img.transformed(transform);
int x = (r.width() - track_img.width()) / 2;
int y = (r.height() - track_img.height()) / 2;
track->setPixmap(r.copy(x, y, track_img.width(), track_img.height()));
};
void Spinner::update(int n) {
std::string line;
std::getline(std::cin, line);
if (line.length()) {
bool number = std::all_of(line.begin(), line.end(), ::isdigit);
text->setVisible(!number);
progress_bar->setVisible(number);
text->setText(QString::fromStdString(line));
if (number) {
progress_bar->setValue(std::stoi(line));
}
}
}
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
Spinner *spinner = new Spinner();
// TODO: get size from QScreen, doesn't work on tici
#ifdef QCOM2
int w = 2160, h = 1080;
#else
int w = 1920, h = 1080;
#endif
spinner->setFixedSize(w, h);
spinner->show();
#ifdef QCOM2
QPlatformNativeInterface *native = QGuiApplication::platformNativeInterface();
wl_surface *s = reinterpret_cast<wl_surface*>(native->nativeResourceForWindow("surface", spinner->windowHandle()));
wl_surface_set_buffer_transform(s, WL_OUTPUT_TRANSFORM_270);
wl_surface_commit(s);
spinner->showFullScreen();
#endif
return a.exec();
}

View File

@ -0,0 +1,27 @@
#include <QTimer>
#include <QLabel>
#include <QWidget>
#include <QPixmap>
#include <QProgressBar>
#include <QTransform>
#include <QSocketNotifier>
class Spinner : public QWidget {
Q_OBJECT
public:
explicit Spinner(QWidget *parent = 0);
private:
QPixmap track_img;
QTimer *rotate_timer;
QLabel *comma, *track;
QLabel *text;
QProgressBar *progress_bar;
QTransform transform;
QSocketNotifier *notifier;
public slots:
void rotate();
void update(int n);
};

View File

@ -0,0 +1,8 @@
#!/bin/sh
if [ -f /EON ]; then
export LD_LIBRARY_PATH="/system/lib64:$LD_LIBRARY_PATH"
exec ./android/spinner/spinner "$1"
else
exec ./qt/spinner "$1"
fi

View File

@ -1,21 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>
#include <unistd.h>
#include <assert.h>
#include <GLES3/gl3.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include "common/framebuffer.h"
#include "common/spinner.h"
int main(int argc, char** argv) {
int err;
spin(argc, argv);
return 0;
}