From fb35d6c3d47c150be8bb6b227e23105e054caf3e Mon Sep 17 00:00:00 2001 From: Hector van der Aa Date: Sun, 5 Apr 2026 14:55:04 +0200 Subject: [PATCH] Segmentation stage 1 --- main.py | 118 +------------------ main2.py | 139 ++++++++++++++++++++++ main3.py | 140 +++++++++++++++++++++++ pyproject.toml | 18 ++- src/dataflux/__init__.py | 0 src/dataflux/app.py | 40 +++++++ src/dataflux/callbacks/__init__.py | 0 src/dataflux/callbacks/menu.py | 11 ++ src/dataflux/config.py | 0 src/dataflux/services/__init__.py | 0 src/dataflux/services/serial/__init__.py | 18 +++ src/dataflux/state.py | 18 +++ src/dataflux/tags.py | 8 ++ src/dataflux/ui/__init__.py | 0 src/dataflux/ui/pages/__init__.py | 0 src/dataflux/ui/routines/__init__.py | 0 src/dataflux/ui/routines/menu.py | 16 +++ src/dataflux/ui/routines/windows.py | 11 ++ src/dataflux/ui/windows.py | 45 ++++++++ uv.lock | 2 +- 20 files changed, 467 insertions(+), 117 deletions(-) create mode 100644 main2.py create mode 100644 main3.py create mode 100644 src/dataflux/__init__.py create mode 100644 src/dataflux/app.py create mode 100644 src/dataflux/callbacks/__init__.py create mode 100644 src/dataflux/callbacks/menu.py create mode 100644 src/dataflux/config.py create mode 100644 src/dataflux/services/__init__.py create mode 100644 src/dataflux/services/serial/__init__.py create mode 100644 src/dataflux/state.py create mode 100644 src/dataflux/tags.py create mode 100644 src/dataflux/ui/__init__.py create mode 100644 src/dataflux/ui/pages/__init__.py create mode 100644 src/dataflux/ui/routines/__init__.py create mode 100644 src/dataflux/ui/routines/menu.py create mode 100644 src/dataflux/ui/routines/windows.py create mode 100644 src/dataflux/ui/windows.py diff --git a/main.py b/main.py index 4453ac7..55676c6 100644 --- a/main.py +++ b/main.py @@ -1,119 +1,7 @@ # Copyright (C) 2026 Hector van der Aa # Copyright (C) 2026 Association Exergie # SPDX-License-Identifier: GPL-3.0-or-later -import dearpygui.dearpygui as dpg -import time -import threading -from serial import Serial -import serial.tools.list_ports +from dataflux.app import run -running = True - -def quit_app(sender, app_data, user_data): - running = False - dpg.destroy_context() - - -def serial_worker(): - while running: - - print(serial_port.read()) - serial_port.close() - -serial_port = Serial() -serial_thread = threading.Thread(target=serial_worker, daemon=True) - -def telemetry_worker(): - speed_data_x = [-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0] - speed_data_y = [5,6,7,8,9,10,9,8,7,6,5] - while running: - time.sleep(0.1) - y_val = speed_data_y.pop(0) - - speed_data_y.append(y_val) - dpg.set_value("speed_series", [speed_data_x, speed_data_y]) - dpg.set_axis_limits("x_axis_speed", speed_data_x[0], speed_data_x[-1]) - -def show_page(sender, app_data, user_data): - pages = ["page_live_data", "page_lap_recap"] - - for page in pages: - dpg.hide_item(page) - - dpg.show_item(user_data) - -def show_connection_menu(sender, app_data, user_data): - ports = serial.tools.list_ports.comports() - port_names = [] - for port in ports: - if port.vid is not None and port.pid is not None: - port_names.append(port.device) - - dpg.configure_item("serial_combo", items=port_names) - dpg.show_item("connection_menu") - -def connect_to_serial(sender, app_data, user_data): - global serial_port - port = dpg.get_value("serial_combo") - print("Connecting to " + port) - serial_port = Serial(port=port, baudrate=115200) - serial_thread.start() - - -dpg.create_context() -dpg.create_viewport(title='DataFlux', width=600, height=600) - -with dpg.font_registry(): - app_font = dpg.add_font("./Inter-Regular.ttf", 18) - -dpg.bind_font(app_font) - -with dpg.window(label='DataFlux',tag="main_window", no_collapse=True): - with dpg.menu_bar(): - with dpg.menu(label='File'): - dpg.add_menu_item(label="Connect", callback=show_connection_menu) - dpg.add_menu_item(label="Quit", callback=quit_app) - with dpg.menu(label='Window'): - dpg.add_menu_item(label="Live Data", callback=show_page, user_data="page_live_data") - dpg.add_menu_item(label="Lap Recap", callback=show_page, user_data="page_lap_recap") - - with dpg.child_window(tag="content_area", autosize_x=True, autosize_y=True, border=False): - with dpg.group(tag="page_live_data", show=True): - dpg.add_text("Live Data") - dpg.add_separator() - with dpg.group(horizontal=True): - with dpg.child_window(tag="realtime_stats", width=250, autosize_y=True, border=True): - dpg.add_text("Speed: 25kmh") - - with dpg.child_window(tag="data_graphs", autosize_x=True, autosize_y=True, border=True): - with dpg.plot(label="Speed", height=250, width=-1, no_inputs=True): - dpg.add_plot_legend() - dpg.add_plot_axis(dpg.mvXAxis, label="Time", tag="x_axis_speed") - y_axis = dpg.add_plot_axis(dpg.mvYAxis, label="Speed", tag="y_axis_speed") - dpg.set_axis_limits("y_axis_speed", 0, 50) - dpg.add_line_series([], [], parent=y_axis, tag="speed_series") - - with dpg.group(tag="page_lap_recap", show=False): - dpg.add_text("Lap Recap") - dpg.add_separator() - -with dpg.window(label="Connection Menu", tag="connection_menu", show=False, modal=True, no_collapse=True, width=300): - dpg.add_combo([], tag="serial_combo") - dpg.add_button(label="Connect", callback=connect_to_serial) - -worker = threading.Thread(target=telemetry_worker, daemon=True) -worker.start() - -dpg.setup_dearpygui() -dpg.show_viewport() - - -vp_w = dpg.get_viewport_client_width() -vp_h = dpg.get_viewport_client_height() -dpg.configure_item("main_window", pos=(0, 0), width=vp_w, height=vp_h) -dpg.set_primary_window("main_window", True) - -dpg.start_dearpygui() - -running = False -dpg.destroy_context() +if __name__ == "__main__": + run() diff --git a/main2.py b/main2.py new file mode 100644 index 0000000..3c0403f --- /dev/null +++ b/main2.py @@ -0,0 +1,139 @@ +# Copyright (C) 2026 Hector van der Aa +# Copyright (C) 2026 Association Exergie +# SPDX-License-Identifier: GPL-3.0-or-later +import dearpygui.dearpygui as dpg +import time +import threading +from serial import Serial +import serial.tools.list_ports + +running = True +serial_connected = False + +def quit_app(sender, app_data, user_data): + global running + running = False + dpg.destroy_context() + + +def serial_worker(): + global serial_connected + global serial_port + global running + while running and serial_connected: + if not serial_port.is_open: + serial_connected = False + print(serial_port.read()) + serial_connected = False + serial_port.close() + dpg.enable_item("menu_file_connect") + dpg.disable_item("menu_file_disconnect") + +serial_port: Serial | None = None +serial_thread: threading.Thread | None = None + +def telemetry_worker(): + speed_data_x = [-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0] + speed_data_y = [5,6,7,8,9,10,9,8,7,6,5] + while running: + time.sleep(0.1) + y_val = speed_data_y.pop(0) + + speed_data_y.append(y_val) + dpg.set_value("speed_series", [speed_data_x, speed_data_y]) + dpg.set_axis_limits("x_axis_speed", speed_data_x[0], speed_data_x[-1]) + +def show_page(sender, app_data, user_data): + pages = ["page_live_data", "page_lap_recap"] + + for page in pages: + dpg.hide_item(page) + + dpg.show_item(user_data) + +def show_connection_menu(sender, app_data, user_data): + ports = serial.tools.list_ports.comports() + port_names = [] + for port in ports: + if port.vid is not None and port.pid is not None: + port_names.append(port.device) + + dpg.configure_item("serial_combo", items=port_names) + dpg.show_item("connection_menu") + +def disconnect_serial(sender, app_data, user_data): + global serial_connected + serial_connected = False + +def connect_to_serial(sender, app_data, user_data): + global serial_port + global serial_connected + global serial_thread + port = dpg.get_value("serial_combo") + print("Connecting to " + port) + serial_port = Serial(port=port, baudrate=115200) + serial_connected = True + dpg.enable_item("menu_file_disconnect") + dpg.disable_item("menu_file_connect") + serial_thread = threading.Thread(target=serial_worker, daemon=True) + serial_thread.start() + + +# dpg.create_context() +# dpg.create_viewport(title='DataFlux', width=600, height=600) +# +# with dpg.font_registry(): +# app_font = dpg.add_font("./Inter-Regular.ttf", 18) +# +# dpg.bind_font(app_font) + +# with dpg.window(label='DataFlux',tag="main_window", no_collapse=True): +# with dpg.menu_bar(): +# with dpg.menu(label='File'): +# dpg.add_menu_item(label="Connect", callback=show_connection_menu, enabled=True, tag="menu_file_connect") +# dpg.add_menu_item(label="Disonnect", callback=disconnect_serial, enabled=False, tag="menu_file_disconnect") +# dpg.add_menu_item(label="Quit", callback=quit_app) +# with dpg.menu(label='Window'): +# dpg.add_menu_item(label="Live Data", callback=show_page, user_data="page_live_data") +# dpg.add_menu_item(label="Lap Recap", callback=show_page, user_data="page_lap_recap") +# +# with dpg.child_window(tag="content_area", autosize_x=True, autosize_y=True, border=False): +# with dpg.group(tag="page_live_data", show=True): +# dpg.add_text("Live Data") +# dpg.add_separator() +# with dpg.group(horizontal=True): +# with dpg.child_window(tag="realtime_stats", width=250, autosize_y=True, border=True): +# dpg.add_text("Speed: 25kmh") +# +# with dpg.child_window(tag="data_graphs", autosize_x=True, autosize_y=True, border=True): +# with dpg.plot(label="Speed", height=250, width=-1, no_inputs=True): +# dpg.add_plot_legend() +# dpg.add_plot_axis(dpg.mvXAxis, label="Time", tag="x_axis_speed") +# y_axis = dpg.add_plot_axis(dpg.mvYAxis, label="Speed", tag="y_axis_speed") +# dpg.set_axis_limits("y_axis_speed", 0, 50) +# dpg.add_line_series([], [], parent=y_axis, tag="speed_series") +# +# with dpg.group(tag="page_lap_recap", show=False): +# dpg.add_text("Lap Recap") +# dpg.add_separator() +# +# with dpg.window(label="Connection Menu", tag="connection_menu", show=False, modal=True, no_collapse=True, width=300): +# dpg.add_combo([], tag="serial_combo") +# dpg.add_button(label="Connect", callback=connect_to_serial) + +worker = threading.Thread(target=telemetry_worker, daemon=True) +worker.start() + +# dpg.setup_dearpygui() +# dpg.show_viewport() +# +# +# vp_w = dpg.get_viewport_client_width() +# vp_h = dpg.get_viewport_client_height() +# dpg.configure_item("main_window", pos=(0, 0), width=vp_w, height=vp_h) +# dpg.set_primary_window("main_window", True) +# +# dpg.start_dearpygui() +# +# running = False +# dpg.destroy_context() diff --git a/main3.py b/main3.py new file mode 100644 index 0000000..667c46d --- /dev/null +++ b/main3.py @@ -0,0 +1,140 @@ + +# Copyright (C) 2026 Hector van der Aa +# Copyright (C) 2026 Association Exergie +# SPDX-License-Identifier: GPL-3.0-or-later +import dearpygui.dearpygui as dpg +import time +import threading +from serial import Serial +import serial.tools.list_ports + +running = True +serial_connected = False + +def quit_app(sender, app_data, user_data): + global running + running = False + dpg.destroy_context() + + +def serial_worker(): + global serial_connected + global serial_port + global running + while running and serial_connected: + if not serial_port.is_open: + serial_connected = False + print(serial_port.read()) + serial_connected = False + serial_port.close() + dpg.enable_item("menu_file_connect") + dpg.disable_item("menu_file_disconnect") + +serial_port: Serial | None = None +serial_thread: threading.Thread | None = None + +def telemetry_worker(): + speed_data_x = [-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0] + speed_data_y = [5,6,7,8,9,10,9,8,7,6,5] + while running: + time.sleep(0.1) + y_val = speed_data_y.pop(0) + + speed_data_y.append(y_val) + dpg.set_value("speed_series", [speed_data_x, speed_data_y]) + dpg.set_axis_limits("x_axis_speed", speed_data_x[0], speed_data_x[-1]) + +def show_page(sender, app_data, user_data): + pages = ["page_live_data", "page_lap_recap"] + + for page in pages: + dpg.hide_item(page) + + dpg.show_item(user_data) + +def show_connection_menu(sender, app_data, user_data): + ports = serial.tools.list_ports.comports() + port_names = [] + for port in ports: + if port.vid is not None and port.pid is not None: + port_names.append(port.device) + + dpg.configure_item("serial_combo", items=port_names) + dpg.show_item("connection_menu") + +def disconnect_serial(sender, app_data, user_data): + global serial_connected + serial_connected = False + +def connect_to_serial(sender, app_data, user_data): + global serial_port + global serial_connected + global serial_thread + port = dpg.get_value("serial_combo") + print("Connecting to " + port) + serial_port = Serial(port=port, baudrate=115200) + serial_connected = True + dpg.enable_item("menu_file_disconnect") + dpg.disable_item("menu_file_connect") + serial_thread = threading.Thread(target=serial_worker, daemon=True) + serial_thread.start() + + +dpg.create_context() +dpg.create_viewport(title='DataFlux', width=600, height=600) + +with dpg.font_registry(): + app_font = dpg.add_font("./Inter-Regular.ttf", 18) + +dpg.bind_font(app_font) + +with dpg.window(label='DataFlux',tag="main_window", no_collapse=True): + with dpg.menu_bar(): + with dpg.menu(label='File'): + dpg.add_menu_item(label="Connect", callback=show_connection_menu, enabled=True, tag="menu_file_connect") + dpg.add_menu_item(label="Disonnect", callback=disconnect_serial, enabled=False, tag="menu_file_disconnect") + dpg.add_menu_item(label="Quit", callback=quit_app) + with dpg.menu(label='Window'): + dpg.add_menu_item(label="Live Data", callback=show_page, user_data="page_live_data") + dpg.add_menu_item(label="Lap Recap", callback=show_page, user_data="page_lap_recap") + + with dpg.child_window(tag="content_area", autosize_x=True, autosize_y=True, border=False): + with dpg.group(tag="page_live_data", show=True): + dpg.add_text("Live Data") + dpg.add_separator() + with dpg.group(horizontal=True): + with dpg.child_window(tag="realtime_stats", width=250, autosize_y=True, border=True): + dpg.add_text("Speed: 25kmh") + + with dpg.child_window(tag="data_graphs", autosize_x=True, autosize_y=True, border=True): + with dpg.plot(label="Speed", height=250, width=-1, no_inputs=True): + dpg.add_plot_legend() + dpg.add_plot_axis(dpg.mvXAxis, label="Time", tag="x_axis_speed") + y_axis = dpg.add_plot_axis(dpg.mvYAxis, label="Speed", tag="y_axis_speed") + dpg.set_axis_limits("y_axis_speed", 0, 50) + dpg.add_line_series([], [], parent=y_axis, tag="speed_series") + + with dpg.group(tag="page_lap_recap", show=False): + dpg.add_text("Lap Recap") + dpg.add_separator() + +with dpg.window(label="Connection Menu", tag="connection_menu", show=False, modal=True, no_collapse=True, width=300): + dpg.add_combo([], tag="serial_combo") + dpg.add_button(label="Connect", callback=connect_to_serial) + +worker = threading.Thread(target=telemetry_worker, daemon=True) +worker.start() + +dpg.setup_dearpygui() +dpg.show_viewport() + + +vp_w = dpg.get_viewport_client_width() +vp_h = dpg.get_viewport_client_height() +dpg.configure_item("main_window", pos=(0, 0), width=vp_w, height=vp_h) +dpg.set_primary_window("main_window", True) + +dpg.start_dearpygui() + +running = False +dpg.destroy_context() diff --git a/pyproject.toml b/pyproject.toml index 1de10db..aa8d177 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,26 @@ [project] name = "dataflux" version = "0.1.0" -description = "Add your description here" +description = "Telemetry dashboard for Exergie vehicle data" readme = "README.md" requires-python = ">=3.14" dependencies = [ "dearpygui>=2.2", "pyserial>=3.5", ] + +[project.scripts] +dataflux = "dataflux.app:run" + +[tool.uv] +package = true + +[build-system] +requires = ["setuptools>=68"] +build-backend = "setuptools.build_meta" + +[tool.setuptools] +package-dir = {"" = "src"} + +[tool.setuptools.packages.find] +where = ["src"] diff --git a/src/dataflux/__init__.py b/src/dataflux/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/dataflux/app.py b/src/dataflux/app.py new file mode 100644 index 0000000..3097a6f --- /dev/null +++ b/src/dataflux/app.py @@ -0,0 +1,40 @@ +# Copyright (C) 2026 Hector van der Aa +# Copyright (C) 2026 Association Exergie +# SPDX-License-Identifier: GPL-3.0-or-later + +import dearpygui.dearpygui as dpg + +from dataflux.state import AppState +import dataflux.ui.windows + +def run() -> None: + state: AppState = AppState() + + # Create application context and viewport + dpg.create_context() + dpg.create_viewport(title='DataFlux', width=600, height=600) + + # Add Inter font to registry and bind as main app font + with dpg.font_registry(): + app_font = dpg.add_font("./Inter-Regular.ttf", 18) + dpg.bind_font(app_font) + + dataflux.ui.windows.build_windows() + + dpg.setup_dearpygui() + dpg.show_viewport() + + + vp_w = dpg.get_viewport_client_width() + vp_h = dpg.get_viewport_client_height() + dpg.configure_item("main_window", pos=(0, 0), width=vp_w, height=vp_h) + dpg.set_primary_window("main_window", True) + + dpg.start_dearpygui() + + dpg.destroy_context() + + + + + diff --git a/src/dataflux/callbacks/__init__.py b/src/dataflux/callbacks/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/dataflux/callbacks/menu.py b/src/dataflux/callbacks/menu.py new file mode 100644 index 0000000..1054e19 --- /dev/null +++ b/src/dataflux/callbacks/menu.py @@ -0,0 +1,11 @@ +# Copyright (C) 2026 Hector van der Aa +# Copyright (C) 2026 Association Exergie +# SPDX-License-Identifier: GPL-3.0-or-later +import dearpygui.dearpygui as dpg +import dataflux.ui.routines.windows + +from dataflux.tags import WINDOW_CONNECTION_MENU + +def open_connection_window(sender, app_data, user_data) -> None: + dataflux.ui.routines.windows.update_window_connection_menu_combo() + dpg.show_item(WINDOW_CONNECTION_MENU) diff --git a/src/dataflux/config.py b/src/dataflux/config.py new file mode 100644 index 0000000..e69de29 diff --git a/src/dataflux/services/__init__.py b/src/dataflux/services/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/dataflux/services/serial/__init__.py b/src/dataflux/services/serial/__init__.py new file mode 100644 index 0000000..c455761 --- /dev/null +++ b/src/dataflux/services/serial/__init__.py @@ -0,0 +1,18 @@ +# Copyright (C) 2026 Hector van der Aa +# Copyright (C) 2026 Association Exergie +# SPDX-License-Identifier: GPL-3.0-or-later + +import serial.tools.list_ports + + +def list_serial_ports() -> list[str]: + ports = serial.tools.list_ports.comports() + valid_ports: list[str] = [] + for port in ports: + if port.vid is not None and port.pid is not None: + valid_ports.append(port.device) + + return valid_ports + + + diff --git a/src/dataflux/state.py b/src/dataflux/state.py new file mode 100644 index 0000000..eddd313 --- /dev/null +++ b/src/dataflux/state.py @@ -0,0 +1,18 @@ +# Copyright (C) 2026 Hector van der Aa +# Copyright (C) 2026 Association Exergie +# SPDX-License-Identifier: GPL-3.0-or-later + +from dataclasses import dataclass, field +from threading import Lock, Thread +from serial import Serial + +@dataclass +class AppState: + running: bool = True + + serial_port: Serial | None = None + serial_thread: Thread | None = None + + telemetry_thread: Thread | None = None + + lock: Lock = field(default_factory=Lock) diff --git a/src/dataflux/tags.py b/src/dataflux/tags.py new file mode 100644 index 0000000..69c267b --- /dev/null +++ b/src/dataflux/tags.py @@ -0,0 +1,8 @@ +# Copyright (C) 2026 Hector van der Aa +# Copyright (C) 2026 Association Exergie +# SPDX-License-Identifier: GPL-3.0-or-later + +MENU_FILE_CONNECT: str = "menu_file_connect" +MENU_FILE_DISCONNECT: str = "menu_file_disconnect" +WINDOW_CONNECTION_MENU: str = "window_connection_menu" +WINDOW_CONNECTION_MENU_COMBO: str = "window_connection_menu_combo" diff --git a/src/dataflux/ui/__init__.py b/src/dataflux/ui/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/dataflux/ui/pages/__init__.py b/src/dataflux/ui/pages/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/dataflux/ui/routines/__init__.py b/src/dataflux/ui/routines/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/dataflux/ui/routines/menu.py b/src/dataflux/ui/routines/menu.py new file mode 100644 index 0000000..a59c7eb --- /dev/null +++ b/src/dataflux/ui/routines/menu.py @@ -0,0 +1,16 @@ +# Copyright (C) 2026 Hector van der Aa +# Copyright (C) 2026 Association Exergie +# SPDX-License-Identifier: GPL-3.0-or-later + +import dearpygui.dearpygui as dpg + +from dataflux.state import AppState +from dataflux.tags import MENU_FILE_CONNECT, MENU_FILE_DISCONNECT + +def update_menu_file_connection_status(state: AppState) -> None: + if state.serial_port is None: + dpg.enable_item(MENU_FILE_CONNECT) + dpg.disable_item(MENU_FILE_DISCONNECT) + else: + dpg.disable_item(MENU_FILE_CONNECT) + dpg.enable_item(MENU_FILE_DISCONNECT) diff --git a/src/dataflux/ui/routines/windows.py b/src/dataflux/ui/routines/windows.py new file mode 100644 index 0000000..53b4178 --- /dev/null +++ b/src/dataflux/ui/routines/windows.py @@ -0,0 +1,11 @@ +# Copyright (C) 2026 Hector van der Aa +# Copyright (C) 2026 Association Exergie +# SPDX-License-Identifier: GPL-3.0-or-later +import dearpygui.dearpygui as dpg + +from dataflux.services.serial import list_serial_ports +from dataflux.tags import WINDOW_CONNECTION_MENU_COMBO + +def update_window_connection_menu_combo() -> None: + ports: list[str] = list_serial_ports() + dpg.configure_item(WINDOW_CONNECTION_MENU_COMBO, items=ports) diff --git a/src/dataflux/ui/windows.py b/src/dataflux/ui/windows.py new file mode 100644 index 0000000..a0e2cc4 --- /dev/null +++ b/src/dataflux/ui/windows.py @@ -0,0 +1,45 @@ +# Copyright (C) 2026 Hector van der Aa +# Copyright (C) 2026 Association Exergie +# SPDX-License-Identifier: GPL-3.0-or-later + +import dearpygui.dearpygui as dpg +import dataflux.callbacks.menu + +from dataflux.tags import MENU_FILE_CONNECT, MENU_FILE_DISCONNECT, WINDOW_CONNECTION_MENU, WINDOW_CONNECTION_MENU_COMBO + + +def build_windows() -> None: + + with dpg.window(label='DataFlux',tag="main_window", no_collapse=True): + with dpg.menu_bar(): + with dpg.menu(label='File'): + dpg.add_menu_item(label="Connect", enabled=True, tag=MENU_FILE_CONNECT, callback=dataflux.callbacks.menu.open_connection_window) + dpg.add_menu_item(label="Disonnect", enabled=False, tag=MENU_FILE_DISCONNECT) + dpg.add_menu_item(label="Quit") + with dpg.menu(label='Window'): + dpg.add_menu_item(label="Live Data", user_data="page_live_data") + dpg.add_menu_item(label="Lap Recap", user_data="page_lap_recap") + + with dpg.child_window(tag="content_area", autosize_x=True, autosize_y=True, border=False): + with dpg.group(tag="page_live_data", show=True): + dpg.add_text("Live Data") + dpg.add_separator() + with dpg.group(horizontal=True): + with dpg.child_window(tag="realtime_stats", width=250, autosize_y=True, border=True): + dpg.add_text("Speed: 25kmh") + + with dpg.child_window(tag="data_graphs", autosize_x=True, autosize_y=True, border=True): + with dpg.plot(label="Speed", height=250, width=-1, no_inputs=True): + dpg.add_plot_legend() + dpg.add_plot_axis(dpg.mvXAxis, label="Time", tag="x_axis_speed") + y_axis = dpg.add_plot_axis(dpg.mvYAxis, label="Speed", tag="y_axis_speed") + dpg.set_axis_limits("y_axis_speed", 0, 50) + dpg.add_line_series([], [], parent=y_axis, tag="speed_series") + + with dpg.group(tag="page_lap_recap", show=False): + dpg.add_text("Lap Recap") + dpg.add_separator() + + with dpg.window(label="Connection Menu", tag=WINDOW_CONNECTION_MENU, show=False, modal=True, no_collapse=True, width=300): + dpg.add_combo([], tag=WINDOW_CONNECTION_MENU_COMBO) + dpg.add_button(label="Connect") diff --git a/uv.lock b/uv.lock index 8561284..79e8626 100644 --- a/uv.lock +++ b/uv.lock @@ -5,7 +5,7 @@ requires-python = ">=3.14" [[package]] name = "dataflux" version = "0.1.0" -source = { virtual = "." } +source = { editable = "." } dependencies = [ { name = "dearpygui" }, { name = "pyserial" },