├── .gitignore
├── docs
└── imgs
│ ├── data.png
│ ├── home.png
│ ├── media.png
│ ├── settings.png
│ ├── openauto_maps.png
│ └── openauto_spotify.png
├── assets
├── fonts
│ ├── Montserrat
│ │ ├── Montserrat-Black.ttf
│ │ ├── Montserrat-Bold.ttf
│ │ ├── Montserrat-Light.ttf
│ │ ├── Montserrat-Thin.ttf
│ │ ├── Montserrat-Italic.ttf
│ │ ├── Montserrat-Medium.ttf
│ │ ├── Montserrat-Regular.ttf
│ │ ├── Montserrat-BoldItalic.ttf
│ │ ├── Montserrat-ExtraBold.ttf
│ │ ├── Montserrat-ExtraLight.ttf
│ │ ├── Montserrat-SemiBold.ttf
│ │ ├── Montserrat-ThinItalic.ttf
│ │ ├── Montserrat-BlackItalic.ttf
│ │ ├── Montserrat-LightItalic.ttf
│ │ ├── Montserrat-MediumItalic.ttf
│ │ ├── Montserrat-ExtraBoldItalic.ttf
│ │ ├── Montserrat-SemiBoldItalic.ttf
│ │ ├── Montserrat-ExtraLightItalic.ttf
│ │ └── OFL.txt
│ └── Titillium_Web
│ │ ├── TitilliumWeb-Black.ttf
│ │ ├── TitilliumWeb-Bold.ttf
│ │ ├── TitilliumWeb-Light.ttf
│ │ ├── TitilliumWeb-Italic.ttf
│ │ ├── TitilliumWeb-Regular.ttf
│ │ ├── TitilliumWeb-BoldItalic.ttf
│ │ ├── TitilliumWeb-ExtraLight.ttf
│ │ ├── TitilliumWeb-SemiBold.ttf
│ │ ├── TitilliumWeb-LightItalic.ttf
│ │ ├── TitilliumWeb-SemiBoldItalic.ttf
│ │ ├── TitilliumWeb-ExtraLightItalic.ttf
│ │ └── OFL.txt
├── icons
│ ├── light
│ │ ├── play-24px.svg
│ │ ├── volume_mute-24px.svg
│ │ ├── pause-24px.svg
│ │ ├── skip_next-24px.svg
│ │ ├── skip_previous-24px.svg
│ │ ├── fast_forward-24px.svg
│ │ ├── fast_rewind-24px.svg
│ │ ├── arrow_drop_down-24px.svg
│ │ ├── check-24px.svg
│ │ ├── report_problem-24px.svg
│ │ ├── tune-24px.svg
│ │ ├── save-24px.svg
│ │ ├── play_circle_outline-24px.svg
│ │ ├── brightness_low-24px.svg
│ │ ├── volume_up-24px.svg
│ │ ├── brightness_high-24px.svg
│ │ ├── speed-24px.svg
│ │ ├── directions_car-24px.svg
│ │ ├── volume_off-24px.svg
│ │ ├── bluetooth_searching-24px.svg
│ │ └── build-24px.svg
│ └── dark
│ │ ├── play-24px.svg
│ │ ├── volume_mute-24px.svg
│ │ ├── pause-24px.svg
│ │ ├── skip_next-24px.svg
│ │ ├── skip_previous-24px.svg
│ │ ├── fast_forward-24px.svg
│ │ ├── fast_rewind-24px.svg
│ │ ├── arrow_drop_down-24px.svg
│ │ ├── check-24px.svg
│ │ ├── report_problem-24px.svg
│ │ ├── tune-24px.svg
│ │ ├── save-24px.svg
│ │ ├── play_circle_outline-24px.svg
│ │ ├── brightness_low-24px.svg
│ │ ├── volume_up-24px.svg
│ │ ├── brightness_high-24px.svg
│ │ ├── speed-24px.svg
│ │ ├── volume_off-24px.svg
│ │ ├── directions_car-24px.svg
│ │ └── bluetooth_searching-24px.svg
├── resources.qrc
└── stylesheets
│ ├── light.qss
│ └── dark.qss
├── .gitmodules
├── include
├── obd
│ ├── conversions.hpp
│ ├── decoders.hpp
│ ├── command.hpp
│ ├── obd.hpp
│ └── message.hpp
└── app
│ ├── widgets
│ ├── tuner.hpp
│ ├── progress.hpp
│ └── switch.hpp
│ ├── tabs
│ ├── media.hpp
│ ├── data.hpp
│ ├── settings.hpp
│ └── open_auto.hpp
│ ├── window.hpp
│ ├── bluetooth.hpp
│ ├── config.hpp
│ └── theme.hpp
├── src
├── obd
│ ├── command.cpp
│ └── obd.cpp
├── dash.cpp
└── app
│ ├── widgets
│ ├── tuner.cpp
│ ├── switch.cpp
│ └── progress.cpp
│ ├── config.cpp
│ ├── bluetooth.cpp
│ ├── tabs
│ ├── open_auto.cpp
│ ├── data.cpp
│ ├── media.cpp
│ └── settings.cpp
│ ├── window.cpp
│ └── theme.cpp
├── cmake_modules
├── Findrtaudio.cmake
└── Findlibusb-1.0.cmake
├── CMakeLists.txt
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode/
2 | bin/
3 | build/
4 |
5 | CMakeLists.txt.user
6 |
--------------------------------------------------------------------------------
/docs/imgs/data.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/docs/imgs/data.png
--------------------------------------------------------------------------------
/docs/imgs/home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/docs/imgs/home.png
--------------------------------------------------------------------------------
/docs/imgs/media.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/docs/imgs/media.png
--------------------------------------------------------------------------------
/docs/imgs/settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/docs/imgs/settings.png
--------------------------------------------------------------------------------
/docs/imgs/openauto_maps.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/docs/imgs/openauto_maps.png
--------------------------------------------------------------------------------
/docs/imgs/openauto_spotify.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/docs/imgs/openauto_spotify.png
--------------------------------------------------------------------------------
/assets/fonts/Montserrat/Montserrat-Black.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/assets/fonts/Montserrat/Montserrat-Black.ttf
--------------------------------------------------------------------------------
/assets/fonts/Montserrat/Montserrat-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/assets/fonts/Montserrat/Montserrat-Bold.ttf
--------------------------------------------------------------------------------
/assets/fonts/Montserrat/Montserrat-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/assets/fonts/Montserrat/Montserrat-Light.ttf
--------------------------------------------------------------------------------
/assets/fonts/Montserrat/Montserrat-Thin.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/assets/fonts/Montserrat/Montserrat-Thin.ttf
--------------------------------------------------------------------------------
/assets/fonts/Montserrat/Montserrat-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/assets/fonts/Montserrat/Montserrat-Italic.ttf
--------------------------------------------------------------------------------
/assets/fonts/Montserrat/Montserrat-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/assets/fonts/Montserrat/Montserrat-Medium.ttf
--------------------------------------------------------------------------------
/assets/fonts/Montserrat/Montserrat-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/assets/fonts/Montserrat/Montserrat-Regular.ttf
--------------------------------------------------------------------------------
/assets/fonts/Montserrat/Montserrat-BoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/assets/fonts/Montserrat/Montserrat-BoldItalic.ttf
--------------------------------------------------------------------------------
/assets/fonts/Montserrat/Montserrat-ExtraBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/assets/fonts/Montserrat/Montserrat-ExtraBold.ttf
--------------------------------------------------------------------------------
/assets/fonts/Montserrat/Montserrat-ExtraLight.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/assets/fonts/Montserrat/Montserrat-ExtraLight.ttf
--------------------------------------------------------------------------------
/assets/fonts/Montserrat/Montserrat-SemiBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/assets/fonts/Montserrat/Montserrat-SemiBold.ttf
--------------------------------------------------------------------------------
/assets/fonts/Montserrat/Montserrat-ThinItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/assets/fonts/Montserrat/Montserrat-ThinItalic.ttf
--------------------------------------------------------------------------------
/assets/fonts/Titillium_Web/TitilliumWeb-Black.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/assets/fonts/Titillium_Web/TitilliumWeb-Black.ttf
--------------------------------------------------------------------------------
/assets/fonts/Titillium_Web/TitilliumWeb-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/assets/fonts/Titillium_Web/TitilliumWeb-Bold.ttf
--------------------------------------------------------------------------------
/assets/fonts/Titillium_Web/TitilliumWeb-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/assets/fonts/Titillium_Web/TitilliumWeb-Light.ttf
--------------------------------------------------------------------------------
/assets/fonts/Montserrat/Montserrat-BlackItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/assets/fonts/Montserrat/Montserrat-BlackItalic.ttf
--------------------------------------------------------------------------------
/assets/fonts/Montserrat/Montserrat-LightItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/assets/fonts/Montserrat/Montserrat-LightItalic.ttf
--------------------------------------------------------------------------------
/assets/fonts/Montserrat/Montserrat-MediumItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/assets/fonts/Montserrat/Montserrat-MediumItalic.ttf
--------------------------------------------------------------------------------
/assets/fonts/Titillium_Web/TitilliumWeb-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/assets/fonts/Titillium_Web/TitilliumWeb-Italic.ttf
--------------------------------------------------------------------------------
/assets/fonts/Titillium_Web/TitilliumWeb-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/assets/fonts/Titillium_Web/TitilliumWeb-Regular.ttf
--------------------------------------------------------------------------------
/assets/fonts/Montserrat/Montserrat-ExtraBoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/assets/fonts/Montserrat/Montserrat-ExtraBoldItalic.ttf
--------------------------------------------------------------------------------
/assets/fonts/Montserrat/Montserrat-SemiBoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/assets/fonts/Montserrat/Montserrat-SemiBoldItalic.ttf
--------------------------------------------------------------------------------
/assets/fonts/Titillium_Web/TitilliumWeb-BoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/assets/fonts/Titillium_Web/TitilliumWeb-BoldItalic.ttf
--------------------------------------------------------------------------------
/assets/fonts/Titillium_Web/TitilliumWeb-ExtraLight.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/assets/fonts/Titillium_Web/TitilliumWeb-ExtraLight.ttf
--------------------------------------------------------------------------------
/assets/fonts/Titillium_Web/TitilliumWeb-SemiBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/assets/fonts/Titillium_Web/TitilliumWeb-SemiBold.ttf
--------------------------------------------------------------------------------
/assets/fonts/Montserrat/Montserrat-ExtraLightItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/assets/fonts/Montserrat/Montserrat-ExtraLightItalic.ttf
--------------------------------------------------------------------------------
/assets/fonts/Titillium_Web/TitilliumWeb-LightItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/assets/fonts/Titillium_Web/TitilliumWeb-LightItalic.ttf
--------------------------------------------------------------------------------
/assets/fonts/Titillium_Web/TitilliumWeb-SemiBoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/assets/fonts/Titillium_Web/TitilliumWeb-SemiBoldItalic.ttf
--------------------------------------------------------------------------------
/assets/fonts/Titillium_Web/TitilliumWeb-ExtraLightItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rsjudka/intelligent-auto/HEAD/assets/fonts/Titillium_Web/TitilliumWeb-ExtraLightItalic.ttf
--------------------------------------------------------------------------------
/assets/icons/light/play-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/dark/play-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "aasdk"]
2 | path = aasdk
3 | url = https://github.com/rsjudka/aasdk.git
4 | branch = master
5 | [submodule "openauto"]
6 | path = openauto
7 | url = https://github.com/rsjudka/openauto.git
8 | branch = master
9 |
--------------------------------------------------------------------------------
/assets/icons/light/volume_mute-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/dark/volume_mute-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/light/pause-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/dark/pause-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/light/skip_next-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/light/skip_previous-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/dark/skip_next-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/dark/skip_previous-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/light/fast_forward-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/light/fast_rewind-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/dark/fast_forward-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/dark/fast_rewind-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/dark/arrow_drop_down-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/light/arrow_drop_down-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/dark/check-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/light/check-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/light/report_problem-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/dark/report_problem-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/light/tune-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/dark/tune-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/light/save-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/dark/save-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/include/obd/conversions.hpp:
--------------------------------------------------------------------------------
1 | #ifndef CONVERSIONS_HPP_
2 | #define CONVERSIONS_HPP_
3 |
4 | double kph_to_mph(double val) { return val * 0.621371; }
5 |
6 | double c_to_f(double val) { return (val * 9 / 5) + 32; }
7 |
8 | double gps_to_gph(double val) { return val * 0.0805; }
9 |
10 | double gps_to_lph(double val) { return val * 3.6; }
11 |
12 | #endif
13 |
--------------------------------------------------------------------------------
/assets/icons/light/play_circle_outline-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/dark/play_circle_outline-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/light/brightness_low-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/dark/brightness_low-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/light/volume_up-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/dark/volume_up-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/light/brightness_high-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/dark/brightness_high-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/light/speed-24px.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/assets/icons/dark/speed-24px.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/include/obd/decoders.hpp:
--------------------------------------------------------------------------------
1 | #ifndef DECODERS_HPP_
2 | #define DECODERS_HPP_
3 |
4 | #include
5 |
6 | double percentage(Response resp) { return (100.0 / 255.0) * resp.A; }
7 |
8 | double temp(Response resp) { return resp.A - 40; }
9 |
10 | double rpm(Response resp) { return ((256.0 * resp.A) + resp.B) / 4.0; }
11 |
12 | double speed(Response resp) { return resp.A; }
13 |
14 | double flow(Response resp) { return ((256.0 * resp.A) + resp.B) / 100.0; }
15 |
16 | #endif
17 |
--------------------------------------------------------------------------------
/include/obd/command.hpp:
--------------------------------------------------------------------------------
1 | #ifndef COMMAND_HPP_
2 | #define COMMAND_HPP_
3 |
4 | #include
5 | #include
6 |
7 | #include
8 |
9 | struct Command {
10 | std::string description;
11 | Request request;
12 | std::function decoder;
13 | };
14 |
15 | struct Commands {
16 | Command LOAD;
17 | Command COOLANT_TEMP;
18 | Command RPM;
19 | Command SPEED;
20 | Command INTAKE_TEMP;
21 | Command MAF;
22 | };
23 |
24 | extern Commands cmds;
25 |
26 | #endif
27 |
--------------------------------------------------------------------------------
/src/obd/command.cpp:
--------------------------------------------------------------------------------
1 | #include "obd/command.hpp"
2 | #include "obd/decoders.hpp"
3 |
4 | Commands cmds = {{"Calculated Engine Load", Request(0x01, 0x04), percentage},
5 | {"Engine Coolant Temperature", Request(0x01, 0x05), temp},
6 | {"Engine Revolutions Per Minute (RPM)", Request(0x01, 0x0C), rpm},
7 | {"Vehicle Speed", Request(0x01, 0x0D), speed},
8 | {"Intake Air Temperature", Request(0x01, 0x0F), temp},
9 | {"Mass Air Flow (MAF) Rate", Request(0x01, 0x10), flow}};
10 |
--------------------------------------------------------------------------------
/assets/icons/light/directions_car-24px.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/assets/icons/light/volume_off-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/dark/volume_off-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/dark/directions_car-24px.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/assets/icons/light/bluetooth_searching-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/dark/bluetooth_searching-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/icons/light/build-24px.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/include/app/widgets/tuner.hpp:
--------------------------------------------------------------------------------
1 | #ifndef TUNER_HPP_
2 | #define TUNER_HPP_
3 |
4 | #include
5 |
6 | #include
7 |
8 | class Tuner : public QSlider {
9 | Q_OBJECT
10 | Q_PROPERTY(QColor color READ get_color WRITE set_color)
11 |
12 | public:
13 | Tuner(QWidget *parent = nullptr);
14 |
15 | QSize sizeHint() const override;
16 |
17 | QColor get_color() { return this->color; }
18 | void set_color(QColor color) { this->color = color; }
19 |
20 | protected:
21 | void paintEvent(QPaintEvent *event) override;
22 |
23 | signals:
24 | void station_updated(int);
25 |
26 | private:
27 | Config *config;
28 | QColor color;
29 | };
30 |
31 | #endif
32 |
--------------------------------------------------------------------------------
/src/dash.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include
5 |
6 | int main(int argc, char *argv[])
7 | {
8 | QApplication dash(argc, argv);
9 | QStringList args = QCoreApplication::arguments();
10 |
11 | MainWindow window;
12 | window.setWindowFlags(Qt::FramelessWindowHint);
13 | if (args.size() > 2) {
14 | int w = args.at(1).toInt();
15 | int h = args.at(2).toInt();
16 | window.setFixedSize(w, h);
17 | }
18 | else {
19 | dash.setOverrideCursor(Qt::BlankCursor);
20 | window.setFixedSize(dash.desktop()->screenGeometry().size());
21 | }
22 | window.move(0, 0);
23 | window.show();
24 |
25 | return dash.exec();
26 | }
27 |
--------------------------------------------------------------------------------
/include/obd/obd.hpp:
--------------------------------------------------------------------------------
1 | #ifndef OBD_HPP_
2 | #define OBD_HPP_
3 |
4 | #include
5 |
6 | #include
7 | #include
8 |
9 | #include
10 |
11 | class OBD {
12 | public:
13 | OBD();
14 | ~OBD();
15 |
16 | bool query(Command &cmd, double &val);
17 |
18 | inline bool is_connected() { return this->connected; }
19 |
20 | static OBD *get_instance();
21 |
22 | private:
23 | void connect(std::string dev_path, speed_t baudrate);
24 | void initialize();
25 | bool send(Request req);
26 | int _write(std::string str);
27 | bool is_failed_response(std::string str);
28 | Response receive();
29 | std::string _read();
30 |
31 | inline std::string raw_query(std::string cmd) { return (this->_write(cmd) > 0) ? this->_read() : ""; }
32 |
33 | int fd;
34 | std::mutex obd_mutex;
35 |
36 | bool connected = false;
37 | };
38 |
39 | #endif
40 |
--------------------------------------------------------------------------------
/include/app/tabs/media.hpp:
--------------------------------------------------------------------------------
1 | #ifndef MEDIA_HPP_
2 | #define MEDIA_HPP_
3 |
4 | #include
5 |
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | class MediaTab : public QTabWidget {
12 | Q_OBJECT
13 |
14 | public:
15 | MediaTab(QWidget *parent = nullptr);
16 | };
17 |
18 | class BluetoothPlayerSubTab : public QWidget {
19 | Q_OBJECT
20 |
21 | public:
22 | BluetoothPlayerSubTab(QWidget *parent = nullptr);
23 |
24 | private:
25 | QWidget *track_widget();
26 | QWidget *controls_widget();
27 |
28 | Bluetooth *bluetooth;
29 | Theme *theme;
30 | };
31 |
32 | class RadioPlayerSubTab : public QWidget {
33 | Q_OBJECT
34 |
35 | public:
36 | RadioPlayerSubTab(QWidget *parent = nullptr);
37 |
38 | private:
39 | QWidget *tuner_widget();
40 | QWidget *controls_widget();
41 |
42 | Config *config;
43 | Theme *theme;
44 | Tuner *tuner;
45 | };
46 |
47 | #endif
48 |
--------------------------------------------------------------------------------
/include/app/window.hpp:
--------------------------------------------------------------------------------
1 | #ifndef WINDOW_HPP_
2 | #define WINDOW_HPP_
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 |
13 | #include
14 | #include
15 | #include
16 |
17 | class MainWindow : public QMainWindow {
18 | Q_OBJECT
19 |
20 | public:
21 | MainWindow();
22 |
23 | protected:
24 | void showEvent(QShowEvent *event);
25 |
26 | private:
27 | static void update_system_volume(int position);
28 | QTabWidget *tabs_widget();
29 | QWidget *controls_widget();
30 | QWidget *volume_widget();
31 |
32 | Config *config;
33 | Theme *theme;
34 | OpenAutoTab *open_auto_tab;
35 |
36 | signals:
37 | void set_data_state(bool enabled);
38 | void set_open_auto_state(unsigned int alpha);
39 | };
40 |
41 | #endif
42 |
--------------------------------------------------------------------------------
/include/app/widgets/progress.hpp:
--------------------------------------------------------------------------------
1 | #ifndef PROGRESS_H
2 | #define PROGRESS_H
3 |
4 | #include
5 | #include
6 |
7 | class ProgressIndicator : public QWidget {
8 | Q_OBJECT
9 | Q_PROPERTY(qreal dash_offset READ get_dash_offset WRITE set_dash_offset)
10 | Q_PROPERTY(qreal dash_length READ get_dash_length WRITE set_dash_length)
11 | Q_PROPERTY(int angle READ get_angle WRITE set_angle)
12 |
13 | public:
14 | ProgressIndicator(QWidget* parent = nullptr);
15 |
16 | inline int get_angle() { return this->angle; }
17 | inline void set_angle(int angle) { this->angle = angle; }
18 |
19 | inline qreal get_dash_length() { return this->dash_length; }
20 | inline void set_dash_length(qreal length) { this->dash_length = length; }
21 |
22 | inline qreal get_dash_offset() { return this->dash_offset; }
23 | inline void set_dash_offset(qreal offset) { this->dash_offset = offset; }
24 |
25 | public slots:
26 | void startAnimation();
27 | void stopAnimation();
28 |
29 | protected:
30 | virtual inline void timerEvent(QTimerEvent* event) { update(); }
31 | virtual void paintEvent(QPaintEvent* event);
32 |
33 | private:
34 | int timer_id = -1;
35 | bool enabled = false;
36 | int angle = 0;
37 | qreal dash_length = 24;
38 | qreal dash_offset = 0;
39 | };
40 |
41 | #endif
--------------------------------------------------------------------------------
/include/app/tabs/data.hpp:
--------------------------------------------------------------------------------
1 | #ifndef DATA_HPP_
2 | #define DATA_HPP_
3 |
4 | #include
5 | #include
6 |
7 | #include
8 |
9 | typedef std::function, bool)> obd_decoder_t;
10 | typedef QPair units_t;
11 |
12 | class Gauge : public QWidget {
13 | Q_OBJECT
14 |
15 | public:
16 | enum Orientation { BOTTOM, RIGHT };
17 |
18 | Gauge(units_t units, QFont value_font, QFont unit_font, Orientation orientation, int rate,
19 | std::vector cmds, int precision, obd_decoder_t decoder, QWidget *parent = nullptr);
20 |
21 | inline void start() { this->timer->start(this->rate); }
22 | inline void stop() { this->timer->stop(); }
23 |
24 | private:
25 | QString format_value(double value);
26 | QString null_value();
27 |
28 | bool si;
29 | int rate;
30 | int precision;
31 | QTimer *timer;
32 |
33 | signals:
34 | void toggle_unit(bool si);
35 | };
36 |
37 | class DataTab : public QWidget {
38 | Q_OBJECT
39 |
40 | public:
41 | DataTab(QWidget *parent = nullptr);
42 |
43 | private:
44 | QWidget *cluster_widget();
45 | QWidget *driving_data_widget();
46 | QWidget *speedo_tach_widget();
47 | QWidget *mileage_data_widget();
48 | QWidget *engine_data_widget();
49 | QWidget *coolant_temp_widget();
50 | QWidget *engine_load_widget();
51 |
52 | std::vector gauges;
53 | };
54 |
55 | #endif
56 |
--------------------------------------------------------------------------------
/include/obd/message.hpp:
--------------------------------------------------------------------------------
1 | #ifndef MESSAGE_HPP_
2 | #define MESSAGE_HPP_
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | struct Message {
9 | unsigned char mode;
10 | unsigned char PID;
11 | };
12 |
13 | struct Request : Message {
14 | Request(unsigned char mode, unsigned char PID)
15 | {
16 | this->mode = mode;
17 | this->PID = PID;
18 | }
19 |
20 | std::string to_str()
21 | {
22 | std::stringstream ss;
23 | ss << std::hex << std::setfill('0');
24 | ss << std::setw(2) << static_cast(this->mode) << std::setw(2) << static_cast(this->PID);
25 | return ss.str();
26 | }
27 | };
28 |
29 | struct Response : Message {
30 | bool success = true;
31 | unsigned char A;
32 | unsigned char B;
33 | unsigned char C;
34 | unsigned char D;
35 |
36 | Response(std::string resp_str)
37 | {
38 | this->mode = std::stoi(resp_str.substr(0, 2), nullptr, 16);
39 | this->PID = std::stoi(resp_str.substr(2, 2), nullptr, 16);
40 | this->A = std::stoi(resp_str.substr(4, 2), nullptr, 16);
41 | if (resp_str.length() >= 8) this->B = std::stoi(resp_str.substr(6, 2), nullptr, 16);
42 | if (resp_str.length() >= 10) this->C = std::stoi(resp_str.substr(8, 2), nullptr, 16);
43 | if (resp_str.length() == 12) this->D = std::stoi(resp_str.substr(10, 2), nullptr, 16);
44 | }
45 |
46 | Response() { this->success = false; }
47 | };
48 |
49 | #endif
50 |
--------------------------------------------------------------------------------
/include/app/widgets/switch.hpp:
--------------------------------------------------------------------------------
1 | #ifndef SWITCH_HPP_
2 | #define SWITCH_HPP_
3 |
4 | #include
5 |
6 | class Switch : public QAbstractButton {
7 | Q_OBJECT
8 | Q_PROPERTY(QColor track_color READ get_track_color WRITE set_track_color)
9 | Q_PROPERTY(QColor thumb_color READ get_thumb_color WRITE set_thumb_color)
10 | Q_PROPERTY(int offset READ get_offset WRITE set_offset)
11 |
12 | public:
13 | Switch(QWidget *parent = nullptr);
14 |
15 | QSize sizeHint() const override;
16 |
17 | QColor get_track_color() { return this->track_color; };
18 | QColor get_thumb_color() { return this->thumb_color; };
19 | int get_offset() { return this->offset; }
20 |
21 | void set_track_color(QColor track_color) { this->track_color = track_color; }
22 | void set_thumb_color(QColor thumb_color) { this->thumb_color = thumb_color; }
23 | void set_offset(int offset) { this->offset = offset; }
24 |
25 | protected:
26 | void paintEvent(QPaintEvent *event) override;
27 | void resizeEvent(QResizeEvent *event) override;
28 | void mouseReleaseEvent(QMouseEvent *event) override;
29 | void nextCheckState() override;
30 |
31 | private:
32 | int track_radius;
33 | int thumb_radius;
34 |
35 | QColor track_color = Qt::transparent;
36 | QColor thumb_color = Qt::transparent;
37 | int offset;
38 | int margin;
39 | int base_offset;
40 | std::function end_offset;
41 |
42 | signals:
43 | void stateChanged(bool);
44 | };
45 |
46 | #endif
47 |
--------------------------------------------------------------------------------
/include/app/bluetooth.hpp:
--------------------------------------------------------------------------------
1 | #ifndef BLUETOOTH_HPP_
2 | #define BLUETOOTH_HPP_
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | #include
17 |
18 | class Bluetooth : public QObject {
19 | Q_OBJECT
20 |
21 | public:
22 | Bluetooth();
23 |
24 | void scan();
25 |
26 | inline QList get_devices()
27 | {
28 | return this->has_adapter() ? this->adapter->devices() : QList();
29 | }
30 | inline QPair get_media_player()
31 | {
32 | if (this->media_player_device != nullptr)
33 | return {this->media_player_device->name(), this->media_player_device->mediaPlayer()};
34 |
35 | return {QString(), nullptr};
36 | }
37 | inline bool has_adapter() { return this->adapter != nullptr; }
38 |
39 | static Bluetooth *get_instance();
40 |
41 | private:
42 | void update_media_player(BluezQt::DevicePtr device);
43 |
44 | BluezQt::AdapterPtr adapter;
45 | BluezQt::DevicePtr media_player_device;
46 |
47 | signals:
48 | void device_added(BluezQt::DevicePtr);
49 | void device_changed(BluezQt::DevicePtr);
50 | void device_removed(BluezQt::DevicePtr);
51 | void media_player_changed(QString, BluezQt::MediaPlayerPtr);
52 | void media_player_status_changed(BluezQt::MediaPlayer::Status);
53 | void media_player_track_changed(BluezQt::MediaPlayerTrack);
54 | void scan_status(bool);
55 | };
56 |
57 | #endif
58 |
--------------------------------------------------------------------------------
/include/app/tabs/settings.hpp:
--------------------------------------------------------------------------------
1 | #ifndef SETTINGS_HPP_
2 | #define SETTINGS_HPP_
3 |
4 | #include
5 | #include
6 |
7 | #include
8 | #include
9 | #include
10 |
11 | class SettingsTab : public QTabWidget {
12 | Q_OBJECT
13 |
14 | public:
15 | SettingsTab(QWidget *parent = nullptr);
16 | };
17 |
18 | class GeneralSettingsSubTab : public QWidget {
19 | Q_OBJECT
20 |
21 | public:
22 | GeneralSettingsSubTab(QWidget *parent = nullptr);
23 |
24 | private:
25 | QWidget *settings_widget();
26 | QWidget *dark_mode_row_widget();
27 | QWidget *brightness_row_widget();
28 | QWidget *brightness_widget();
29 | QWidget *si_units_row_widget();
30 | QWidget *color_row_widget();
31 | QWidget *controls_widget();
32 |
33 | Config *config;
34 | Theme *theme;
35 | };
36 |
37 | class BluetoothSettingsSubTab : public QWidget {
38 | Q_OBJECT
39 |
40 | public:
41 | BluetoothSettingsSubTab(QWidget *parent = nullptr);
42 |
43 | private:
44 | QWidget *controls_widget();
45 | QWidget *scanner_widget();
46 | QWidget *devices_widget();
47 |
48 | Bluetooth *bluetooth;
49 | Config *config;
50 | Theme *theme;
51 | QMap devices;
52 | };
53 |
54 | class OpenAutoSettingsSubTab : public QWidget {
55 | Q_OBJECT
56 |
57 | public:
58 | OpenAutoSettingsSubTab(QWidget *parent = nullptr);
59 |
60 | private:
61 | QWidget *settings_widget();
62 | QWidget *rhd_row_widget();
63 | QWidget *frame_rate_row_widget();
64 | QWidget *resolution_row_widget();
65 | QWidget *dpi_row_widget();
66 | QWidget *dpi_widget();
67 | QWidget *rt_audio_row_widget();
68 | QWidget *audio_channels_row_widget();
69 | QWidget *bluetooth_row_widget();
70 |
71 | Bluetooth *bluetooth;
72 | Config *config;
73 | Theme *theme;
74 | };
75 |
76 | #endif
77 |
--------------------------------------------------------------------------------
/src/app/widgets/tuner.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include
6 |
7 | Tuner::Tuner(QWidget *parent) : QSlider(Qt::Orientation::Horizontal, parent)
8 | {
9 | this->config = Config::get_instance();
10 |
11 | setRange(880, 1080);
12 | setTickInterval(1);
13 | setSliderPosition(this->config->get_radio_station());
14 |
15 | connect(this, &QSlider::valueChanged, [this](int value) {
16 | this->config->set_radio_station(value);
17 | emit station_updated(value);
18 | });
19 | }
20 |
21 | QSize Tuner::sizeHint() const
22 | {
23 | auto size = QSlider::sizeHint();
24 |
25 | return QSize(size.width(), size.height() + 96);
26 | }
27 |
28 | void Tuner::paintEvent(QPaintEvent *event)
29 | {
30 | QPainter painter(this);
31 |
32 | QFontMetrics fontMetrics = QFontMetrics(this->font());
33 |
34 | double count = maximum() - minimum();
35 | double tick_dist = (this->width() - 40) / count;
36 | for (int i = 0; i <= count; i++) {
37 | double x = (i * tick_dist) + 20;
38 | double y = this->height();
39 |
40 | int tick_num = i + minimum();
41 | if (tick_num % 10 == 0) {
42 | painter.setPen(QPen(this->color, 2));
43 | painter.drawLine(QLineF(x, 32, x, this->height() - 32));
44 |
45 | tick_num /= 10;
46 | double font_width = fontMetrics.width(QString::number(tick_num));
47 | painter.drawText(QPointF(x - (font_width / 2.0), y), QString::number(tick_num));
48 | }
49 | else if (tick_num % 5 == 0) {
50 | painter.setPen(QPen(this->color, 2));
51 | painter.drawLine(QLineF(x, 40, x, this->height() - 40));
52 | }
53 | else {
54 | painter.setPen(QPen(this->color, 1));
55 | painter.drawLine(QLineF(x, 48, x, this->height() - 48));
56 | }
57 | }
58 |
59 | QSlider::paintEvent(event);
60 | }
61 |
--------------------------------------------------------------------------------
/cmake_modules/Findrtaudio.cmake:
--------------------------------------------------------------------------------
1 | #
2 | # This file is part of openauto project.
3 | # Copyright (C) 2018 f1x.studio (Michal Szwaj)
4 | #
5 | # openauto is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation; either version 3 of the License, or
8 | # (at your option) any later version.
9 |
10 | # openauto is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with openauto. If not, see .
17 | #
18 |
19 | if (RTAUDIO_LIBRARIES AND RTAUDIO_INCLUDE_DIRS)
20 | # in cache already
21 | set(RTAUDIO_FOUND TRUE)
22 | else (RTAUDIO_LIBRARIES AND RTAUDIO_INCLUDE_DIRS)
23 | find_path(RTAUDIO_INCLUDE_DIR
24 | NAMES
25 | RtAudio.h
26 | PATHS
27 | /usr/include
28 | /usr/local/include
29 | /opt/local/include
30 | /sw/include
31 | PATH_SUFFIXES
32 | rtaudio
33 | )
34 |
35 | find_library(RTAUDIO_LIBRARY
36 | NAMES
37 | rtaudio
38 | PATHS
39 | /usr/lib
40 | /usr/local/lib
41 | /opt/local/lib
42 | /sw/lib
43 | )
44 |
45 | set(RTAUDIO_INCLUDE_DIRS
46 | ${RTAUDIO_INCLUDE_DIR}
47 | )
48 | set(RTAUDIO_LIBRARIES
49 | ${RTAUDIO_LIBRARY}
50 | )
51 |
52 | if (RTAUDIO_INCLUDE_DIRS AND RTAUDIO_LIBRARIES)
53 | set(RTAUDIO_FOUND TRUE)
54 | endif (RTAUDIO_INCLUDE_DIRS AND RTAUDIO_LIBRARIES)
55 |
56 | if (RTAUDIO_FOUND)
57 | if (NOT rtaudio_FIND_QUIETLY)
58 | message(STATUS "Found rtaudio:")
59 | message(STATUS " - Includes: ${RTAUDIO_INCLUDE_DIRS}")
60 | message(STATUS " - Libraries: ${RTAUDIO_LIBRARIES}")
61 | endif (NOT rtaudio_FIND_QUIETLY)
62 | else (RTAUDIO_FOUND)
63 | if (rtaudio_FIND_REQUIRED)
64 | message(FATAL_ERROR "Could not find rtaudio")
65 | endif (rtaudio_FIND_REQUIRED)
66 | endif (RTAUDIO_FOUND)
67 |
68 | mark_as_advanced(RTAUDIO_INCLUDE_DIRS RTAUDIO_LIBRARIES)
69 |
70 | endif (RTAUDIO_LIBRARIES AND RTAUDIO_INCLUDE_DIRS)
71 |
--------------------------------------------------------------------------------
/include/app/config.hpp:
--------------------------------------------------------------------------------
1 | #ifndef CONFIG_HPP_
2 | #define CONFIG_HPP_
3 |
4 | #include
5 |
6 | #include
7 | #include
8 | #include
9 |
10 | class Config : public QObject {
11 | Q_OBJECT
12 |
13 | public:
14 | Config();
15 |
16 | void save();
17 |
18 | inline int get_volume() { return this->volume; }
19 | inline void set_volume(int volume) { this->volume = volume; }
20 |
21 | inline bool get_dark_mode() { return this->dark_mode; }
22 | inline void set_dark_mode(bool dark_mode) { this->dark_mode = dark_mode; }
23 |
24 | inline int get_brightness() { return this->brightness; }
25 | inline void set_brightness(int brightness)
26 | {
27 | this->brightness = brightness;
28 | emit brightness_changed(this->brightness);
29 | }
30 |
31 | inline bool get_si_units() { return this->si_units; }
32 | inline void set_si_units(bool si_units)
33 | {
34 | this->si_units = si_units;
35 | emit si_units_changed(this->si_units);
36 | }
37 |
38 | inline QString get_color() { return this->color; }
39 | inline void set_color(QString color) { this->color = color; }
40 |
41 | inline QString get_bluetooth_device() { return this->bluetooth_device; }
42 | inline void set_bluetooth_device(QString bluetooth_device) { this->bluetooth_device = bluetooth_device; }
43 |
44 | inline double get_radio_station() { return this->radio_station; }
45 | inline void set_radio_station(double radio_station) { this->radio_station = radio_station; }
46 |
47 | inline bool get_radio_muted() { return this->radio_muted; }
48 | inline void set_radio_muted(bool radio_muted) { this->radio_muted = radio_muted; }
49 |
50 | std::shared_ptr open_auto_config;
51 |
52 | static Config *get_instance();
53 |
54 | private:
55 | QSettings ia_config;
56 | int volume;
57 | bool dark_mode;
58 | int brightness;
59 | bool si_units;
60 | QString color;
61 | QString bluetooth_device;
62 | double radio_station;
63 | bool radio_muted;
64 |
65 | signals:
66 | void brightness_changed(unsigned int);
67 | void si_units_changed(bool);
68 | };
69 |
70 | #endif
71 |
--------------------------------------------------------------------------------
/include/app/tabs/open_auto.hpp:
--------------------------------------------------------------------------------
1 | #ifndef OPEN_AUTO_HPP_
2 | #define OPEN_AUTO_HPP_
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 |
18 | namespace aasdk = f1x::aasdk;
19 | namespace autoapp = f1x::openauto::autoapp;
20 |
21 | class OpenAutoWorker {
22 | public:
23 | OpenAutoWorker(std::function callback = nullptr, QWidget *parent = nullptr);
24 | ~OpenAutoWorker();
25 |
26 | inline void start() { this->app->waitForUSBDevice(); }
27 | inline void set_opacity(unsigned int alpha) { this->service_factory.setOpacity(alpha); }
28 |
29 | private:
30 | void create_usb_workers();
31 | void create_io_service_workers();
32 |
33 | libusb_context *usb_context;
34 | boost::asio::io_service io_service;
35 | boost::asio::io_service::work work;
36 | std::shared_ptr configuration;
37 | aasdk::tcp::TCPWrapper tcp_wrapper;
38 | aasdk::usb::USBWrapper usb_wrapper;
39 | aasdk::usb::AccessoryModeQueryFactory query_factory;
40 | aasdk::usb::AccessoryModeQueryChainFactory query_chain_factory;
41 | autoapp::service::ServiceFactory service_factory;
42 | autoapp::service::AndroidAutoEntityFactory android_auto_entity_factory;
43 | std::shared_ptr usb_hub;
44 | std::shared_ptr connected_accessories_enumerator;
45 | std::shared_ptr app;
46 | std::vector thread_pool;
47 | };
48 |
49 | class OpenAutoTab : public QWidget {
50 | Q_OBJECT
51 |
52 | public:
53 | OpenAutoTab(QWidget *parent = nullptr);
54 |
55 | void start_worker();
56 |
57 | private:
58 | QWidget *msg_widget();
59 |
60 | OpenAutoWorker *worker = nullptr;
61 | };
62 |
63 | #endif
64 |
--------------------------------------------------------------------------------
/src/app/config.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include
5 |
6 | Config::Config()
7 | : QObject(qApp),
8 | open_auto_config(std::make_shared()),
9 | ia_config(QSettings::IniFormat, QSettings::UserScope, "ia")
10 | {
11 | this->volume = this->ia_config.value("volume", 50).toInt();
12 | this->dark_mode = this->ia_config.value("dark_mode", false).toBool();
13 | this->brightness = this->ia_config.value("brightness", 255).toInt();
14 | this->si_units = this->ia_config.value("si_units", false).toBool();
15 | this->color = this->ia_config.value("color", "blue").toString();
16 | this->bluetooth_device = this->ia_config.value("Bluetooth/device", QString()).toString();
17 | this->radio_station = this->ia_config.value("Radio/station", 98.0).toDouble();
18 | this->radio_muted = this->ia_config.value("Radio/muted", true).toBool();
19 |
20 | QTimer *timer = new QTimer(this);
21 | connect(timer, &QTimer::timeout, [this]() { this->save(); });
22 | timer->start(10000);
23 | }
24 |
25 | void Config::save()
26 | {
27 | if (this->volume != this->ia_config.value("volume", 50).toInt())
28 | this->ia_config.setValue("volume", this->volume);
29 | if (this->dark_mode != this->ia_config.value("dark_mode", false).toBool())
30 | this->ia_config.setValue("dark_mode", this->dark_mode);
31 | if (this->brightness != this->ia_config.value("brightness", 255).toInt())
32 | this->ia_config.setValue("brightness", this->brightness);
33 | if (this->si_units != this->ia_config.value("si_units", false).toBool())
34 | this->ia_config.setValue("si_units", this->si_units);
35 | if (this->color != this->ia_config.value("color", "blue").toString())
36 | this->ia_config.setValue("color", this->color);
37 | if (this->bluetooth_device != this->ia_config.value("Bluetooth/device", QString()).toString())
38 | this->ia_config.setValue("Bluetooth/device", this->bluetooth_device);
39 | if (this->radio_station != this->ia_config.value("Radio/station", 98.0).toDouble())
40 | this->ia_config.setValue("Radio/station", this->radio_station);
41 | if (this->radio_muted != this->ia_config.value("Radio/muted", true).toBool())
42 | this->ia_config.setValue("Radio/muted", this->radio_muted);
43 |
44 | this->open_auto_config->save();
45 | }
46 |
47 | Config *Config::get_instance()
48 | {
49 | static Config config;
50 | return &config;
51 | }
52 |
--------------------------------------------------------------------------------
/src/app/widgets/switch.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 |
5 | Switch::Switch(QWidget* parent) : QAbstractButton(parent)
6 | {
7 | QAbstractButton::setCheckable(true);
8 | QAbstractButton::setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
9 |
10 | this->track_radius = 8;
11 | this->thumb_radius = 12;
12 | this->margin = std::max(0, this->thumb_radius - this->track_radius);
13 | this->base_offset = std::max(this->thumb_radius, this->track_radius);
14 | this->end_offset = [this](bool checked) { return checked ? this->width() - this->base_offset : this->base_offset; };
15 | this->offset = this->base_offset;
16 | }
17 |
18 | QSize Switch::sizeHint() const
19 | {
20 | return QSize(4.5 * this->track_radius + 2 * this->margin, 2 * this->track_radius + 2 * this->margin);
21 | }
22 |
23 | void Switch::paintEvent(QPaintEvent*)
24 | {
25 | QPainter painter(this);
26 |
27 | painter.setRenderHint(QPainter::Antialiasing);
28 | painter.setPen(Qt::NoPen);
29 |
30 | QColor track_brush = this->isChecked() ? palette().color(QPalette::AlternateBase) : this->track_color;
31 | QColor thumb_brush = this->isChecked() ? palette().color(QPalette::Base) : this->thumb_color;
32 |
33 | painter.setBrush(track_brush);
34 | painter.drawRoundedRect(this->margin, this->margin, this->width() - 2 * this->margin,
35 | this->height() - 2 * this->margin, this->track_radius, this->track_radius);
36 | painter.setBrush(thumb_brush);
37 | painter.drawEllipse(this->offset - this->thumb_radius, this->base_offset - this->thumb_radius,
38 | 2 * this->thumb_radius, 2 * this->thumb_radius);
39 | }
40 |
41 | void Switch::resizeEvent(QResizeEvent* event)
42 | {
43 | QAbstractButton::resizeEvent(event);
44 |
45 | this->offset = this->end_offset(this->isChecked());
46 | }
47 |
48 | void Switch::mouseReleaseEvent(QMouseEvent* event)
49 | {
50 | QAbstractButton::mouseReleaseEvent(event);
51 |
52 | if (event->button() == Qt::LeftButton) {
53 | QPropertyAnimation *offset_animation = new QPropertyAnimation(this, "offset");
54 | offset_animation->setDuration(120);
55 | offset_animation->setStartValue(this->offset);
56 | offset_animation->setEndValue(this->end_offset(this->isChecked()));
57 | offset_animation->start();
58 | }
59 | }
60 |
61 | void Switch::nextCheckState()
62 | {
63 | QAbstractButton::nextCheckState();
64 |
65 | bool checked = this->isChecked();
66 | this->offset = this->end_offset(checked);
67 | emit stateChanged(checked);
68 | }
69 |
--------------------------------------------------------------------------------
/assets/resources.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | icons/dark/play-24px.svg
4 | icons/dark/pause-24px.svg
5 | icons/dark/brightness_low-24px.svg
6 | icons/dark/play_circle_outline-24px.svg
7 | icons/dark/speed-24px.svg
8 | icons/dark/brightness_high-24px.svg
9 | icons/dark/report_problem-24px.svg
10 | icons/dark/tune-24px.svg
11 | icons/dark/skip_next-24px.svg
12 | icons/dark/skip_previous-24px.svg
13 | icons/dark/directions_car-24px.svg
14 | icons/dark/volume_mute-24px.svg
15 | icons/dark/volume_up-24px.svg
16 | icons/dark/arrow_drop_down-24px.svg
17 | icons/dark/check-24px.svg
18 | icons/dark/fast_forward-24px.svg
19 | icons/dark/fast_rewind-24px.svg
20 | icons/dark/volume_off-24px.svg
21 | icons/dark/save-24px.svg
22 | icons/dark/bluetooth_searching-24px.svg
23 | icons/light/play-24px.svg
24 | icons/light/pause-24px.svg
25 | icons/light/brightness_low-24px.svg
26 | icons/light/play_circle_outline-24px.svg
27 | icons/light/speed-24px.svg
28 | icons/light/brightness_high-24px.svg
29 | icons/light/report_problem-24px.svg
30 | icons/light/tune-24px.svg
31 | icons/light/skip_next-24px.svg
32 | icons/light/skip_previous-24px.svg
33 | icons/light/directions_car-24px.svg
34 | icons/light/volume_mute-24px.svg
35 | icons/light/volume_up-24px.svg
36 | icons/light/arrow_drop_down-24px.svg
37 | icons/light/check-24px.svg
38 | icons/light/fast_forward-24px.svg
39 | icons/light/fast_rewind-24px.svg
40 | icons/light/volume_off-24px.svg
41 | icons/light/save-24px.svg
42 | icons/light/bluetooth_searching-24px.svg
43 | stylesheets/light.qss
44 | stylesheets/dark.qss
45 | fonts/Titillium_Web/TitilliumWeb-Regular.ttf
46 | fonts/Montserrat/Montserrat-LightItalic.ttf
47 | fonts/Montserrat/Montserrat-Regular.ttf
48 |
49 |
50 |
--------------------------------------------------------------------------------
/src/app/widgets/progress.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | #include
8 |
9 | ProgressIndicator::ProgressIndicator(QWidget* parent) : QWidget(parent)
10 | {
11 | setFocusPolicy(Qt::NoFocus);
12 |
13 | QParallelAnimationGroup* group = new QParallelAnimationGroup(this);
14 | group->setLoopCount(-1);
15 |
16 | this->dash_length=0;
17 | QPropertyAnimation *length_animation = new QPropertyAnimation(this, "dash_length");
18 | length_animation->setEasingCurve(QEasingCurve::InOutQuad);
19 | length_animation->setStartValue(0.1);
20 | length_animation->setKeyValueAt(0.15, 1);
21 | length_animation->setKeyValueAt(0.5, 18);
22 | length_animation->setKeyValueAt(0.6, 18);
23 | length_animation->setEndValue(18);
24 | length_animation->setDuration(1500);
25 | group->addAnimation(length_animation);
26 |
27 | QPropertyAnimation *offset_animation = new QPropertyAnimation(this, "dash_offset");
28 | offset_animation->setEasingCurve(QEasingCurve::InOutSine);
29 | offset_animation->setStartValue(0);
30 | offset_animation->setKeyValueAt(0.15, 0);
31 | offset_animation->setKeyValueAt(0.7, -7);
32 | offset_animation->setKeyValueAt(0.75, -7);
33 | offset_animation->setEndValue(-25);
34 | offset_animation->setDuration(1500);
35 | group->addAnimation(offset_animation);
36 |
37 | QPropertyAnimation *angle_animation = new QPropertyAnimation(this, "angle");
38 | angle_animation->setStartValue(-90);
39 | angle_animation->setEndValue(270);
40 | angle_animation->setDuration(1500);
41 | group->addAnimation(angle_animation);
42 |
43 | group->start();
44 | }
45 |
46 | void ProgressIndicator::startAnimation()
47 | {
48 | if (this->timer_id == -1) this->timer_id = startTimer(0);
49 | this->enabled = true;
50 | }
51 |
52 | void ProgressIndicator::stopAnimation()
53 | {
54 | if (this->timer_id != -1) killTimer(this->timer_id);
55 | this->enabled = false;
56 |
57 | this->timer_id = -1;
58 |
59 | update();
60 | }
61 |
62 | void ProgressIndicator::paintEvent(QPaintEvent*)
63 | {
64 | QPainter painter(this);
65 | painter.setRenderHint(QPainter::Antialiasing);
66 |
67 | if (!enabled) return;
68 |
69 | painter.translate(width() / 2, height() / 2);
70 | painter.rotate(this->angle);
71 |
72 | QPen pen;
73 | pen.setWidth(3);
74 | pen.setColor(palette().color(QPalette::Base));
75 |
76 | QVector pattern;
77 | pattern << this->dash_length * 48 / 36 << 30 * 48 / 36;
78 |
79 | pen.setDashOffset(this->dash_offset * 48 / 36);
80 | pen.setDashPattern(pattern);
81 |
82 | painter.setPen(pen);
83 |
84 | painter.drawEllipse(QPoint(0, 0), 48 / 3, 48 / 3);
85 | }
86 |
--------------------------------------------------------------------------------
/src/app/bluetooth.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 |
18 | #include
19 | #include
20 |
21 | Bluetooth::Bluetooth() : QObject(qApp)
22 | {
23 | BluezQt::Manager *manager = new BluezQt::Manager();
24 | BluezQt::InitManagerJob *job = manager->init();
25 | job->exec();
26 |
27 | this->adapter = manager->usableAdapter();
28 |
29 | if (this->has_adapter()) {
30 | for (auto device : this->get_devices()) {
31 | if (device->mediaPlayer() != nullptr) {
32 | this->media_player_device = device;
33 | break;
34 | }
35 | }
36 |
37 | connect(this->adapter.get(), &BluezQt::Adapter::deviceAdded,
38 | [this](BluezQt::DevicePtr device) { emit device_added(device); });
39 | connect(this->adapter.get(), &BluezQt::Adapter::deviceChanged, [this](BluezQt::DevicePtr device) {
40 | emit device_changed(device);
41 | this->update_media_player(device);
42 | });
43 | connect(this->adapter.get(), &BluezQt::Adapter::deviceRemoved,
44 | [this](BluezQt::DevicePtr device) { emit device_removed(device); });
45 | }
46 | }
47 |
48 | void Bluetooth::scan()
49 | {
50 | if (this->has_adapter()) {
51 | emit scan_status(true);
52 | this->adapter->startDiscovery();
53 | QTimer::singleShot(10000, [this]() {
54 | this->adapter->stopDiscovery();
55 | emit scan_status(false);
56 | });
57 | }
58 | }
59 |
60 | void Bluetooth::update_media_player(BluezQt::DevicePtr device)
61 | {
62 | if (device->mediaPlayer() != nullptr) {
63 | emit media_player_status_changed(device->mediaPlayer()->status());
64 | emit media_player_track_changed(device->mediaPlayer()->track());
65 | emit media_player_changed(device->name(), device->mediaPlayer());
66 | this->media_player_device = device;
67 | }
68 | else if (this->media_player_device == device) {
69 | emit media_player_status_changed(BluezQt::MediaPlayer::Status::Paused);
70 | emit media_player_track_changed(BluezQt::MediaPlayerTrack());
71 | emit media_player_changed(QString(), nullptr);
72 | }
73 | }
74 |
75 | Bluetooth *Bluetooth::get_instance()
76 | {
77 | static Bluetooth bluetooth;
78 | return &bluetooth;
79 | }
80 |
--------------------------------------------------------------------------------
/include/app/theme.hpp:
--------------------------------------------------------------------------------
1 | #ifndef THEME_HPP_
2 | #define THEME_HPP_
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | typedef QPair tab_icon_t;
12 | typedef QPair button_icon_t;
13 |
14 | class Theme : public QObject {
15 | Q_OBJECT
16 |
17 | public:
18 | enum Orientation { BOTTOM, RIGHT };
19 |
20 | static const QFont font_14;
21 | static const QFont font_16;
22 | static const QFont font_18;
23 | static const QFont font_36;
24 |
25 | static const QSize icon_16;
26 | static const QSize icon_24;
27 | static const QSize icon_32;
28 | static const QSize icon_36;
29 | static const QSize icon_42;
30 | static const QSize icon_48;
31 | static const QSize icon_56;
32 | static const QSize icon_84;
33 | static const QSize icon_96;
34 |
35 | static const QColor danger_color;
36 | static const QColor success_color;
37 |
38 | Theme();
39 |
40 | inline void set_mode(bool mode)
41 | {
42 | this->mode = mode;
43 | this->update();
44 | }
45 | inline void set_color(QString color)
46 | {
47 | this->color = color;
48 | this->update();
49 | }
50 | inline const QMap get_colors() { return this->colors[this->mode ? "dark" : "light"]; }
51 |
52 | void add_tab_icon(QString name, int index, Qt::Orientation orientation = Qt::Orientation::Horizontal);
53 | void add_button_icon(QString name, QPushButton *button, QString active_name = QString());
54 | void update();
55 |
56 | inline static QFrame *br(QWidget *parent = nullptr, bool vertical = false)
57 | {
58 | QFrame *br = new QFrame(parent);
59 | br->setLineWidth(1);
60 | br->setFrameShape(vertical ? QFrame::VLine : QFrame::HLine);
61 | br->setFrameShadow(QFrame::Plain);
62 |
63 | return br;
64 | }
65 | static Theme *get_instance();
66 |
67 | private:
68 | QMap> colors = {{"light",
69 | {{"blue", QColor(33, 150, 243)},
70 | {"red", QColor(244, 67, 54)},
71 | {"green", QColor(76, 175, 80)},
72 | {"orange", QColor(255, 152, 0)},
73 | {"steel", QColor(96, 125, 139)}}},
74 | {"dark",
75 | {{"blue", QColor(144, 202, 249)},
76 | {"red", QColor(239, 154, 154)},
77 | {"green", QColor(165, 214, 167)},
78 | {"orange", QColor(255, 204, 128)},
79 | {"steel", QColor(176, 190, 197)}}}};
80 |
81 | QPalette palette;
82 | QString color;
83 | QMap> tab_icons;
84 | QMap> button_icons;
85 | QMap stylesheets;
86 | bool mode = false;
87 |
88 | void set_palette();
89 | QString parse_stylesheet(QString file);
90 | QPixmap create_pixmap_variant(QPixmap &base, qreal opacity);
91 |
92 | signals:
93 | void icons_updated(QList &, QList &);
94 | void color_updated(QMap &);
95 | };
96 |
97 | #endif
98 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.5.1)
2 | project(ia CXX)
3 |
4 | add_subdirectory(aasdk)
5 | set(AASDK_INCLUDE_DIRS ${aasdk_SOURCE_DIR}/include)
6 | set(AASDK_LIBRARIES ${aasdk_SOURCE_DIR}/lib/libaasdk.so)
7 | set(AASDK_PROTO_INCLUDE_DIRS ${aasdk_BINARY_DIR})
8 | set(AASDK_PROTO_LIBRARIES ${aasdk_SOURCE_DIR}/lib/libaasdk_proto.so)
9 |
10 | add_subdirectory(openauto)
11 | set(OPENAUTO_INCLUDE_DIRS ${openauto_SOURCE_DIR}/include)
12 |
13 | set(CMAKE_AUTOMOC ON)
14 | set(CMAKE_AUTOUIC ON)
15 | set(CMAKE_AUTORCC ON)
16 | set(base_directory ${CMAKE_CURRENT_SOURCE_DIR})
17 | set(resources_directory ${base_directory}/assets)
18 | set(sources_directory ${base_directory}/src)
19 | set(include_directory ${base_directory}/include)
20 |
21 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${base_directory}/bin)
22 | set(EXECUTABLE_OUTPUT_PATH ${base_directory}/bin)
23 |
24 | set(Boost_USE_STATIC_LIBS OFF)
25 | set(Boost_USE_MULTITHREADED ON)
26 | set(Boost_USE_STATIC_RUNTIME OFF)
27 |
28 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake_modules/")
29 | SET(CMAKE_CXX_STANDARD 14)
30 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_INIT} -Wall -pedantic -fPIC")
31 | set(CMAKE_CXX_FLAGS_DEBUG "-g -O0")
32 | set(CMAKE_CXX_FLAGS_RELEASE "-g -O3")
33 |
34 | add_definitions(-DBOOST_ALL_DYN_LINK)
35 |
36 | find_package(Boost REQUIRED COMPONENTS system log OPTIONAL_COMPONENTS unit_test_framework)
37 | find_package(libusb-1.0 REQUIRED)
38 | find_package(Qt5 COMPONENTS Multimedia MultimediaWidgets Bluetooth)
39 | find_package(KF5BluezQt REQUIRED)
40 | find_package(Protobuf REQUIRED)
41 | find_package(OpenSSL REQUIRED)
42 | find_package(rtaudio REQUIRED)
43 |
44 | if(RPI_BUILD)
45 | add_definitions(-DUSE_OMX -DOMX_SKIP64BIT)
46 | set(BCM_HOST_LIBRARIES "/opt/vc/lib/libbcm_host.so")
47 | set(BCM_HOST_INCLUDE_DIRS "/opt/vc/include")
48 | set(ILCLIENT_INCLUDE_DIRS "/opt/vc/src/hello_pi/libs/ilclient")
49 | set(ILCLIENT_LIBRARIES "/opt/vc/src/hello_pi/libs/ilclient/libilclient.a;/opt/vc/lib/libvcos.so;/opt/vc/lib/libvcilcs.a;/opt/vc/lib/libvchiq_arm.so")
50 | endif(RPI_BUILD)
51 |
52 | include_directories(${CMAKE_CURRENT_BINARY_DIR}
53 | ${Qt5Multimedia_INCLUDE_DIRS}
54 | ${Qt5MultimediaWidgets_INCLUDE_DIRS}
55 | ${Qt5Widgets_INCLUDE_DIRS}
56 | ${Qt5Bluetooth_INCLUDE_DIRS}
57 | ${Boost_INCLUDE_DIRS}
58 | ${LIBUSB_1_INCLUDE_DIRS}
59 | ${PROTOBUF_INCLUDE_DIR}
60 | ${OPENSSL_INCLUDE_DIR}
61 | ${RTAUDIO_INCLUDE_DIRS}
62 | ${AASDK_PROTO_INCLUDE_DIRS}
63 | ${AASDK_INCLUDE_DIRS}
64 | ${OPENAUTO_INCLUDE_DIRS}
65 | ${BCM_HOST_INCLUDE_DIRS}
66 | ${ILCLIENT_INCLUDE_DIRS}
67 | ${include_directory})
68 |
69 | link_directories(${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
70 |
71 | file(GLOB_RECURSE source_files ${sources_directory}/*.cpp ${include_directory}/*.hpp ${resources_directory}/*.qrc)
72 |
73 | add_executable(ia ${source_files})
74 |
75 | add_dependencies(auto aasdk)
76 | target_link_libraries(ia
77 | aasdk_proto
78 | aasdk
79 | auto
80 | ${Boost_LIBRARIES}
81 | ${Qt5Multimedia_LIBRARIES}
82 | ${Qt5MultimediaWidgets_LIBRARIES}
83 | ${Qt5Bluetooth_LIBRARIES}
84 | KF5::BluezQt
85 | ${LIBUSB_1_LIBRARIES}
86 | ${PROTOBUF_LIBRARIES}
87 | ${BCM_HOST_LIBRARIES}
88 | ${ILCLIENT_LIBRARIES}
89 | ${WINSOCK2_LIBRARIES}
90 | ${RTAUDIO_LIBRARIES})
91 |
92 |
--------------------------------------------------------------------------------
/cmake_modules/Findlibusb-1.0.cmake:
--------------------------------------------------------------------------------
1 | # - Try to find libusb-1.0
2 | # Once done this will define
3 | #
4 | # LIBUSB_1_FOUND - system has libusb
5 | # LIBUSB_1_INCLUDE_DIRS - the libusb include directory
6 | # LIBUSB_1_LIBRARIES - Link these to use libusb
7 | # LIBUSB_1_DEFINITIONS - Compiler switches required for using libusb
8 | #
9 | # Adapted from cmake-modules Google Code project
10 | #
11 | # Copyright (c) 2006 Andreas Schneider
12 | #
13 | # (Changes for libusb) Copyright (c) 2008 Kyle Machulis
14 | #
15 | # Redistribution and use is allowed according to the terms of the New BSD license.
16 | #
17 | # CMake-Modules Project New BSD License
18 | #
19 | # Redistribution and use in source and binary forms, with or without
20 | # modification, are permitted provided that the following conditions are met:
21 | #
22 | # * Redistributions of source code must retain the above copyright notice, this
23 | # list of conditions and the following disclaimer.
24 | #
25 | # * Redistributions in binary form must reproduce the above copyright notice,
26 | # this list of conditions and the following disclaimer in the
27 | # documentation and/or other materials provided with the distribution.
28 | #
29 | # * Neither the name of the CMake-Modules Project nor the names of its
30 | # contributors may be used to endorse or promote products derived from this
31 | # software without specific prior written permission.
32 | #
33 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
34 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
35 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
37 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
39 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
40 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
41 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
42 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 | #
44 |
45 |
46 | if (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS)
47 | # in cache already
48 | set(LIBUSB_FOUND TRUE)
49 | else (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS)
50 | find_path(LIBUSB_1_INCLUDE_DIR
51 | NAMES
52 | libusb.h
53 | PATHS
54 | /usr/include
55 | /usr/local/include
56 | /opt/local/include
57 | /sw/include
58 | PATH_SUFFIXES
59 | libusb-1.0
60 | )
61 |
62 | find_library(LIBUSB_1_LIBRARY
63 | NAMES
64 | usb-1.0 usb
65 | PATHS
66 | /usr/lib
67 | /usr/local/lib
68 | /opt/local/lib
69 | /sw/lib
70 | )
71 |
72 | set(LIBUSB_1_INCLUDE_DIRS
73 | ${LIBUSB_1_INCLUDE_DIR}
74 | )
75 | set(LIBUSB_1_LIBRARIES
76 | ${LIBUSB_1_LIBRARY}
77 | )
78 |
79 | if (LIBUSB_1_INCLUDE_DIRS AND LIBUSB_1_LIBRARIES)
80 | set(LIBUSB_1_FOUND TRUE)
81 | endif (LIBUSB_1_INCLUDE_DIRS AND LIBUSB_1_LIBRARIES)
82 |
83 | if (LIBUSB_1_FOUND)
84 | if (NOT libusb_1_FIND_QUIETLY)
85 | message(STATUS "Found libusb-1.0:")
86 | message(STATUS " - Includes: ${LIBUSB_1_INCLUDE_DIRS}")
87 | message(STATUS " - Libraries: ${LIBUSB_1_LIBRARIES}")
88 | endif (NOT libusb_1_FIND_QUIETLY)
89 | else (LIBUSB_1_FOUND)
90 | if (libusb_1_FIND_REQUIRED)
91 | message(FATAL_ERROR "Could not find libusb")
92 | endif (libusb_1_FIND_REQUIRED)
93 | endif (LIBUSB_1_FOUND)
94 |
95 | # show the LIBUSB_1_INCLUDE_DIRS and LIBUSB_1_LIBRARIES variables only in the advanced view
96 | mark_as_advanced(LIBUSB_1_INCLUDE_DIRS LIBUSB_1_LIBRARIES)
97 |
98 | endif (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS)
99 |
--------------------------------------------------------------------------------
/assets/stylesheets/light.qss:
--------------------------------------------------------------------------------
1 | QMainWindow {
2 | background-color: rgb(238, 238, 238);
3 | }
4 |
5 | QLabel {
6 | color: rgba(0, 0, 0, 222);
7 | }
8 |
9 | QTabWidget::pane {
10 | background-color: rgba(255, 255, 255, 80);
11 | border-top: 0px;
12 | }
13 |
14 | QTabWidget::tab-bar[tabPosition="2"] {
15 | alignment: center;
16 | }
17 |
18 | QTabBar::tab {
19 | background-color: transparent;
20 | color: rgba(0, 0, 0, 138);
21 | padding: 4px;
22 | }
23 |
24 | QTabBar::tab:selected:top {
25 | color: palette(base);
26 | border-bottom: 2px solid palette(base);
27 | }
28 |
29 | QTabBar::tab:disabled:top {
30 | color: rgba(0, 0, 0, 97);
31 | }
32 |
33 | QSlider {
34 | height: 30px;
35 | }
36 |
37 | QSlider::groove {
38 | background-color: palette(alternate-base);
39 | height: 4px;
40 | }
41 |
42 | QSlider::handle {
43 | background-color: palette(base);
44 | width: 24px;
45 | height: 4px;
46 | line-height: 25px;
47 | margin-top: -10px;
48 | margin-bottom: -10px;
49 | border-radius: 12px;
50 | }
51 |
52 | QSlider::sub-page {
53 | background-color: palette(base);
54 | height: 4px;
55 | }
56 |
57 | QPushButton {
58 | color: rgba(0, 0, 0, 222);
59 | border: none;
60 | padding: 8px;
61 | }
62 |
63 | QPushButton:pressed {
64 | background-color: rgba(0, 0, 0, 25);
65 | }
66 |
67 | QPushButton:disabled {
68 | color: rgba(0, 0, 0, 97);
69 | }
70 |
71 | QPushButton:!flat {
72 | background-color: rgba(0, 0, 0, 31);
73 | }
74 |
75 | QPushButton:!flat:checked {
76 | color: rgba(255, 255, 255, 222);
77 | background-color: palette(base);
78 | }
79 |
80 | QPushButton:!flat:disabled {
81 | background-color: rgba(0, 0, 0, 13);
82 | }
83 |
84 | QFrame[frameShape="4"][frameShadow="16"],
85 | QFrame[frameShape="5"][frameShadow="16"] {
86 | color: rgba(0, 0, 0, 31);
87 | }
88 |
89 | QComboBox {
90 | color: rgba(0, 0, 0, 222);
91 | background: transparent;
92 | border: none;
93 | border-bottom: 2px solid rgba(0, 0, 0, 31);
94 | }
95 |
96 | QComboBox::drop-down {
97 | border: none;
98 | padding-right: 16px;
99 | }
100 |
101 | QComboBox::down-arrow {
102 | image: url(:/icons/light/arrow_drop_down-24px.svg);
103 | }
104 |
105 | QComboBox QAbstractItemView::item {
106 | border: none;
107 | color: rgba(0, 0, 0, 222);
108 | background-color: rgb(245, 245, 245);
109 | }
110 |
111 | QGroupBox {
112 | border: none;
113 | }
114 |
115 | QCheckBox {
116 | color: rgba(0, 0, 0, 222);
117 | background-color: transparent;
118 | }
119 |
120 | QRadioButton {
121 | color: rgba(0, 0, 0, 222);
122 | background-color: transparent;
123 | }
124 |
125 | QCheckBox::indicator {
126 | width: 22px;
127 | height: 22px;
128 | border: 2px solid rgb(97, 97, 97);
129 | }
130 |
131 | QRadioButton::indicator {
132 | width: 18px;
133 | height: 18px;
134 | border: 2px solid rgb(97, 97, 97);
135 | border-radius: 11px;
136 | }
137 |
138 | QCheckBox::indicator::checked {
139 | image: url(:/icons/light/check-24px.svg);
140 | background-color: palette(base);
141 | border: 2px solid palette(base);
142 | }
143 |
144 | QRadioButton::indicator::checked {
145 | background-color: qradialgradient(cx:0.5, cy:0.5, fx:0.5, fy:0.5, radius:.4, stop:.65 palette(base), stop:.75 transparent);
146 | border: 2px solid palette(base);
147 | }
148 |
149 | Switch {
150 | qproperty-track_color: rgba(0, 0, 0, 64);
151 | qproperty-thumb_color: rgb(224, 224, 224);
152 | }
153 |
154 | Tuner {
155 | qproperty-color: rgb(0, 0, 0);
156 | padding-left: 16px;
157 | padding-right: 16px;
158 | }
159 |
160 | Tuner::groove {
161 | background-color: rgb(0, 0, 0);
162 | }
163 |
164 | Tuner::handle {
165 | width: 6px;
166 | margin-top: -32px;
167 | margin-bottom: -32px;
168 | }
169 |
170 | Tuner::sub-page {
171 | background-color: rgb(0, 0, 0);
172 | }
173 |
--------------------------------------------------------------------------------
/assets/stylesheets/dark.qss:
--------------------------------------------------------------------------------
1 | QMainWindow {
2 | background-color: rgb(18, 18, 18);
3 | }
4 |
5 | QLabel {
6 | color: rgb(255, 255, 255);
7 | }
8 |
9 | QTabWidget::pane {
10 | background-color: rgba(255, 255, 255, 5);
11 | border-top: 0px;
12 | }
13 |
14 | QTabWidget::tab-bar[tabPosition="2"] {
15 | alignment: center;
16 | }
17 |
18 | QTabBar::tab {
19 | background-color: transparent;
20 | color: rgba(255, 255, 255, 179);
21 | padding: 4px;
22 | }
23 |
24 | QTabBar::tab:selected:top {
25 | color: palette(base);
26 | border-bottom: 2px solid palette(base);
27 | }
28 |
29 | QTabBar::tab:disabled:top {
30 | color: rgba(255, 255, 255, 128);
31 | }
32 |
33 | QSlider {
34 | height: 30px;
35 | }
36 |
37 | QSlider::groove {
38 | background-color: palette(alternate-base);
39 | height: 4px;
40 | }
41 |
42 | QSlider::handle {
43 | background-color: palette(base);
44 | width: 24px;
45 | height: 4px;
46 | line-height: 25px;
47 | margin-top: -10px;
48 | margin-bottom: -10px;
49 | border-radius: 12px;
50 | }
51 |
52 | QSlider::sub-page {
53 | background-color: palette(base);
54 | height: 4px;
55 | }
56 |
57 | QPushButton {
58 | color: rgb(255, 255, 255);
59 | border: none;
60 | padding: 8px;
61 | }
62 |
63 | QPushButton:pressed {
64 | background-color: rgba(255, 255, 255, 25);
65 | }
66 |
67 | QPushButton:disabled {
68 | color: rgba(255, 255, 255, 128);
69 | }
70 |
71 | QPushButton:!flat {
72 | background-color: rgba(255, 255, 255, 31);
73 | }
74 |
75 | QPushButton:!flat:checked {
76 | color: rgb(0, 0, 0);
77 | background-color: palette(base);
78 | }
79 |
80 | QPushButton:!flat:disabled {
81 | background-color: rgba(255, 255, 255, 13);
82 | }
83 |
84 | QFrame[frameShape="4"][frameShadow="16"],
85 | QFrame[frameShape="5"][frameShadow="16"] {
86 | color: rgba(255, 255, 255, 31);
87 | }
88 |
89 | QComboBox {
90 | color: rgb(255, 255, 255);
91 | background: transparent;
92 | border: none;
93 | border-bottom: 2px solid rgba(255, 255, 255, 31);
94 | }
95 |
96 | QComboBox::drop-down {
97 | border: none;
98 | padding-right: 16px;
99 | }
100 |
101 | QComboBox::down-arrow {
102 | image: url(:/icons/dark/arrow_drop_down-24px.svg);
103 | }
104 |
105 | QComboBox QAbstractItemView::item {
106 | border: none;
107 | color: rgb(255, 255, 255);
108 | background-color: rgb(33, 33, 33);
109 | }
110 |
111 | QGroupBox {
112 | border: none;
113 | }
114 |
115 | QCheckBox {
116 | color: rgb(255, 255, 255);
117 | background-color: transparent;
118 | }
119 |
120 | QRadioButton {
121 | color: rgb(255, 255, 255);
122 | background-color: transparent;
123 | }
124 |
125 | QCheckBox::indicator {
126 | width: 22px;
127 | height: 22px;
128 | border: 2px solid rgb(255, 255, 255);
129 | }
130 |
131 | QRadioButton::indicator {
132 | width: 18px;
133 | height: 18px;
134 | border: 2px solid rgb(255, 255, 255);
135 | border-radius: 11px;
136 | }
137 |
138 | QCheckBox::indicator::checked {
139 | image: url(:/icons/dark/check-24px.svg);
140 | background-color: palette(base);
141 | border: 2px solid palette(base);
142 | }
143 |
144 | QRadioButton::indicator::checked {
145 | background-color: qradialgradient(cx:0.5, cy:0.5, fx:0.5, fy:0.5, radius:.4, stop:.65 palette(base), stop:.75 transparent);
146 | border: 2px solid palette(base);
147 | }
148 |
149 | Switch {
150 | qproperty-track_color: rgba(255, 255, 255, 31);
151 | qproperty-thumb_color: rgb(158, 158, 158);
152 | }
153 |
154 | Tuner {
155 | qproperty-color: rgb(224, 224, 224);
156 | padding-left: 16px;
157 | padding-right: 16px;
158 | }
159 |
160 | Tuner::groove {
161 | background-color: rgb(224, 224, 224);
162 | }
163 |
164 | Tuner::handle {
165 | width: 6px;
166 | margin-top: -32px;
167 | margin-bottom: -32px;
168 | }
169 |
170 | Tuner::sub-page {
171 | background-color: rgb(224, 224, 224);
172 | }
173 |
--------------------------------------------------------------------------------
/src/obd/obd.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | #include
9 |
10 | OBD::OBD()
11 | {
12 | this->connect("/dev/ttyUSB0", B115200);
13 | if (this->connected) this->initialize();
14 | }
15 |
16 | OBD::~OBD()
17 | {
18 | this->raw_query("ATZ");
19 | sleep(1);
20 | close(this->fd);
21 | this->connected = false;
22 | }
23 |
24 | bool OBD::query(Command &cmd, double &val)
25 | {
26 | if (!this->connected) return false;
27 |
28 | std::lock_guard guard(this->obd_mutex);
29 | if (this->send(cmd.request)) {
30 | Response resp = this->receive();
31 | val = cmd.decoder(resp);
32 | return resp.success;
33 | }
34 | else {
35 | std::cout << "unable to send command" << std::endl;
36 | }
37 |
38 | return false;
39 | }
40 |
41 | OBD *OBD::get_instance()
42 | {
43 | static OBD obd;
44 | return &obd;
45 | }
46 |
47 | void OBD::connect(std::string dev_path, speed_t baudrate)
48 | {
49 | if (this->connected) return;
50 |
51 | this->fd = open(dev_path.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
52 | if (this->fd == -1) {
53 | this->connected = false;
54 | return;
55 | }
56 |
57 | fcntl(this->fd, F_SETFL, 0);
58 |
59 | struct termios options;
60 | tcgetattr(this->fd, &options);
61 |
62 | options.c_cflag |= (CLOCAL | CREAD);
63 | options.c_lflag &= !(ICANON | ECHO | ECHOE | ISIG);
64 | options.c_oflag &= !(OPOST);
65 | options.c_cc[VMIN] = 0;
66 | options.c_cc[VTIME] = 100;
67 |
68 | tcflush(this->fd, TCIOFLUSH);
69 | tcsetattr(this->fd, TCSANOW, &options);
70 |
71 | cfsetispeed(&options, baudrate);
72 | cfsetospeed(&options, baudrate);
73 | tcsetattr(this->fd, TCSANOW, &options);
74 | tcflush(this->fd, TCIOFLUSH);
75 |
76 | this->connected = true;
77 | }
78 |
79 | void OBD::initialize()
80 | {
81 | std::vector cmds = {"ATD", "ATZ", "ATE0", "ATL0", "ATS0", "ATH0", "ATSP0", "0100"};
82 | for (auto const cmd : cmds) {
83 | this->raw_query(cmd);
84 | usleep(500000);
85 | }
86 | }
87 |
88 | bool OBD::send(Request req)
89 | {
90 | std::string req_str = req.to_str();
91 |
92 | return this->_write(req_str) >= 0;
93 | }
94 |
95 | int OBD::_write(std::string str)
96 | {
97 | str += '\r';
98 | int size;
99 | if ((size = write(this->fd, str.c_str(), str.length())) < 0) {
100 | std::cout << "failed write" << std::endl;
101 | this->connected = false;
102 | return 0;
103 | }
104 |
105 | return size;
106 | }
107 |
108 | bool OBD::is_failed_response(std::string str)
109 | {
110 | std::vector failed_msgs = {
111 | "UNABLE TO CONNECT", "BUS INIT...ERROR", "NO DATA", "STOPPED", "ERROR", "?"};
112 |
113 | for (auto const &msg : failed_msgs)
114 | if (str.find(msg) != std::string::npos) return true;
115 |
116 | return false;
117 | }
118 |
119 | Response OBD::receive()
120 | {
121 | std::string resp_str = this->_read();
122 |
123 | if (is_failed_response(resp_str)) return Response();
124 |
125 | std::string searching_phrase = "SEARCHING...";
126 | std::string::size_type i = resp_str.find(searching_phrase);
127 | if (i != std::string::npos) resp_str.erase(i, searching_phrase.length());
128 | resp_str.erase(
129 | std::remove_if(resp_str.begin(), resp_str.end(), [](auto const &c) -> bool { return !std::isalnum(c); }),
130 | resp_str.end());
131 |
132 | return Response(resp_str);
133 | }
134 |
135 | std::string OBD::_read()
136 | {
137 | char buf[1];
138 | std::string str;
139 |
140 | while (true) {
141 | if (read(this->fd, (void *)buf, 1) != 1) {
142 | std::cout << "failed read" << std::endl;
143 | this->connected = false;
144 | return "";
145 | }
146 | if (buf[0] == '>')
147 | break;
148 | else
149 | str += buf[0];
150 | }
151 |
152 | return str;
153 | }
154 |
--------------------------------------------------------------------------------
/src/app/tabs/open_auto.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | OpenAutoWorker::OpenAutoWorker(std::function callback, QWidget *parent)
7 | : io_service(),
8 | work(io_service),
9 | configuration(Config::get_instance()->open_auto_config),
10 | tcp_wrapper(),
11 | usb_wrapper((libusb_init(&this->usb_context), usb_context)),
12 | query_factory(usb_wrapper, io_service),
13 | query_chain_factory(usb_wrapper, io_service, query_factory),
14 | service_factory(io_service, configuration, parent, callback),
15 | android_auto_entity_factory(io_service, configuration, service_factory),
16 | usb_hub(std::make_shared(this->usb_wrapper, this->io_service, this->query_chain_factory)),
17 | connected_accessories_enumerator(std::make_shared(
18 | this->usb_wrapper, this->io_service, this->query_chain_factory)),
19 | app(std::make_shared(this->io_service, this->usb_wrapper, this->tcp_wrapper,
20 | this->android_auto_entity_factory, usb_hub, connected_accessories_enumerator))
21 | {
22 | this->create_usb_workers();
23 | this->create_io_service_workers();
24 | }
25 |
26 | OpenAutoWorker::~OpenAutoWorker()
27 | {
28 | std::for_each(this->thread_pool.begin(), this->thread_pool.end(),
29 | std::bind(&std::thread::join, std::placeholders::_1));
30 | libusb_exit(this->usb_context);
31 | }
32 |
33 | void OpenAutoWorker::create_usb_workers()
34 | {
35 | auto worker = [this]() {
36 | timeval event_timeout = {180, 0};
37 | while (!this->io_service.stopped())
38 | libusb_handle_events_timeout_completed(this->usb_context, &event_timeout, nullptr);
39 | };
40 |
41 | this->thread_pool.emplace_back(worker);
42 | this->thread_pool.emplace_back(worker);
43 | this->thread_pool.emplace_back(worker);
44 | this->thread_pool.emplace_back(worker);
45 | }
46 |
47 | void OpenAutoWorker::create_io_service_workers()
48 | {
49 | auto worker = [this]() { this->io_service.run(); };
50 |
51 | this->thread_pool.emplace_back(worker);
52 | this->thread_pool.emplace_back(worker);
53 | this->thread_pool.emplace_back(worker);
54 | this->thread_pool.emplace_back(worker);
55 | }
56 |
57 | OpenAutoTab::OpenAutoTab(QWidget *parent) : QWidget(parent)
58 | {
59 | MainWindow *window = qobject_cast(parent);
60 |
61 | connect(window, &MainWindow::set_open_auto_state, [this](unsigned int alpha) {
62 | if (this->worker != nullptr) this->worker->set_opacity(alpha);
63 | if (alpha > 0) this->setFocus();
64 | });
65 |
66 | QStackedLayout *layout = new QStackedLayout(this);
67 | layout->setContentsMargins(0, 0, 0, 0);
68 |
69 | layout->addWidget(this->msg_widget());
70 | #ifdef USE_OMX
71 | QWidget *omx_backdrop = new QWidget(this);
72 | omx_backdrop->setStyleSheet("background-color: black;");
73 | layout->addWidget(omx_backdrop);
74 | #endif
75 | }
76 |
77 | void OpenAutoTab::start_worker()
78 | {
79 | QStackedLayout *layout = qobject_cast(this->layout());
80 | auto callback = [layout](bool is_active) { layout->setCurrentIndex(is_active ? 1 : 0); };
81 | if (this->worker == nullptr) this->worker = new OpenAutoWorker(callback, this);
82 |
83 | this->worker->start();
84 | }
85 |
86 | QWidget *OpenAutoTab::msg_widget()
87 | {
88 | QWidget *widget = new QWidget(this);
89 | QVBoxLayout *layout = new QVBoxLayout(widget);
90 | layout->setContentsMargins(24, 24, 24, 24);
91 |
92 | QLabel *top_msg = new QLabel("waiting for device...", widget);
93 | top_msg->setFont(Theme::font_16);
94 | top_msg->setAlignment(Qt::AlignHCenter);
95 | layout->addStretch();
96 | layout->addWidget(top_msg);
97 |
98 | QLabel *bottom_msg = new QLabel("plug in your device to start OpenAuto", widget);
99 | bottom_msg->setFont(Theme::font_16);
100 | bottom_msg->setAlignment(Qt::AlignHCenter);
101 | layout->addWidget(bottom_msg);
102 | layout->addStretch();
103 |
104 | return widget;
105 | }
106 |
--------------------------------------------------------------------------------
/assets/fonts/Montserrat/OFL.txt:
--------------------------------------------------------------------------------
1 | Copyright 2011 The Montserrat Project Authors (https://github.com/JulietaUla/Montserrat)
2 |
3 | This Font Software is licensed under the SIL Open Font License, Version 1.1.
4 | This license is copied below, and is also available with a FAQ at:
5 | http://scripts.sil.org/OFL
6 |
7 |
8 | -----------------------------------------------------------
9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
10 | -----------------------------------------------------------
11 |
12 | PREAMBLE
13 | The goals of the Open Font License (OFL) are to stimulate worldwide
14 | development of collaborative font projects, to support the font creation
15 | efforts of academic and linguistic communities, and to provide a free and
16 | open framework in which fonts may be shared and improved in partnership
17 | with others.
18 |
19 | The OFL allows the licensed fonts to be used, studied, modified and
20 | redistributed freely as long as they are not sold by themselves. The
21 | fonts, including any derivative works, can be bundled, embedded,
22 | redistributed and/or sold with any software provided that any reserved
23 | names are not used by derivative works. The fonts and derivatives,
24 | however, cannot be released under any other type of license. The
25 | requirement for fonts to remain under this license does not apply
26 | to any document created using the fonts or their derivatives.
27 |
28 | DEFINITIONS
29 | "Font Software" refers to the set of files released by the Copyright
30 | Holder(s) under this license and clearly marked as such. This may
31 | include source files, build scripts and documentation.
32 |
33 | "Reserved Font Name" refers to any names specified as such after the
34 | copyright statement(s).
35 |
36 | "Original Version" refers to the collection of Font Software components as
37 | distributed by the Copyright Holder(s).
38 |
39 | "Modified Version" refers to any derivative made by adding to, deleting,
40 | or substituting -- in part or in whole -- any of the components of the
41 | Original Version, by changing formats or by porting the Font Software to a
42 | new environment.
43 |
44 | "Author" refers to any designer, engineer, programmer, technical
45 | writer or other person who contributed to the Font Software.
46 |
47 | PERMISSION & CONDITIONS
48 | Permission is hereby granted, free of charge, to any person obtaining
49 | a copy of the Font Software, to use, study, copy, merge, embed, modify,
50 | redistribute, and sell modified and unmodified copies of the Font
51 | Software, subject to the following conditions:
52 |
53 | 1) Neither the Font Software nor any of its individual components,
54 | in Original or Modified Versions, may be sold by itself.
55 |
56 | 2) Original or Modified Versions of the Font Software may be bundled,
57 | redistributed and/or sold with any software, provided that each copy
58 | contains the above copyright notice and this license. These can be
59 | included either as stand-alone text files, human-readable headers or
60 | in the appropriate machine-readable metadata fields within text or
61 | binary files as long as those fields can be easily viewed by the user.
62 |
63 | 3) No Modified Version of the Font Software may use the Reserved Font
64 | Name(s) unless explicit written permission is granted by the corresponding
65 | Copyright Holder. This restriction only applies to the primary font name as
66 | presented to the users.
67 |
68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
69 | Software shall not be used to promote, endorse or advertise any
70 | Modified Version, except to acknowledge the contribution(s) of the
71 | Copyright Holder(s) and the Author(s) or with their explicit written
72 | permission.
73 |
74 | 5) The Font Software, modified or unmodified, in part or in whole,
75 | must be distributed entirely under this license, and must not be
76 | distributed under any other license. The requirement for fonts to
77 | remain under this license does not apply to any document created
78 | using the Font Software.
79 |
80 | TERMINATION
81 | This license becomes null and void if any of the above conditions are
82 | not met.
83 |
84 | DISCLAIMER
85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
93 | OTHER DEALINGS IN THE FONT SOFTWARE.
94 |
--------------------------------------------------------------------------------
/assets/fonts/Titillium_Web/OFL.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2009-2011 by Accademia di Belle Arti di Urbino and students of MA course of Visual design. Some rights reserved.
2 |
3 | This Font Software is licensed under the SIL Open Font License, Version 1.1.
4 | This license is copied below, and is also available with a FAQ at:
5 | http://scripts.sil.org/OFL
6 |
7 |
8 | -----------------------------------------------------------
9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
10 | -----------------------------------------------------------
11 |
12 | PREAMBLE
13 | The goals of the Open Font License (OFL) are to stimulate worldwide
14 | development of collaborative font projects, to support the font creation
15 | efforts of academic and linguistic communities, and to provide a free and
16 | open framework in which fonts may be shared and improved in partnership
17 | with others.
18 |
19 | The OFL allows the licensed fonts to be used, studied, modified and
20 | redistributed freely as long as they are not sold by themselves. The
21 | fonts, including any derivative works, can be bundled, embedded,
22 | redistributed and/or sold with any software provided that any reserved
23 | names are not used by derivative works. The fonts and derivatives,
24 | however, cannot be released under any other type of license. The
25 | requirement for fonts to remain under this license does not apply
26 | to any document created using the fonts or their derivatives.
27 |
28 | DEFINITIONS
29 | "Font Software" refers to the set of files released by the Copyright
30 | Holder(s) under this license and clearly marked as such. This may
31 | include source files, build scripts and documentation.
32 |
33 | "Reserved Font Name" refers to any names specified as such after the
34 | copyright statement(s).
35 |
36 | "Original Version" refers to the collection of Font Software components as
37 | distributed by the Copyright Holder(s).
38 |
39 | "Modified Version" refers to any derivative made by adding to, deleting,
40 | or substituting -- in part or in whole -- any of the components of the
41 | Original Version, by changing formats or by porting the Font Software to a
42 | new environment.
43 |
44 | "Author" refers to any designer, engineer, programmer, technical
45 | writer or other person who contributed to the Font Software.
46 |
47 | PERMISSION & CONDITIONS
48 | Permission is hereby granted, free of charge, to any person obtaining
49 | a copy of the Font Software, to use, study, copy, merge, embed, modify,
50 | redistribute, and sell modified and unmodified copies of the Font
51 | Software, subject to the following conditions:
52 |
53 | 1) Neither the Font Software nor any of its individual components,
54 | in Original or Modified Versions, may be sold by itself.
55 |
56 | 2) Original or Modified Versions of the Font Software may be bundled,
57 | redistributed and/or sold with any software, provided that each copy
58 | contains the above copyright notice and this license. These can be
59 | included either as stand-alone text files, human-readable headers or
60 | in the appropriate machine-readable metadata fields within text or
61 | binary files as long as those fields can be easily viewed by the user.
62 |
63 | 3) No Modified Version of the Font Software may use the Reserved Font
64 | Name(s) unless explicit written permission is granted by the corresponding
65 | Copyright Holder. This restriction only applies to the primary font name as
66 | presented to the users.
67 |
68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
69 | Software shall not be used to promote, endorse or advertise any
70 | Modified Version, except to acknowledge the contribution(s) of the
71 | Copyright Holder(s) and the Author(s) or with their explicit written
72 | permission.
73 |
74 | 5) The Font Software, modified or unmodified, in part or in whole,
75 | must be distributed entirely under this license, and must not be
76 | distributed under any other license. The requirement for fonts to
77 | remain under this license does not apply to any document created
78 | using the Font Software.
79 |
80 | TERMINATION
81 | This license becomes null and void if any of the above conditions are
82 | not met.
83 |
84 | DISCLAIMER
85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
93 | OTHER DEALINGS IN THE FONT SOFTWARE.
94 |
--------------------------------------------------------------------------------
/src/app/window.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | MainWindow::MainWindow()
9 | {
10 | this->config = Config::get_instance();
11 | this->setWindowOpacity(this->config->get_brightness() / 255.0);
12 |
13 | this->theme = Theme::get_instance();
14 | this->theme->set_mode(this->config->get_dark_mode());
15 | this->theme->set_color(this->config->get_color());
16 |
17 | this->open_auto_tab = new OpenAutoTab(this);
18 |
19 | QWidget *widget = new QWidget(this);
20 | QVBoxLayout *layout = new QVBoxLayout(widget);
21 |
22 | layout->addWidget(this->tabs_widget());
23 | layout->addWidget(this->controls_widget());
24 |
25 | setCentralWidget(widget);
26 | }
27 |
28 | QTabWidget *MainWindow::tabs_widget()
29 | {
30 | QTabWidget *widget = new QTabWidget(this);
31 | widget->setTabPosition(QTabWidget::TabPosition::West);
32 | widget->tabBar()->setIconSize(Theme::icon_48);
33 |
34 | widget->addTab(this->open_auto_tab, QString());
35 | this->theme->add_tab_icon("directions_car", 0, Qt::Orientation::Vertical);
36 |
37 | widget->addTab(new BluetoothPlayerSubTab(this), QString());
38 | this->theme->add_tab_icon("play_circle_outline", 1, Qt::Orientation::Vertical);
39 |
40 | widget->addTab(new DataTab(this), QString());
41 | this->theme->add_tab_icon("speed", 2, Qt::Orientation::Vertical);
42 |
43 | widget->addTab(new SettingsTab(this), "");
44 | this->theme->add_tab_icon("tune", 3, Qt::Orientation::Vertical);
45 |
46 | connect(this->config, &Config::brightness_changed, [this, widget](int position) {
47 | this->setWindowOpacity(position / 255.0);
48 | if (widget->currentIndex() == 0) emit set_open_auto_state(position);
49 | });
50 | connect(this->theme, &Theme::icons_updated,
51 | [widget](QList &tab_icons, QList &button_icons) {
52 | for (auto &icon : tab_icons) widget->tabBar()->setTabIcon(icon.first, icon.second);
53 | for (auto &icon : button_icons) icon.first->setIcon(icon.second);
54 | });
55 | connect(widget, &QTabWidget::currentChanged, [this](int index) {
56 | emit set_open_auto_state((index == 0) ? (windowOpacity() * 255) : 0);
57 | emit set_data_state(index == 2);
58 | });
59 |
60 | return widget;
61 | }
62 |
63 | QWidget *MainWindow::controls_widget()
64 | {
65 | QWidget *widget = new QWidget(this);
66 | QHBoxLayout *layout = new QHBoxLayout(widget);
67 | layout->setContentsMargins(0, 0, 0, 0);
68 |
69 | layout->addStretch(5);
70 | layout->addWidget(this->volume_widget(), 3);
71 |
72 | return widget;
73 | }
74 |
75 | QWidget *MainWindow::volume_widget()
76 | {
77 | QWidget *widget = new QWidget(this);
78 | QHBoxLayout *layout = new QHBoxLayout(widget);
79 | layout->setContentsMargins(0, 0, 0, 0);
80 |
81 | QSlider *slider = new QSlider(Qt::Orientation::Horizontal, widget);
82 | slider->setRange(0, 100);
83 | slider->setSliderPosition(this->config->get_volume());
84 | update_system_volume(slider->sliderPosition());
85 | connect(slider, &QSlider::valueChanged, [config = this->config](int position) {
86 | config->set_volume(position);
87 | MainWindow::update_system_volume(position);
88 | });
89 |
90 | QPushButton *lower_button = new QPushButton(widget);
91 | lower_button->setFlat(true);
92 | lower_button->setIconSize(Theme::icon_32);
93 | this->theme->add_button_icon("volume_mute", lower_button);
94 | connect(lower_button, &QPushButton::clicked, [slider]() {
95 | int position = slider->sliderPosition() - 10;
96 | slider->setSliderPosition(position);
97 | });
98 |
99 | QPushButton *raise_button = new QPushButton(widget);
100 | raise_button->setFlat(true);
101 | raise_button->setIconSize(Theme::icon_32);
102 | this->theme->add_button_icon("volume_up", raise_button);
103 | connect(raise_button, &QPushButton::clicked, [slider]() {
104 | int position = slider->sliderPosition() + 10;
105 | slider->setSliderPosition(position);
106 | });
107 |
108 | layout->addWidget(lower_button);
109 | layout->addWidget(slider, 4);
110 | layout->addWidget(raise_button);
111 |
112 | return widget;
113 | }
114 |
115 | void MainWindow::update_system_volume(int position)
116 | {
117 | QProcess *lProc = new QProcess();
118 | std::string command = "amixer set Master " + std::to_string(position) + "% --quiet";
119 | lProc->start(QString(command.c_str()));
120 | lProc->waitForFinished();
121 | }
122 |
123 | void MainWindow::showEvent(QShowEvent *event)
124 | {
125 | QWidget::showEvent(event);
126 |
127 | this->open_auto_tab->start_worker();
128 | this->open_auto_tab->setFocus();
129 | }
130 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # *THIS PROJECT HAS MOVED!*
2 |
3 | Please head over to [dash](https://github.com/openDsh/dash), part of the [openDsh](https://github.com/openDsh) org, for the latest and greatest of this project!
4 |
5 | 
6 |
7 | # IntelligentAuto
8 |
9 | IntelligentAuto is a Qt-based infotainment center for your current Linux OpenAuto installation!
10 |
11 | Main features include:
12 |
13 | * volume control
14 | * responsive UI (adjusts to any screen size)
15 | * embedded OpenAuto
16 | * bluetooth media control
17 | * read vehicle OBD-II data
18 | * theming (dark/light mode and accent color)
19 | * brightness (simulated)
20 |
21 | 
22 |
23 | 
24 |
25 | 
26 |
27 | 
28 |
29 | 
30 |
31 | 
32 |
33 | ## Getting Started
34 |
35 | ### Prerequisites
36 |
37 | The following packages have been used while developing this application (NOTE some things may be missing and others are not actually needed):
38 |
39 | * alsa-utils
40 | * cmake
41 | * libboost-all-dev
42 | * libusb-1.0.0-dev
43 | * libssl-dev
44 | * libprotobuf-dev
45 | * protobuf-c-compiler
46 | * protobuf-compiler
47 | * libqt5multimedia5
48 | * libqt5multimedia5-plugins
49 | * libqt5multimediawidgets5
50 | * qtmultimedia5-dev
51 | * libqt5bluetooth5
52 | * libqt5bluetooth5-bin
53 | * qtconnectivity5-dev
54 | * pulseaudio
55 | * librtaudio-dev
56 | * librtaudio6
57 | * libkf5bluezqt-dev
58 |
59 | If you plan on using the Qt video library instead of the OMX library (i.e. not using a Raspberry Pi) you'll also most likely want the following packages:
60 |
61 | * libgstreamer1.0-0
62 | * gstreamer1.0-plugins-base
63 | * gstreamer1.0-plugins-good
64 | * gstreamer1.0-plugins-bad
65 | * gstreamer1.0-plugins-ugly
66 | * gstreamer1.0-libav
67 | * gstreamer1.0-doc
68 | * gstreamer1.0-tools
69 | * gstreamer1.0-x
70 | * gstreamer1.0-alsa
71 | * gstreamer1.0-gl
72 | * gstreamer1.0-gtk3
73 | * gstreamer1.0-qt5
74 | * gstreamer1.0-pulseaudio
75 |
76 | For a Raspberry Pi, you will also need to run the following commands:
77 | ```
78 | cd /opt/vc/src/hello_pi/libs/ilclient
79 | make
80 | ```
81 |
82 | ### Building
83 |
84 | It is assumed you have cloned this repo with all submodules and are in the root directory.
85 |
86 | ```
87 | mkdir build
88 | cd build
89 | cmake -DCMAKE_BUILD_TYPE=Release ../
90 | make
91 | ```
92 |
93 | If building this for a Raspberry Pi, add `-DRPI_BUILD=TRUE` to the `cmake` command.
94 |
95 | ### Running
96 |
97 | Building dash will create the `ia` binary in `bin/`. Depending on what you're running it on, you may need to make some adjustments to your system.
98 |
99 | Some things to consider when configuring your system:
100 |
101 | * use a desktop environment that supports transparency (consider using xfce on Raspberry Pi)
102 | * set background color to black and hide any desktop elements (icons, panel, dock, etc.)
103 | * set USB permissions
104 |
105 | ### Gotchas
106 |
107 | Adjusting the brightness does not actually change the screens brightness, it just changes the opacity of the window.
108 |
109 | Authentication of bluetooth connections are not handled in the application (i.e. the first time you are connecting a device). To keep things simple, you could install `blueman` which will prompt you for the necessary actions. If you are still having problems, you may need to try manually authenticating the bluetooth connection.
110 |
111 | There is currently no option for setting the OBD-II interface. Right now it is assumed you have an adapter connected on `/dev/ttyUSB0`.
112 |
113 | Settings are saved periodically every 10 seconds (or anytime the `save` button is clicked).
114 |
115 | Not all OpenAuto settings are acessible.
116 |
117 | If using GStreamer for your video backend (i.e. not a Raspberry Pi), you may get some black bars around the margins of OpenAuto. I'm still trying to figure out a way for it to ignore the aspect ratio.
118 |
119 | ### Future Features/Fixes
120 |
121 | - [ ] add radio player (UI elements exist, just haven't had anything to interface with yet)
122 | - [ ] support bluetooth OBD-II adapter
123 | - [ ] control screen brightness
124 | - [ ] incorporate wireless OpenAuto
125 | - [ ] add wireless hotspot controls
126 | - [ ] add modular OBD-II data tabs
127 | - [ ] add OBD-II error codes tab
128 | - [ ] add dashcam video tab
129 | - [ ] ignore apsect ratio of OpenAuto for GStreamer backend
130 | - [ ] debug issue for OpenAuto randomly disconnecting
131 | - [ ] add automatic light/dark mode
132 | - [ ] add local media player
133 | - [ ] add audio equalizer
134 |
--------------------------------------------------------------------------------
/src/app/theme.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | #include
13 |
14 | const QFont Theme::font_14 = QFont("Montserrat", 14);
15 | const QFont Theme::font_16 = QFont("Montserrat", 16);
16 | const QFont Theme::font_18 = QFont("Montserrat", 18);
17 | const QFont Theme::font_36 = QFont("Montserrat", 36);
18 |
19 | const QSize Theme::icon_16 = QSize(16, 16);
20 | const QSize Theme::icon_24 = QSize(24, 24);
21 | const QSize Theme::icon_32 = QSize(32, 32);
22 | const QSize Theme::icon_36 = QSize(36, 36);
23 | const QSize Theme::icon_42 = QSize(42, 42);
24 | const QSize Theme::icon_48 = QSize(48, 48);
25 | const QSize Theme::icon_56 = QSize(56, 56);
26 | const QSize Theme::icon_84 = QSize(84, 84);
27 | const QSize Theme::icon_96 = QSize(96, 96);
28 |
29 | const QColor Theme::danger_color = QColor(211, 47, 47);
30 | const QColor Theme::success_color = QColor(56, 142, 60);
31 |
32 | Theme::Theme() : QObject(qApp), palette(), color("blue")
33 | {
34 | QFontDatabase::addApplicationFont(":/fonts/Titillium_Web/TitilliumWeb-Regular.ttf");
35 | QFontDatabase::addApplicationFont(":/fonts/Montserrat/Montserrat-LightItalic.ttf");
36 | QFontDatabase::addApplicationFont(":/fonts/Montserrat/Montserrat-Regular.ttf");
37 |
38 | this->stylesheets["light"] = this->parse_stylesheet(":/stylesheets/light.qss");
39 | this->stylesheets["dark"] = this->parse_stylesheet(":/stylesheets/dark.qss");
40 |
41 | qApp->setStyleSheet(this->stylesheets[this->mode ? "dark" : "light"]);
42 |
43 | this->set_palette();
44 | }
45 |
46 | QString Theme::parse_stylesheet(QString file)
47 | {
48 | QString stylesheet;
49 |
50 | QFile *f = new QFile(file);
51 | f->open(QFile::ReadOnly | QFile::Text);
52 | QTextStream s(f);
53 | stylesheet = s.readAll();
54 | f->close();
55 |
56 | delete f;
57 |
58 | return stylesheet;
59 | }
60 |
61 | void Theme::set_palette()
62 | {
63 | QColor new_color(this->colors[this->mode ? "dark" : "light"][this->color]);
64 | this->palette.setColor(QPalette::Base, new_color);
65 | new_color.setAlphaF(.5);
66 | this->palette.setColor(QPalette::AlternateBase, new_color);
67 | qApp->setPalette(this->palette);
68 | }
69 |
70 | QPixmap Theme::create_pixmap_variant(QPixmap &base, qreal opacity)
71 | {
72 | QPixmap image(base.size());
73 | image.fill(Qt::transparent);
74 |
75 | QPainter painter(&image);
76 | painter.setOpacity(opacity);
77 | painter.drawPixmap(0, 0, base);
78 | painter.end();
79 |
80 | return image;
81 | }
82 |
83 | void Theme::add_tab_icon(QString name, int index, Qt::Orientation orientation)
84 | {
85 | QTransform t;
86 | t.rotate((orientation == Qt::Orientation::Horizontal) ? 0 : 90);
87 |
88 | QPixmap dark_base = QIcon(QString(":/icons/dark/%1-24px.svg").arg(name)).pixmap(512, 512).transformed(t);
89 | QPixmap dark_active = this->create_pixmap_variant(dark_base, .87);
90 | QPixmap dark_normal = this->create_pixmap_variant(dark_base, .54);
91 | QPixmap dark_disabled = this->create_pixmap_variant(dark_base, .38);
92 |
93 | QIcon dark_icon = QIcon(dark_normal);
94 | dark_icon.addPixmap(dark_active, QIcon::Active, QIcon::On);
95 | dark_icon.addPixmap(dark_disabled, QIcon::Disabled);
96 | this->tab_icons["dark"].append({index, dark_icon});
97 |
98 | QPixmap light_base = QIcon(QString(":/icons/light/%1-24px.svg").arg(name)).pixmap(512, 512).transformed(t);
99 | QPixmap light_active = this->create_pixmap_variant(light_base, 1);
100 | QPixmap light_normal = this->create_pixmap_variant(light_base, .7);
101 | QPixmap light_disabled = this->create_pixmap_variant(light_base, .5);
102 |
103 | QIcon light_icon = QIcon(light_normal);
104 | light_icon.addPixmap(light_active, QIcon::Active, QIcon::On);
105 | light_icon.addPixmap(light_disabled, QIcon::Disabled);
106 | this->tab_icons["light"].append({index, light_icon});
107 |
108 | this->update();
109 | }
110 |
111 | void Theme::add_button_icon(QString name, QPushButton *button, QString normal_name)
112 | {
113 | bool checkable = button->isCheckable();
114 |
115 | QPixmap dark_base = QIcon(QString(":/icons/dark/%1-24px.svg").arg(name)).pixmap(512, 512);
116 | QPixmap light_base = QIcon(QString(":/icons/light/%1-24px.svg").arg(name)).pixmap(512, 512);
117 |
118 | QPixmap dark_active = this->create_pixmap_variant(dark_base, .87);
119 | QPixmap dark_disabled = this->create_pixmap_variant(dark_base, .38);
120 |
121 | QPixmap light_active = this->create_pixmap_variant(light_base, 1);
122 | QPixmap light_disabled = this->create_pixmap_variant(light_base, .5);
123 |
124 | QPixmap dark_normal;
125 | QPixmap light_normal;
126 | if (normal_name.isNull()) {
127 | dark_normal = checkable ? this->create_pixmap_variant(dark_base, .54) : dark_active;
128 | light_normal = checkable ? this->create_pixmap_variant(light_base, .7) : light_active;
129 | }
130 | else {
131 | QPixmap dark_normal_base = QIcon(QString(":/icons/dark/%1-24px.svg").arg(normal_name)).pixmap(512, 512);
132 | QPixmap light_normal_base = QIcon(QString(":/icons/light/%1-24px.svg").arg(normal_name)).pixmap(512, 512);
133 |
134 | dark_normal = this->create_pixmap_variant(dark_normal_base, .87);
135 | light_normal = this->create_pixmap_variant(light_normal_base, 1);
136 | }
137 |
138 | QIcon dark_icon = QIcon(dark_normal);
139 | dark_icon.addPixmap(dark_active, QIcon::Active, QIcon::On);
140 | dark_icon.addPixmap(dark_disabled, QIcon::Disabled);
141 | this->button_icons["dark"].append({button, dark_icon});
142 |
143 | QIcon light_icon = QIcon(light_normal);
144 | light_icon.addPixmap(light_active, QIcon::Active, QIcon::On);
145 | light_icon.addPixmap(light_disabled, QIcon::Disabled);
146 | this->button_icons["light"].append({button, light_icon});
147 |
148 | this->update();
149 | }
150 |
151 | void Theme::update()
152 | {
153 | this->set_palette();
154 | qApp->setStyleSheet(this->stylesheets[this->mode ? "dark" : "light"]);
155 |
156 | emit icons_updated(this->tab_icons[this->mode ? "dark" : "light"],
157 | this->button_icons[this->mode ? "dark" : "light"]);
158 | emit color_updated(this->colors[this->mode ? "dark" : "light"]);
159 | }
160 |
161 | Theme *Theme::get_instance()
162 | {
163 | static Theme theme;
164 | return &theme;
165 | }
166 |
--------------------------------------------------------------------------------
/src/app/tabs/data.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | Gauge::Gauge(units_t units, QFont value_font, QFont unit_font, Gauge::Orientation orientation, int rate,
9 | std::vector cmds, int precision, obd_decoder_t decoder, QWidget *parent)
10 | : QWidget(parent)
11 | {
12 | Config *config = Config::get_instance();
13 | this->si = config->get_si_units();
14 |
15 | this->rate = rate;
16 | this->precision = precision;
17 |
18 | QBoxLayout *layout;
19 | if (orientation == BOTTOM)
20 | layout = new QVBoxLayout(this);
21 | else
22 | layout = new QHBoxLayout(this);
23 |
24 | QLabel *value_label = new QLabel(this->null_value(), this);
25 | value_label->setFont(value_font);
26 | value_label->setAlignment(Qt::AlignCenter);
27 |
28 | QLabel *unit_label = new QLabel(this->si ? units.second : units.first, this);
29 | unit_label->setFont(unit_font);
30 | unit_label->setAlignment(Qt::AlignCenter);
31 |
32 | this->timer = new QTimer(this);
33 | connect(this->timer, &QTimer::timeout, [this, cmds, decoder, value_label]() {
34 | std::vector results;
35 | for (auto cmd : cmds) {
36 | double result = 0;
37 | if (!OBD::get_instance()->query(cmd, result)) return;
38 | results.push_back(result);
39 | }
40 |
41 | value_label->setText(this->format_value(decoder(results, this->si)));
42 | });
43 |
44 | connect(config, &Config::si_units_changed, [this, units, unit_label, value_label](bool si) {
45 | this->si = si;
46 | unit_label->setText(this->si ? units.second : units.first);
47 | value_label->setText(this->null_value());
48 | });
49 |
50 | layout->addStretch();
51 | layout->addWidget(value_label);
52 | layout->addWidget(unit_label);
53 | }
54 |
55 | QString Gauge::format_value(double value)
56 | {
57 | if (this->precision == 0)
58 | return QString::number((int)value);
59 | else
60 | return QString::number(value, 'f', this->precision);
61 | }
62 |
63 | QString Gauge::null_value()
64 | {
65 | QString null_str = "-";
66 | if (this->precision > 0)
67 | null_str += ".-";
68 | else
69 | null_str += '-';
70 |
71 | return null_str;
72 | }
73 |
74 | DataTab::DataTab(QWidget *parent) : QWidget(parent)
75 | {
76 | MainWindow *app = qobject_cast(parent);
77 |
78 | QVBoxLayout *layout = new QVBoxLayout(this);
79 | layout->setContentsMargins(0, 0, 0, 0);
80 |
81 | QFrame *status_indicator = new QFrame(this);
82 | status_indicator->setFixedHeight(6);
83 | status_indicator->setAutoFillBackground(true);
84 | connect(app, &MainWindow::set_data_state, [this, status_indicator](bool enabled) {
85 | if (enabled) {
86 | QPalette p(palette());
87 | if (OBD::get_instance()->is_connected()) {
88 | p.setColor(QPalette::Window, Theme::success_color);
89 | for (auto &gauge : this->gauges) gauge->start();
90 | }
91 | else {
92 | p.setColor(QPalette::Window, Theme::danger_color);
93 | }
94 | status_indicator->setPalette(p);
95 | }
96 | else {
97 | for (auto &gauge : this->gauges) gauge->stop();
98 | }
99 | });
100 | layout->addWidget(status_indicator);
101 | layout->addWidget(this->cluster_widget());
102 | }
103 |
104 | QWidget *DataTab::cluster_widget()
105 | {
106 | QWidget *widget = new QWidget(this);
107 | QHBoxLayout *layout = new QHBoxLayout(widget);
108 | layout->setContentsMargins(24, 24, 24, 24);
109 |
110 | QWidget *driving_data = this->driving_data_widget();
111 | layout->addWidget(driving_data);
112 | layout->addWidget(Theme::br(widget, true));
113 |
114 | QWidget *engine_data = this->engine_data_widget();
115 | layout->addWidget(engine_data);
116 |
117 | QSizePolicy sp_left(QSizePolicy::Preferred, QSizePolicy::Preferred);
118 | sp_left.setHorizontalStretch(5);
119 | driving_data->setSizePolicy(sp_left);
120 | QSizePolicy sp_right(QSizePolicy::Preferred, QSizePolicy::Preferred);
121 | sp_right.setHorizontalStretch(2);
122 | engine_data->setSizePolicy(sp_right);
123 |
124 | return widget;
125 | }
126 |
127 | QWidget *DataTab::driving_data_widget()
128 | {
129 | QWidget *widget = new QWidget(this);
130 | QVBoxLayout *layout = new QVBoxLayout(widget);
131 |
132 | layout->addStretch();
133 | layout->addWidget(this->speedo_tach_widget());
134 | layout->addStretch();
135 | layout->addWidget(Theme::br(widget));
136 | layout->addWidget(this->mileage_data_widget());
137 |
138 | return widget;
139 | }
140 |
141 | QWidget *DataTab::speedo_tach_widget()
142 | {
143 | QWidget *widget = new QWidget(this);
144 | QHBoxLayout *layout = new QHBoxLayout(widget);
145 |
146 | Gauge *speed = new Gauge({"mph", "km/h"}, QFont("Titillium Web", 72), QFont("Montserrat", 16, QFont::Light, true),
147 | Gauge::BOTTOM, 100, {cmds.SPEED}, 0,
148 | [](std::vector x, bool si) { return si ? x[0] : kph_to_mph(x[0]); }, widget);
149 | layout->addWidget(speed);
150 | this->gauges.push_back(speed);
151 |
152 | Gauge *rpm = new Gauge({"x1000rpm", "x1000rpm"}, QFont("Titillium Web", 72),
153 | QFont("Montserrat", 16, QFont::Light, true), Gauge::BOTTOM, 100, {cmds.RPM}, 1,
154 | [](std::vector x, bool _) { return x[0] / 1000.0; }, widget);
155 | layout->addWidget(rpm);
156 | this->gauges.push_back(rpm);
157 |
158 | return widget;
159 | }
160 |
161 | QWidget *DataTab::mileage_data_widget()
162 | {
163 | QWidget *widget = new QWidget(this);
164 | QHBoxLayout *layout = new QHBoxLayout(widget);
165 |
166 | Gauge *mileage = new Gauge({"mpg", "km/L"}, QFont("Titillium Web", 36), QFont("Montserrat", 14, QFont::Light, true),
167 | Gauge::BOTTOM, 100, {cmds.SPEED, cmds.MAF}, 1,
168 | [](std::vector x, bool si) {
169 | return (si ? x[0] : kph_to_mph(x[0])) / (si ? gps_to_lph(x[1]) : gps_to_gph(x[1]));
170 | },
171 | widget);
172 | layout->addWidget(mileage);
173 | this->gauges.push_back(mileage);
174 |
175 | return widget;
176 | }
177 |
178 | QWidget *DataTab::engine_data_widget()
179 | {
180 | QWidget *widget = new QWidget(this);
181 | QVBoxLayout *layout = new QVBoxLayout(widget);
182 |
183 | layout->addStretch();
184 | layout->addWidget(this->coolant_temp_widget());
185 | layout->addStretch();
186 | layout->addWidget(Theme::br(widget));
187 | layout->addStretch();
188 | layout->addWidget(this->engine_load_widget());
189 | layout->addStretch();
190 |
191 | return widget;
192 | }
193 |
194 | QWidget *DataTab::coolant_temp_widget()
195 | {
196 | QWidget *widget = new QWidget(this);
197 | QVBoxLayout *layout = new QVBoxLayout(widget);
198 |
199 | Gauge *coolant_temp = new Gauge(
200 | {"°F", "°C"}, QFont("Titillium Web", 36), QFont("Montserrat", 14, QFont::Light, true), Gauge::RIGHT, 5000,
201 | {cmds.COOLANT_TEMP}, 1, [](std::vector x, bool si) { return si ? x[0] : c_to_f(x[0]); }, widget);
202 | layout->addWidget(coolant_temp);
203 | this->gauges.push_back(coolant_temp);
204 |
205 | QLabel *coolant_temp_label = new QLabel("coolant", widget);
206 | coolant_temp_label->setFont(QFont("Montserrat", 14, QFont::Light));
207 | coolant_temp_label->setAlignment(Qt::AlignHCenter);
208 | layout->addWidget(coolant_temp_label);
209 |
210 | return widget;
211 | }
212 |
213 | QWidget *DataTab::engine_load_widget()
214 | {
215 | QWidget *widget = new QWidget(this);
216 | QVBoxLayout *layout = new QVBoxLayout(widget);
217 |
218 | Gauge *engine_load =
219 | new Gauge({"%", "%"}, QFont("Titillium Web", 36), QFont("Montserrat", 14, QFont::Light, true), Gauge::RIGHT,
220 | 500, {cmds.LOAD}, 1, [](std::vector x, bool _) { return x[0]; }, widget);
221 | layout->addWidget(engine_load);
222 | this->gauges.push_back(engine_load);
223 |
224 | QLabel *engine_load_label = new QLabel("load", widget);
225 | engine_load_label->setFont(QFont("Montserrat", 14, QFont::Light));
226 | engine_load_label->setAlignment(Qt::AlignHCenter);
227 | layout->addWidget(engine_load_label);
228 | return widget;
229 | }
230 |
--------------------------------------------------------------------------------
/src/app/tabs/media.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 | #include
5 |
6 | MediaTab::MediaTab(QWidget *parent) : QTabWidget(parent)
7 | {
8 | this->tabBar()->setFont(Theme::font_18);
9 |
10 | this->addTab(new RadioPlayerSubTab(this), "Radio");
11 | this->addTab(new BluetoothPlayerSubTab(this), "Bluetooth");
12 | }
13 |
14 | BluetoothPlayerSubTab::BluetoothPlayerSubTab(QWidget *parent) : QWidget(parent)
15 | {
16 | this->bluetooth = Bluetooth::get_instance();
17 |
18 | QVBoxLayout *layout = new QVBoxLayout(this);
19 | layout->setContentsMargins(24, 24, 24, 24);
20 |
21 | layout->addStretch();
22 | layout->addWidget(this->track_widget());
23 | layout->addStretch();
24 | layout->addWidget(this->controls_widget());
25 | layout->addStretch();
26 | }
27 |
28 | QWidget *BluetoothPlayerSubTab::track_widget()
29 | {
30 | BluezQt::MediaPlayerPtr media_player = this->bluetooth->get_media_player().second;
31 |
32 | QWidget *widget = new QWidget(this);
33 | QVBoxLayout *layout = new QVBoxLayout(widget);
34 |
35 | QLabel *artist_hdr = new QLabel("Artist", widget);
36 | artist_hdr->setFont(Theme::font_16);
37 | QLabel *artist = new QLabel((media_player != nullptr) ? media_player->track().artist() : QString(), widget);
38 | artist->setFont(Theme::font_14);
39 | artist->setStyleSheet("padding-left: 16px;");
40 | layout->addWidget(artist_hdr);
41 | layout->addWidget(artist);
42 |
43 | QLabel *album_hdr = new QLabel("Album", widget);
44 | album_hdr->setFont(Theme::font_16);
45 | QLabel *album = new QLabel((media_player != nullptr) ? media_player->track().album() : QString(), widget);
46 | album->setFont(Theme::font_14);
47 | album->setStyleSheet("padding-left: 16px;");
48 | layout->addWidget(album_hdr);
49 | layout->addWidget(album);
50 |
51 | QLabel *title_hdr = new QLabel("Title", widget);
52 | title_hdr->setFont(Theme::font_16);
53 | QLabel *title = new QLabel((media_player != nullptr) ? media_player->track().title() : QString(), widget);
54 | title->setFont(Theme::font_14);
55 | title->setStyleSheet("padding-left: 16px;");
56 | layout->addWidget(title_hdr);
57 | layout->addWidget(title);
58 |
59 | connect(this->bluetooth, &Bluetooth::media_player_track_changed,
60 | [artist, album, title](BluezQt::MediaPlayerTrack track) {
61 | artist->setText(track.artist());
62 | album->setText(track.album());
63 | title->setText(track.title());
64 | });
65 |
66 | return widget;
67 | }
68 |
69 | QWidget *BluetoothPlayerSubTab::controls_widget()
70 | {
71 | BluezQt::MediaPlayerPtr media_player = this->bluetooth->get_media_player().second;
72 | Theme *theme = Theme::get_instance();
73 |
74 | QWidget *widget = new QWidget(this);
75 | QHBoxLayout *layout = new QHBoxLayout(widget);
76 |
77 | QPushButton *previous_button = new QPushButton(widget);
78 | previous_button->setFlat(true);
79 | previous_button->setIconSize(Theme::icon_84);
80 | connect(previous_button, &QPushButton::clicked, [bluetooth = this->bluetooth]() {
81 | BluezQt::MediaPlayerPtr media_player = bluetooth->get_media_player().second;
82 | if (media_player != nullptr) media_player->previous()->waitForFinished();
83 | });
84 | theme->add_button_icon("skip_previous", previous_button);
85 | layout->addStretch();
86 | layout->addWidget(previous_button);
87 |
88 | QPushButton *play_button = new QPushButton(widget);
89 | play_button->setFlat(true);
90 | play_button->setCheckable(true);
91 | bool status = (media_player != nullptr) ? media_player->status() == BluezQt::MediaPlayer::Status::Playing : false;
92 | play_button->setChecked(status);
93 | play_button->setIconSize(Theme::icon_84);
94 | connect(play_button, &QPushButton::clicked, [bluetooth = this->bluetooth, play_button](bool checked = false) {
95 | play_button->setChecked(!checked);
96 |
97 | BluezQt::MediaPlayerPtr media_player = bluetooth->get_media_player().second;
98 | if (media_player != nullptr) {
99 | if (checked)
100 | media_player->play()->waitForFinished();
101 | else
102 | media_player->pause()->waitForFinished();
103 | }
104 | });
105 | connect(this->bluetooth, &Bluetooth::media_player_status_changed,
106 | [play_button](BluezQt::MediaPlayer::Status status) {
107 | play_button->setChecked(status == BluezQt::MediaPlayer::Status::Playing);
108 | });
109 | theme->add_button_icon("pause", play_button, "play");
110 | layout->addStretch();
111 | layout->addWidget(play_button);
112 |
113 | QPushButton *forward_button = new QPushButton(widget);
114 | forward_button->setFlat(true);
115 | forward_button->setIconSize(Theme::icon_84);
116 | connect(forward_button, &QPushButton::clicked, [bluetooth = this->bluetooth]() {
117 | BluezQt::MediaPlayerPtr media_player = bluetooth->get_media_player().second;
118 | if (media_player != nullptr) media_player->next()->waitForFinished();
119 | });
120 | theme->add_button_icon("skip_next", forward_button);
121 | layout->addStretch();
122 | layout->addWidget(forward_button);
123 | layout->addStretch();
124 |
125 | return widget;
126 | }
127 |
128 | RadioPlayerSubTab::RadioPlayerSubTab(QWidget *parent) : QWidget(parent)
129 | {
130 | this->theme = Theme::get_instance();
131 | this->config = Config::get_instance();
132 | this->tuner = new Tuner();
133 |
134 | QVBoxLayout *layout = new QVBoxLayout(this);
135 | layout->setContentsMargins(24, 24, 24, 24);
136 |
137 | layout->addStretch();
138 | layout->addWidget(this->tuner_widget());
139 | layout->addStretch();
140 | layout->addWidget(this->controls_widget());
141 | layout->addStretch();
142 | }
143 |
144 | QWidget *RadioPlayerSubTab::tuner_widget()
145 | {
146 | QWidget *widget = new QWidget(this);
147 | QVBoxLayout *layout = new QVBoxLayout(widget);
148 |
149 | this->tuner->setParent(widget);
150 | this->tuner->setFont(Theme::font_14);
151 |
152 | QLabel *station = new QLabel(QString::number(this->tuner->sliderPosition() / 10.0, 'f', 1), widget);
153 | station->setAlignment(Qt::AlignCenter);
154 | station->setFont(Theme::font_36);
155 | connect(this->tuner, &Tuner::station_updated,
156 | [station](int freq) { station->setText(QString::number(freq / 10.0, 'f', 1)); });
157 | layout->addWidget(station);
158 | layout->addStretch();
159 | layout->addWidget(this->tuner);
160 |
161 | return widget;
162 | }
163 |
164 | QWidget *RadioPlayerSubTab::controls_widget()
165 | {
166 | QWidget *widget = new QWidget(this);
167 | QHBoxLayout *layout = new QHBoxLayout(widget);
168 |
169 | QPushButton *scan_reverse_button = new QPushButton(widget);
170 | scan_reverse_button->setFlat(true);
171 | scan_reverse_button->setIconSize(Theme::icon_84);
172 | this->theme->add_button_icon("fast_rewind", scan_reverse_button);
173 | connect(scan_reverse_button, &QPushButton::clicked,
174 | [tuner = this->tuner]() { tuner->setSliderPosition(tuner->sliderPosition() - 5); });
175 | layout->addStretch();
176 | layout->addWidget(scan_reverse_button);
177 |
178 | QPushButton *prev_station_button = new QPushButton(widget);
179 | prev_station_button->setFlat(true);
180 | prev_station_button->setIconSize(Theme::icon_84);
181 | this->theme->add_button_icon("skip_previous", prev_station_button);
182 | connect(prev_station_button, &QPushButton::clicked,
183 | [tuner = this->tuner]() { tuner->setSliderPosition(tuner->sliderPosition() - 1); });
184 | layout->addStretch();
185 | layout->addWidget(prev_station_button);
186 |
187 | QPushButton *next_station_button = new QPushButton(widget);
188 | next_station_button->setFlat(true);
189 | next_station_button->setIconSize(Theme::icon_84);
190 | this->theme->add_button_icon("skip_next", next_station_button);
191 | connect(next_station_button, &QPushButton::clicked,
192 | [tuner = this->tuner]() { tuner->setSliderPosition(tuner->sliderPosition() + 1); });
193 | layout->addStretch();
194 | layout->addWidget(next_station_button);
195 |
196 | QPushButton *scan_forward_button = new QPushButton(widget);
197 | scan_forward_button->setFlat(true);
198 | scan_forward_button->setIconSize(Theme::icon_84);
199 | this->theme->add_button_icon("fast_forward", scan_forward_button);
200 | connect(scan_forward_button, &QPushButton::clicked,
201 | [tuner = this->tuner]() { tuner->setSliderPosition(tuner->sliderPosition() + 5); });
202 | layout->addStretch();
203 | layout->addWidget(scan_forward_button);
204 |
205 | QFrame *vert_break = new QFrame(widget);
206 | vert_break->setLineWidth(1);
207 | vert_break->setFrameShape(QFrame::VLine);
208 | vert_break->setFrameShadow(QFrame::Plain);
209 | layout->addStretch();
210 | layout->addWidget(vert_break);
211 |
212 | QPushButton *mute_button = new QPushButton(widget);
213 | mute_button->setFlat(true);
214 | mute_button->setCheckable(true);
215 | mute_button->setChecked(this->config->get_radio_muted());
216 | mute_button->setIconSize(Theme::icon_48);
217 | connect(mute_button, &QPushButton::clicked,
218 | [config = this->config](bool checked = false) { config->set_radio_muted(checked); });
219 | this->theme->add_button_icon("volume_off", mute_button);
220 | layout->addStretch();
221 | layout->addWidget(mute_button);
222 | layout->addStretch();
223 |
224 | return widget;
225 | }
226 |
--------------------------------------------------------------------------------
/src/app/tabs/settings.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | namespace aasdk = f1x::aasdk;
17 | namespace autoapp = f1x::openauto::autoapp;
18 |
19 | SettingsTab::SettingsTab(QWidget *parent) : QTabWidget(parent)
20 | {
21 | this->tabBar()->setFont(Theme::font_18);
22 |
23 | this->addTab(new GeneralSettingsSubTab(this), "General");
24 | this->addTab(new BluetoothSettingsSubTab(this), "Bluetooth");
25 | this->addTab(new OpenAutoSettingsSubTab(this), "OpenAuto");
26 | }
27 |
28 | GeneralSettingsSubTab::GeneralSettingsSubTab(QWidget *parent) : QWidget(parent)
29 | {
30 | this->theme = Theme::get_instance();
31 | this->config = Config::get_instance();
32 |
33 | QVBoxLayout *layout = new QVBoxLayout(this);
34 | layout->setContentsMargins(24, 24, 24, 24);
35 |
36 | layout->addWidget(this->settings_widget());
37 | layout->addWidget(this->controls_widget());
38 | }
39 |
40 | QWidget *GeneralSettingsSubTab::settings_widget()
41 | {
42 | QWidget *widget = new QWidget(this);
43 | QVBoxLayout *layout = new QVBoxLayout(widget);
44 |
45 | layout->addWidget(this->dark_mode_row_widget(), 1);
46 | layout->addWidget(this->color_row_widget(), 1);
47 | layout->addWidget(Theme::br(widget), 1);
48 | layout->addWidget(this->si_units_row_widget(), 1);
49 | layout->addWidget(Theme::br(widget), 1);
50 | layout->addWidget(this->brightness_row_widget(), 1);
51 |
52 | return widget;
53 | }
54 |
55 | QWidget *GeneralSettingsSubTab::dark_mode_row_widget()
56 | {
57 | QWidget *widget = new QWidget(this);
58 | QHBoxLayout *layout = new QHBoxLayout(widget);
59 |
60 | QLabel *label = new QLabel("Dark Mode", widget);
61 | label->setFont(Theme::font_16);
62 | layout->addWidget(label, 1);
63 |
64 | Switch *toggle = new Switch(widget);
65 | toggle->setChecked(this->config->get_dark_mode());
66 | connect(toggle, &Switch::stateChanged, [theme = this->theme, config = this->config](bool state) {
67 | theme->set_mode(state);
68 | config->set_dark_mode(state);
69 | });
70 | layout->addWidget(toggle, 1, Qt::AlignHCenter);
71 |
72 | return widget;
73 | }
74 |
75 | QWidget *GeneralSettingsSubTab::brightness_row_widget()
76 | {
77 | QWidget *widget = new QWidget(this);
78 | QHBoxLayout *layout = new QHBoxLayout(widget);
79 |
80 | QLabel *label = new QLabel("Brightness", widget);
81 | label->setFont(Theme::font_16);
82 | layout->addWidget(label, 1);
83 |
84 | layout->addWidget(this->brightness_widget(), 1);
85 |
86 | return widget;
87 | }
88 |
89 | QWidget *GeneralSettingsSubTab::brightness_widget()
90 | {
91 | QWidget *widget = new QWidget(this);
92 | QHBoxLayout *layout = new QHBoxLayout(widget);
93 |
94 | QSlider *slider = new QSlider(Qt::Orientation::Horizontal, widget);
95 | slider->setRange(76, 255);
96 | slider->setSliderPosition(this->config->get_brightness());
97 | connect(slider, &QSlider::valueChanged,
98 | [config = this->config](int position) { config->set_brightness(position); });
99 |
100 | QPushButton *dim_button = new QPushButton(widget);
101 | dim_button->setFlat(true);
102 | dim_button->setIconSize(Theme::icon_32);
103 | this->theme->add_button_icon("brightness_low", dim_button);
104 | connect(dim_button, &QPushButton::clicked,
105 | [slider]() { slider->setSliderPosition(std::max(76, slider->sliderPosition() - 18)); });
106 |
107 | QPushButton *brighten_button = new QPushButton(widget);
108 | brighten_button->setFlat(true);
109 | brighten_button->setIconSize(Theme::icon_32);
110 | this->theme->add_button_icon("brightness_high", brighten_button);
111 | connect(brighten_button, &QPushButton::clicked,
112 | [slider]() { slider->setSliderPosition(std::min(255, slider->sliderPosition() + 18)); });
113 |
114 | layout->addStretch(1);
115 | layout->addWidget(dim_button);
116 | layout->addWidget(slider, 4);
117 | layout->addWidget(brighten_button);
118 | layout->addStretch(1);
119 |
120 | return widget;
121 | }
122 |
123 | QWidget *GeneralSettingsSubTab::si_units_row_widget()
124 | {
125 | QWidget *widget = new QWidget(this);
126 | QHBoxLayout *layout = new QHBoxLayout(widget);
127 |
128 | QLabel *label = new QLabel("SI Units", widget);
129 | label->setFont(Theme::font_16);
130 | layout->addWidget(label, 1);
131 |
132 | Switch *toggle = new Switch(widget);
133 | toggle->setChecked(this->config->get_si_units());
134 | connect(toggle, &Switch::stateChanged, [config = this->config](bool state) { config->set_si_units(state); });
135 | layout->addWidget(toggle, 1, Qt::AlignHCenter);
136 |
137 | return widget;
138 | }
139 |
140 | QWidget *GeneralSettingsSubTab::color_row_widget()
141 | {
142 | QWidget *widget = new QWidget(this);
143 | QHBoxLayout *layout = new QHBoxLayout(widget);
144 |
145 | QLabel *label = new QLabel("Color", widget);
146 | label->setFont(Theme::font_16);
147 | layout->addWidget(label, 1);
148 |
149 | QComboBox *box = new QComboBox(widget);
150 | box->setMinimumContentsLength(16);
151 | box->setItemDelegate(new QStyledItemDelegate());
152 | box->setFont(Theme::font_14);
153 | QMap colors = this->theme->get_colors();
154 | QMap::iterator it;
155 | QPixmap pixmap(Theme::icon_16);
156 | for (it = colors.begin(); it != colors.end(); it++) {
157 | pixmap.fill(it.value());
158 | box->addItem(QIcon(pixmap), it.key());
159 | }
160 | box->setCurrentText(this->config->get_color());
161 | connect(box, QOverload::of(&QComboBox::activated),
162 | [theme = this->theme, config = this->config](const QString &color) {
163 | theme->set_color(color);
164 | config->set_color(color);
165 | });
166 | connect(this->theme, &Theme::color_updated, [box](QMap &colors) {
167 | QMap::iterator it;
168 | QPixmap pixmap(Theme::icon_16);
169 | for (it = colors.begin(); it != colors.end(); it++) {
170 | pixmap.fill(it.value());
171 | box->setItemIcon(box->findText(it.key()), QIcon(pixmap));
172 | }
173 | });
174 | layout->addWidget(box, 1, Qt::AlignHCenter);
175 |
176 | return widget;
177 | }
178 |
179 | QWidget *GeneralSettingsSubTab::controls_widget()
180 | {
181 | QWidget *widget = new QWidget(this);
182 | QVBoxLayout *layout = new QVBoxLayout(widget);
183 |
184 | QPushButton *save_button = new QPushButton("save", widget);
185 | save_button->setFont(Theme::font_14);
186 | save_button->setFlat(true);
187 | save_button->setIconSize(Theme::icon_36);
188 | this->theme->add_button_icon("save", save_button);
189 | connect(save_button, &QPushButton::clicked, [config = this->config]() { config->save(); });
190 | layout->addWidget(save_button, 0, Qt::AlignRight);
191 |
192 | return widget;
193 | }
194 |
195 | BluetoothSettingsSubTab::BluetoothSettingsSubTab(QWidget *parent) : QWidget(parent)
196 | {
197 | this->bluetooth = Bluetooth::get_instance();
198 | this->theme = Theme::get_instance();
199 | this->config = Config::get_instance();
200 |
201 | QHBoxLayout *layout = new QHBoxLayout(this);
202 | layout->setContentsMargins(24, 24, 24, 24);
203 |
204 | layout->addWidget(this->controls_widget());
205 | layout->addWidget(this->devices_widget());
206 | }
207 |
208 | QWidget *BluetoothSettingsSubTab::controls_widget()
209 | {
210 | QWidget *widget = new QWidget(this);
211 | QVBoxLayout *layout = new QVBoxLayout(widget);
212 |
213 | QLabel *label = new QLabel("Media Player", widget);
214 | label->setFont(Theme::font_16);
215 | layout->addStretch();
216 | layout->addWidget(label);
217 |
218 | QLabel *connected_device = new QLabel(this->bluetooth->get_media_player().first, widget);
219 | connected_device->setStyleSheet("padding-left: 16px;");
220 | connected_device->setFont(Theme::font_14);
221 | connect(this->bluetooth, &Bluetooth::media_player_changed,
222 | [connected_device](QString name, BluezQt::MediaPlayerPtr) { connected_device->setText(name); });
223 | layout->addWidget(connected_device);
224 | layout->addStretch();
225 |
226 | layout->addWidget(this->scanner_widget());
227 |
228 | return widget;
229 | }
230 |
231 | QWidget *BluetoothSettingsSubTab::scanner_widget()
232 | {
233 | QWidget *widget = new QWidget(this);
234 | QHBoxLayout *layout = new QHBoxLayout(widget);
235 |
236 | QPushButton *button = new QPushButton("scan", widget);
237 | button->setFont(Theme::font_14);
238 | button->setFlat(true);
239 | button->setEnabled(this->bluetooth->has_adapter());
240 | button->setIconSize(Theme::icon_36);
241 | this->theme->add_button_icon("bluetooth_searching", button);
242 | connect(button, &QPushButton::clicked, [bluetooth = this->bluetooth]() { bluetooth->scan(); });
243 | layout->addWidget(button);
244 |
245 | ProgressIndicator *loader = new ProgressIndicator(widget);
246 | connect(this->bluetooth, &Bluetooth::scan_status, [button, loader](bool status) {
247 | button->setEnabled(!status);
248 | if (status)
249 | loader->startAnimation();
250 | else
251 | loader->stopAnimation();
252 | });
253 | layout->addWidget(loader);
254 |
255 | return widget;
256 | }
257 |
258 | QWidget *BluetoothSettingsSubTab::devices_widget()
259 | {
260 | QWidget *widget = new QWidget(this);
261 | QVBoxLayout *layout = new QVBoxLayout(widget);
262 |
263 | for (BluezQt::DevicePtr device : this->bluetooth->get_devices()) {
264 | if (device->address() == this->config->get_bluetooth_device()) device->connectToDevice()->waitForFinished();
265 | QPushButton *button = new QPushButton(device->name(), widget);
266 | button->setFont(Theme::font_16);
267 | button->setCheckable(true);
268 | if (device->isConnected()) button->setChecked(true);
269 | connect(button, &QPushButton::clicked, [config = this->config, button, device](bool checked = false) {
270 | button->setChecked(!checked);
271 | if (checked) {
272 | device->connectToDevice()->waitForFinished();
273 | config->set_bluetooth_device(device->address());
274 | }
275 | else {
276 | device->disconnectFromDevice()->waitForFinished();
277 | config->set_bluetooth_device(QString());
278 | }
279 | });
280 |
281 | this->devices[device] = button;
282 | layout->addWidget(button);
283 | }
284 | connect(this->bluetooth, &Bluetooth::device_added, [this, layout, widget](BluezQt::DevicePtr device) {
285 | QPushButton *button = new QPushButton(device->name(), widget);
286 | button->setFont(Theme::font_16);
287 | button->setCheckable(true);
288 | if (device->isConnected()) button->setChecked(true);
289 | connect(button, &QPushButton::clicked, [button, device](bool checked = false) {
290 | button->setChecked(!checked);
291 | if (checked)
292 | device->connectToDevice()->waitForFinished();
293 | else
294 | device->disconnectFromDevice()->waitForFinished();
295 | });
296 | this->devices[device] = button;
297 | layout->addWidget(button);
298 | });
299 | connect(this->bluetooth, &Bluetooth::device_changed, [this](BluezQt::DevicePtr device) {
300 | this->devices[device]->setText(device->name());
301 | this->devices[device]->setChecked(device->isConnected());
302 | });
303 | connect(this->bluetooth, &Bluetooth::device_removed, [this, layout](BluezQt::DevicePtr device) {
304 | layout->removeWidget(devices[device]);
305 | delete this->devices[device];
306 | this->devices.remove(device);
307 | });
308 |
309 | return widget;
310 | }
311 |
312 | OpenAutoSettingsSubTab::OpenAutoSettingsSubTab(QWidget *parent) : QWidget(parent)
313 | {
314 | this->bluetooth = Bluetooth::get_instance();
315 | this->theme = Theme::get_instance();
316 | this->config = Config::get_instance();
317 |
318 | QVBoxLayout *layout = new QVBoxLayout(this);
319 | layout->setContentsMargins(24, 24, 24, 24);
320 |
321 | layout->addWidget(this->settings_widget());
322 | }
323 |
324 | QWidget *OpenAutoSettingsSubTab::settings_widget()
325 | {
326 | QWidget *widget = new QWidget(this);
327 | QVBoxLayout *layout = new QVBoxLayout(widget);
328 |
329 | layout->addWidget(this->rhd_row_widget(), 1);
330 | layout->addWidget(Theme::br(widget), 1);
331 | layout->addWidget(this->frame_rate_row_widget(), 1);
332 | layout->addWidget(this->resolution_row_widget(), 1);
333 | layout->addWidget(this->dpi_row_widget(), 1);
334 | layout->addWidget(Theme::br(widget), 1);
335 | layout->addWidget(this->rt_audio_row_widget(), 1);
336 | layout->addWidget(this->audio_channels_row_widget(), 1);
337 | layout->addWidget(Theme::br(widget), 1);
338 | layout->addWidget(this->bluetooth_row_widget(), 1);
339 |
340 | return widget;
341 | }
342 |
343 | QWidget *OpenAutoSettingsSubTab::rhd_row_widget()
344 | {
345 | QWidget *widget = new QWidget(this);
346 | QHBoxLayout *layout = new QHBoxLayout(widget);
347 |
348 | QLabel *label = new QLabel("Right-Hand-Drive", widget);
349 | label->setFont(Theme::font_16);
350 | layout->addWidget(label, 1);
351 |
352 | Switch *toggle = new Switch(widget);
353 | toggle->setChecked(this->config->open_auto_config->getHandednessOfTrafficType() ==
354 | autoapp::configuration::HandednessOfTrafficType::RIGHT_HAND_DRIVE);
355 | connect(toggle, &Switch::stateChanged, [config = this->config](bool state) {
356 | config->open_auto_config->setHandednessOfTrafficType(
357 | state ? autoapp::configuration::HandednessOfTrafficType::RIGHT_HAND_DRIVE
358 | : autoapp::configuration::HandednessOfTrafficType::LEFT_HAND_DRIVE);
359 | });
360 | layout->addWidget(toggle, 1, Qt::AlignHCenter);
361 |
362 | return widget;
363 | }
364 |
365 | QWidget *OpenAutoSettingsSubTab::frame_rate_row_widget()
366 | {
367 | QWidget *widget = new QWidget(this);
368 | QHBoxLayout *layout = new QHBoxLayout(widget);
369 |
370 | QLabel *label = new QLabel("Frame Rate", widget);
371 | label->setFont(Theme::font_16);
372 | layout->addWidget(label, 1);
373 |
374 | QGroupBox *group = new QGroupBox(widget);
375 | QHBoxLayout *group_layout = new QHBoxLayout(group);
376 |
377 | QRadioButton *fps_30_button = new QRadioButton("30fps", group);
378 | fps_30_button->setFixedHeight(fps_30_button->height());
379 | fps_30_button->setFont(Theme::font_14);
380 | fps_30_button->setChecked(this->config->open_auto_config->getVideoFPS() == aasdk::proto::enums::VideoFPS::_30);
381 | connect(fps_30_button, &QRadioButton::clicked,
382 | [config = this->config]() { config->open_auto_config->setVideoFPS(aasdk::proto::enums::VideoFPS::_30); });
383 | group_layout->addWidget(fps_30_button);
384 |
385 | QRadioButton *fps_60_button = new QRadioButton("60fps", group);
386 | fps_60_button->setFixedHeight(fps_60_button->height());
387 | fps_60_button->setFont(Theme::font_14);
388 | fps_60_button->setChecked(this->config->open_auto_config->getVideoFPS() == aasdk::proto::enums::VideoFPS::_60);
389 | connect(fps_60_button, &QRadioButton::clicked,
390 | [config = this->config]() { config->open_auto_config->setVideoFPS(aasdk::proto::enums::VideoFPS::_60); });
391 | group_layout->addWidget(fps_60_button);
392 |
393 | layout->addWidget(group, 1, Qt::AlignHCenter);
394 |
395 | return widget;
396 | }
397 |
398 | QWidget *OpenAutoSettingsSubTab::resolution_row_widget()
399 | {
400 | QWidget *widget = new QWidget(this);
401 | QHBoxLayout *layout = new QHBoxLayout(widget);
402 |
403 | QLabel *label = new QLabel("Resolution", widget);
404 | label->setFont(Theme::font_16);
405 | layout->addWidget(label, 1);
406 |
407 | QGroupBox *group = new QGroupBox(widget);
408 | QHBoxLayout *group_layout = new QHBoxLayout(group);
409 |
410 | QRadioButton *res_480_button = new QRadioButton("480p", group);
411 | res_480_button->setFixedHeight(res_480_button->height());
412 | res_480_button->setFont(Theme::font_14);
413 | res_480_button->setChecked(this->config->open_auto_config->getVideoResolution() ==
414 | aasdk::proto::enums::VideoResolution::_480p);
415 | connect(res_480_button, &QRadioButton::clicked, [config = this->config]() {
416 | config->open_auto_config->setVideoResolution(aasdk::proto::enums::VideoResolution::_480p);
417 | });
418 | group_layout->addWidget(res_480_button);
419 |
420 | QRadioButton *res_720_button = new QRadioButton("720p", group);
421 | res_720_button->setFixedHeight(res_720_button->height());
422 | res_720_button->setFont(Theme::font_14);
423 | res_720_button->setChecked(this->config->open_auto_config->getVideoResolution() ==
424 | aasdk::proto::enums::VideoResolution::_720p);
425 | connect(res_720_button, &QRadioButton::clicked, [config = this->config]() {
426 | config->open_auto_config->setVideoResolution(aasdk::proto::enums::VideoResolution::_720p);
427 | });
428 | group_layout->addWidget(res_720_button);
429 |
430 | QRadioButton *res_1080_button = new QRadioButton("1080p", group);
431 | res_1080_button->setFixedHeight(res_1080_button->height());
432 | res_1080_button->setFont(Theme::font_14);
433 | res_1080_button->setChecked(this->config->open_auto_config->getVideoResolution() ==
434 | aasdk::proto::enums::VideoResolution::_1080p);
435 | connect(res_1080_button, &QRadioButton::clicked, [config = this->config]() {
436 | config->open_auto_config->setVideoResolution(aasdk::proto::enums::VideoResolution::_1080p);
437 | });
438 | group_layout->addWidget(res_1080_button);
439 |
440 | layout->addWidget(group, 1, Qt::AlignHCenter);
441 |
442 | return widget;
443 | }
444 |
445 | QWidget *OpenAutoSettingsSubTab::dpi_row_widget()
446 | {
447 | QWidget *widget = new QWidget(this);
448 | QHBoxLayout *layout = new QHBoxLayout(widget);
449 |
450 | QLabel *label = new QLabel("DPI", widget);
451 | label->setFont(Theme::font_16);
452 | layout->addWidget(label, 1);
453 |
454 | layout->addWidget(this->dpi_widget(), 1);
455 |
456 | return widget;
457 | }
458 |
459 | QWidget *OpenAutoSettingsSubTab::dpi_widget()
460 | {
461 | QWidget *widget = new QWidget(this);
462 | QHBoxLayout *layout = new QHBoxLayout(widget);
463 |
464 | QSlider *slider = new QSlider(Qt::Orientation::Horizontal, widget);
465 | slider->setFixedHeight(slider->height());
466 | slider->setRange(0, 512);
467 | slider->setSliderPosition(this->config->open_auto_config->getScreenDPI());
468 | QLabel *value = new QLabel(QString::number(slider->sliderPosition()), widget);
469 | value->setFixedHeight(value->height());
470 | value->setFont(Theme::font_14);
471 | connect(slider, &QSlider::valueChanged, [config = this->config, value](int position) {
472 | value->setText(QString::number(position));
473 | config->open_auto_config->setScreenDPI(position);
474 | });
475 |
476 | layout->addStretch(2);
477 | layout->addWidget(slider, 4);
478 | layout->addWidget(value, 1);
479 | layout->addStretch(1);
480 |
481 | return widget;
482 | }
483 |
484 | QWidget *OpenAutoSettingsSubTab::rt_audio_row_widget()
485 | {
486 | QWidget *widget = new QWidget(this);
487 | QHBoxLayout *layout = new QHBoxLayout(widget);
488 |
489 | QLabel *label = new QLabel("RtAudio", widget);
490 | label->setFont(Theme::font_16);
491 | layout->addWidget(label, 1);
492 |
493 | Switch *toggle = new Switch(widget);
494 | toggle->setChecked(this->config->open_auto_config->getAudioOutputBackendType() ==
495 | autoapp::configuration::AudioOutputBackendType::RTAUDIO);
496 | connect(toggle, &Switch::stateChanged, [config = this->config](bool state) {
497 | config->open_auto_config->setAudioOutputBackendType(
498 | state ? autoapp::configuration::AudioOutputBackendType::RTAUDIO
499 | : autoapp::configuration::AudioOutputBackendType::QT);
500 | });
501 | layout->addWidget(toggle, 1, Qt::AlignHCenter);
502 |
503 | return widget;
504 | }
505 |
506 | QWidget *OpenAutoSettingsSubTab::audio_channels_row_widget()
507 | {
508 | QWidget *widget = new QWidget(this);
509 | QHBoxLayout *layout = new QHBoxLayout(widget);
510 |
511 | QLabel *label = new QLabel("Audio Channels", widget);
512 | label->setFont(Theme::font_16);
513 | layout->addWidget(label, 1);
514 |
515 | QGroupBox *group = new QGroupBox(widget);
516 | QHBoxLayout *group_layout = new QHBoxLayout(group);
517 |
518 | QCheckBox *music_button = new QCheckBox("Music", group);
519 | music_button->setFixedHeight(music_button->height());
520 | music_button->setFont(Theme::font_14);
521 | music_button->setChecked(this->config->open_auto_config->musicAudioChannelEnabled());
522 | connect(music_button, &QCheckBox::toggled,
523 | [config = this->config](bool checked) { config->open_auto_config->setMusicAudioChannelEnabled(checked); });
524 | group_layout->addWidget(music_button);
525 | group_layout->addStretch(2);
526 |
527 | QCheckBox *speech_button = new QCheckBox("Speech", group);
528 | speech_button->setFixedHeight(speech_button->height());
529 | speech_button->setFont(Theme::font_14);
530 | speech_button->setChecked(this->config->open_auto_config->speechAudioChannelEnabled());
531 | connect(speech_button, &QCheckBox::toggled,
532 | [config = this->config](bool checked) { config->open_auto_config->setSpeechAudioChannelEnabled(checked); });
533 | group_layout->addWidget(speech_button);
534 |
535 | layout->addWidget(group, 1, Qt::AlignHCenter);
536 |
537 | return widget;
538 | }
539 |
540 | QWidget *OpenAutoSettingsSubTab::bluetooth_row_widget()
541 | {
542 | QWidget *widget = new QWidget(this);
543 | QHBoxLayout *layout = new QHBoxLayout(widget);
544 |
545 | QLabel *label = new QLabel("Bluetooth", widget);
546 | label->setFont(Theme::font_16);
547 | layout->addWidget(label, 1);
548 |
549 | Switch *toggle = new Switch(widget);
550 | toggle->setChecked(this->config->open_auto_config->getBluetoothAdapterType() ==
551 | autoapp::configuration::BluetoothAdapterType::LOCAL);
552 | connect(toggle, &Switch::stateChanged, [config = this->config](bool state) {
553 | config->open_auto_config->setBluetoothAdapterType(state ? autoapp::configuration::BluetoothAdapterType::LOCAL
554 | : autoapp::configuration::BluetoothAdapterType::NONE);
555 | });
556 | layout->addWidget(toggle, 1, Qt::AlignHCenter);
557 |
558 | return widget;
559 | }
560 |
--------------------------------------------------------------------------------