# 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 dpg_gauges as dpgg from dynalab.state import AppState from dynalab.tags import ( LISTBOX_RECORD_CONFIGURATION, LISTBOX_RECORD_CONFIGURATION_ADD_SINGAL, MENU_FILE_QUIT, MENU_RECORD_CONFIGURATION, MENU_WINDOW_DATA_INPUT, MENU_WINDOW_RECORD, TEXT_INPUT_RECORD_CONFIGURATION, WINDOW_DATA_INPUT_GAUGE_GRID, WINDOW_GROUP_DATA_INPUT, WINDOW_GROUP_RECORD, WINDOW_RECORD_CONFIGURATION, WINDOW_RECORD_CONFIGURATION_ADD_SIGNAL, ) from dynalab.ui.routines import ( listbox_record_configuration_add_item, listbox_record_configuration_add_item_select, listbox_record_configuration_remove_selected_item, show_window_record_configuration, switch_window, ) from dynalab.i18n import _ LOADING_WINDOW_WIDTH = 600 LOADING_WINDOW_HEIGHT = 400 def _loading_content_layout( viewport_size: tuple[int, int], logo_size: tuple[int, int], text_size: tuple[int, int], bottom_margin: int = 24, ) -> tuple[list[float], list[float], float]: viewport_width, viewport_height = viewport_size logo_width, logo_height = logo_size text_width, text_height = text_size logo_pos = [ (viewport_width - logo_width) / 2, (viewport_height - logo_height) / 2, ] text_row_pos = [ 0, max(viewport_height - text_height - bottom_margin, 0), ] text_spacer_width = max((viewport_width - text_width) / 2, 0) return logo_pos, text_row_pos, text_spacer_width def build_loading() -> None: with dpg.window( label="DynaLab", tag="loading_window", width=LOADING_WINDOW_WIDTH, height=LOADING_WINDOW_HEIGHT, no_collapse=True, no_resize=True, no_move=True, no_title_bar=True, ): dpg.set_global_font_scale(0.5) with dpg.group(horizontal=False, tag="loading_logo_group"): dpg.add_image(texture_tag="logo", tag="loading_logo") with dpg.group(horizontal=True, tag="loading_text_row"): dpg.add_spacer(width=0, tag="loading_text_left_spacer") dpg.add_text( default_value="Loading DynaLab", tag="loading_text", color=(150, 150, 150, 255), ) def center_loading_content() -> None: if not dpg.does_item_exist("loading_window"): return dpg.set_item_pos("loading_window", [0, 0]) dpg.set_item_width("loading_window", LOADING_WINDOW_WIDTH) dpg.set_item_height("loading_window", LOADING_WINDOW_HEIGHT) # These may be unavailable before the first rendered frame logo_size = dpg.get_item_rect_size("loading_logo") text_size = dpg.get_item_rect_size("loading_text") if logo_size is None or text_size is None: return logo_pos, text_row_pos, text_spacer_width = _loading_content_layout( (LOADING_WINDOW_WIDTH, LOADING_WINDOW_HEIGHT), logo_size, text_size ) dpg.set_item_pos("loading_logo_group", logo_pos) dpg.set_item_pos("loading_text_row", text_row_pos) dpg.set_item_width("loading_text_left_spacer", text_spacer_width) def build_record_configuration_add_signal_window(state: AppState) -> None: with dpg.window( label="Add Signal", tag=WINDOW_RECORD_CONFIGURATION_ADD_SIGNAL, no_collapse=True, show=False, min_size=(500, 300), modal=True, ): dpg.add_listbox( tag=LISTBOX_RECORD_CONFIGURATION_ADD_SINGAL, num_items=10, width=480, ) with dpg.group(horizontal=True): dpg.add_button( label="Select", callback=listbox_record_configuration_add_item_select, user_data=state, ) dpg.add_button( label="Refresh", callback=listbox_record_configuration_add_item, user_data=state, ) def build_record_configuration_window(state: AppState) -> None: with dpg.window( label="Recording Configuration", tag=WINDOW_RECORD_CONFIGURATION, no_collapse=True, show=False, min_size=(500, 300), ): with dpg.group(): dpg.add_text("Configuration Name") dpg.add_input_text(tag=TEXT_INPUT_RECORD_CONFIGURATION) dpg.add_text("Selected Signals") dpg.add_listbox( tag=LISTBOX_RECORD_CONFIGURATION, num_items=10, width=480, ) with dpg.group(horizontal=True): dpg.add_button( label="Add", callback=listbox_record_configuration_add_item, user_data=state, ) dpg.add_button( label="Remove", callback=listbox_record_configuration_remove_selected_item, user_data=state, ) def build_windows(state: AppState) -> None: with dpg.window(label="DynaLab", tag="main_window", no_collapse=True): with dpg.menu_bar(): with dpg.menu(label=_("File")): dpg.add_menu_item(tag=MENU_FILE_QUIT, label=_("Quit"), enabled=True) with dpg.menu(label=_("Record")): dpg.add_menu_item( tag=MENU_RECORD_CONFIGURATION, label=_("Configuration"), callback=show_window_record_configuration, user_data=state, ) with dpg.menu(label=_("Window")): dpg.add_menu_item( tag=MENU_WINDOW_RECORD, label=_("Record"), callback=switch_window, user_data=state, ) dpg.add_menu_item( tag=MENU_WINDOW_DATA_INPUT, label=_("Data Input"), callback=switch_window, user_data=state, ) with dpg.child_window( tag="content_area", autosize_x=True, height=0, border=False ): # with dpg.group(tag=MENU_WINDOW_DATA_INPUT): with dpg.group(tag=WINDOW_GROUP_DATA_INPUT): state.window_map[MENU_WINDOW_DATA_INPUT] = WINDOW_GROUP_DATA_INPUT with dpgg.gauge_panel(autosize_x=True, autosize_y=True): with dpgg.gauge_grid( columns="auto", min_column_width=180, tag=WINDOW_DATA_INPUT_GAUGE_GRID, ): pass with dpg.group(tag=WINDOW_GROUP_RECORD, show=False): state.window_map[MENU_WINDOW_RECORD] = WINDOW_GROUP_RECORD dpg.add_text("Some text") build_record_configuration_window(state) build_record_configuration_add_signal_window(state)