diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index cb564d3d6..b23dae7d8 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,11 +1,8 @@ -# default owners -* @hoffstadt # directories /thirdparty/ @hoffstadt /scripts/ @hoffstadt -/src/ @hoffstadt @Pcothren -/docs/* @hoffstadt @Pcothren +/docs/* @hoffstadt # specific files /src/distribution.cmake @hoffstadt @@ -18,7 +15,7 @@ setup.py @hoffstadt .gitattributes @hoffstadt .gitignore @hoffstadt .gitmodules @hoffstadt -.readthedocs.yaml @hoffstadt @Pcothren +.readthedocs.yaml @hoffstadt # no owners README.md diff --git a/.github/workflows/Deployment.yml b/.github/workflows/Deployment.yml index 89bc21bc7..1c78a8ab8 100644 --- a/.github/workflows/Deployment.yml +++ b/.github/workflows/Deployment.yml @@ -14,7 +14,7 @@ on: version: description: 'Dear PyGui Version' required: false - default: '2.0.0b1' + default: '2.1.2' deploy: description: 'Deploy (true will deploy to pypi)' @@ -30,10 +30,10 @@ jobs: build-windows-wheels: - runs-on: windows-2019 + runs-on: windows-2022 strategy: matrix: - python-version: [ 3.8, 3.9, "3.10", "3.11", "3.12", "3.13" ] + python-version: [ 3.8, 3.9, "3.10", "3.11", "3.12", "3.13", "3.14" ] steps: @@ -74,10 +74,10 @@ jobs: build-mac10-wheels: - runs-on: macos-12 + runs-on: macos-13 strategy: matrix: - python-version: [ 3.8, 3.9, "3.10", "3.11", "3.12", "3.13" ] + python-version: [ 3.8, 3.9, "3.10", "3.11", "3.12", "3.13", "3.14" ] steps: @@ -118,7 +118,7 @@ jobs: runs-on: macos-latest-xlarge strategy: matrix: - python-version: [ "3.10", "3.11", "3.12", "3.13" ] + python-version: [ "3.10", "3.11", "3.12", "3.13", "3.14" ] steps: @@ -156,12 +156,12 @@ jobs: build-linux-wheels: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 env: - CXX: g++-9 + CXX: g++-10 strategy: matrix: - python-version: [ 3.8, 3.9, "3.10", "3.11", "3.12", "3.13" ] + python-version: [ 3.8, 3.9, "3.10", "3.11", "3.12", "3.13", "3.14" ] steps: @@ -202,7 +202,7 @@ jobs: deploy-packages: needs: [build-windows-wheels, build-mac10-wheels, build-linux-wheels, build-mac-silicon-wheels] - runs-on: windows-2019 + runs-on: windows-2022 steps: @@ -238,4 +238,4 @@ jobs: python -m twine upload --repository testpypi windowsbuild*/* -u __token__ -p ${{ secrets.TEST_PYPI_PASSWORD }} --skip-existing python -m twine upload --repository testpypi apple10build*/* -u __token__ -p ${{ secrets.TEST_PYPI_PASSWORD }} --skip-existing python -m twine upload --repository testpypi apple10sbuild*/* -u __token__ -p ${{ secrets.TEST_PYPI_PASSWORD }} --skip-existing - python -m twine upload --repository testpypi linuxbuild*/* -u __token__ -p ${{ secrets.TEST_PYPI_PASSWORD }} --skip-existing \ No newline at end of file + python -m twine upload --repository testpypi linuxbuild*/* -u __token__ -p ${{ secrets.TEST_PYPI_PASSWORD }} --skip-existing diff --git a/.github/workflows/EmbeddedBuild.yml b/.github/workflows/EmbeddedBuild.yml index 6814927b4..03f23e342 100644 --- a/.github/workflows/EmbeddedBuild.yml +++ b/.github/workflows/EmbeddedBuild.yml @@ -25,7 +25,7 @@ jobs: build-windows: - runs-on: windows-2019 + runs-on: windows-2022 if: ${{! contains(github.event.head_commit.message, '[individual]') || contains(github.event.head_commit.message, '[windows]')}} steps: @@ -97,9 +97,9 @@ jobs: build-Ubuntu: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 env: - CXX: g++-9 + CXX: g++-10 if: ${{! contains(github.event.head_commit.message, '[individual]') || contains(github.event.head_commit.message, '[linux]')}} steps: diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 750884461..12c507982 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -18,7 +18,7 @@ on: jobs: PVS-Studio: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 if: ${{! contains(github.event.head_commit.message, '[individual]') || contains(github.event.head_commit.message, '[static analysis]')}} steps: - uses: actions/checkout@v4 diff --git a/CMakeLists.txt b/CMakeLists.txt index a86797350..adb1bce8d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,17 @@ if(MV_TESTS_ONLY) add_definitions(-DMV_TESTS_ONLY) endif() +# Specifying MV_NO_USER_THREADS turns off some thread safety features (might give +# you some perf gain, yeah, those 0.01%) and must only be used when no user threads +# (threading.Thread) **ever** call DPG API. With MV_NO_USER_THREADS, it's only +# allowed to call DPG from the main thread and from handlers/callbacks. +# Also can be used to get back the behavior of old DPG versions that were thread +# unsafe (for testing/debugging). +set(MV_NO_USER_THREADS ${MV_NO_USER_THREADS}) +if(MV_NO_USER_THREADS) + add_definitions(-DMV_NO_USER_THREADS) +endif() + add_subdirectory("thirdparty") # if this is not a distribution build diff --git a/LICENSE b/LICENSE index e382656bb..15b4874d5 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 Dear PyGui, LLC +Copyright (c) 2025 Dear PyGui, LLC Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index e14a6dcbf..ff9e8c949 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,8 @@

- static-analysis - static-analysis + static-analysis + static-analysis Deployment Documentation Status

diff --git a/dearpygui/_dearpygui.pyi b/dearpygui/_dearpygui.pyi index b821d6276..9701c53c9 100644 --- a/dearpygui/_dearpygui.pyi +++ b/dearpygui/_dearpygui.pyi @@ -54,15 +54,15 @@ def add_checkbox(*, label: str ='', user_data: Any ='', use_internal_label: bool """Adds a checkbox.""" ... -def add_child_window(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', width: int ='', height: int ='', indent: int ='', parent: Union[int, str] ='', before: Union[int, str] ='', payload_type: str ='', drop_callback: Callable ='', show: bool ='', pos: Union[List[int], Tuple[int, ...]] ='', filter_key: str ='', delay_search: bool ='', tracked: bool ='', track_offset: float ='', border: bool ='', autosize_x: bool ='', autosize_y: bool ='', no_scrollbar: bool ='', horizontal_scrollbar: bool ='', menubar: bool ='', no_scroll_with_mouse: bool ='', flattened_navigation: bool ='', always_use_window_padding: bool ='', resizable_x: bool ='', resizable_y: bool ='', always_auto_resize: bool ='', frame_style: bool ='', auto_resize_x: bool ='', auto_resize_y: bool ='') -> Union[int, str]: +def add_child_window(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', width: int ='', height: int ='', indent: int ='', parent: Union[int, str] ='', before: Union[int, str] ='', payload_type: str ='', drop_callback: Callable ='', show: bool ='', pos: Union[List[int], Tuple[int, ...]] ='', filter_key: str ='', tracked: bool ='', track_offset: float ='', border: bool ='', autosize_x: bool ='', autosize_y: bool ='', no_scrollbar: bool ='', horizontal_scrollbar: bool ='', menubar: bool ='', no_scroll_with_mouse: bool ='', flattened_navigation: bool ='', always_use_window_padding: bool ='', resizable_x: bool ='', resizable_y: bool ='', always_auto_resize: bool ='', frame_style: bool ='', auto_resize_x: bool ='', auto_resize_y: bool ='') -> Union[int, str]: """Adds an embedded child window. Will show scrollbars when items do not fit. About using auto_resize/resizable flags: size measurement for a given axis is only performed when the child window is within visible boundaries, or is just appearing and it won't update its auto-size while clipped. While not perfect, it is a better default behavior as the always-on performance gain is more valuable than the occasional 'resizing after becoming visible again' glitch. You may also use always_auto_resize to force an update even when child window is not in view. However doing so will degrade performance. Remember that combining both auto_resize_x and auto_resize_y defeats purpose of a scrolling region and is NOT recommended.""" ... -def add_clipper(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', width: int ='', indent: int ='', parent: Union[int, str] ='', before: Union[int, str] ='', show: bool ='', delay_search: bool ='') -> Union[int, str]: +def add_clipper(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', width: int ='', indent: int ='', parent: Union[int, str] ='', before: Union[int, str] ='', show: bool ='') -> Union[int, str]: """Helper to manually clip large list of items. Increases performance by not searching or drawing widgets outside of the clipped region.""" ... -def add_collapsing_header(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', indent: int ='', parent: Union[int, str] ='', before: Union[int, str] ='', payload_type: str ='', drag_callback: Callable ='', drop_callback: Callable ='', show: bool ='', pos: Union[List[int], Tuple[int, ...]] ='', filter_key: str ='', delay_search: bool ='', tracked: bool ='', track_offset: float ='', closable: bool ='', default_open: bool ='', open_on_double_click: bool ='', open_on_arrow: bool ='', leaf: bool ='', bullet: bool ='') -> Union[int, str]: +def add_collapsing_header(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', indent: int ='', parent: Union[int, str] ='', before: Union[int, str] ='', payload_type: str ='', drag_callback: Callable ='', drop_callback: Callable ='', show: bool ='', pos: Union[List[int], Tuple[int, ...]] ='', filter_key: str ='', tracked: bool ='', track_offset: float ='', closable: bool ='', default_open: bool ='', open_on_double_click: bool ='', open_on_arrow: bool ='', leaf: bool ='', bullet: bool ='') -> Union[int, str]: """Adds a collapsing header to add items to. Must be closed with the end command.""" ... @@ -111,7 +111,7 @@ def add_custom_series(x : Union[List[float], Tuple[float, ...]], y : Union[List[ ... def add_date_picker(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', indent: int ='', parent: Union[int, str] ='', before: Union[int, str] ='', payload_type: str ='', callback: Callable ='', drag_callback: Callable ='', drop_callback: Callable ='', show: bool ='', pos: Union[List[int], Tuple[int, ...]] ='', filter_key: str ='', tracked: bool ='', track_offset: float ='', default_value: dict ='', level: int ='') -> Union[int, str]: - """Adds a data picker.""" + """Adds a date picker.""" ... def add_digital_series(x : Union[List[float], Tuple[float, ...]], y : Union[List[float], Tuple[float, ...]], *, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', parent: Union[int, str] ='', before: Union[int, str] ='', source: Union[int, str] ='', show: bool ='') -> Union[int, str]: @@ -174,7 +174,7 @@ def add_draw_node(*, label: str ='', user_data: Any ='', use_internal_label: boo """New in 1.1. Creates a drawing node to associate a transformation matrix. Child node matricies will concatenate.""" ... -def add_drawlist(width : int, height : int, *, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', parent: Union[int, str] ='', before: Union[int, str] ='', callback: Callable ='', show: bool ='', pos: Union[List[int], Tuple[int, ...]] ='', filter_key: str ='', delay_search: bool ='', tracked: bool ='', track_offset: float ='') -> Union[int, str]: +def add_drawlist(width : int, height : int, *, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', parent: Union[int, str] ='', before: Union[int, str] ='', callback: Callable ='', show: bool ='', pos: Union[List[int], Tuple[int, ...]] ='', filter_key: str ='', tracked: bool ='', track_offset: float ='') -> Union[int, str]: """Adds a drawing canvas.""" ... @@ -194,7 +194,7 @@ def add_file_extension(extension : str, *, label: str ='', user_data: Any ='', u """Creates a file extension filter option in the file dialog.""" ... -def add_filter_set(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', width: int ='', indent: int ='', parent: Union[int, str] ='', before: Union[int, str] ='', show: bool ='', delay_search: bool ='') -> Union[int, str]: +def add_filter_set(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', width: int ='', indent: int ='', parent: Union[int, str] ='', before: Union[int, str] ='', show: bool ='') -> Union[int, str]: """Helper to parse and apply text filters (e.g. aaaaa[, bbbbb][, ccccc])""" ... @@ -230,7 +230,7 @@ def add_font_registry(*, label: str ='', user_data: Any ='', use_internal_label: """Adds a font registry.""" ... -def add_group(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', width: int ='', height: int ='', indent: int ='', parent: Union[int, str] ='', before: Union[int, str] ='', payload_type: str ='', drag_callback: Callable ='', drop_callback: Callable ='', show: bool ='', enabled: bool ='', pos: Union[List[int], Tuple[int, ...]] ='', filter_key: str ='', delay_search: bool ='', tracked: bool ='', track_offset: float ='', horizontal: bool ='', horizontal_spacing: float ='', xoffset: float ='') -> Union[int, str]: +def add_group(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', width: int ='', height: int ='', indent: int ='', parent: Union[int, str] ='', before: Union[int, str] ='', payload_type: str ='', drag_callback: Callable ='', drop_callback: Callable ='', show: bool ='', enabled: bool ='', pos: Union[List[int], Tuple[int, ...]] ='', filter_key: str ='', tracked: bool ='', track_offset: float ='', horizontal: bool ='', horizontal_spacing: float ='', xoffset: float ='') -> Union[int, str]: """Creates a group that other widgets can belong to. The group allows item commands to be issued for all of its members. Enable property acts in a special way enabling/disabling everything inside the group. (Use mvStyleVar_DisabledAlpha to edit colors within the disabled group.)""" ... @@ -327,7 +327,7 @@ def add_item_edited_handler(*, label: str ='', user_data: Any ='', use_internal_ """Adds an edited handler.""" ... -def add_item_focus_handler(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', parent: Union[int, str] ='', callback: Callable ='', show: bool ='') -> Union[int, str]: +def add_item_focus_handler(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', parent: Union[int, str] ='', callback: Callable ='', show: bool ='', event_type: int ='') -> Union[int, str]: """Adds a focus handler.""" ... @@ -335,7 +335,7 @@ def add_item_handler_registry(*, label: str ='', user_data: Any ='', use_interna """Adds an item handler registry.""" ... -def add_item_hover_handler(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', parent: Union[int, str] ='', callback: Callable ='', show: bool ='') -> Union[int, str]: +def add_item_hover_handler(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', parent: Union[int, str] ='', callback: Callable ='', show: bool ='', event_type: int ='') -> Union[int, str]: """Adds a hover handler.""" ... @@ -343,6 +343,10 @@ def add_item_resize_handler(*, label: str ='', user_data: Any ='', use_internal_ """Adds a resize handler.""" ... +def add_item_scroll_handler(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', parent: Union[int, str] ='', callback: Callable ='', show: bool ='') -> Union[int, str]: + """Adds a scroll handler.""" + ... + def add_item_toggled_open_handler(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', parent: Union[int, str] ='', callback: Callable ='', show: bool ='') -> Union[int, str]: """Adds a togged open handler.""" ... @@ -379,11 +383,11 @@ def add_loading_indicator(*, label: str ='', user_data: Any ='', use_internal_la """Adds a rotating animated loading symbol.""" ... -def add_menu(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', indent: int ='', parent: Union[int, str] ='', before: Union[int, str] ='', payload_type: str ='', drop_callback: Callable ='', show: bool ='', enabled: bool ='', filter_key: str ='', delay_search: bool ='', tracked: bool ='', track_offset: float ='') -> Union[int, str]: +def add_menu(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', indent: int ='', parent: Union[int, str] ='', before: Union[int, str] ='', payload_type: str ='', drop_callback: Callable ='', show: bool ='', enabled: bool ='', filter_key: str ='', tracked: bool ='', track_offset: float ='') -> Union[int, str]: """Adds a menu to an existing menu bar.""" ... -def add_menu_bar(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', indent: int ='', parent: Union[int, str] ='', show: bool ='', delay_search: bool ='') -> Union[int, str]: +def add_menu_bar(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', indent: int ='', parent: Union[int, str] ='', show: bool ='') -> Union[int, str]: """Adds a menu bar to a window.""" ... @@ -419,7 +423,7 @@ def add_mouse_wheel_handler(*, label: str ='', user_data: Any ='', use_internal_ """Adds a mouse wheel handler.""" ... -def add_node(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', parent: Union[int, str] ='', before: Union[int, str] ='', payload_type: str ='', drag_callback: Callable ='', drop_callback: Callable ='', show: bool ='', pos: Union[List[int], Tuple[int, ...]] ='', filter_key: str ='', delay_search: bool ='', tracked: bool ='', track_offset: float ='', draggable: bool ='') -> Union[int, str]: +def add_node(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', parent: Union[int, str] ='', before: Union[int, str] ='', payload_type: str ='', drag_callback: Callable ='', drop_callback: Callable ='', show: bool ='', pos: Union[List[int], Tuple[int, ...]] ='', filter_key: str ='', tracked: bool ='', track_offset: float ='', draggable: bool ='') -> Union[int, str]: """Adds a node to a node editor.""" ... @@ -427,7 +431,7 @@ def add_node_attribute(*, label: str ='', user_data: Any ='', use_internal_label """Adds a node attribute to a node.""" ... -def add_node_editor(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', width: int ='', height: int ='', parent: Union[int, str] ='', before: Union[int, str] ='', callback: Callable ='', show: bool ='', filter_key: str ='', delay_search: bool ='', tracked: bool ='', track_offset: float ='', delink_callback: Callable ='', menubar: bool ='', minimap: bool ='', minimap_location: int ='') -> Union[int, str]: +def add_node_editor(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', width: int ='', height: int ='', parent: Union[int, str] ='', before: Union[int, str] ='', callback: Callable ='', show: bool ='', filter_key: str ='', tracked: bool ='', track_offset: float ='', delink_callback: Callable ='', menubar: bool ='', minimap: bool ='', minimap_location: int ='') -> Union[int, str]: """Adds a node editor.""" ... @@ -439,7 +443,7 @@ def add_pie_series(x : float, y : float, radius : float, values : Union[List[flo """Adds an pie series to a plot.""" ... -def add_plot(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', width: int ='', height: int ='', indent: int ='', parent: Union[int, str] ='', before: Union[int, str] ='', payload_type: str ='', callback: Callable ='', drag_callback: Callable ='', drop_callback: Callable ='', show: bool ='', pos: Union[List[int], Tuple[int, ...]] ='', filter_key: str ='', delay_search: bool ='', tracked: bool ='', track_offset: float ='', no_title: bool ='', no_menus: bool ='', no_box_select: bool ='', no_mouse_pos: bool ='', query: bool ='', query_color: Union[List[float], Tuple[float, ...]] ='', min_query_rects: int ='', max_query_rects: int ='', crosshairs: bool ='', equal_aspects: bool ='', no_inputs: bool ='', no_frame: bool ='', use_local_time: bool ='', use_ISO8601: bool ='', use_24hour_clock: bool ='', pan_button: int ='', pan_mod: int ='', context_menu_button: int ='', fit_button: int ='', box_select_button: int ='', box_select_mod: int ='', box_select_cancel_button: int ='', query_toggle_mod: int ='', horizontal_mod: int ='', vertical_mod: int ='', override_mod: int ='', zoom_mod: int ='', zoom_rate: int ='') -> Union[int, str]: +def add_plot(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', width: int ='', height: int ='', indent: int ='', parent: Union[int, str] ='', before: Union[int, str] ='', payload_type: str ='', callback: Callable ='', drag_callback: Callable ='', drop_callback: Callable ='', show: bool ='', pos: Union[List[int], Tuple[int, ...]] ='', filter_key: str ='', tracked: bool ='', track_offset: float ='', no_title: bool ='', no_menus: bool ='', no_box_select: bool ='', no_mouse_pos: bool ='', query: bool ='', query_color: Union[List[float], Tuple[float, ...]] ='', min_query_rects: int ='', max_query_rects: int ='', crosshairs: bool ='', equal_aspects: bool ='', no_inputs: bool ='', no_frame: bool ='', use_local_time: bool ='', use_ISO8601: bool ='', use_24hour_clock: bool ='', pan_button: int ='', pan_mod: int ='', context_menu_button: int ='', fit_button: int ='', box_select_button: int ='', box_select_mod: int ='', box_select_cancel_button: int ='', query_toggle_mod: int ='', horizontal_mod: int ='', vertical_mod: int ='', override_mod: int ='', zoom_mod: int ='', zoom_rate: int ='') -> Union[int, str]: """Adds a plot which is used to hold series, and can be drawn to with draw commands. For all _mod parameters use mvKey_ModX enums, or mvKey_ModDisabled to disable the modifier.""" ... @@ -539,15 +543,20 @@ def add_string_value(*, label: str ='', user_data: Any ='', use_internal_label: """Adds a string value.""" ... -def add_subplots(rows : int, columns : int, *, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', width: int ='', height: int ='', indent: int ='', parent: Union[int, str] ='', before: Union[int, str] ='', callback: Callable ='', show: bool ='', pos: Union[List[int], Tuple[int, ...]] ='', filter_key: str ='', delay_search: bool ='', tracked: bool ='', track_offset: float ='', row_ratios: Union[List[float], Tuple[float, ...]] ='', column_ratios: Union[List[float], Tuple[float, ...]] ='', no_title: bool ='', no_menus: bool ='', no_resize: bool ='', no_align: bool ='', share_series: bool ='', link_rows: bool ='', link_columns: bool ='', link_all_x: bool ='', link_all_y: bool ='', column_major: bool ='') -> Union[int, str]: +def add_subplots(rows : int, columns : int, *, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', width: int ='', height: int ='', indent: int ='', parent: Union[int, str] ='', before: Union[int, str] ='', callback: Callable ='', show: bool ='', pos: Union[List[int], Tuple[int, ...]] ='', filter_key: str ='', tracked: bool ='', track_offset: float ='', row_ratios: Union[List[float], Tuple[float, ...]] ='', column_ratios: Union[List[float], Tuple[float, ...]] ='', no_title: bool ='', no_menus: bool ='', no_resize: bool ='', no_align: bool ='', share_series: bool ='', link_rows: bool ='', link_columns: bool ='', link_all_x: bool ='', link_all_y: bool ='', column_major: bool ='') -> Union[int, str]: """Adds a collection of plots.""" ... +def add_synced_tables(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', parent: Union[int, str] ='', before: Union[int, str] ='', show: bool ='', filter_key: str ='') -> Union[int, str]: + """Links all tables that are immediate children of this container so that they share their state (mostly column sizes). Other children are rendered as is. This is an experimental feature, use with caution.""" + ... + def add_tab(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', indent: int ='', parent: Union[int, str] ='', before: Union[int, str] ='', payload_type: str ='', drop_callback: Callable ='', show: bool ='', filter_key: str ='', delay_search: bool ='', tracked: bool ='', track_offset: float ='', closable: bool ='', no_tooltip: bool ='', order_mode: int ='') -> Union[int, str]: + """Adds a tab to a tab bar.""" ... -def add_tab_bar(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', indent: int ='', parent: Union[int, str] ='', before: Union[int, str] ='', callback: Callable ='', show: bool ='', pos: Union[List[int], Tuple[int, ...]] ='', filter_key: str ='', delay_search: bool ='', tracked: bool ='', track_offset: float ='', reorderable: bool ='') -> Union[int, str]: +def add_tab_bar(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', indent: int ='', parent: Union[int, str] ='', before: Union[int, str] ='', callback: Callable ='', show: bool ='', pos: Union[List[int], Tuple[int, ...]] ='', filter_key: str ='', tracked: bool ='', track_offset: float ='', reorderable: bool ='') -> Union[int, str]: """Adds a tab bar.""" ... @@ -555,7 +564,7 @@ def add_tab_button(*, label: str ='', user_data: Any ='', use_internal_label: bo """Adds a tab button to a tab bar.""" ... -def add_table(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', width: int ='', height: int ='', indent: int ='', parent: Union[int, str] ='', before: Union[int, str] ='', source: Union[int, str] ='', callback: Callable ='', show: bool ='', pos: Union[List[int], Tuple[int, ...]] ='', filter_key: str ='', delay_search: bool ='', header_row: bool ='', clipper: bool ='', inner_width: int ='', policy: int ='', freeze_rows: int ='', freeze_columns: int ='', sort_multi: bool ='', sort_tristate: bool ='', resizable: bool ='', reorderable: bool ='', hideable: bool ='', sortable: bool ='', context_menu_in_body: bool ='', row_background: bool ='', borders_innerH: bool ='', borders_outerH: bool ='', borders_innerV: bool ='', borders_outerV: bool ='', no_host_extendX: bool ='', no_host_extendY: bool ='', no_keep_columns_visible: bool ='', precise_widths: bool ='', no_clip: bool ='', pad_outerX: bool ='', no_pad_outerX: bool ='', no_pad_innerX: bool ='', scrollX: bool ='', scrollY: bool ='', no_saved_settings: bool ='') -> Union[int, str]: +def add_table(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', width: int ='', height: int ='', indent: int ='', parent: Union[int, str] ='', before: Union[int, str] ='', source: Union[int, str] ='', callback: Callable ='', show: bool ='', pos: Union[List[int], Tuple[int, ...]] ='', filter_key: str ='', header_row: bool ='', clipper: bool ='', inner_width: int ='', policy: int ='', freeze_rows: int ='', freeze_columns: int ='', sort_multi: bool ='', sort_tristate: bool ='', resizable: bool ='', reorderable: bool ='', hideable: bool ='', sortable: bool ='', context_menu_in_body: bool ='', row_background: bool ='', borders_innerH: bool ='', borders_outerH: bool ='', borders_innerV: bool ='', borders_outerV: bool ='', no_host_extendX: bool ='', no_host_extendY: bool ='', no_keep_columns_visible: bool ='', precise_widths: bool ='', no_clip: bool ='', pad_outerX: bool ='', no_pad_outerX: bool ='', no_pad_innerX: bool ='', scrollX: bool ='', scrollY: bool ='', no_saved_settings: bool ='') -> Union[int, str]: """Adds a table.""" ... @@ -611,7 +620,7 @@ def add_tooltip(parent : Union[int, str], *, label: str ='', user_data: Any ='', """Adds a tooltip window.""" ... -def add_tree_node(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', indent: int ='', parent: Union[int, str] ='', before: Union[int, str] ='', payload_type: str ='', drag_callback: Callable ='', drop_callback: Callable ='', show: bool ='', pos: Union[List[int], Tuple[int, ...]] ='', filter_key: str ='', delay_search: bool ='', tracked: bool ='', track_offset: float ='', default_open: bool ='', open_on_double_click: bool ='', open_on_arrow: bool ='', leaf: bool ='', bullet: bool ='', selectable: bool ='', span_text_width: bool ='', span_full_width: bool ='') -> Union[int, str]: +def add_tree_node(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', indent: int ='', parent: Union[int, str] ='', before: Union[int, str] ='', payload_type: str ='', drag_callback: Callable ='', drop_callback: Callable ='', show: bool ='', pos: Union[List[int], Tuple[int, ...]] ='', filter_key: str ='', tracked: bool ='', track_offset: float ='', default_open: bool ='', open_on_double_click: bool ='', open_on_arrow: bool ='', leaf: bool ='', bullet: bool ='', selectable: bool ='', span_text_width: bool ='', span_full_width: bool ='') -> Union[int, str]: """Adds a tree node to add items to.""" ... @@ -619,15 +628,15 @@ def add_value_registry(*, label: str ='', user_data: Any ='', use_internal_label """Adds a value registry.""" ... -def add_viewport_drawlist(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', show: bool ='', filter_key: str ='', delay_search: bool ='', front: bool ='') -> Union[int, str]: +def add_viewport_drawlist(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', show: bool ='', filter_key: str ='', front: bool ='') -> Union[int, str]: """A container that is used to present draw items or layers directly to the viewport. By default this will draw to the back of the viewport. Layers and draw items should be added to this widget as children.""" ... -def add_viewport_menu_bar(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', indent: int ='', parent: Union[int, str] ='', show: bool ='', delay_search: bool ='') -> Union[int, str]: +def add_viewport_menu_bar(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', indent: int ='', parent: Union[int, str] ='', show: bool ='') -> Union[int, str]: """Adds a menubar to the viewport.""" ... -def add_window(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', width: int ='', height: int ='', indent: int ='', show: bool ='', pos: Union[List[int], Tuple[int, ...]] ='', delay_search: bool ='', min_size: Union[List[int], Tuple[int, ...]] ='', max_size: Union[List[int], Tuple[int, ...]] ='', menubar: bool ='', collapsed: bool ='', autosize: bool ='', no_resize: bool ='', unsaved_document: bool ='', no_title_bar: bool ='', no_move: bool ='', no_scrollbar: bool ='', no_collapse: bool ='', horizontal_scrollbar: bool ='', no_focus_on_appearing: bool ='', no_bring_to_front_on_focus: bool ='', no_close: bool ='', no_background: bool ='', modal: bool ='', popup: bool ='', no_saved_settings: bool ='', no_open_over_existing_popup: bool ='', no_scroll_with_mouse: bool ='', on_close: Callable ='') -> Union[int, str]: +def add_window(*, label: str ='', user_data: Any ='', use_internal_label: bool ='', tag: Union[int, str] ='', width: int ='', height: int ='', indent: int ='', show: bool ='', pos: Union[List[int], Tuple[int, ...]] ='', min_size: Union[List[int], Tuple[int, ...]] ='', max_size: Union[List[int], Tuple[int, ...]] ='', menubar: bool ='', collapsed: bool ='', autosize: bool ='', no_resize: bool ='', unsaved_document: bool ='', no_title_bar: bool ='', no_move: bool ='', no_scrollbar: bool ='', no_collapse: bool ='', horizontal_scrollbar: bool ='', no_focus_on_appearing: bool ='', no_bring_to_front_on_focus: bool ='', no_close: bool ='', no_background: bool ='', modal: bool ='', popup: bool ='', no_saved_settings: bool ='', no_open_over_existing_popup: bool ='', no_scroll_with_mouse: bool ='', on_close: Callable ='') -> Union[int, str]: """Creates a new window for following items to be added to.""" ... @@ -1179,12 +1188,12 @@ def set_viewport_resize_callback(callback : Callable, *, user_data: Any ='') -> """Sets a callback to run on viewport resize.""" ... -def set_x_scroll(item : Union[int, str], value : float) -> None: - """Undocumented""" +def set_x_scroll(item : Union[int, str], value : float, *, when: int ='') -> None: + """Sets horizontal scroll position.""" ... -def set_y_scroll(item : Union[int, str], value : float) -> None: - """Undocumented""" +def set_y_scroll(item : Union[int, str], value : float, *, when: int ='') -> None: + """Sets vertical scroll position.""" ... def setup_dearpygui() -> None: @@ -1211,7 +1220,7 @@ def show_viewport(*, minimized: bool ='', maximized: bool ='') -> None: """Shows the main viewport.""" ... -def split_frame(*, delay: int ='') -> None: +def split_frame() -> None: """Waits one frame.""" ... @@ -1331,6 +1340,8 @@ mvKey_NumPad6=0 mvKey_NumPad7=0 mvKey_NumPad8=0 mvKey_NumPad9=0 +mvKey_NumPadEnter=0 +mvKey_NumPadEqual=0 mvKey_Subtract=0 mvKey_Decimal=0 mvKey_Divide=0 @@ -1428,6 +1439,19 @@ mvComboHeight_Small=0 mvComboHeight_Regular=0 mvComboHeight_Large=0 mvComboHeight_Largest=0 +mvEventType_Off=0 +mvEventType_Enter=0 +mvEventType_On=0 +mvEventType_Leave=0 +mvSetScrollFlags_Now=0 +mvSetScrollFlags_Delayed=0 +mvSetScrollFlags_Both=0 +mvScrollDirection_XAxis=0 +mvScrollDirection_YAxis=0 +mvScrollDirection_Horizontal=0 +mvScrollDirection_Vertical=0 +mvLoadInd_DottedCircle=0 +mvLoadInd_Ring=0 mvPlatform_Windows=0 mvPlatform_Apple=0 mvPlatform_Linux=0 @@ -1771,6 +1795,7 @@ mvNodeAttribute=0 mvTable=0 mvTableColumn=0 mvTableRow=0 +mvSyncedTables=0 mvDrawLine=0 mvDrawArrow=0 mvDrawTriangle=0 @@ -1850,6 +1875,7 @@ mvDeactivatedAfterEditHandler=0 mvToggledOpenHandler=0 mvClickedHandler=0 mvDoubleClickedHandler=0 +mvScrollHandler=0 mvDragPayload=0 mvResizeHandler=0 mvFont=0 diff --git a/dearpygui/_dearpygui_RTD.py b/dearpygui/_dearpygui_RTD.py index be2649027..b4e28ab8e 100644 --- a/dearpygui/_dearpygui_RTD.py +++ b/dearpygui/_dearpygui_RTD.py @@ -566,15 +566,6 @@ def is_item_tracked(item: Union[int, str]) -> Union[bool, None]: return internal_dpg.get_item_configuration(item)["tracked"] -def is_item_search_delayed(item: Union[int, str]) -> Union[bool, None]: - """Checks if item is search delayed. - - Returns: - tracked as a bool or None - """ - return internal_dpg.get_item_configuration(item)["delay_search"] - - def get_item_indent(item: Union[int, str]) -> Union[int, None]: """Gets the item's indent. @@ -1542,6 +1533,15 @@ def setup_registries() -> None: internal_dpg.add_value_registry(tag=internal_dpg.mvReservedUUID_3) internal_dpg.add_colormap_registry(tag=internal_dpg.mvReservedUUID_4) +@deprecated("Useless and doesn't work anyway") +def is_item_search_delayed(item: Union[int, str]) -> Union[bool, None]: + """Checks if item is search delayed. + + Returns: + tracked as a bool or None + """ + return internal_dpg.get_item_configuration(item)["delay_search"] + @deprecated("Use: `set_frame_callback()`") def set_start_callback(callback): """ deprecated function """ @@ -1571,7 +1571,6 @@ def child_window(**kwargs): show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom border (bool, optional): Shows/Hides the border around the sides. @@ -1590,6 +1589,7 @@ def child_window(**kwargs): auto_resize_x (bool, optional): Enable auto-resizing width based on child content. Read 'IMPORTANT: Size measurement' details above. auto_resize_y (bool, optional): Enable auto-resizing height based on child content. Read 'IMPORTANT: Size measurement' details above. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -1614,8 +1614,8 @@ def clipper(**kwargs): parent (Union[int, str], optional): Parent to add this item to. (runtime adding) before (Union[int, str], optional): This item will be displayed before the specified item in the parent. show (bool, optional): Attempt to render widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -1644,7 +1644,6 @@ def collapsing_header(**kwargs): show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom closable (bool, optional): Adds the ability to hide this widget by pressing the (x) in the top right of widget. @@ -1654,6 +1653,7 @@ def collapsing_header(**kwargs): leaf (bool, optional): No collapsing, no arrow (use as a convenience for leaf nodes). bullet (bool, optional): Display a bullet instead of arrow. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -1809,10 +1809,10 @@ def drawlist(width, height, **kwargs): show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -1869,8 +1869,8 @@ def filter_set(**kwargs): parent (Union[int, str], optional): Parent to add this item to. (runtime adding) before (Union[int, str], optional): This item will be displayed before the specified item in the parent. show (bool, optional): Attempt to render widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -1949,13 +1949,13 @@ def group(**kwargs): enabled (bool, optional): Turns off functionality of widget and applies the disabled theme. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom horizontal (bool, optional): Forces child widgets to be added in a horizontal layout. horizontal_spacing (float, optional): Spacing for the horizontal layout. xoffset (float, optional): Offset from containing window x item location within group. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -2025,10 +2025,10 @@ def menu(**kwargs): show (bool, optional): Attempt to render widget. enabled (bool, optional): Turns off functionality of widget and applies the disabled theme. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -2051,8 +2051,8 @@ def menu_bar(**kwargs): indent (int, optional): Offsets the widget to the right the specified number multiplied by the indent style. parent (Union[int, str], optional): Parent to add this item to. (runtime adding) show (bool, optional): Attempt to render widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -2080,11 +2080,11 @@ def node(**kwargs): show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom draggable (bool, optional): Allow node to be draggable. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -2141,7 +2141,6 @@ def node_editor(**kwargs): callback (Callable, optional): Registers a callback. show (bool, optional): Attempt to render widget. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom delink_callback (Callable, optional): Callback ran when a link is detached. @@ -2149,6 +2148,7 @@ def node_editor(**kwargs): minimap (bool, optional): Shows or hides the Minimap. New in 1.6. minimap_location (int, optional): mvNodeMiniMap_Location_* constants. New in 1.6. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -2180,7 +2180,6 @@ def plot(**kwargs): show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom no_title (bool, optional): the plot title will not be displayed @@ -2212,6 +2211,7 @@ def plot(**kwargs): zoom_mod (int, optional): optional modifier that must be held for scroll wheel zooming zoom_rate (int, optional): zoom rate for scroll (e.g. 0.1f = 10% plot range every scroll click); make negative to invert id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. no_highlight (bool, optional): (deprecated)Removed because not supported from the backend anymore. To control the highlighting of series use the same argument in `add_plot_legend` no_child (bool, optional): (deprecated)a child window region will not be used to capture mouse scroll (can boost performance for single ImGui window applications) anti_aliased (bool, optional): (deprecated)This feature was deprecated in ImPlot. To enable/disable anti_aliasing use `dpg.configure_app()` with the `anti_aliasing` parameters. @@ -2312,7 +2312,6 @@ def subplots(rows, columns, **kwargs): show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom row_ratios (Union[List[float], Tuple[float, ...]], optional): @@ -2328,6 +2327,7 @@ def subplots(rows, columns, **kwargs): link_all_y (bool, optional): link the y-axis limits in every plot in the subplot (does not apply to auxiliary y-axes) column_major (bool, optional): subplots are added in column major order instead of the default row major order id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -2338,6 +2338,30 @@ def subplots(rows, columns, **kwargs): finally: internal_dpg.pop_container_stack() +@contextmanager +def synced_tables(**kwargs): + """ Links all tables that are immediate children of this container so that they share their state (mostly column sizes). Other children are rendered as is. This is an experimental feature, use with caution. + + Args: + label (str, optional): Overrides 'name' as label. + user_data (Any, optional): User data for callbacks + use_internal_label (bool, optional): Use generated internal label instead of user specified (appends ### uuid). + tag (Union[int, str], optional): Unique id used to programmatically refer to the item.If label is unused this will be the label. + parent (Union[int, str], optional): Parent to add this item to. (runtime adding) + before (Union[int, str], optional): This item will be displayed before the specified item in the parent. + show (bool, optional): Attempt to render widget. + filter_key (str, optional): Used by filter widget. + id (Union[int, str], optional): (deprecated) + Yields: + Union[int, str] + """ + try: + widget = internal_dpg.add_synced_tables(**kwargs) + internal_dpg.push_container_stack(widget) + yield widget + finally: + internal_dpg.pop_container_stack() + @contextmanager def tab(**kwargs): """ Adds a tab to a tab bar. @@ -2354,13 +2378,13 @@ def tab(**kwargs): drop_callback (Callable, optional): Registers a drop callback for drag and drop. show (bool, optional): Attempt to render widget. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom closable (bool, optional): Creates a button on the tab that can hide the tab. no_tooltip (bool, optional): Disable tooltip for the given tab. order_mode (int, optional): set using a constant: mvTabOrder_Reorderable: allows reordering, mvTabOrder_Fixed: fixed ordering, mvTabOrder_Leading: adds tab to front, mvTabOrder_Trailing: adds tab to back id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -2387,11 +2411,11 @@ def tab_bar(**kwargs): show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom reorderable (bool, optional): Allows for the user to change the order of the tabs. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -2421,7 +2445,6 @@ def table(**kwargs): show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. header_row (bool, optional): show headers at the top of the columns clipper (bool, optional): Use clipper (rows must be same height). inner_width (int, optional): @@ -2452,6 +2475,7 @@ def table(**kwargs): scrollY (bool, optional): Enable vertical scrolling. no_saved_settings (bool, optional): Never load/save settings in .ini file. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -2640,7 +2664,6 @@ def tree_node(**kwargs): show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom default_open (bool, optional): Sets the tree node open by default. @@ -2652,6 +2675,7 @@ def tree_node(**kwargs): span_text_width (bool, optional): Makes hitbox and highlight only cover the label. span_full_width (bool, optional): Extend hit box to the left-most and right-most edges (cover the indent area). id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -2693,9 +2717,9 @@ def viewport_drawlist(**kwargs): tag (Union[int, str], optional): Unique id used to programmatically refer to the item.If label is unused this will be the label. show (bool, optional): Attempt to render widget. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. front (bool, optional): Draws to the front of the view port instead of the back. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -2718,8 +2742,8 @@ def viewport_menu_bar(**kwargs): indent (int, optional): Offsets the widget to the right the specified number multiplied by the indent style. parent (Union[int, str], optional): Parent to add this item to. (runtime adding) show (bool, optional): Attempt to render widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -2744,7 +2768,6 @@ def window(**kwargs): indent (int, optional): Offsets the widget to the right the specified number multiplied by the indent style. show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. min_size (Union[List[int], Tuple[int, ...]], optional): Minimum window size. max_size (Union[List[int], Tuple[int, ...]], optional): Maximum window size. menubar (bool, optional): Shows or hides the menubar. @@ -2768,6 +2791,7 @@ def window(**kwargs): no_scroll_with_mouse (bool, optional): Disable user vertically scrolling with mouse wheel. on_close (Callable, optional): Callback ran when window is closed. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -3103,7 +3127,6 @@ def add_child_window(**kwargs): show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom border (bool, optional): Shows/Hides the border around the sides. @@ -3122,6 +3145,7 @@ def add_child_window(**kwargs): auto_resize_x (bool, optional): Enable auto-resizing width based on child content. Read 'IMPORTANT: Size measurement' details above. auto_resize_y (bool, optional): Enable auto-resizing height based on child content. Read 'IMPORTANT: Size measurement' details above. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -3141,8 +3165,8 @@ def add_clipper(**kwargs): parent (Union[int, str], optional): Parent to add this item to. (runtime adding) before (Union[int, str], optional): This item will be displayed before the specified item in the parent. show (bool, optional): Attempt to render widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -3166,7 +3190,6 @@ def add_collapsing_header(**kwargs): show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom closable (bool, optional): Adds the ability to hide this widget by pressing the (x) in the top right of widget. @@ -3176,6 +3199,7 @@ def add_collapsing_header(**kwargs): leaf (bool, optional): No collapsing, no arrow (use as a convenience for leaf nodes). bullet (bool, optional): Display a bullet instead of arrow. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -3519,7 +3543,7 @@ def add_custom_series(x, y, channel_count, **kwargs): return internal_dpg.add_custom_series(x, y, channel_count, **kwargs) def add_date_picker(**kwargs): - """ Adds a data picker. + """ Adds a date picker. Args: label (str, optional): Overrides 'name' as label. @@ -3989,10 +4013,10 @@ def add_drawlist(width, height, **kwargs): show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -4105,8 +4129,8 @@ def add_filter_set(**kwargs): parent (Union[int, str], optional): Parent to add this item to. (runtime adding) before (Union[int, str], optional): This item will be displayed before the specified item in the parent. show (bool, optional): Attempt to render widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -4276,13 +4300,13 @@ def add_group(**kwargs): enabled (bool, optional): Turns off functionality of widget and applies the disabled theme. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom horizontal (bool, optional): Forces child widgets to be added in a horizontal layout. horizontal_spacing (float, optional): Spacing for the horizontal layout. xoffset (float, optional): Offset from containing window x item location within group. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -4940,6 +4964,7 @@ def add_item_focus_handler(**kwargs): parent (Union[int, str], optional): Parent to add this item to. (runtime adding) callback (Callable, optional): Registers a callback. show (bool, optional): Attempt to render widget. + event_type (int, optional): What kind of events to track: just got focus (mvEventType_Enter), currently having focus (mvEventType_On), lost focus (mvEventType_Leave). Can be a combination of these flags. Defaults to mvEventType_On. id (Union[int, str], optional): (deprecated) Returns: Union[int, str] @@ -4974,6 +4999,7 @@ def add_item_hover_handler(**kwargs): parent (Union[int, str], optional): Parent to add this item to. (runtime adding) callback (Callable, optional): Registers a callback. show (bool, optional): Attempt to render widget. + event_type (int, optional): What kind of events to track: mouse-in (mvEventType_Enter), mouse-over (mvEventType_On), mouse-out (mvEventType_Leave). Can be a combination of these flags. Defaults to mouse-over. id (Union[int, str], optional): (deprecated) Returns: Union[int, str] @@ -4999,6 +5025,24 @@ def add_item_resize_handler(**kwargs): return internal_dpg.add_item_resize_handler(**kwargs) +def add_item_scroll_handler(**kwargs): + """ Adds a scroll handler. + + Args: + label (str, optional): Overrides 'name' as label. + user_data (Any, optional): User data for callbacks + use_internal_label (bool, optional): Use generated internal label instead of user specified (appends ### uuid). + tag (Union[int, str], optional): Unique id used to programmatically refer to the item.If label is unused this will be the label. + parent (Union[int, str], optional): Parent to add this item to. (runtime adding) + callback (Callable, optional): Registers a callback. + show (bool, optional): Attempt to render widget. + id (Union[int, str], optional): (deprecated) + Returns: + Union[int, str] + """ + + return internal_dpg.add_item_scroll_handler(**kwargs) + def add_item_toggled_open_handler(**kwargs): """ Adds a togged open handler. @@ -5202,13 +5246,13 @@ def add_loading_indicator(**kwargs): drop_callback (Callable, optional): Registers a drop callback for drag and drop. show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. - style (int, optional): 0 is rotating dots style, 1 is rotating bar style. - circle_count (int, optional): Number of dots show if dots or size of circle if circle. - speed (float, optional): Speed the anamation will rotate. - radius (float, optional): Radius size of the loading indicator. - thickness (float, optional): Thickness of the circles or line. - color (Union[List[int], Tuple[int, ...]], optional): Color of the growing center circle. - secondary_color (Union[List[int], Tuple[int, ...]], optional): Background of the dots in dot mode. + style (int, optional): mvLoadInd_DottedCircle is rotating dots style, mvLoadInd_Ring is rotating bar style. + circle_count (int, optional): DottedCircle style: number of dots to show. + speed (float, optional): Speed with which the animation will rotate. + radius (float, optional): Scale factor for the loading indicator radius. The size of the indicator is determined by font size and this scale factor. + thickness (float, optional): Ring style: scale factor of line thickness; thickness=1 corresponds to line width being 1/8 of the ring diameter. + color (Union[List[int], Tuple[int, ...]], optional): Main color of the indicator. If omitted, the color for mvThemeCol_Button will be used. + secondary_color (Union[List[int], Tuple[int, ...]], optional): DottedCircle style: color of 'inactive' dots. If omitted, the color for mvThemeCol_ButtonHovered will be used. id (Union[int, str], optional): (deprecated) Returns: Union[int, str] @@ -5232,10 +5276,10 @@ def add_menu(**kwargs): show (bool, optional): Attempt to render widget. enabled (bool, optional): Turns off functionality of widget and applies the disabled theme. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -5253,8 +5297,8 @@ def add_menu_bar(**kwargs): indent (int, optional): Offsets the widget to the right the specified number multiplied by the indent style. parent (Union[int, str], optional): Parent to add this item to. (runtime adding) show (bool, optional): Attempt to render widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -5439,11 +5483,11 @@ def add_node(**kwargs): show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom draggable (bool, optional): Allow node to be draggable. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -5490,7 +5534,6 @@ def add_node_editor(**kwargs): callback (Callable, optional): Registers a callback. show (bool, optional): Attempt to render widget. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom delink_callback (Callable, optional): Callback ran when a link is detached. @@ -5498,6 +5541,7 @@ def add_node_editor(**kwargs): minimap (bool, optional): Shows or hides the Minimap. New in 1.6. minimap_location (int, optional): mvNodeMiniMap_Location_* constants. New in 1.6. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -5571,7 +5615,6 @@ def add_plot(**kwargs): show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom no_title (bool, optional): the plot title will not be displayed @@ -5603,6 +5646,7 @@ def add_plot(**kwargs): zoom_mod (int, optional): optional modifier that must be held for scroll wheel zooming zoom_rate (int, optional): zoom rate for scroll (e.g. 0.1f = 10% plot range every scroll click); make negative to invert id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. no_highlight (bool, optional): (deprecated)Removed because not supported from the backend anymore. To control the highlighting of series use the same argument in `add_plot_legend` no_child (bool, optional): (deprecated)a child window region will not be used to capture mouse scroll (can boost performance for single ImGui window applications) anti_aliased (bool, optional): (deprecated)This feature was deprecated in ImPlot. To enable/disable anti_aliasing use `dpg.configure_app()` with the `anti_aliasing` parameters. @@ -6301,7 +6345,6 @@ def add_subplots(rows, columns, **kwargs): show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom row_ratios (Union[List[float], Tuple[float, ...]], optional): @@ -6317,12 +6360,32 @@ def add_subplots(rows, columns, **kwargs): link_all_y (bool, optional): link the y-axis limits in every plot in the subplot (does not apply to auxiliary y-axes) column_major (bool, optional): subplots are added in column major order instead of the default row major order id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ return internal_dpg.add_subplots(rows, columns, **kwargs) +def add_synced_tables(**kwargs): + """ Links all tables that are immediate children of this container so that they share their state (mostly column sizes). Other children are rendered as is. This is an experimental feature, use with caution. + + Args: + label (str, optional): Overrides 'name' as label. + user_data (Any, optional): User data for callbacks + use_internal_label (bool, optional): Use generated internal label instead of user specified (appends ### uuid). + tag (Union[int, str], optional): Unique id used to programmatically refer to the item.If label is unused this will be the label. + parent (Union[int, str], optional): Parent to add this item to. (runtime adding) + before (Union[int, str], optional): This item will be displayed before the specified item in the parent. + show (bool, optional): Attempt to render widget. + filter_key (str, optional): Used by filter widget. + id (Union[int, str], optional): (deprecated) + Returns: + Union[int, str] + """ + + return internal_dpg.add_synced_tables(**kwargs) + def add_tab(**kwargs): """ Adds a tab to a tab bar. @@ -6338,13 +6401,13 @@ def add_tab(**kwargs): drop_callback (Callable, optional): Registers a drop callback for drag and drop. show (bool, optional): Attempt to render widget. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom closable (bool, optional): Creates a button on the tab that can hide the tab. no_tooltip (bool, optional): Disable tooltip for the given tab. order_mode (int, optional): set using a constant: mvTabOrder_Reorderable: allows reordering, mvTabOrder_Fixed: fixed ordering, mvTabOrder_Leading: adds tab to front, mvTabOrder_Trailing: adds tab to back id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -6366,11 +6429,11 @@ def add_tab_bar(**kwargs): show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom reorderable (bool, optional): Allows for the user to change the order of the tabs. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -6425,7 +6488,6 @@ def add_table(**kwargs): show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. header_row (bool, optional): show headers at the top of the columns clipper (bool, optional): Use clipper (rows must be same height). inner_width (int, optional): @@ -6456,6 +6518,7 @@ def add_table(**kwargs): scrollY (bool, optional): Enable vertical scrolling. no_saved_settings (bool, optional): Never load/save settings in .ini file. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -6768,7 +6831,6 @@ def add_tree_node(**kwargs): show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom default_open (bool, optional): Sets the tree node open by default. @@ -6780,6 +6842,7 @@ def add_tree_node(**kwargs): span_text_width (bool, optional): Makes hitbox and highlight only cover the label. span_full_width (bool, optional): Extend hit box to the left-most and right-most edges (cover the indent area). id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -6811,9 +6874,9 @@ def add_viewport_drawlist(**kwargs): tag (Union[int, str], optional): Unique id used to programmatically refer to the item.If label is unused this will be the label. show (bool, optional): Attempt to render widget. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. front (bool, optional): Draws to the front of the view port instead of the back. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -6831,8 +6894,8 @@ def add_viewport_menu_bar(**kwargs): indent (int, optional): Offsets the widget to the right the specified number multiplied by the indent style. parent (Union[int, str], optional): Parent to add this item to. (runtime adding) show (bool, optional): Attempt to render widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -6852,7 +6915,6 @@ def add_window(**kwargs): indent (int, optional): Offsets the widget to the right the specified number multiplied by the indent style. show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. min_size (Union[List[int], Tuple[int, ...]], optional): Minimum window size. max_size (Union[List[int], Tuple[int, ...]], optional): Maximum window size. menubar (bool, optional): Shows or hides the menubar. @@ -6876,6 +6938,7 @@ def add_window(**kwargs): no_scroll_with_mouse (bool, optional): Disable user vertically scrolling with mouse wheel. on_close (Callable, optional): Callback ran when window is closed. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated)This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -8598,29 +8661,31 @@ def set_viewport_resize_callback(callback, **kwargs): return internal_dpg.set_viewport_resize_callback(callback, **kwargs) -def set_x_scroll(item, value): - """ Undocumented +def set_x_scroll(item, value, **kwargs): + """ Sets horizontal scroll position. Args: item (Union[int, str]): - value (float): + value (float): Scroll position + when (int, optional): Specifies whether the scroll position will be set in the nearest frame (mvSetScrollFlags_Now) or with a 1-frame delay (mvSetScrollFlags_Delayed). The former prevents flickering, the latter works better if contents change in the same frame as when set_x_scroll called. mvSetScrollFlags_Both can also be used to set the position twice. Returns: None """ - return internal_dpg.set_x_scroll(item, value) + return internal_dpg.set_x_scroll(item, value, **kwargs) -def set_y_scroll(item, value): - """ Undocumented +def set_y_scroll(item, value, **kwargs): + """ Sets vertical scroll position. Args: item (Union[int, str]): - value (float): + value (float): Scroll position + when (int, optional): Specifies whether the scroll position will be set in the nearest frame (mvSetScrollFlags_Now) or with a 1-frame delay (mvSetScrollFlags_Delayed). The former prevents flickering, the latter works better if contents change in the same frame as when set_x_scroll called. mvSetScrollFlags_Both can also be used to set the position twice. Returns: None """ - return internal_dpg.set_y_scroll(item, value) + return internal_dpg.set_y_scroll(item, value, **kwargs) def setup_dearpygui(): """ Sets up Dear PyGui @@ -8688,16 +8753,16 @@ def show_viewport(**kwargs): return internal_dpg.show_viewport(**kwargs) -def split_frame(**kwargs): +def split_frame(): """ Waits one frame. Args: - delay (int, optional): Minimal delay in in milliseconds + delay (int, optional): (deprecated)Do not use it anymore, it has no effect. Returns: None """ - return internal_dpg.split_frame(**kwargs) + return internal_dpg.split_frame() def stop_dearpygui(): """ Stops Dear PyGui @@ -8884,6 +8949,8 @@ def unstage(item): mvKey_NumPad7=internal_dpg.mvKey_NumPad7 mvKey_NumPad8=internal_dpg.mvKey_NumPad8 mvKey_NumPad9=internal_dpg.mvKey_NumPad9 +mvKey_NumPadEnter=internal_dpg.mvKey_NumPadEnter +mvKey_NumPadEqual=internal_dpg.mvKey_NumPadEqual mvKey_Subtract=internal_dpg.mvKey_Subtract mvKey_Decimal=internal_dpg.mvKey_Decimal mvKey_Divide=internal_dpg.mvKey_Divide @@ -8981,6 +9048,19 @@ def unstage(item): mvComboHeight_Regular=internal_dpg.mvComboHeight_Regular mvComboHeight_Large=internal_dpg.mvComboHeight_Large mvComboHeight_Largest=internal_dpg.mvComboHeight_Largest +mvEventType_Off=internal_dpg.mvEventType_Off +mvEventType_Enter=internal_dpg.mvEventType_Enter +mvEventType_On=internal_dpg.mvEventType_On +mvEventType_Leave=internal_dpg.mvEventType_Leave +mvSetScrollFlags_Now=internal_dpg.mvSetScrollFlags_Now +mvSetScrollFlags_Delayed=internal_dpg.mvSetScrollFlags_Delayed +mvSetScrollFlags_Both=internal_dpg.mvSetScrollFlags_Both +mvScrollDirection_XAxis=internal_dpg.mvScrollDirection_XAxis +mvScrollDirection_YAxis=internal_dpg.mvScrollDirection_YAxis +mvScrollDirection_Horizontal=internal_dpg.mvScrollDirection_Horizontal +mvScrollDirection_Vertical=internal_dpg.mvScrollDirection_Vertical +mvLoadInd_DottedCircle=internal_dpg.mvLoadInd_DottedCircle +mvLoadInd_Ring=internal_dpg.mvLoadInd_Ring mvPlatform_Windows=internal_dpg.mvPlatform_Windows mvPlatform_Apple=internal_dpg.mvPlatform_Apple mvPlatform_Linux=internal_dpg.mvPlatform_Linux @@ -9324,6 +9404,7 @@ def unstage(item): mvTable=internal_dpg.mvTable mvTableColumn=internal_dpg.mvTableColumn mvTableRow=internal_dpg.mvTableRow +mvSyncedTables=internal_dpg.mvSyncedTables mvDrawLine=internal_dpg.mvDrawLine mvDrawArrow=internal_dpg.mvDrawArrow mvDrawTriangle=internal_dpg.mvDrawTriangle @@ -9403,6 +9484,7 @@ def unstage(item): mvToggledOpenHandler=internal_dpg.mvToggledOpenHandler mvClickedHandler=internal_dpg.mvClickedHandler mvDoubleClickedHandler=internal_dpg.mvDoubleClickedHandler +mvScrollHandler=internal_dpg.mvScrollHandler mvDragPayload=internal_dpg.mvDragPayload mvResizeHandler=internal_dpg.mvResizeHandler mvFont=internal_dpg.mvFont diff --git a/dearpygui/_deprecated.py b/dearpygui/_deprecated.py index b5d18ea1b..c6335fc48 100644 --- a/dearpygui/_deprecated.py +++ b/dearpygui/_deprecated.py @@ -410,6 +410,15 @@ def setup_registries() -> None: internal_dpg.add_value_registry(tag=internal_dpg.mvReservedUUID_3) internal_dpg.add_colormap_registry(tag=internal_dpg.mvReservedUUID_4) +@deprecated("Useless and doesn't work anyway") +def is_item_search_delayed(item: Union[int, str]) -> Union[bool, None]: + """Checks if item is search delayed. + + Returns: + tracked as a bool or None + """ + return internal_dpg.get_item_configuration(item)["delay_search"] + @deprecated("Use: `set_frame_callback()`") def set_start_callback(callback): """ deprecated function """ diff --git a/dearpygui/_header.py b/dearpygui/_header.py index 873c2c183..1a1731e23 100644 --- a/dearpygui/_header.py +++ b/dearpygui/_header.py @@ -550,15 +550,6 @@ def is_item_tracked(item: Union[int, str]) -> Union[bool, None]: return internal_dpg.get_item_configuration(item)["tracked"] -def is_item_search_delayed(item: Union[int, str]) -> Union[bool, None]: - """Checks if item is search delayed. - - Returns: - tracked as a bool or None - """ - return internal_dpg.get_item_configuration(item)["delay_search"] - - def get_item_indent(item: Union[int, str]) -> Union[int, None]: """Gets the item's indent. diff --git a/dearpygui/dearpygui.py b/dearpygui/dearpygui.py index 3fecfaa12..2699a54ad 100644 --- a/dearpygui/dearpygui.py +++ b/dearpygui/dearpygui.py @@ -566,15 +566,6 @@ def is_item_tracked(item: Union[int, str]) -> Union[bool, None]: return internal_dpg.get_item_configuration(item)["tracked"] -def is_item_search_delayed(item: Union[int, str]) -> Union[bool, None]: - """Checks if item is search delayed. - - Returns: - tracked as a bool or None - """ - return internal_dpg.get_item_configuration(item)["delay_search"] - - def get_item_indent(item: Union[int, str]) -> Union[int, None]: """Gets the item's indent. @@ -1542,6 +1533,15 @@ def setup_registries() -> None: internal_dpg.add_value_registry(tag=internal_dpg.mvReservedUUID_3) internal_dpg.add_colormap_registry(tag=internal_dpg.mvReservedUUID_4) +@deprecated("Useless and doesn't work anyway") +def is_item_search_delayed(item: Union[int, str]) -> Union[bool, None]: + """Checks if item is search delayed. + + Returns: + tracked as a bool or None + """ + return internal_dpg.get_item_configuration(item)["delay_search"] + @deprecated("Use: `set_frame_callback()`") def set_start_callback(callback): """ deprecated function """ @@ -1553,7 +1553,7 @@ def set_start_callback(callback): @contextmanager -def child_window(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, height: int =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', drop_callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', delay_search: bool =False, tracked: bool =False, track_offset: float =0.5, border: bool =True, autosize_x: bool =False, autosize_y: bool =False, no_scrollbar: bool =False, horizontal_scrollbar: bool =False, menubar: bool =False, no_scroll_with_mouse: bool =False, flattened_navigation: bool =True, always_use_window_padding: bool =False, resizable_x: bool =False, resizable_y: bool =False, always_auto_resize: bool =False, frame_style: bool =False, auto_resize_x: bool =False, auto_resize_y: bool =False, **kwargs) -> Union[int, str]: +def child_window(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, height: int =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', drop_callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', tracked: bool =False, track_offset: float =0.5, border: bool =True, autosize_x: bool =False, autosize_y: bool =False, no_scrollbar: bool =False, horizontal_scrollbar: bool =False, menubar: bool =False, no_scroll_with_mouse: bool =False, flattened_navigation: bool =True, always_use_window_padding: bool =False, resizable_x: bool =False, resizable_y: bool =False, always_auto_resize: bool =False, frame_style: bool =False, auto_resize_x: bool =False, auto_resize_y: bool =False, **kwargs) -> Union[int, str]: """ Adds an embedded child window. Will show scrollbars when items do not fit. About using auto_resize/resizable flags: size measurement for a given axis is only performed when the child window is within visible boundaries, or is just appearing and it won't update its auto-size while clipped. While not perfect, it is a better default behavior as the always-on performance gain is more valuable than the occasional 'resizing after becoming visible again' glitch. You may also use always_auto_resize to force an update even when child window is not in view. However doing so will degrade performance. Remember that combining both auto_resize_x and auto_resize_y defeats purpose of a scrolling region and is NOT recommended. Args: @@ -1571,7 +1571,6 @@ def child_window(*, label: str =None, user_data: Any =None, use_internal_label: show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom border (bool, optional): Shows/Hides the border around the sides. @@ -1590,6 +1589,7 @@ def child_window(*, label: str =None, user_data: Any =None, use_internal_label: auto_resize_x (bool, optional): Enable auto-resizing width based on child content. Read 'IMPORTANT: Size measurement' details above. auto_resize_y (bool, optional): Enable auto-resizing height based on child content. Read 'IMPORTANT: Size measurement' details above. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -1598,14 +1598,17 @@ def child_window(*, label: str =None, user_data: Any =None, use_internal_label: if 'id' in kwargs.keys(): warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - widget = internal_dpg.add_child_window(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, height=height, indent=indent, parent=parent, before=before, payload_type=payload_type, drop_callback=drop_callback, show=show, pos=pos, filter_key=filter_key, delay_search=delay_search, tracked=tracked, track_offset=track_offset, border=border, autosize_x=autosize_x, autosize_y=autosize_y, no_scrollbar=no_scrollbar, horizontal_scrollbar=horizontal_scrollbar, menubar=menubar, no_scroll_with_mouse=no_scroll_with_mouse, flattened_navigation=flattened_navigation, always_use_window_padding=always_use_window_padding, resizable_x=resizable_x, resizable_y=resizable_y, always_auto_resize=always_auto_resize, frame_style=frame_style, auto_resize_x=auto_resize_x, auto_resize_y=auto_resize_y, **kwargs) + + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + widget = internal_dpg.add_child_window(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, height=height, indent=indent, parent=parent, before=before, payload_type=payload_type, drop_callback=drop_callback, show=show, pos=pos, filter_key=filter_key, tracked=tracked, track_offset=track_offset, border=border, autosize_x=autosize_x, autosize_y=autosize_y, no_scrollbar=no_scrollbar, horizontal_scrollbar=horizontal_scrollbar, menubar=menubar, no_scroll_with_mouse=no_scroll_with_mouse, flattened_navigation=flattened_navigation, always_use_window_padding=always_use_window_padding, resizable_x=resizable_x, resizable_y=resizable_y, always_auto_resize=always_auto_resize, frame_style=frame_style, auto_resize_x=auto_resize_x, auto_resize_y=auto_resize_y, **kwargs) internal_dpg.push_container_stack(widget) yield widget finally: internal_dpg.pop_container_stack() @contextmanager -def clipper(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, show: bool =True, delay_search: bool =False, **kwargs) -> Union[int, str]: +def clipper(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, show: bool =True, **kwargs) -> Union[int, str]: """ Helper to manually clip large list of items. Increases performance by not searching or drawing widgets outside of the clipped region. Args: @@ -1618,8 +1621,8 @@ def clipper(*, label: str =None, user_data: Any =None, use_internal_label: bool parent (Union[int, str], optional): Parent to add this item to. (runtime adding) before (Union[int, str], optional): This item will be displayed before the specified item in the parent. show (bool, optional): Attempt to render widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -1628,14 +1631,17 @@ def clipper(*, label: str =None, user_data: Any =None, use_internal_label: bool if 'id' in kwargs.keys(): warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - widget = internal_dpg.add_clipper(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, indent=indent, parent=parent, before=before, show=show, delay_search=delay_search, **kwargs) + + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + widget = internal_dpg.add_clipper(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, indent=indent, parent=parent, before=before, show=show, **kwargs) internal_dpg.push_container_stack(widget) yield widget finally: internal_dpg.pop_container_stack() @contextmanager -def collapsing_header(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', drag_callback: Callable =None, drop_callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', delay_search: bool =False, tracked: bool =False, track_offset: float =0.5, closable: bool =False, default_open: bool =False, open_on_double_click: bool =False, open_on_arrow: bool =False, leaf: bool =False, bullet: bool =False, **kwargs) -> Union[int, str]: +def collapsing_header(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', drag_callback: Callable =None, drop_callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', tracked: bool =False, track_offset: float =0.5, closable: bool =False, default_open: bool =False, open_on_double_click: bool =False, open_on_arrow: bool =False, leaf: bool =False, bullet: bool =False, **kwargs) -> Union[int, str]: """ Adds a collapsing header to add items to. Must be closed with the end command. Args: @@ -1652,7 +1658,6 @@ def collapsing_header(*, label: str =None, user_data: Any =None, use_internal_la show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom closable (bool, optional): Adds the ability to hide this widget by pressing the (x) in the top right of widget. @@ -1662,6 +1667,7 @@ def collapsing_header(*, label: str =None, user_data: Any =None, use_internal_la leaf (bool, optional): No collapsing, no arrow (use as a convenience for leaf nodes). bullet (bool, optional): Display a bullet instead of arrow. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -1670,7 +1676,10 @@ def collapsing_header(*, label: str =None, user_data: Any =None, use_internal_la if 'id' in kwargs.keys(): warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - widget = internal_dpg.add_collapsing_header(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, before=before, payload_type=payload_type, drag_callback=drag_callback, drop_callback=drop_callback, show=show, pos=pos, filter_key=filter_key, delay_search=delay_search, tracked=tracked, track_offset=track_offset, closable=closable, default_open=default_open, open_on_double_click=open_on_double_click, open_on_arrow=open_on_arrow, leaf=leaf, bullet=bullet, **kwargs) + + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + widget = internal_dpg.add_collapsing_header(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, before=before, payload_type=payload_type, drag_callback=drag_callback, drop_callback=drop_callback, show=show, pos=pos, filter_key=filter_key, tracked=tracked, track_offset=track_offset, closable=closable, default_open=default_open, open_on_double_click=open_on_double_click, open_on_arrow=open_on_arrow, leaf=leaf, bullet=bullet, **kwargs) internal_dpg.push_container_stack(widget) yield widget finally: @@ -1825,7 +1834,7 @@ def draw_node(*, label: str =None, user_data: Any =None, use_internal_label: boo internal_dpg.pop_container_stack() @contextmanager -def drawlist(width : int, height : int, *, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, parent: Union[int, str] =0, before: Union[int, str] =0, callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', delay_search: bool =False, tracked: bool =False, track_offset: float =0.5, **kwargs) -> Union[int, str]: +def drawlist(width : int, height : int, *, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, parent: Union[int, str] =0, before: Union[int, str] =0, callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', tracked: bool =False, track_offset: float =0.5, **kwargs) -> Union[int, str]: """ Adds a drawing canvas. Args: @@ -1841,10 +1850,10 @@ def drawlist(width : int, height : int, *, label: str =None, user_data: Any =Non show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -1853,7 +1862,10 @@ def drawlist(width : int, height : int, *, label: str =None, user_data: Any =Non if 'id' in kwargs.keys(): warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - widget = internal_dpg.add_drawlist(width, height, label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, parent=parent, before=before, callback=callback, show=show, pos=pos, filter_key=filter_key, delay_search=delay_search, tracked=tracked, track_offset=track_offset, **kwargs) + + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + widget = internal_dpg.add_drawlist(width, height, label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, parent=parent, before=before, callback=callback, show=show, pos=pos, filter_key=filter_key, tracked=tracked, track_offset=track_offset, **kwargs) internal_dpg.push_container_stack(widget) yield widget finally: @@ -1896,7 +1908,7 @@ def file_dialog(*, label: str =None, user_data: Any =None, use_internal_label: b internal_dpg.pop_container_stack() @contextmanager -def filter_set(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, show: bool =True, delay_search: bool =False, **kwargs) -> Union[int, str]: +def filter_set(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, show: bool =True, **kwargs) -> Union[int, str]: """ Helper to parse and apply text filters (e.g. aaaaa[, bbbbb][, ccccc]) Args: @@ -1909,8 +1921,8 @@ def filter_set(*, label: str =None, user_data: Any =None, use_internal_label: bo parent (Union[int, str], optional): Parent to add this item to. (runtime adding) before (Union[int, str], optional): This item will be displayed before the specified item in the parent. show (bool, optional): Attempt to render widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -1919,7 +1931,10 @@ def filter_set(*, label: str =None, user_data: Any =None, use_internal_label: bo if 'id' in kwargs.keys(): warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - widget = internal_dpg.add_filter_set(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, indent=indent, parent=parent, before=before, show=show, delay_search=delay_search, **kwargs) + + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + widget = internal_dpg.add_filter_set(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, indent=indent, parent=parent, before=before, show=show, **kwargs) internal_dpg.push_container_stack(widget) yield widget finally: @@ -1984,7 +1999,7 @@ def font_registry(*, label: str =None, user_data: Any =None, use_internal_label: internal_dpg.pop_container_stack() @contextmanager -def group(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, height: int =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', drag_callback: Callable =None, drop_callback: Callable =None, show: bool =True, enabled: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', delay_search: bool =False, tracked: bool =False, track_offset: float =0.5, horizontal: bool =False, horizontal_spacing: float =-1, xoffset: float =0.0, **kwargs) -> Union[int, str]: +def group(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, height: int =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', drag_callback: Callable =None, drop_callback: Callable =None, show: bool =True, enabled: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', tracked: bool =False, track_offset: float =0.5, horizontal: bool =False, horizontal_spacing: float =-1, xoffset: float =0.0, **kwargs) -> Union[int, str]: """ Creates a group that other widgets can belong to. The group allows item commands to be issued for all of its members. Enable property acts in a special way enabling/disabling everything inside the group. (Use mvStyleVar_DisabledAlpha to edit colors within the disabled group.) @@ -2005,13 +2020,13 @@ def group(*, label: str =None, user_data: Any =None, use_internal_label: bool =T enabled (bool, optional): Turns off functionality of widget and applies the disabled theme. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom horizontal (bool, optional): Forces child widgets to be added in a horizontal layout. horizontal_spacing (float, optional): Spacing for the horizontal layout. xoffset (float, optional): Offset from containing window x item location within group. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -2020,7 +2035,10 @@ def group(*, label: str =None, user_data: Any =None, use_internal_label: bool =T if 'id' in kwargs.keys(): warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - widget = internal_dpg.add_group(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, height=height, indent=indent, parent=parent, before=before, payload_type=payload_type, drag_callback=drag_callback, drop_callback=drop_callback, show=show, enabled=enabled, pos=pos, filter_key=filter_key, delay_search=delay_search, tracked=tracked, track_offset=track_offset, horizontal=horizontal, horizontal_spacing=horizontal_spacing, xoffset=xoffset, **kwargs) + + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + widget = internal_dpg.add_group(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, height=height, indent=indent, parent=parent, before=before, payload_type=payload_type, drag_callback=drag_callback, drop_callback=drop_callback, show=show, enabled=enabled, pos=pos, filter_key=filter_key, tracked=tracked, track_offset=track_offset, horizontal=horizontal, horizontal_spacing=horizontal_spacing, xoffset=xoffset, **kwargs) internal_dpg.push_container_stack(widget) yield widget finally: @@ -2077,7 +2095,7 @@ def item_handler_registry(*, label: str =None, user_data: Any =None, use_interna internal_dpg.pop_container_stack() @contextmanager -def menu(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', drop_callback: Callable =None, show: bool =True, enabled: bool =True, filter_key: str ='', delay_search: bool =False, tracked: bool =False, track_offset: float =0.5, **kwargs) -> Union[int, str]: +def menu(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', drop_callback: Callable =None, show: bool =True, enabled: bool =True, filter_key: str ='', tracked: bool =False, track_offset: float =0.5, **kwargs) -> Union[int, str]: """ Adds a menu to an existing menu bar. Args: @@ -2093,10 +2111,10 @@ def menu(*, label: str =None, user_data: Any =None, use_internal_label: bool =Tr show (bool, optional): Attempt to render widget. enabled (bool, optional): Turns off functionality of widget and applies the disabled theme. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -2105,14 +2123,17 @@ def menu(*, label: str =None, user_data: Any =None, use_internal_label: bool =Tr if 'id' in kwargs.keys(): warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - widget = internal_dpg.add_menu(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, before=before, payload_type=payload_type, drop_callback=drop_callback, show=show, enabled=enabled, filter_key=filter_key, delay_search=delay_search, tracked=tracked, track_offset=track_offset, **kwargs) + + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + widget = internal_dpg.add_menu(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, before=before, payload_type=payload_type, drop_callback=drop_callback, show=show, enabled=enabled, filter_key=filter_key, tracked=tracked, track_offset=track_offset, **kwargs) internal_dpg.push_container_stack(widget) yield widget finally: internal_dpg.pop_container_stack() @contextmanager -def menu_bar(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, indent: int =-1, parent: Union[int, str] =0, show: bool =True, delay_search: bool =False, **kwargs) -> Union[int, str]: +def menu_bar(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, indent: int =-1, parent: Union[int, str] =0, show: bool =True, **kwargs) -> Union[int, str]: """ Adds a menu bar to a window. Args: @@ -2123,8 +2144,8 @@ def menu_bar(*, label: str =None, user_data: Any =None, use_internal_label: bool indent (int, optional): Offsets the widget to the right the specified number multiplied by the indent style. parent (Union[int, str], optional): Parent to add this item to. (runtime adding) show (bool, optional): Attempt to render widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -2133,14 +2154,17 @@ def menu_bar(*, label: str =None, user_data: Any =None, use_internal_label: bool if 'id' in kwargs.keys(): warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - widget = internal_dpg.add_menu_bar(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, show=show, delay_search=delay_search, **kwargs) + + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + widget = internal_dpg.add_menu_bar(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, show=show, **kwargs) internal_dpg.push_container_stack(widget) yield widget finally: internal_dpg.pop_container_stack() @contextmanager -def node(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', drag_callback: Callable =None, drop_callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', delay_search: bool =False, tracked: bool =False, track_offset: float =0.5, draggable: bool =True, **kwargs) -> Union[int, str]: +def node(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', drag_callback: Callable =None, drop_callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', tracked: bool =False, track_offset: float =0.5, draggable: bool =True, **kwargs) -> Union[int, str]: """ Adds a node to a node editor. Args: @@ -2156,11 +2180,11 @@ def node(*, label: str =None, user_data: Any =None, use_internal_label: bool =Tr show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom draggable (bool, optional): Allow node to be draggable. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -2169,7 +2193,10 @@ def node(*, label: str =None, user_data: Any =None, use_internal_label: bool =Tr if 'id' in kwargs.keys(): warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - widget = internal_dpg.add_node(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, parent=parent, before=before, payload_type=payload_type, drag_callback=drag_callback, drop_callback=drop_callback, show=show, pos=pos, filter_key=filter_key, delay_search=delay_search, tracked=tracked, track_offset=track_offset, draggable=draggable, **kwargs) + + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + widget = internal_dpg.add_node(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, parent=parent, before=before, payload_type=payload_type, drag_callback=drag_callback, drop_callback=drop_callback, show=show, pos=pos, filter_key=filter_key, tracked=tracked, track_offset=track_offset, draggable=draggable, **kwargs) internal_dpg.push_container_stack(widget) yield widget finally: @@ -2210,7 +2237,7 @@ def node_attribute(*, label: str =None, user_data: Any =None, use_internal_label internal_dpg.pop_container_stack() @contextmanager -def node_editor(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, height: int =0, parent: Union[int, str] =0, before: Union[int, str] =0, callback: Callable =None, show: bool =True, filter_key: str ='', delay_search: bool =False, tracked: bool =False, track_offset: float =0.5, delink_callback: Callable =None, menubar: bool =False, minimap: bool =False, minimap_location: int =2, **kwargs) -> Union[int, str]: +def node_editor(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, height: int =0, parent: Union[int, str] =0, before: Union[int, str] =0, callback: Callable =None, show: bool =True, filter_key: str ='', tracked: bool =False, track_offset: float =0.5, delink_callback: Callable =None, menubar: bool =False, minimap: bool =False, minimap_location: int =2, **kwargs) -> Union[int, str]: """ Adds a node editor. Args: @@ -2225,7 +2252,6 @@ def node_editor(*, label: str =None, user_data: Any =None, use_internal_label: b callback (Callable, optional): Registers a callback. show (bool, optional): Attempt to render widget. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom delink_callback (Callable, optional): Callback ran when a link is detached. @@ -2233,6 +2259,7 @@ def node_editor(*, label: str =None, user_data: Any =None, use_internal_label: b minimap (bool, optional): Shows or hides the Minimap. New in 1.6. minimap_location (int, optional): mvNodeMiniMap_Location_* constants. New in 1.6. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -2241,14 +2268,17 @@ def node_editor(*, label: str =None, user_data: Any =None, use_internal_label: b if 'id' in kwargs.keys(): warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - widget = internal_dpg.add_node_editor(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, height=height, parent=parent, before=before, callback=callback, show=show, filter_key=filter_key, delay_search=delay_search, tracked=tracked, track_offset=track_offset, delink_callback=delink_callback, menubar=menubar, minimap=minimap, minimap_location=minimap_location, **kwargs) + + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + widget = internal_dpg.add_node_editor(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, height=height, parent=parent, before=before, callback=callback, show=show, filter_key=filter_key, tracked=tracked, track_offset=track_offset, delink_callback=delink_callback, menubar=menubar, minimap=minimap, minimap_location=minimap_location, **kwargs) internal_dpg.push_container_stack(widget) yield widget finally: internal_dpg.pop_container_stack() @contextmanager -def plot(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, height: int =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', callback: Callable =None, drag_callback: Callable =None, drop_callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', delay_search: bool =False, tracked: bool =False, track_offset: float =0.5, no_title: bool =False, no_menus: bool =False, no_box_select: bool =False, no_mouse_pos: bool =False, query: bool =False, query_color: Union[List[float], Tuple[float, ...]] =(0, 255, 0, 255), min_query_rects: int =1, max_query_rects: int =1, crosshairs: bool =False, equal_aspects: bool =False, no_inputs: bool =False, no_frame: bool =False, use_local_time: bool =False, use_ISO8601: bool =False, use_24hour_clock: bool =False, pan_button: int =internal_dpg.mvMouseButton_Left, pan_mod: int =internal_dpg.mvKey_None, context_menu_button: int =internal_dpg.mvMouseButton_Right, fit_button: int =internal_dpg.mvMouseButton_Left, box_select_button: int =internal_dpg.mvMouseButton_Right, box_select_mod: int =internal_dpg.mvKey_None, box_select_cancel_button: int =internal_dpg.mvMouseButton_Left, query_toggle_mod: int =internal_dpg.mvKey_ModCtrl, horizontal_mod: int =internal_dpg.mvKey_ModAlt, vertical_mod: int =internal_dpg.mvKey_ModShift, override_mod: int =internal_dpg.mvKey_ModCtrl, zoom_mod: int =internal_dpg.mvKey_None, zoom_rate: int =0.1, **kwargs) -> Union[int, str]: +def plot(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, height: int =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', callback: Callable =None, drag_callback: Callable =None, drop_callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', tracked: bool =False, track_offset: float =0.5, no_title: bool =False, no_menus: bool =False, no_box_select: bool =False, no_mouse_pos: bool =False, query: bool =False, query_color: Union[List[float], Tuple[float, ...]] =(0, 255, 0, 255), min_query_rects: int =1, max_query_rects: int =1, crosshairs: bool =False, equal_aspects: bool =False, no_inputs: bool =False, no_frame: bool =False, use_local_time: bool =False, use_ISO8601: bool =False, use_24hour_clock: bool =False, pan_button: int =internal_dpg.mvMouseButton_Left, pan_mod: int =internal_dpg.mvKey_None, context_menu_button: int =internal_dpg.mvMouseButton_Right, fit_button: int =internal_dpg.mvMouseButton_Left, box_select_button: int =internal_dpg.mvMouseButton_Right, box_select_mod: int =internal_dpg.mvKey_None, box_select_cancel_button: int =internal_dpg.mvMouseButton_Left, query_toggle_mod: int =internal_dpg.mvKey_ModCtrl, horizontal_mod: int =internal_dpg.mvKey_ModAlt, vertical_mod: int =internal_dpg.mvKey_ModShift, override_mod: int =internal_dpg.mvKey_ModCtrl, zoom_mod: int =internal_dpg.mvKey_None, zoom_rate: int =0.1, **kwargs) -> Union[int, str]: """ Adds a plot which is used to hold series, and can be drawn to with draw commands. For all _mod parameters use mvKey_ModX enums, or mvKey_ModDisabled to disable the modifier. Args: @@ -2268,7 +2298,6 @@ def plot(*, label: str =None, user_data: Any =None, use_internal_label: bool =Tr show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom no_title (bool, optional): the plot title will not be displayed @@ -2300,6 +2329,7 @@ def plot(*, label: str =None, user_data: Any =None, use_internal_label: bool =Tr zoom_mod (int, optional): optional modifier that must be held for scroll wheel zooming zoom_rate (int, optional): zoom rate for scroll (e.g. 0.1f = 10% plot range every scroll click); make negative to invert id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. no_highlight (bool, optional): (deprecated) Removed because not supported from the backend anymore. To control the highlighting of series use the same argument in `add_plot_legend` no_child (bool, optional): (deprecated) a child window region will not be used to capture mouse scroll (can boost performance for single ImGui window applications) anti_aliased (bool, optional): (deprecated) This feature was deprecated in ImPlot. To enable/disable anti_aliasing use `dpg.configure_app()` with the `anti_aliasing` parameters. @@ -2314,6 +2344,9 @@ def plot(*, label: str =None, user_data: Any =None, use_internal_label: bool =Tr warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + if 'no_highlight' in kwargs.keys(): warnings.warn('no_highlight keyword removed', DeprecationWarning, 2) kwargs.pop('no_highlight', None) @@ -2333,7 +2366,7 @@ def plot(*, label: str =None, user_data: Any =None, use_internal_label: bool =Tr if 'query_mod' in kwargs.keys(): warnings.warn('query_mod keyword removed', DeprecationWarning, 2) kwargs.pop('query_mod', None) - widget = internal_dpg.add_plot(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, height=height, indent=indent, parent=parent, before=before, payload_type=payload_type, callback=callback, drag_callback=drag_callback, drop_callback=drop_callback, show=show, pos=pos, filter_key=filter_key, delay_search=delay_search, tracked=tracked, track_offset=track_offset, no_title=no_title, no_menus=no_menus, no_box_select=no_box_select, no_mouse_pos=no_mouse_pos, query=query, query_color=query_color, min_query_rects=min_query_rects, max_query_rects=max_query_rects, crosshairs=crosshairs, equal_aspects=equal_aspects, no_inputs=no_inputs, no_frame=no_frame, use_local_time=use_local_time, use_ISO8601=use_ISO8601, use_24hour_clock=use_24hour_clock, pan_button=pan_button, pan_mod=pan_mod, context_menu_button=context_menu_button, fit_button=fit_button, box_select_button=box_select_button, box_select_mod=box_select_mod, box_select_cancel_button=box_select_cancel_button, query_toggle_mod=query_toggle_mod, horizontal_mod=horizontal_mod, vertical_mod=vertical_mod, override_mod=override_mod, zoom_mod=zoom_mod, zoom_rate=zoom_rate, **kwargs) + widget = internal_dpg.add_plot(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, height=height, indent=indent, parent=parent, before=before, payload_type=payload_type, callback=callback, drag_callback=drag_callback, drop_callback=drop_callback, show=show, pos=pos, filter_key=filter_key, tracked=tracked, track_offset=track_offset, no_title=no_title, no_menus=no_menus, no_box_select=no_box_select, no_mouse_pos=no_mouse_pos, query=query, query_color=query_color, min_query_rects=min_query_rects, max_query_rects=max_query_rects, crosshairs=crosshairs, equal_aspects=equal_aspects, no_inputs=no_inputs, no_frame=no_frame, use_local_time=use_local_time, use_ISO8601=use_ISO8601, use_24hour_clock=use_24hour_clock, pan_button=pan_button, pan_mod=pan_mod, context_menu_button=context_menu_button, fit_button=fit_button, box_select_button=box_select_button, box_select_mod=box_select_mod, box_select_cancel_button=box_select_cancel_button, query_toggle_mod=query_toggle_mod, horizontal_mod=horizontal_mod, vertical_mod=vertical_mod, override_mod=override_mod, zoom_mod=zoom_mod, zoom_rate=zoom_rate, **kwargs) internal_dpg.push_container_stack(widget) yield widget finally: @@ -2419,7 +2452,7 @@ def stage(*, label: str =None, user_data: Any =None, use_internal_label: bool =T internal_dpg.pop_container_stack() @contextmanager -def subplots(rows : int, columns : int, *, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, height: int =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', delay_search: bool =False, tracked: bool =False, track_offset: float =0.5, row_ratios: Union[List[float], Tuple[float, ...]] =[], column_ratios: Union[List[float], Tuple[float, ...]] =[], no_title: bool =False, no_menus: bool =False, no_resize: bool =False, no_align: bool =False, share_series: bool =False, link_rows: bool =False, link_columns: bool =False, link_all_x: bool =False, link_all_y: bool =False, column_major: bool =False, **kwargs) -> Union[int, str]: +def subplots(rows : int, columns : int, *, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, height: int =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', tracked: bool =False, track_offset: float =0.5, row_ratios: Union[List[float], Tuple[float, ...]] =[], column_ratios: Union[List[float], Tuple[float, ...]] =[], no_title: bool =False, no_menus: bool =False, no_resize: bool =False, no_align: bool =False, share_series: bool =False, link_rows: bool =False, link_columns: bool =False, link_all_x: bool =False, link_all_y: bool =False, column_major: bool =False, **kwargs) -> Union[int, str]: """ Adds a collection of plots. Args: @@ -2438,7 +2471,6 @@ def subplots(rows : int, columns : int, *, label: str =None, user_data: Any =Non show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom row_ratios (Union[List[float], Tuple[float, ...]], optional): @@ -2454,6 +2486,7 @@ def subplots(rows : int, columns : int, *, label: str =None, user_data: Any =Non link_all_y (bool, optional): link the y-axis limits in every plot in the subplot (does not apply to auxiliary y-axes) column_major (bool, optional): subplots are added in column major order instead of the default row major order id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -2462,7 +2495,38 @@ def subplots(rows : int, columns : int, *, label: str =None, user_data: Any =Non if 'id' in kwargs.keys(): warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - widget = internal_dpg.add_subplots(rows, columns, label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, height=height, indent=indent, parent=parent, before=before, callback=callback, show=show, pos=pos, filter_key=filter_key, delay_search=delay_search, tracked=tracked, track_offset=track_offset, row_ratios=row_ratios, column_ratios=column_ratios, no_title=no_title, no_menus=no_menus, no_resize=no_resize, no_align=no_align, share_series=share_series, link_rows=link_rows, link_columns=link_columns, link_all_x=link_all_x, link_all_y=link_all_y, column_major=column_major, **kwargs) + + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + widget = internal_dpg.add_subplots(rows, columns, label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, height=height, indent=indent, parent=parent, before=before, callback=callback, show=show, pos=pos, filter_key=filter_key, tracked=tracked, track_offset=track_offset, row_ratios=row_ratios, column_ratios=column_ratios, no_title=no_title, no_menus=no_menus, no_resize=no_resize, no_align=no_align, share_series=share_series, link_rows=link_rows, link_columns=link_columns, link_all_x=link_all_x, link_all_y=link_all_y, column_major=column_major, **kwargs) + internal_dpg.push_container_stack(widget) + yield widget + finally: + internal_dpg.pop_container_stack() + +@contextmanager +def synced_tables(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, parent: Union[int, str] =0, before: Union[int, str] =0, show: bool =True, filter_key: str ='', **kwargs) -> Union[int, str]: + """ Links all tables that are immediate children of this container so that they share their state (mostly column sizes). Other children are rendered as is. This is an experimental feature, use with caution. + + Args: + label (str, optional): Overrides 'name' as label. + user_data (Any, optional): User data for callbacks + use_internal_label (bool, optional): Use generated internal label instead of user specified (appends ### uuid). + tag (Union[int, str], optional): Unique id used to programmatically refer to the item.If label is unused this will be the label. + parent (Union[int, str], optional): Parent to add this item to. (runtime adding) + before (Union[int, str], optional): This item will be displayed before the specified item in the parent. + show (bool, optional): Attempt to render widget. + filter_key (str, optional): Used by filter widget. + id (Union[int, str], optional): (deprecated) + Yields: + Union[int, str] + """ + try: + + if 'id' in kwargs.keys(): + warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) + tag=kwargs['id'] + widget = internal_dpg.add_synced_tables(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, parent=parent, before=before, show=show, filter_key=filter_key, **kwargs) internal_dpg.push_container_stack(widget) yield widget finally: @@ -2484,13 +2548,13 @@ def tab(*, label: str =None, user_data: Any =None, use_internal_label: bool =Tru drop_callback (Callable, optional): Registers a drop callback for drag and drop. show (bool, optional): Attempt to render widget. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom closable (bool, optional): Creates a button on the tab that can hide the tab. no_tooltip (bool, optional): Disable tooltip for the given tab. order_mode (int, optional): set using a constant: mvTabOrder_Reorderable: allows reordering, mvTabOrder_Fixed: fixed ordering, mvTabOrder_Leading: adds tab to front, mvTabOrder_Trailing: adds tab to back id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -2499,14 +2563,17 @@ def tab(*, label: str =None, user_data: Any =None, use_internal_label: bool =Tru if 'id' in kwargs.keys(): warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - widget = internal_dpg.add_tab(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, before=before, payload_type=payload_type, drop_callback=drop_callback, show=show, filter_key=filter_key, delay_search=delay_search, tracked=tracked, track_offset=track_offset, closable=closable, no_tooltip=no_tooltip, order_mode=order_mode, **kwargs) + + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + widget = internal_dpg.add_tab(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, before=before, payload_type=payload_type, drop_callback=drop_callback, show=show, filter_key=filter_key, tracked=tracked, track_offset=track_offset, closable=closable, no_tooltip=no_tooltip, order_mode=order_mode, **kwargs) internal_dpg.push_container_stack(widget) yield widget finally: internal_dpg.pop_container_stack() @contextmanager -def tab_bar(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', delay_search: bool =False, tracked: bool =False, track_offset: float =0.5, reorderable: bool =False, **kwargs) -> Union[int, str]: +def tab_bar(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', tracked: bool =False, track_offset: float =0.5, reorderable: bool =False, **kwargs) -> Union[int, str]: """ Adds a tab bar. Args: @@ -2521,11 +2588,11 @@ def tab_bar(*, label: str =None, user_data: Any =None, use_internal_label: bool show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom reorderable (bool, optional): Allows for the user to change the order of the tabs. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -2534,14 +2601,17 @@ def tab_bar(*, label: str =None, user_data: Any =None, use_internal_label: bool if 'id' in kwargs.keys(): warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - widget = internal_dpg.add_tab_bar(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, before=before, callback=callback, show=show, pos=pos, filter_key=filter_key, delay_search=delay_search, tracked=tracked, track_offset=track_offset, reorderable=reorderable, **kwargs) + + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + widget = internal_dpg.add_tab_bar(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, before=before, callback=callback, show=show, pos=pos, filter_key=filter_key, tracked=tracked, track_offset=track_offset, reorderable=reorderable, **kwargs) internal_dpg.push_container_stack(widget) yield widget finally: internal_dpg.pop_container_stack() @contextmanager -def table(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, height: int =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, source: Union[int, str] =0, callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', delay_search: bool =False, header_row: bool =True, clipper: bool =False, inner_width: int =0, policy: int =0, freeze_rows: int =0, freeze_columns: int =0, sort_multi: bool =False, sort_tristate: bool =False, resizable: bool =False, reorderable: bool =False, hideable: bool =False, sortable: bool =False, context_menu_in_body: bool =False, row_background: bool =False, borders_innerH: bool =False, borders_outerH: bool =False, borders_innerV: bool =False, borders_outerV: bool =False, no_host_extendX: bool =False, no_host_extendY: bool =False, no_keep_columns_visible: bool =False, precise_widths: bool =False, no_clip: bool =False, pad_outerX: bool =False, no_pad_outerX: bool =False, no_pad_innerX: bool =False, scrollX: bool =False, scrollY: bool =False, no_saved_settings: bool =False, **kwargs) -> Union[int, str]: +def table(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, height: int =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, source: Union[int, str] =0, callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', header_row: bool =True, clipper: bool =False, inner_width: int =0, policy: int =0, freeze_rows: int =0, freeze_columns: int =0, sort_multi: bool =False, sort_tristate: bool =False, resizable: bool =False, reorderable: bool =False, hideable: bool =False, sortable: bool =False, context_menu_in_body: bool =False, row_background: bool =False, borders_innerH: bool =False, borders_outerH: bool =False, borders_innerV: bool =False, borders_outerV: bool =False, no_host_extendX: bool =False, no_host_extendY: bool =False, no_keep_columns_visible: bool =False, precise_widths: bool =False, no_clip: bool =False, pad_outerX: bool =False, no_pad_outerX: bool =False, no_pad_innerX: bool =False, scrollX: bool =False, scrollY: bool =False, no_saved_settings: bool =False, **kwargs) -> Union[int, str]: """ Adds a table. Args: @@ -2559,7 +2629,6 @@ def table(*, label: str =None, user_data: Any =None, use_internal_label: bool =T show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. header_row (bool, optional): show headers at the top of the columns clipper (bool, optional): Use clipper (rows must be same height). inner_width (int, optional): @@ -2590,6 +2659,7 @@ def table(*, label: str =None, user_data: Any =None, use_internal_label: bool =T scrollY (bool, optional): Enable vertical scrolling. no_saved_settings (bool, optional): Never load/save settings in .ini file. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -2598,7 +2668,10 @@ def table(*, label: str =None, user_data: Any =None, use_internal_label: bool =T if 'id' in kwargs.keys(): warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - widget = internal_dpg.add_table(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, height=height, indent=indent, parent=parent, before=before, source=source, callback=callback, show=show, pos=pos, filter_key=filter_key, delay_search=delay_search, header_row=header_row, clipper=clipper, inner_width=inner_width, policy=policy, freeze_rows=freeze_rows, freeze_columns=freeze_columns, sort_multi=sort_multi, sort_tristate=sort_tristate, resizable=resizable, reorderable=reorderable, hideable=hideable, sortable=sortable, context_menu_in_body=context_menu_in_body, row_background=row_background, borders_innerH=borders_innerH, borders_outerH=borders_outerH, borders_innerV=borders_innerV, borders_outerV=borders_outerV, no_host_extendX=no_host_extendX, no_host_extendY=no_host_extendY, no_keep_columns_visible=no_keep_columns_visible, precise_widths=precise_widths, no_clip=no_clip, pad_outerX=pad_outerX, no_pad_outerX=no_pad_outerX, no_pad_innerX=no_pad_innerX, scrollX=scrollX, scrollY=scrollY, no_saved_settings=no_saved_settings, **kwargs) + + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + widget = internal_dpg.add_table(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, height=height, indent=indent, parent=parent, before=before, source=source, callback=callback, show=show, pos=pos, filter_key=filter_key, header_row=header_row, clipper=clipper, inner_width=inner_width, policy=policy, freeze_rows=freeze_rows, freeze_columns=freeze_columns, sort_multi=sort_multi, sort_tristate=sort_tristate, resizable=resizable, reorderable=reorderable, hideable=hideable, sortable=sortable, context_menu_in_body=context_menu_in_body, row_background=row_background, borders_innerH=borders_innerH, borders_outerH=borders_outerH, borders_innerV=borders_innerV, borders_outerV=borders_outerV, no_host_extendX=no_host_extendX, no_host_extendY=no_host_extendY, no_keep_columns_visible=no_keep_columns_visible, precise_widths=precise_widths, no_clip=no_clip, pad_outerX=pad_outerX, no_pad_outerX=no_pad_outerX, no_pad_innerX=no_pad_innerX, scrollX=scrollX, scrollY=scrollY, no_saved_settings=no_saved_settings, **kwargs) internal_dpg.push_container_stack(widget) yield widget finally: @@ -2797,7 +2870,7 @@ def tooltip(parent : Union[int, str], *, label: str =None, user_data: Any =None, internal_dpg.pop_container_stack() @contextmanager -def tree_node(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', drag_callback: Callable =None, drop_callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', delay_search: bool =False, tracked: bool =False, track_offset: float =0.5, default_open: bool =False, open_on_double_click: bool =False, open_on_arrow: bool =False, leaf: bool =False, bullet: bool =False, selectable: bool =False, span_text_width: bool =False, span_full_width: bool =False, **kwargs) -> Union[int, str]: +def tree_node(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', drag_callback: Callable =None, drop_callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', tracked: bool =False, track_offset: float =0.5, default_open: bool =False, open_on_double_click: bool =False, open_on_arrow: bool =False, leaf: bool =False, bullet: bool =False, selectable: bool =False, span_text_width: bool =False, span_full_width: bool =False, **kwargs) -> Union[int, str]: """ Adds a tree node to add items to. Args: @@ -2814,7 +2887,6 @@ def tree_node(*, label: str =None, user_data: Any =None, use_internal_label: boo show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom default_open (bool, optional): Sets the tree node open by default. @@ -2826,6 +2898,7 @@ def tree_node(*, label: str =None, user_data: Any =None, use_internal_label: boo span_text_width (bool, optional): Makes hitbox and highlight only cover the label. span_full_width (bool, optional): Extend hit box to the left-most and right-most edges (cover the indent area). id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -2834,7 +2907,10 @@ def tree_node(*, label: str =None, user_data: Any =None, use_internal_label: boo if 'id' in kwargs.keys(): warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - widget = internal_dpg.add_tree_node(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, before=before, payload_type=payload_type, drag_callback=drag_callback, drop_callback=drop_callback, show=show, pos=pos, filter_key=filter_key, delay_search=delay_search, tracked=tracked, track_offset=track_offset, default_open=default_open, open_on_double_click=open_on_double_click, open_on_arrow=open_on_arrow, leaf=leaf, bullet=bullet, selectable=selectable, span_text_width=span_text_width, span_full_width=span_full_width, **kwargs) + + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + widget = internal_dpg.add_tree_node(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, before=before, payload_type=payload_type, drag_callback=drag_callback, drop_callback=drop_callback, show=show, pos=pos, filter_key=filter_key, tracked=tracked, track_offset=track_offset, default_open=default_open, open_on_double_click=open_on_double_click, open_on_arrow=open_on_arrow, leaf=leaf, bullet=bullet, selectable=selectable, span_text_width=span_text_width, span_full_width=span_full_width, **kwargs) internal_dpg.push_container_stack(widget) yield widget finally: @@ -2865,7 +2941,7 @@ def value_registry(*, label: str =None, user_data: Any =None, use_internal_label internal_dpg.pop_container_stack() @contextmanager -def viewport_drawlist(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, show: bool =True, filter_key: str ='', delay_search: bool =False, front: bool =True, **kwargs) -> Union[int, str]: +def viewport_drawlist(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, show: bool =True, filter_key: str ='', front: bool =True, **kwargs) -> Union[int, str]: """ A container that is used to present draw items or layers directly to the viewport. By default this will draw to the back of the viewport. Layers and draw items should be added to this widget as children. Args: @@ -2875,9 +2951,9 @@ def viewport_drawlist(*, label: str =None, user_data: Any =None, use_internal_la tag (Union[int, str], optional): Unique id used to programmatically refer to the item.If label is unused this will be the label. show (bool, optional): Attempt to render widget. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. front (bool, optional): Draws to the front of the view port instead of the back. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -2886,14 +2962,17 @@ def viewport_drawlist(*, label: str =None, user_data: Any =None, use_internal_la if 'id' in kwargs.keys(): warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - widget = internal_dpg.add_viewport_drawlist(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, show=show, filter_key=filter_key, delay_search=delay_search, front=front, **kwargs) + + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + widget = internal_dpg.add_viewport_drawlist(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, show=show, filter_key=filter_key, front=front, **kwargs) internal_dpg.push_container_stack(widget) yield widget finally: internal_dpg.pop_container_stack() @contextmanager -def viewport_menu_bar(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, indent: int =-1, parent: Union[int, str] =0, show: bool =True, delay_search: bool =False, **kwargs) -> Union[int, str]: +def viewport_menu_bar(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, indent: int =-1, parent: Union[int, str] =0, show: bool =True, **kwargs) -> Union[int, str]: """ Adds a menubar to the viewport. Args: @@ -2904,8 +2983,8 @@ def viewport_menu_bar(*, label: str =None, user_data: Any =None, use_internal_la indent (int, optional): Offsets the widget to the right the specified number multiplied by the indent style. parent (Union[int, str], optional): Parent to add this item to. (runtime adding) show (bool, optional): Attempt to render widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -2914,14 +2993,17 @@ def viewport_menu_bar(*, label: str =None, user_data: Any =None, use_internal_la if 'id' in kwargs.keys(): warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - widget = internal_dpg.add_viewport_menu_bar(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, show=show, delay_search=delay_search, **kwargs) + + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + widget = internal_dpg.add_viewport_menu_bar(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, show=show, **kwargs) internal_dpg.push_container_stack(widget) yield widget finally: internal_dpg.pop_container_stack() @contextmanager -def window(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, height: int =0, indent: int =-1, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], delay_search: bool =False, min_size: Union[List[int], Tuple[int, ...]] =[100, 100], max_size: Union[List[int], Tuple[int, ...]] =[30000, 30000], menubar: bool =False, collapsed: bool =False, autosize: bool =False, no_resize: bool =False, unsaved_document: bool =False, no_title_bar: bool =False, no_move: bool =False, no_scrollbar: bool =False, no_collapse: bool =False, horizontal_scrollbar: bool =False, no_focus_on_appearing: bool =False, no_bring_to_front_on_focus: bool =False, no_close: bool =False, no_background: bool =False, modal: bool =False, popup: bool =False, no_saved_settings: bool =False, no_open_over_existing_popup: bool =True, no_scroll_with_mouse: bool =False, on_close: Callable =None, **kwargs) -> Union[int, str]: +def window(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, height: int =0, indent: int =-1, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], min_size: Union[List[int], Tuple[int, ...]] =[100, 100], max_size: Union[List[int], Tuple[int, ...]] =[30000, 30000], menubar: bool =False, collapsed: bool =False, autosize: bool =False, no_resize: bool =False, unsaved_document: bool =False, no_title_bar: bool =False, no_move: bool =False, no_scrollbar: bool =False, no_collapse: bool =False, horizontal_scrollbar: bool =False, no_focus_on_appearing: bool =False, no_bring_to_front_on_focus: bool =False, no_close: bool =False, no_background: bool =False, modal: bool =False, popup: bool =False, no_saved_settings: bool =False, no_open_over_existing_popup: bool =True, no_scroll_with_mouse: bool =False, on_close: Callable =None, **kwargs) -> Union[int, str]: """ Creates a new window for following items to be added to. Args: @@ -2934,7 +3016,6 @@ def window(*, label: str =None, user_data: Any =None, use_internal_label: bool = indent (int, optional): Offsets the widget to the right the specified number multiplied by the indent style. show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. min_size (Union[List[int], Tuple[int, ...]], optional): Minimum window size. max_size (Union[List[int], Tuple[int, ...]], optional): Maximum window size. menubar (bool, optional): Shows or hides the menubar. @@ -2958,6 +3039,7 @@ def window(*, label: str =None, user_data: Any =None, use_internal_label: bool = no_scroll_with_mouse (bool, optional): Disable user vertically scrolling with mouse wheel. on_close (Callable, optional): Callback ran when window is closed. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Yields: Union[int, str] """ @@ -2966,7 +3048,10 @@ def window(*, label: str =None, user_data: Any =None, use_internal_label: bool = if 'id' in kwargs.keys(): warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - widget = internal_dpg.add_window(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, height=height, indent=indent, show=show, pos=pos, delay_search=delay_search, min_size=min_size, max_size=max_size, menubar=menubar, collapsed=collapsed, autosize=autosize, no_resize=no_resize, unsaved_document=unsaved_document, no_title_bar=no_title_bar, no_move=no_move, no_scrollbar=no_scrollbar, no_collapse=no_collapse, horizontal_scrollbar=horizontal_scrollbar, no_focus_on_appearing=no_focus_on_appearing, no_bring_to_front_on_focus=no_bring_to_front_on_focus, no_close=no_close, no_background=no_background, modal=modal, popup=popup, no_saved_settings=no_saved_settings, no_open_over_existing_popup=no_open_over_existing_popup, no_scroll_with_mouse=no_scroll_with_mouse, on_close=on_close, **kwargs) + + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + widget = internal_dpg.add_window(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, height=height, indent=indent, show=show, pos=pos, min_size=min_size, max_size=max_size, menubar=menubar, collapsed=collapsed, autosize=autosize, no_resize=no_resize, unsaved_document=unsaved_document, no_title_bar=no_title_bar, no_move=no_move, no_scrollbar=no_scrollbar, no_collapse=no_collapse, horizontal_scrollbar=horizontal_scrollbar, no_focus_on_appearing=no_focus_on_appearing, no_bring_to_front_on_focus=no_bring_to_front_on_focus, no_close=no_close, no_background=no_background, modal=modal, popup=popup, no_saved_settings=no_saved_settings, no_open_over_existing_popup=no_open_over_existing_popup, no_scroll_with_mouse=no_scroll_with_mouse, on_close=on_close, **kwargs) internal_dpg.push_container_stack(widget) yield widget finally: @@ -3323,7 +3408,7 @@ def add_checkbox(*, label: str =None, user_data: Any =None, use_internal_label: return internal_dpg.add_checkbox(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, before=before, source=source, payload_type=payload_type, callback=callback, drag_callback=drag_callback, drop_callback=drop_callback, show=show, enabled=enabled, pos=pos, filter_key=filter_key, tracked=tracked, track_offset=track_offset, default_value=default_value, **kwargs) -def add_child_window(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, height: int =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', drop_callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', delay_search: bool =False, tracked: bool =False, track_offset: float =0.5, border: bool =True, autosize_x: bool =False, autosize_y: bool =False, no_scrollbar: bool =False, horizontal_scrollbar: bool =False, menubar: bool =False, no_scroll_with_mouse: bool =False, flattened_navigation: bool =True, always_use_window_padding: bool =False, resizable_x: bool =False, resizable_y: bool =False, always_auto_resize: bool =False, frame_style: bool =False, auto_resize_x: bool =False, auto_resize_y: bool =False, **kwargs) -> Union[int, str]: +def add_child_window(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, height: int =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', drop_callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', tracked: bool =False, track_offset: float =0.5, border: bool =True, autosize_x: bool =False, autosize_y: bool =False, no_scrollbar: bool =False, horizontal_scrollbar: bool =False, menubar: bool =False, no_scroll_with_mouse: bool =False, flattened_navigation: bool =True, always_use_window_padding: bool =False, resizable_x: bool =False, resizable_y: bool =False, always_auto_resize: bool =False, frame_style: bool =False, auto_resize_x: bool =False, auto_resize_y: bool =False, **kwargs) -> Union[int, str]: """ Adds an embedded child window. Will show scrollbars when items do not fit. About using auto_resize/resizable flags: size measurement for a given axis is only performed when the child window is within visible boundaries, or is just appearing and it won't update its auto-size while clipped. While not perfect, it is a better default behavior as the always-on performance gain is more valuable than the occasional 'resizing after becoming visible again' glitch. You may also use always_auto_resize to force an update even when child window is not in view. However doing so will degrade performance. Remember that combining both auto_resize_x and auto_resize_y defeats purpose of a scrolling region and is NOT recommended. Args: @@ -3341,7 +3426,6 @@ def add_child_window(*, label: str =None, user_data: Any =None, use_internal_lab show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom border (bool, optional): Shows/Hides the border around the sides. @@ -3360,6 +3444,7 @@ def add_child_window(*, label: str =None, user_data: Any =None, use_internal_lab auto_resize_x (bool, optional): Enable auto-resizing width based on child content. Read 'IMPORTANT: Size measurement' details above. auto_resize_y (bool, optional): Enable auto-resizing height based on child content. Read 'IMPORTANT: Size measurement' details above. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -3368,9 +3453,12 @@ def add_child_window(*, label: str =None, user_data: Any =None, use_internal_lab warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - return internal_dpg.add_child_window(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, height=height, indent=indent, parent=parent, before=before, payload_type=payload_type, drop_callback=drop_callback, show=show, pos=pos, filter_key=filter_key, delay_search=delay_search, tracked=tracked, track_offset=track_offset, border=border, autosize_x=autosize_x, autosize_y=autosize_y, no_scrollbar=no_scrollbar, horizontal_scrollbar=horizontal_scrollbar, menubar=menubar, no_scroll_with_mouse=no_scroll_with_mouse, flattened_navigation=flattened_navigation, always_use_window_padding=always_use_window_padding, resizable_x=resizable_x, resizable_y=resizable_y, always_auto_resize=always_auto_resize, frame_style=frame_style, auto_resize_x=auto_resize_x, auto_resize_y=auto_resize_y, **kwargs) + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + + return internal_dpg.add_child_window(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, height=height, indent=indent, parent=parent, before=before, payload_type=payload_type, drop_callback=drop_callback, show=show, pos=pos, filter_key=filter_key, tracked=tracked, track_offset=track_offset, border=border, autosize_x=autosize_x, autosize_y=autosize_y, no_scrollbar=no_scrollbar, horizontal_scrollbar=horizontal_scrollbar, menubar=menubar, no_scroll_with_mouse=no_scroll_with_mouse, flattened_navigation=flattened_navigation, always_use_window_padding=always_use_window_padding, resizable_x=resizable_x, resizable_y=resizable_y, always_auto_resize=always_auto_resize, frame_style=frame_style, auto_resize_x=auto_resize_x, auto_resize_y=auto_resize_y, **kwargs) -def add_clipper(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, show: bool =True, delay_search: bool =False, **kwargs) -> Union[int, str]: +def add_clipper(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, show: bool =True, **kwargs) -> Union[int, str]: """ Helper to manually clip large list of items. Increases performance by not searching or drawing widgets outside of the clipped region. Args: @@ -3383,8 +3471,8 @@ def add_clipper(*, label: str =None, user_data: Any =None, use_internal_label: b parent (Union[int, str], optional): Parent to add this item to. (runtime adding) before (Union[int, str], optional): This item will be displayed before the specified item in the parent. show (bool, optional): Attempt to render widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -3393,9 +3481,12 @@ def add_clipper(*, label: str =None, user_data: Any =None, use_internal_label: b warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - return internal_dpg.add_clipper(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, indent=indent, parent=parent, before=before, show=show, delay_search=delay_search, **kwargs) + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) -def add_collapsing_header(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', drag_callback: Callable =None, drop_callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', delay_search: bool =False, tracked: bool =False, track_offset: float =0.5, closable: bool =False, default_open: bool =False, open_on_double_click: bool =False, open_on_arrow: bool =False, leaf: bool =False, bullet: bool =False, **kwargs) -> Union[int, str]: + return internal_dpg.add_clipper(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, indent=indent, parent=parent, before=before, show=show, **kwargs) + +def add_collapsing_header(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', drag_callback: Callable =None, drop_callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', tracked: bool =False, track_offset: float =0.5, closable: bool =False, default_open: bool =False, open_on_double_click: bool =False, open_on_arrow: bool =False, leaf: bool =False, bullet: bool =False, **kwargs) -> Union[int, str]: """ Adds a collapsing header to add items to. Must be closed with the end command. Args: @@ -3412,7 +3503,6 @@ def add_collapsing_header(*, label: str =None, user_data: Any =None, use_interna show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom closable (bool, optional): Adds the ability to hide this widget by pressing the (x) in the top right of widget. @@ -3422,6 +3512,7 @@ def add_collapsing_header(*, label: str =None, user_data: Any =None, use_interna leaf (bool, optional): No collapsing, no arrow (use as a convenience for leaf nodes). bullet (bool, optional): Display a bullet instead of arrow. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -3430,7 +3521,10 @@ def add_collapsing_header(*, label: str =None, user_data: Any =None, use_interna warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - return internal_dpg.add_collapsing_header(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, before=before, payload_type=payload_type, drag_callback=drag_callback, drop_callback=drop_callback, show=show, pos=pos, filter_key=filter_key, delay_search=delay_search, tracked=tracked, track_offset=track_offset, closable=closable, default_open=default_open, open_on_double_click=open_on_double_click, open_on_arrow=open_on_arrow, leaf=leaf, bullet=bullet, **kwargs) + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + + return internal_dpg.add_collapsing_header(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, before=before, payload_type=payload_type, drag_callback=drag_callback, drop_callback=drop_callback, show=show, pos=pos, filter_key=filter_key, tracked=tracked, track_offset=track_offset, closable=closable, default_open=default_open, open_on_double_click=open_on_double_click, open_on_arrow=open_on_arrow, leaf=leaf, bullet=bullet, **kwargs) def add_color_button(default_value : Union[List[int], Tuple[int, ...]] =(0, 0, 0, 255), *, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, height: int =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', callback: Callable =None, drag_callback: Callable =None, drop_callback: Callable =None, show: bool =True, enabled: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', tracked: bool =False, track_offset: float =0.5, no_alpha: bool =False, no_border: bool =False, no_drag_drop: bool =False, **kwargs) -> Union[int, str]: """ Adds a color button. @@ -3825,7 +3919,7 @@ def add_custom_series(x : Union[List[float], Tuple[float, ...]], y : Union[List[ return internal_dpg.add_custom_series(x, y, channel_count, label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, parent=parent, before=before, source=source, callback=callback, show=show, y1=y1, y2=y2, y3=y3, tooltip=tooltip, no_fit=no_fit, **kwargs) def add_date_picker(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', callback: Callable =None, drag_callback: Callable =None, drop_callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', tracked: bool =False, track_offset: float =0.5, default_value: dict ={'month_day': 14, 'year':20, 'month':5}, level: int =0, **kwargs) -> Union[int, str]: - """ Adds a data picker. + """ Adds a date picker. Args: label (str, optional): Overrides 'name' as label. @@ -4343,7 +4437,7 @@ def add_draw_node(*, label: str =None, user_data: Any =None, use_internal_label: return internal_dpg.add_draw_node(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, parent=parent, before=before, show=show, **kwargs) -def add_drawlist(width : int, height : int, *, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, parent: Union[int, str] =0, before: Union[int, str] =0, callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', delay_search: bool =False, tracked: bool =False, track_offset: float =0.5, **kwargs) -> Union[int, str]: +def add_drawlist(width : int, height : int, *, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, parent: Union[int, str] =0, before: Union[int, str] =0, callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', tracked: bool =False, track_offset: float =0.5, **kwargs) -> Union[int, str]: """ Adds a drawing canvas. Args: @@ -4359,10 +4453,10 @@ def add_drawlist(width : int, height : int, *, label: str =None, user_data: Any show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -4371,7 +4465,10 @@ def add_drawlist(width : int, height : int, *, label: str =None, user_data: Any warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - return internal_dpg.add_drawlist(width, height, label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, parent=parent, before=before, callback=callback, show=show, pos=pos, filter_key=filter_key, delay_search=delay_search, tracked=tracked, track_offset=track_offset, **kwargs) + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + + return internal_dpg.add_drawlist(width, height, label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, parent=parent, before=before, callback=callback, show=show, pos=pos, filter_key=filter_key, tracked=tracked, track_offset=track_offset, **kwargs) def add_dynamic_texture(width : int, height : int, default_value : Union[List[float], Tuple[float, ...]], *, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, parent: Union[int, str] =internal_dpg.mvReservedUUID_2, **kwargs) -> Union[int, str]: """ Adds a dynamic texture. @@ -4482,7 +4579,7 @@ def add_file_extension(extension : str, *, label: str =None, user_data: Any =Non return internal_dpg.add_file_extension(extension, label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, height=height, parent=parent, before=before, custom_text=custom_text, color=color, **kwargs) -def add_filter_set(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, show: bool =True, delay_search: bool =False, **kwargs) -> Union[int, str]: +def add_filter_set(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, show: bool =True, **kwargs) -> Union[int, str]: """ Helper to parse and apply text filters (e.g. aaaaa[, bbbbb][, ccccc]) Args: @@ -4495,8 +4592,8 @@ def add_filter_set(*, label: str =None, user_data: Any =None, use_internal_label parent (Union[int, str], optional): Parent to add this item to. (runtime adding) before (Union[int, str], optional): This item will be displayed before the specified item in the parent. show (bool, optional): Attempt to render widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -4505,7 +4602,10 @@ def add_filter_set(*, label: str =None, user_data: Any =None, use_internal_label warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - return internal_dpg.add_filter_set(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, indent=indent, parent=parent, before=before, show=show, delay_search=delay_search, **kwargs) + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + + return internal_dpg.add_filter_set(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, indent=indent, parent=parent, before=before, show=show, **kwargs) def add_float4_value(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, source: Union[int, str] =0, default_value: Union[List[float], Tuple[float, ...]] =(0.0, 0.0, 0.0, 0.0), parent: Union[int, str] =internal_dpg.mvReservedUUID_3, **kwargs) -> Union[int, str]: """ Adds a float4 value. @@ -4687,7 +4787,7 @@ def add_font_registry(*, label: str =None, user_data: Any =None, use_internal_la return internal_dpg.add_font_registry(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, show=show, **kwargs) -def add_group(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, height: int =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', drag_callback: Callable =None, drop_callback: Callable =None, show: bool =True, enabled: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', delay_search: bool =False, tracked: bool =False, track_offset: float =0.5, horizontal: bool =False, horizontal_spacing: float =-1, xoffset: float =0.0, **kwargs) -> Union[int, str]: +def add_group(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, height: int =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', drag_callback: Callable =None, drop_callback: Callable =None, show: bool =True, enabled: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', tracked: bool =False, track_offset: float =0.5, horizontal: bool =False, horizontal_spacing: float =-1, xoffset: float =0.0, **kwargs) -> Union[int, str]: """ Creates a group that other widgets can belong to. The group allows item commands to be issued for all of its members. Enable property acts in a special way enabling/disabling everything inside the group. (Use mvStyleVar_DisabledAlpha to edit colors within the disabled group.) @@ -4708,13 +4808,13 @@ def add_group(*, label: str =None, user_data: Any =None, use_internal_label: boo enabled (bool, optional): Turns off functionality of widget and applies the disabled theme. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom horizontal (bool, optional): Forces child widgets to be added in a horizontal layout. horizontal_spacing (float, optional): Spacing for the horizontal layout. xoffset (float, optional): Offset from containing window x item location within group. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -4723,7 +4823,10 @@ def add_group(*, label: str =None, user_data: Any =None, use_internal_label: boo warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - return internal_dpg.add_group(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, height=height, indent=indent, parent=parent, before=before, payload_type=payload_type, drag_callback=drag_callback, drop_callback=drop_callback, show=show, enabled=enabled, pos=pos, filter_key=filter_key, delay_search=delay_search, tracked=tracked, track_offset=track_offset, horizontal=horizontal, horizontal_spacing=horizontal_spacing, xoffset=xoffset, **kwargs) + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + + return internal_dpg.add_group(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, height=height, indent=indent, parent=parent, before=before, payload_type=payload_type, drag_callback=drag_callback, drop_callback=drop_callback, show=show, enabled=enabled, pos=pos, filter_key=filter_key, tracked=tracked, track_offset=track_offset, horizontal=horizontal, horizontal_spacing=horizontal_spacing, xoffset=xoffset, **kwargs) def add_handler_registry(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, show: bool =True, **kwargs) -> Union[int, str]: """ Adds a handler registry. @@ -5464,7 +5567,7 @@ def add_item_edited_handler(*, label: str =None, user_data: Any =None, use_inter return internal_dpg.add_item_edited_handler(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, parent=parent, callback=callback, show=show, **kwargs) -def add_item_focus_handler(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, parent: Union[int, str] =0, callback: Callable =None, show: bool =True, **kwargs) -> Union[int, str]: +def add_item_focus_handler(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, parent: Union[int, str] =0, callback: Callable =None, show: bool =True, event_type: int =None, **kwargs) -> Union[int, str]: """ Adds a focus handler. Args: @@ -5475,6 +5578,7 @@ def add_item_focus_handler(*, label: str =None, user_data: Any =None, use_intern parent (Union[int, str], optional): Parent to add this item to. (runtime adding) callback (Callable, optional): Registers a callback. show (bool, optional): Attempt to render widget. + event_type (int, optional): What kind of events to track: just got focus (mvEventType_Enter), currently having focus (mvEventType_On), lost focus (mvEventType_Leave). Can be a combination of these flags. Defaults to mvEventType_On. id (Union[int, str], optional): (deprecated) Returns: Union[int, str] @@ -5484,7 +5588,7 @@ def add_item_focus_handler(*, label: str =None, user_data: Any =None, use_intern warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - return internal_dpg.add_item_focus_handler(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, parent=parent, callback=callback, show=show, **kwargs) + return internal_dpg.add_item_focus_handler(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, parent=parent, callback=callback, show=show, event_type=event_type, **kwargs) def add_item_handler_registry(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, show: bool =True, **kwargs) -> Union[int, str]: """ Adds an item handler registry. @@ -5506,7 +5610,7 @@ def add_item_handler_registry(*, label: str =None, user_data: Any =None, use_int return internal_dpg.add_item_handler_registry(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, show=show, **kwargs) -def add_item_hover_handler(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, parent: Union[int, str] =0, callback: Callable =None, show: bool =True, **kwargs) -> Union[int, str]: +def add_item_hover_handler(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, parent: Union[int, str] =0, callback: Callable =None, show: bool =True, event_type: int =None, **kwargs) -> Union[int, str]: """ Adds a hover handler. Args: @@ -5517,6 +5621,7 @@ def add_item_hover_handler(*, label: str =None, user_data: Any =None, use_intern parent (Union[int, str], optional): Parent to add this item to. (runtime adding) callback (Callable, optional): Registers a callback. show (bool, optional): Attempt to render widget. + event_type (int, optional): What kind of events to track: mouse-in (mvEventType_Enter), mouse-over (mvEventType_On), mouse-out (mvEventType_Leave). Can be a combination of these flags. Defaults to mouse-over. id (Union[int, str], optional): (deprecated) Returns: Union[int, str] @@ -5526,7 +5631,7 @@ def add_item_hover_handler(*, label: str =None, user_data: Any =None, use_intern warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - return internal_dpg.add_item_hover_handler(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, parent=parent, callback=callback, show=show, **kwargs) + return internal_dpg.add_item_hover_handler(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, parent=parent, callback=callback, show=show, event_type=event_type, **kwargs) def add_item_resize_handler(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, parent: Union[int, str] =0, callback: Callable =None, show: bool =True, **kwargs) -> Union[int, str]: """ Adds a resize handler. @@ -5550,6 +5655,28 @@ def add_item_resize_handler(*, label: str =None, user_data: Any =None, use_inter return internal_dpg.add_item_resize_handler(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, parent=parent, callback=callback, show=show, **kwargs) +def add_item_scroll_handler(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, parent: Union[int, str] =0, callback: Callable =None, show: bool =True, **kwargs) -> Union[int, str]: + """ Adds a scroll handler. + + Args: + label (str, optional): Overrides 'name' as label. + user_data (Any, optional): User data for callbacks + use_internal_label (bool, optional): Use generated internal label instead of user specified (appends ### uuid). + tag (Union[int, str], optional): Unique id used to programmatically refer to the item.If label is unused this will be the label. + parent (Union[int, str], optional): Parent to add this item to. (runtime adding) + callback (Callable, optional): Registers a callback. + show (bool, optional): Attempt to render widget. + id (Union[int, str], optional): (deprecated) + Returns: + Union[int, str] + """ + + if 'id' in kwargs.keys(): + warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) + tag=kwargs['id'] + + return internal_dpg.add_item_scroll_handler(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, parent=parent, callback=callback, show=show, **kwargs) + def add_item_toggled_open_handler(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, parent: Union[int, str] =0, callback: Callable =None, show: bool =True, **kwargs) -> Union[int, str]: """ Adds a togged open handler. @@ -5768,7 +5895,7 @@ def add_listbox(items : Union[List[str], Tuple[str, ...]] =(), *, label: str =No return internal_dpg.add_listbox(items, label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, indent=indent, parent=parent, before=before, source=source, payload_type=payload_type, callback=callback, drag_callback=drag_callback, drop_callback=drop_callback, show=show, enabled=enabled, pos=pos, filter_key=filter_key, tracked=tracked, track_offset=track_offset, default_value=default_value, num_items=num_items, **kwargs) -def add_loading_indicator(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, height: int =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', drop_callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], style: int =0, circle_count: int =8, speed: float =1.0, radius: float =3.0, thickness: float =1.0, color: Union[List[int], Tuple[int, ...]] =(51, 51, 55, 255), secondary_color: Union[List[int], Tuple[int, ...]] =(29, 151, 236, 103), **kwargs) -> Union[int, str]: +def add_loading_indicator(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, height: int =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', drop_callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], style: int =0, circle_count: int =8, speed: float =1.0, radius: float =3.0, thickness: float =1.0, color: Union[List[int], Tuple[int, ...]] =None, secondary_color: Union[List[int], Tuple[int, ...]] =None, **kwargs) -> Union[int, str]: """ Adds a rotating animated loading symbol. Args: @@ -5785,13 +5912,13 @@ def add_loading_indicator(*, label: str =None, user_data: Any =None, use_interna drop_callback (Callable, optional): Registers a drop callback for drag and drop. show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. - style (int, optional): 0 is rotating dots style, 1 is rotating bar style. - circle_count (int, optional): Number of dots show if dots or size of circle if circle. - speed (float, optional): Speed the anamation will rotate. - radius (float, optional): Radius size of the loading indicator. - thickness (float, optional): Thickness of the circles or line. - color (Union[List[int], Tuple[int, ...]], optional): Color of the growing center circle. - secondary_color (Union[List[int], Tuple[int, ...]], optional): Background of the dots in dot mode. + style (int, optional): mvLoadInd_DottedCircle is rotating dots style, mvLoadInd_Ring is rotating bar style. + circle_count (int, optional): DottedCircle style: number of dots to show. + speed (float, optional): Speed with which the animation will rotate. + radius (float, optional): Scale factor for the loading indicator radius. The size of the indicator is determined by font size and this scale factor. + thickness (float, optional): Ring style: scale factor of line thickness; thickness=1 corresponds to line width being 1/8 of the ring diameter. + color (Union[List[int], Tuple[int, ...]], optional): Main color of the indicator. If omitted, the color for mvThemeCol_Button will be used. + secondary_color (Union[List[int], Tuple[int, ...]], optional): DottedCircle style: color of 'inactive' dots. If omitted, the color for mvThemeCol_ButtonHovered will be used. id (Union[int, str], optional): (deprecated) Returns: Union[int, str] @@ -5803,7 +5930,7 @@ def add_loading_indicator(*, label: str =None, user_data: Any =None, use_interna return internal_dpg.add_loading_indicator(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, height=height, indent=indent, parent=parent, before=before, payload_type=payload_type, drop_callback=drop_callback, show=show, pos=pos, style=style, circle_count=circle_count, speed=speed, radius=radius, thickness=thickness, color=color, secondary_color=secondary_color, **kwargs) -def add_menu(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', drop_callback: Callable =None, show: bool =True, enabled: bool =True, filter_key: str ='', delay_search: bool =False, tracked: bool =False, track_offset: float =0.5, **kwargs) -> Union[int, str]: +def add_menu(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', drop_callback: Callable =None, show: bool =True, enabled: bool =True, filter_key: str ='', tracked: bool =False, track_offset: float =0.5, **kwargs) -> Union[int, str]: """ Adds a menu to an existing menu bar. Args: @@ -5819,10 +5946,10 @@ def add_menu(*, label: str =None, user_data: Any =None, use_internal_label: bool show (bool, optional): Attempt to render widget. enabled (bool, optional): Turns off functionality of widget and applies the disabled theme. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -5831,9 +5958,12 @@ def add_menu(*, label: str =None, user_data: Any =None, use_internal_label: bool warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - return internal_dpg.add_menu(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, before=before, payload_type=payload_type, drop_callback=drop_callback, show=show, enabled=enabled, filter_key=filter_key, delay_search=delay_search, tracked=tracked, track_offset=track_offset, **kwargs) + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) -def add_menu_bar(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, indent: int =-1, parent: Union[int, str] =0, show: bool =True, delay_search: bool =False, **kwargs) -> Union[int, str]: + return internal_dpg.add_menu(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, before=before, payload_type=payload_type, drop_callback=drop_callback, show=show, enabled=enabled, filter_key=filter_key, tracked=tracked, track_offset=track_offset, **kwargs) + +def add_menu_bar(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, indent: int =-1, parent: Union[int, str] =0, show: bool =True, **kwargs) -> Union[int, str]: """ Adds a menu bar to a window. Args: @@ -5844,8 +5974,8 @@ def add_menu_bar(*, label: str =None, user_data: Any =None, use_internal_label: indent (int, optional): Offsets the widget to the right the specified number multiplied by the indent style. parent (Union[int, str], optional): Parent to add this item to. (runtime adding) show (bool, optional): Attempt to render widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -5854,7 +5984,10 @@ def add_menu_bar(*, label: str =None, user_data: Any =None, use_internal_label: warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - return internal_dpg.add_menu_bar(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, show=show, delay_search=delay_search, **kwargs) + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + + return internal_dpg.add_menu_bar(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, show=show, **kwargs) def add_menu_item(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', callback: Callable =None, drop_callback: Callable =None, show: bool =True, enabled: bool =True, filter_key: str ='', tracked: bool =False, track_offset: float =0.5, default_value: bool =False, shortcut: str ='', check: bool =False, **kwargs) -> Union[int, str]: """ Adds a menu item to an existing menu. Menu items act similar to selectables and has a bool value. When placed in a menu the checkmark will reflect its value. @@ -6056,7 +6189,7 @@ def add_mouse_wheel_handler(*, label: str =None, user_data: Any =None, use_inter return internal_dpg.add_mouse_wheel_handler(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, callback=callback, show=show, parent=parent, **kwargs) -def add_node(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', drag_callback: Callable =None, drop_callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', delay_search: bool =False, tracked: bool =False, track_offset: float =0.5, draggable: bool =True, **kwargs) -> Union[int, str]: +def add_node(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', drag_callback: Callable =None, drop_callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', tracked: bool =False, track_offset: float =0.5, draggable: bool =True, **kwargs) -> Union[int, str]: """ Adds a node to a node editor. Args: @@ -6072,11 +6205,11 @@ def add_node(*, label: str =None, user_data: Any =None, use_internal_label: bool show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom draggable (bool, optional): Allow node to be draggable. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -6085,7 +6218,10 @@ def add_node(*, label: str =None, user_data: Any =None, use_internal_label: bool warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - return internal_dpg.add_node(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, parent=parent, before=before, payload_type=payload_type, drag_callback=drag_callback, drop_callback=drop_callback, show=show, pos=pos, filter_key=filter_key, delay_search=delay_search, tracked=tracked, track_offset=track_offset, draggable=draggable, **kwargs) + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + + return internal_dpg.add_node(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, parent=parent, before=before, payload_type=payload_type, drag_callback=drag_callback, drop_callback=drop_callback, show=show, pos=pos, filter_key=filter_key, tracked=tracked, track_offset=track_offset, draggable=draggable, **kwargs) def add_node_attribute(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, show: bool =True, filter_key: str ='', tracked: bool =False, track_offset: float =0.5, attribute_type: int =0, shape: int =1, category: str ='general', **kwargs) -> Union[int, str]: """ Adds a node attribute to a node. @@ -6116,7 +6252,7 @@ def add_node_attribute(*, label: str =None, user_data: Any =None, use_internal_l return internal_dpg.add_node_attribute(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, before=before, show=show, filter_key=filter_key, tracked=tracked, track_offset=track_offset, attribute_type=attribute_type, shape=shape, category=category, **kwargs) -def add_node_editor(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, height: int =0, parent: Union[int, str] =0, before: Union[int, str] =0, callback: Callable =None, show: bool =True, filter_key: str ='', delay_search: bool =False, tracked: bool =False, track_offset: float =0.5, delink_callback: Callable =None, menubar: bool =False, minimap: bool =False, minimap_location: int =2, **kwargs) -> Union[int, str]: +def add_node_editor(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, height: int =0, parent: Union[int, str] =0, before: Union[int, str] =0, callback: Callable =None, show: bool =True, filter_key: str ='', tracked: bool =False, track_offset: float =0.5, delink_callback: Callable =None, menubar: bool =False, minimap: bool =False, minimap_location: int =2, **kwargs) -> Union[int, str]: """ Adds a node editor. Args: @@ -6131,7 +6267,6 @@ def add_node_editor(*, label: str =None, user_data: Any =None, use_internal_labe callback (Callable, optional): Registers a callback. show (bool, optional): Attempt to render widget. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom delink_callback (Callable, optional): Callback ran when a link is detached. @@ -6139,6 +6274,7 @@ def add_node_editor(*, label: str =None, user_data: Any =None, use_internal_labe minimap (bool, optional): Shows or hides the Minimap. New in 1.6. minimap_location (int, optional): mvNodeMiniMap_Location_* constants. New in 1.6. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -6147,7 +6283,10 @@ def add_node_editor(*, label: str =None, user_data: Any =None, use_internal_labe warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - return internal_dpg.add_node_editor(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, height=height, parent=parent, before=before, callback=callback, show=show, filter_key=filter_key, delay_search=delay_search, tracked=tracked, track_offset=track_offset, delink_callback=delink_callback, menubar=menubar, minimap=minimap, minimap_location=minimap_location, **kwargs) + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + + return internal_dpg.add_node_editor(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, height=height, parent=parent, before=before, callback=callback, show=show, filter_key=filter_key, tracked=tracked, track_offset=track_offset, delink_callback=delink_callback, menubar=menubar, minimap=minimap, minimap_location=minimap_location, **kwargs) def add_node_link(attr_1 : Union[int, str], attr_2 : Union[int, str], *, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, parent: Union[int, str] =0, show: bool =True, **kwargs) -> Union[int, str]: """ Adds a node link between 2 node attributes. @@ -6204,7 +6343,7 @@ def add_pie_series(x : float, y : float, radius : float, values : Union[List[flo return internal_dpg.add_pie_series(x, y, radius, values, labels, label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, parent=parent, before=before, source=source, show=show, format=format, angle=angle, normalize=normalize, ignore_hidden=ignore_hidden, **kwargs) -def add_plot(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, height: int =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', callback: Callable =None, drag_callback: Callable =None, drop_callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', delay_search: bool =False, tracked: bool =False, track_offset: float =0.5, no_title: bool =False, no_menus: bool =False, no_box_select: bool =False, no_mouse_pos: bool =False, query: bool =False, query_color: Union[List[float], Tuple[float, ...]] =(0, 255, 0, 255), min_query_rects: int =1, max_query_rects: int =1, crosshairs: bool =False, equal_aspects: bool =False, no_inputs: bool =False, no_frame: bool =False, use_local_time: bool =False, use_ISO8601: bool =False, use_24hour_clock: bool =False, pan_button: int =internal_dpg.mvMouseButton_Left, pan_mod: int =internal_dpg.mvKey_None, context_menu_button: int =internal_dpg.mvMouseButton_Right, fit_button: int =internal_dpg.mvMouseButton_Left, box_select_button: int =internal_dpg.mvMouseButton_Right, box_select_mod: int =internal_dpg.mvKey_None, box_select_cancel_button: int =internal_dpg.mvMouseButton_Left, query_toggle_mod: int =internal_dpg.mvKey_ModCtrl, horizontal_mod: int =internal_dpg.mvKey_ModAlt, vertical_mod: int =internal_dpg.mvKey_ModShift, override_mod: int =internal_dpg.mvKey_ModCtrl, zoom_mod: int =internal_dpg.mvKey_None, zoom_rate: int =0.1, **kwargs) -> Union[int, str]: +def add_plot(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, height: int =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', callback: Callable =None, drag_callback: Callable =None, drop_callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', tracked: bool =False, track_offset: float =0.5, no_title: bool =False, no_menus: bool =False, no_box_select: bool =False, no_mouse_pos: bool =False, query: bool =False, query_color: Union[List[float], Tuple[float, ...]] =(0, 255, 0, 255), min_query_rects: int =1, max_query_rects: int =1, crosshairs: bool =False, equal_aspects: bool =False, no_inputs: bool =False, no_frame: bool =False, use_local_time: bool =False, use_ISO8601: bool =False, use_24hour_clock: bool =False, pan_button: int =internal_dpg.mvMouseButton_Left, pan_mod: int =internal_dpg.mvKey_None, context_menu_button: int =internal_dpg.mvMouseButton_Right, fit_button: int =internal_dpg.mvMouseButton_Left, box_select_button: int =internal_dpg.mvMouseButton_Right, box_select_mod: int =internal_dpg.mvKey_None, box_select_cancel_button: int =internal_dpg.mvMouseButton_Left, query_toggle_mod: int =internal_dpg.mvKey_ModCtrl, horizontal_mod: int =internal_dpg.mvKey_ModAlt, vertical_mod: int =internal_dpg.mvKey_ModShift, override_mod: int =internal_dpg.mvKey_ModCtrl, zoom_mod: int =internal_dpg.mvKey_None, zoom_rate: int =0.1, **kwargs) -> Union[int, str]: """ Adds a plot which is used to hold series, and can be drawn to with draw commands. For all _mod parameters use mvKey_ModX enums, or mvKey_ModDisabled to disable the modifier. Args: @@ -6224,7 +6363,6 @@ def add_plot(*, label: str =None, user_data: Any =None, use_internal_label: bool show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom no_title (bool, optional): the plot title will not be displayed @@ -6256,6 +6394,7 @@ def add_plot(*, label: str =None, user_data: Any =None, use_internal_label: bool zoom_mod (int, optional): optional modifier that must be held for scroll wheel zooming zoom_rate (int, optional): zoom rate for scroll (e.g. 0.1f = 10% plot range every scroll click); make negative to invert id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. no_highlight (bool, optional): (deprecated) Removed because not supported from the backend anymore. To control the highlighting of series use the same argument in `add_plot_legend` no_child (bool, optional): (deprecated) a child window region will not be used to capture mouse scroll (can boost performance for single ImGui window applications) anti_aliased (bool, optional): (deprecated) This feature was deprecated in ImPlot. To enable/disable anti_aliasing use `dpg.configure_app()` with the `anti_aliasing` parameters. @@ -6269,6 +6408,9 @@ def add_plot(*, label: str =None, user_data: Any =None, use_internal_label: bool warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + if 'no_highlight' in kwargs.keys(): warnings.warn('no_highlight keyword removed', DeprecationWarning, 2) @@ -6299,7 +6441,7 @@ def add_plot(*, label: str =None, user_data: Any =None, use_internal_label: bool kwargs.pop('query_mod', None) - return internal_dpg.add_plot(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, height=height, indent=indent, parent=parent, before=before, payload_type=payload_type, callback=callback, drag_callback=drag_callback, drop_callback=drop_callback, show=show, pos=pos, filter_key=filter_key, delay_search=delay_search, tracked=tracked, track_offset=track_offset, no_title=no_title, no_menus=no_menus, no_box_select=no_box_select, no_mouse_pos=no_mouse_pos, query=query, query_color=query_color, min_query_rects=min_query_rects, max_query_rects=max_query_rects, crosshairs=crosshairs, equal_aspects=equal_aspects, no_inputs=no_inputs, no_frame=no_frame, use_local_time=use_local_time, use_ISO8601=use_ISO8601, use_24hour_clock=use_24hour_clock, pan_button=pan_button, pan_mod=pan_mod, context_menu_button=context_menu_button, fit_button=fit_button, box_select_button=box_select_button, box_select_mod=box_select_mod, box_select_cancel_button=box_select_cancel_button, query_toggle_mod=query_toggle_mod, horizontal_mod=horizontal_mod, vertical_mod=vertical_mod, override_mod=override_mod, zoom_mod=zoom_mod, zoom_rate=zoom_rate, **kwargs) + return internal_dpg.add_plot(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, height=height, indent=indent, parent=parent, before=before, payload_type=payload_type, callback=callback, drag_callback=drag_callback, drop_callback=drop_callback, show=show, pos=pos, filter_key=filter_key, tracked=tracked, track_offset=track_offset, no_title=no_title, no_menus=no_menus, no_box_select=no_box_select, no_mouse_pos=no_mouse_pos, query=query, query_color=query_color, min_query_rects=min_query_rects, max_query_rects=max_query_rects, crosshairs=crosshairs, equal_aspects=equal_aspects, no_inputs=no_inputs, no_frame=no_frame, use_local_time=use_local_time, use_ISO8601=use_ISO8601, use_24hour_clock=use_24hour_clock, pan_button=pan_button, pan_mod=pan_mod, context_menu_button=context_menu_button, fit_button=fit_button, box_select_button=box_select_button, box_select_mod=box_select_mod, box_select_cancel_button=box_select_cancel_button, query_toggle_mod=query_toggle_mod, horizontal_mod=horizontal_mod, vertical_mod=vertical_mod, override_mod=override_mod, zoom_mod=zoom_mod, zoom_rate=zoom_rate, **kwargs) def add_plot_annotation(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, parent: Union[int, str] =0, before: Union[int, str] =0, source: Union[int, str] =0, show: bool =True, default_value: Any =(0.0, 0.0), offset: Union[List[float], Tuple[float, ...]] =(0.0, 0.0), color: Union[List[int], Tuple[int, ...]] =(0, 0, 0, -255), clamped: bool =True, **kwargs) -> Union[int, str]: """ Adds an annotation to a plot. @@ -7071,7 +7213,7 @@ def add_string_value(*, label: str =None, user_data: Any =None, use_internal_lab return internal_dpg.add_string_value(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, source=source, default_value=default_value, parent=parent, **kwargs) -def add_subplots(rows : int, columns : int, *, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, height: int =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', delay_search: bool =False, tracked: bool =False, track_offset: float =0.5, row_ratios: Union[List[float], Tuple[float, ...]] =[], column_ratios: Union[List[float], Tuple[float, ...]] =[], no_title: bool =False, no_menus: bool =False, no_resize: bool =False, no_align: bool =False, share_series: bool =False, link_rows: bool =False, link_columns: bool =False, link_all_x: bool =False, link_all_y: bool =False, column_major: bool =False, **kwargs) -> Union[int, str]: +def add_subplots(rows : int, columns : int, *, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, height: int =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', tracked: bool =False, track_offset: float =0.5, row_ratios: Union[List[float], Tuple[float, ...]] =[], column_ratios: Union[List[float], Tuple[float, ...]] =[], no_title: bool =False, no_menus: bool =False, no_resize: bool =False, no_align: bool =False, share_series: bool =False, link_rows: bool =False, link_columns: bool =False, link_all_x: bool =False, link_all_y: bool =False, column_major: bool =False, **kwargs) -> Union[int, str]: """ Adds a collection of plots. Args: @@ -7090,7 +7232,6 @@ def add_subplots(rows : int, columns : int, *, label: str =None, user_data: Any show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom row_ratios (Union[List[float], Tuple[float, ...]], optional): @@ -7106,6 +7247,7 @@ def add_subplots(rows : int, columns : int, *, label: str =None, user_data: Any link_all_y (bool, optional): link the y-axis limits in every plot in the subplot (does not apply to auxiliary y-axes) column_major (bool, optional): subplots are added in column major order instead of the default row major order id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -7114,9 +7256,12 @@ def add_subplots(rows : int, columns : int, *, label: str =None, user_data: Any warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - return internal_dpg.add_subplots(rows, columns, label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, height=height, indent=indent, parent=parent, before=before, callback=callback, show=show, pos=pos, filter_key=filter_key, delay_search=delay_search, tracked=tracked, track_offset=track_offset, row_ratios=row_ratios, column_ratios=column_ratios, no_title=no_title, no_menus=no_menus, no_resize=no_resize, no_align=no_align, share_series=share_series, link_rows=link_rows, link_columns=link_columns, link_all_x=link_all_x, link_all_y=link_all_y, column_major=column_major, **kwargs) + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + + return internal_dpg.add_subplots(rows, columns, label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, height=height, indent=indent, parent=parent, before=before, callback=callback, show=show, pos=pos, filter_key=filter_key, tracked=tracked, track_offset=track_offset, row_ratios=row_ratios, column_ratios=column_ratios, no_title=no_title, no_menus=no_menus, no_resize=no_resize, no_align=no_align, share_series=share_series, link_rows=link_rows, link_columns=link_columns, link_all_x=link_all_x, link_all_y=link_all_y, column_major=column_major, **kwargs) -def add_tab(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', drop_callback: Callable =None, show: bool =True, filter_key: str ='', delay_search: bool =False, tracked: bool =False, track_offset: float =0.5, closable: bool =False, no_tooltip: bool =False, order_mode: int =0, **kwargs) -> Union[int, str]: +def add_tab(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', drop_callback: Callable =None, show: bool =True, filter_key: str ='', tracked: bool =False, track_offset: float =0.5, closable: bool =False, no_tooltip: bool =False, order_mode: int =0, **kwargs) -> Union[int, str]: """ Adds a tab to a tab bar. Args: @@ -7131,13 +7276,13 @@ def add_tab(*, label: str =None, user_data: Any =None, use_internal_label: bool drop_callback (Callable, optional): Registers a drop callback for drag and drop. show (bool, optional): Attempt to render widget. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom closable (bool, optional): Creates a button on the tab that can hide the tab. no_tooltip (bool, optional): Disable tooltip for the given tab. order_mode (int, optional): set using a constant: mvTabOrder_Reorderable: allows reordering, mvTabOrder_Fixed: fixed ordering, mvTabOrder_Leading: adds tab to front, mvTabOrder_Trailing: adds tab to back id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -7146,9 +7291,12 @@ def add_tab(*, label: str =None, user_data: Any =None, use_internal_label: bool warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - return internal_dpg.add_tab(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, before=before, payload_type=payload_type, drop_callback=drop_callback, show=show, filter_key=filter_key, delay_search=delay_search, tracked=tracked, track_offset=track_offset, closable=closable, no_tooltip=no_tooltip, order_mode=order_mode, **kwargs) + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + + return internal_dpg.add_tab(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, before=before, payload_type=payload_type, drop_callback=drop_callback, show=show, filter_key=filter_key, tracked=tracked, track_offset=track_offset, closable=closable, no_tooltip=no_tooltip, order_mode=order_mode, **kwargs) -def add_tab_bar(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', delay_search: bool =False, tracked: bool =False, track_offset: float =0.5, reorderable: bool =False, **kwargs) -> Union[int, str]: +def add_tab_bar(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', tracked: bool =False, track_offset: float =0.5, reorderable: bool =False, **kwargs) -> Union[int, str]: """ Adds a tab bar. Args: @@ -7163,11 +7311,11 @@ def add_tab_bar(*, label: str =None, user_data: Any =None, use_internal_label: b show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom reorderable (bool, optional): Allows for the user to change the order of the tabs. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -7176,7 +7324,10 @@ def add_tab_bar(*, label: str =None, user_data: Any =None, use_internal_label: b warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - return internal_dpg.add_tab_bar(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, before=before, callback=callback, show=show, pos=pos, filter_key=filter_key, delay_search=delay_search, tracked=tracked, track_offset=track_offset, reorderable=reorderable, **kwargs) + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + + return internal_dpg.add_tab_bar(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, before=before, callback=callback, show=show, pos=pos, filter_key=filter_key, tracked=tracked, track_offset=track_offset, reorderable=reorderable, **kwargs) def add_tab_button(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', callback: Callable =None, drag_callback: Callable =None, drop_callback: Callable =None, show: bool =True, filter_key: str ='', tracked: bool =False, track_offset: float =0.5, no_reorder: bool =False, leading: bool =False, trailing: bool =False, no_tooltip: bool =False, **kwargs) -> Union[int, str]: """ Adds a tab button to a tab bar. @@ -7212,7 +7363,7 @@ def add_tab_button(*, label: str =None, user_data: Any =None, use_internal_label return internal_dpg.add_tab_button(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, before=before, payload_type=payload_type, callback=callback, drag_callback=drag_callback, drop_callback=drop_callback, show=show, filter_key=filter_key, tracked=tracked, track_offset=track_offset, no_reorder=no_reorder, leading=leading, trailing=trailing, no_tooltip=no_tooltip, **kwargs) -def add_table(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, height: int =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, source: Union[int, str] =0, callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', delay_search: bool =False, header_row: bool =True, clipper: bool =False, inner_width: int =0, policy: int =0, freeze_rows: int =0, freeze_columns: int =0, sort_multi: bool =False, sort_tristate: bool =False, resizable: bool =False, reorderable: bool =False, hideable: bool =False, sortable: bool =False, context_menu_in_body: bool =False, row_background: bool =False, borders_innerH: bool =False, borders_outerH: bool =False, borders_innerV: bool =False, borders_outerV: bool =False, no_host_extendX: bool =False, no_host_extendY: bool =False, no_keep_columns_visible: bool =False, precise_widths: bool =False, no_clip: bool =False, pad_outerX: bool =False, no_pad_outerX: bool =False, no_pad_innerX: bool =False, scrollX: bool =False, scrollY: bool =False, no_saved_settings: bool =False, **kwargs) -> Union[int, str]: +def add_table(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, height: int =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, source: Union[int, str] =0, callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', header_row: bool =True, clipper: bool =False, inner_width: int =0, policy: int =0, freeze_rows: int =0, freeze_columns: int =0, sort_multi: bool =False, sort_tristate: bool =False, resizable: bool =False, reorderable: bool =False, hideable: bool =False, sortable: bool =False, context_menu_in_body: bool =False, row_background: bool =False, borders_innerH: bool =False, borders_outerH: bool =False, borders_innerV: bool =False, borders_outerV: bool =False, no_host_extendX: bool =False, no_host_extendY: bool =False, no_keep_columns_visible: bool =False, precise_widths: bool =False, no_clip: bool =False, pad_outerX: bool =False, no_pad_outerX: bool =False, no_pad_innerX: bool =False, scrollX: bool =False, scrollY: bool =False, no_saved_settings: bool =False, **kwargs) -> Union[int, str]: """ Adds a table. Args: @@ -7230,7 +7381,6 @@ def add_table(*, label: str =None, user_data: Any =None, use_internal_label: boo show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. header_row (bool, optional): show headers at the top of the columns clipper (bool, optional): Use clipper (rows must be same height). inner_width (int, optional): @@ -7261,6 +7411,7 @@ def add_table(*, label: str =None, user_data: Any =None, use_internal_label: boo scrollY (bool, optional): Enable vertical scrolling. no_saved_settings (bool, optional): Never load/save settings in .ini file. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -7269,7 +7420,10 @@ def add_table(*, label: str =None, user_data: Any =None, use_internal_label: boo warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - return internal_dpg.add_table(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, height=height, indent=indent, parent=parent, before=before, source=source, callback=callback, show=show, pos=pos, filter_key=filter_key, delay_search=delay_search, header_row=header_row, clipper=clipper, inner_width=inner_width, policy=policy, freeze_rows=freeze_rows, freeze_columns=freeze_columns, sort_multi=sort_multi, sort_tristate=sort_tristate, resizable=resizable, reorderable=reorderable, hideable=hideable, sortable=sortable, context_menu_in_body=context_menu_in_body, row_background=row_background, borders_innerH=borders_innerH, borders_outerH=borders_outerH, borders_innerV=borders_innerV, borders_outerV=borders_outerV, no_host_extendX=no_host_extendX, no_host_extendY=no_host_extendY, no_keep_columns_visible=no_keep_columns_visible, precise_widths=precise_widths, no_clip=no_clip, pad_outerX=pad_outerX, no_pad_outerX=no_pad_outerX, no_pad_innerX=no_pad_innerX, scrollX=scrollX, scrollY=scrollY, no_saved_settings=no_saved_settings, **kwargs) + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + + return internal_dpg.add_table(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, height=height, indent=indent, parent=parent, before=before, source=source, callback=callback, show=show, pos=pos, filter_key=filter_key, header_row=header_row, clipper=clipper, inner_width=inner_width, policy=policy, freeze_rows=freeze_rows, freeze_columns=freeze_columns, sort_multi=sort_multi, sort_tristate=sort_tristate, resizable=resizable, reorderable=reorderable, hideable=hideable, sortable=sortable, context_menu_in_body=context_menu_in_body, row_background=row_background, borders_innerH=borders_innerH, borders_outerH=borders_outerH, borders_innerV=borders_innerV, borders_outerV=borders_outerV, no_host_extendX=no_host_extendX, no_host_extendY=no_host_extendY, no_keep_columns_visible=no_keep_columns_visible, precise_widths=precise_widths, no_clip=no_clip, pad_outerX=pad_outerX, no_pad_outerX=no_pad_outerX, no_pad_innerX=no_pad_innerX, scrollX=scrollX, scrollY=scrollY, no_saved_settings=no_saved_settings, **kwargs) def add_table_cell(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, height: int =0, parent: Union[int, str] =0, before: Union[int, str] =0, show: bool =True, filter_key: str ='', **kwargs) -> Union[int, str]: """ Adds a table. @@ -7624,7 +7778,7 @@ def add_tooltip(parent : Union[int, str], *, label: str =None, user_data: Any =N return internal_dpg.add_tooltip(parent, label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, show=show, delay=delay, hide_on_activity=hide_on_activity, **kwargs) -def add_tree_node(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', drag_callback: Callable =None, drop_callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', delay_search: bool =False, tracked: bool =False, track_offset: float =0.5, default_open: bool =False, open_on_double_click: bool =False, open_on_arrow: bool =False, leaf: bool =False, bullet: bool =False, selectable: bool =False, span_text_width: bool =False, span_full_width: bool =False, **kwargs) -> Union[int, str]: +def add_tree_node(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, indent: int =-1, parent: Union[int, str] =0, before: Union[int, str] =0, payload_type: str ='$$DPG_PAYLOAD', drag_callback: Callable =None, drop_callback: Callable =None, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], filter_key: str ='', tracked: bool =False, track_offset: float =0.5, default_open: bool =False, open_on_double_click: bool =False, open_on_arrow: bool =False, leaf: bool =False, bullet: bool =False, selectable: bool =False, span_text_width: bool =False, span_full_width: bool =False, **kwargs) -> Union[int, str]: """ Adds a tree node to add items to. Args: @@ -7641,7 +7795,6 @@ def add_tree_node(*, label: str =None, user_data: Any =None, use_internal_label: show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. tracked (bool, optional): Scroll tracking track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom default_open (bool, optional): Sets the tree node open by default. @@ -7653,6 +7806,7 @@ def add_tree_node(*, label: str =None, user_data: Any =None, use_internal_label: span_text_width (bool, optional): Makes hitbox and highlight only cover the label. span_full_width (bool, optional): Extend hit box to the left-most and right-most edges (cover the indent area). id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -7661,7 +7815,10 @@ def add_tree_node(*, label: str =None, user_data: Any =None, use_internal_label: warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - return internal_dpg.add_tree_node(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, before=before, payload_type=payload_type, drag_callback=drag_callback, drop_callback=drop_callback, show=show, pos=pos, filter_key=filter_key, delay_search=delay_search, tracked=tracked, track_offset=track_offset, default_open=default_open, open_on_double_click=open_on_double_click, open_on_arrow=open_on_arrow, leaf=leaf, bullet=bullet, selectable=selectable, span_text_width=span_text_width, span_full_width=span_full_width, **kwargs) + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + + return internal_dpg.add_tree_node(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, before=before, payload_type=payload_type, drag_callback=drag_callback, drop_callback=drop_callback, show=show, pos=pos, filter_key=filter_key, tracked=tracked, track_offset=track_offset, default_open=default_open, open_on_double_click=open_on_double_click, open_on_arrow=open_on_arrow, leaf=leaf, bullet=bullet, selectable=selectable, span_text_width=span_text_width, span_full_width=span_full_width, **kwargs) def add_value_registry(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, **kwargs) -> Union[int, str]: """ Adds a value registry. @@ -7682,7 +7839,7 @@ def add_value_registry(*, label: str =None, user_data: Any =None, use_internal_l return internal_dpg.add_value_registry(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, **kwargs) -def add_viewport_drawlist(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, show: bool =True, filter_key: str ='', delay_search: bool =False, front: bool =True, **kwargs) -> Union[int, str]: +def add_viewport_drawlist(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, show: bool =True, filter_key: str ='', front: bool =True, **kwargs) -> Union[int, str]: """ A container that is used to present draw items or layers directly to the viewport. By default this will draw to the back of the viewport. Layers and draw items should be added to this widget as children. Args: @@ -7692,9 +7849,9 @@ def add_viewport_drawlist(*, label: str =None, user_data: Any =None, use_interna tag (Union[int, str], optional): Unique id used to programmatically refer to the item.If label is unused this will be the label. show (bool, optional): Attempt to render widget. filter_key (str, optional): Used by filter widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. front (bool, optional): Draws to the front of the view port instead of the back. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -7703,9 +7860,12 @@ def add_viewport_drawlist(*, label: str =None, user_data: Any =None, use_interna warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - return internal_dpg.add_viewport_drawlist(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, show=show, filter_key=filter_key, delay_search=delay_search, front=front, **kwargs) + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) -def add_viewport_menu_bar(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, indent: int =-1, parent: Union[int, str] =0, show: bool =True, delay_search: bool =False, **kwargs) -> Union[int, str]: + return internal_dpg.add_viewport_drawlist(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, show=show, filter_key=filter_key, front=front, **kwargs) + +def add_viewport_menu_bar(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, indent: int =-1, parent: Union[int, str] =0, show: bool =True, **kwargs) -> Union[int, str]: """ Adds a menubar to the viewport. Args: @@ -7716,8 +7876,8 @@ def add_viewport_menu_bar(*, label: str =None, user_data: Any =None, use_interna indent (int, optional): Offsets the widget to the right the specified number multiplied by the indent style. parent (Union[int, str], optional): Parent to add this item to. (runtime adding) show (bool, optional): Attempt to render widget. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -7726,9 +7886,12 @@ def add_viewport_menu_bar(*, label: str =None, user_data: Any =None, use_interna warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - return internal_dpg.add_viewport_menu_bar(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, show=show, delay_search=delay_search, **kwargs) + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) -def add_window(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, height: int =0, indent: int =-1, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], delay_search: bool =False, min_size: Union[List[int], Tuple[int, ...]] =[100, 100], max_size: Union[List[int], Tuple[int, ...]] =[30000, 30000], menubar: bool =False, collapsed: bool =False, autosize: bool =False, no_resize: bool =False, unsaved_document: bool =False, no_title_bar: bool =False, no_move: bool =False, no_scrollbar: bool =False, no_collapse: bool =False, horizontal_scrollbar: bool =False, no_focus_on_appearing: bool =False, no_bring_to_front_on_focus: bool =False, no_close: bool =False, no_background: bool =False, modal: bool =False, popup: bool =False, no_saved_settings: bool =False, no_open_over_existing_popup: bool =True, no_scroll_with_mouse: bool =False, on_close: Callable =None, **kwargs) -> Union[int, str]: + return internal_dpg.add_viewport_menu_bar(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, indent=indent, parent=parent, show=show, **kwargs) + +def add_window(*, label: str =None, user_data: Any =None, use_internal_label: bool =True, tag: Union[int, str] =0, width: int =0, height: int =0, indent: int =-1, show: bool =True, pos: Union[List[int], Tuple[int, ...]] =[], min_size: Union[List[int], Tuple[int, ...]] =[100, 100], max_size: Union[List[int], Tuple[int, ...]] =[30000, 30000], menubar: bool =False, collapsed: bool =False, autosize: bool =False, no_resize: bool =False, unsaved_document: bool =False, no_title_bar: bool =False, no_move: bool =False, no_scrollbar: bool =False, no_collapse: bool =False, horizontal_scrollbar: bool =False, no_focus_on_appearing: bool =False, no_bring_to_front_on_focus: bool =False, no_close: bool =False, no_background: bool =False, modal: bool =False, popup: bool =False, no_saved_settings: bool =False, no_open_over_existing_popup: bool =True, no_scroll_with_mouse: bool =False, on_close: Callable =None, **kwargs) -> Union[int, str]: """ Creates a new window for following items to be added to. Args: @@ -7741,7 +7904,6 @@ def add_window(*, label: str =None, user_data: Any =None, use_internal_label: bo indent (int, optional): Offsets the widget to the right the specified number multiplied by the indent style. show (bool, optional): Attempt to render widget. pos (Union[List[int], Tuple[int, ...]], optional): Places the item relative to window coordinates, [0,0] is top left. - delay_search (bool, optional): Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often. min_size (Union[List[int], Tuple[int, ...]], optional): Minimum window size. max_size (Union[List[int], Tuple[int, ...]], optional): Maximum window size. menubar (bool, optional): Shows or hides the menubar. @@ -7765,6 +7927,7 @@ def add_window(*, label: str =None, user_data: Any =None, use_internal_label: bo no_scroll_with_mouse (bool, optional): Disable user vertically scrolling with mouse wheel. on_close (Callable, optional): Callback ran when window is closed. id (Union[int, str], optional): (deprecated) + delay_search (bool, optional): (deprecated) This was used as an optimization hint but is not relevant anymore. Returns: Union[int, str] """ @@ -7773,7 +7936,10 @@ def add_window(*, label: str =None, user_data: Any =None, use_internal_label: bo warnings.warn('id keyword renamed to tag', DeprecationWarning, 2) tag=kwargs['id'] - return internal_dpg.add_window(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, height=height, indent=indent, show=show, pos=pos, delay_search=delay_search, min_size=min_size, max_size=max_size, menubar=menubar, collapsed=collapsed, autosize=autosize, no_resize=no_resize, unsaved_document=unsaved_document, no_title_bar=no_title_bar, no_move=no_move, no_scrollbar=no_scrollbar, no_collapse=no_collapse, horizontal_scrollbar=horizontal_scrollbar, no_focus_on_appearing=no_focus_on_appearing, no_bring_to_front_on_focus=no_bring_to_front_on_focus, no_close=no_close, no_background=no_background, modal=modal, popup=popup, no_saved_settings=no_saved_settings, no_open_over_existing_popup=no_open_over_existing_popup, no_scroll_with_mouse=no_scroll_with_mouse, on_close=on_close, **kwargs) + if 'delay_search' in kwargs.keys(): + warnings.warn('delay_search keyword deprecated. ', DeprecationWarning, 2) + + return internal_dpg.add_window(label=label, user_data=user_data, use_internal_label=use_internal_label, tag=tag, width=width, height=height, indent=indent, show=show, pos=pos, min_size=min_size, max_size=max_size, menubar=menubar, collapsed=collapsed, autosize=autosize, no_resize=no_resize, unsaved_document=unsaved_document, no_title_bar=no_title_bar, no_move=no_move, no_scrollbar=no_scrollbar, no_collapse=no_collapse, horizontal_scrollbar=horizontal_scrollbar, no_focus_on_appearing=no_focus_on_appearing, no_bring_to_front_on_focus=no_bring_to_front_on_focus, no_close=no_close, no_background=no_background, modal=modal, popup=popup, no_saved_settings=no_saved_settings, no_open_over_existing_popup=no_open_over_existing_popup, no_scroll_with_mouse=no_scroll_with_mouse, on_close=on_close, **kwargs) def apply_transform(item : Union[int, str], transform : Any, **kwargs) -> None: """ New in 1.1. Applies a transformation matrix to a layer. @@ -9559,29 +9725,31 @@ def set_viewport_resize_callback(callback : Callable, *, user_data: Any =None, * return internal_dpg.set_viewport_resize_callback(callback, user_data=user_data, **kwargs) -def set_x_scroll(item : Union[int, str], value : float, **kwargs) -> None: - """ Undocumented +def set_x_scroll(item : Union[int, str], value : float, *, when: int =internal_dpg.mvSetScrollFlags_Delayed, **kwargs) -> None: + """ Sets horizontal scroll position. Args: item (Union[int, str]): - value (float): + value (float): Scroll position + when (int, optional): Specifies whether the scroll position will be set in the nearest frame (mvSetScrollFlags_Now) or with a 1-frame delay (mvSetScrollFlags_Delayed). The former prevents flickering, the latter works better if contents change in the same frame as when set_x_scroll called. mvSetScrollFlags_Both can also be used to set the position twice. Returns: None """ - return internal_dpg.set_x_scroll(item, value, **kwargs) + return internal_dpg.set_x_scroll(item, value, when=when, **kwargs) -def set_y_scroll(item : Union[int, str], value : float, **kwargs) -> None: - """ Undocumented +def set_y_scroll(item : Union[int, str], value : float, *, when: int =internal_dpg.mvSetScrollFlags_Delayed, **kwargs) -> None: + """ Sets vertical scroll position. Args: item (Union[int, str]): - value (float): + value (float): Scroll position + when (int, optional): Specifies whether the scroll position will be set in the nearest frame (mvSetScrollFlags_Now) or with a 1-frame delay (mvSetScrollFlags_Delayed). The former prevents flickering, the latter works better if contents change in the same frame as when set_x_scroll called. mvSetScrollFlags_Both can also be used to set the position twice. Returns: None """ - return internal_dpg.set_y_scroll(item, value, **kwargs) + return internal_dpg.set_y_scroll(item, value, when=when, **kwargs) def setup_dearpygui(**kwargs) -> None: """ Sets up Dear PyGui @@ -9661,16 +9829,22 @@ def show_viewport(*, minimized: bool =False, maximized: bool =False, **kwargs) - return internal_dpg.show_viewport(minimized=minimized, maximized=maximized, **kwargs) -def split_frame(*, delay: int =32, **kwargs) -> None: +def split_frame(**kwargs) -> None: """ Waits one frame. Args: - delay (int, optional): Minimal delay in in milliseconds + delay (int, optional): (deprecated) Do not use it anymore, it has no effect. Returns: None """ - return internal_dpg.split_frame(delay=delay, **kwargs) + if 'delay' in kwargs.keys(): + + warnings.warn('delay keyword removed', DeprecationWarning, 2) + + kwargs.pop('delay', None) + + return internal_dpg.split_frame(**kwargs) def stop_dearpygui(**kwargs) -> None: """ Stops Dear PyGui @@ -9857,6 +10031,8 @@ def unstage(item : Union[int, str], **kwargs) -> None: mvKey_NumPad7=internal_dpg.mvKey_NumPad7 mvKey_NumPad8=internal_dpg.mvKey_NumPad8 mvKey_NumPad9=internal_dpg.mvKey_NumPad9 +mvKey_NumPadEnter=internal_dpg.mvKey_NumPadEnter +mvKey_NumPadEqual=internal_dpg.mvKey_NumPadEqual mvKey_Subtract=internal_dpg.mvKey_Subtract mvKey_Decimal=internal_dpg.mvKey_Decimal mvKey_Divide=internal_dpg.mvKey_Divide @@ -9954,6 +10130,19 @@ def unstage(item : Union[int, str], **kwargs) -> None: mvComboHeight_Regular=internal_dpg.mvComboHeight_Regular mvComboHeight_Large=internal_dpg.mvComboHeight_Large mvComboHeight_Largest=internal_dpg.mvComboHeight_Largest +mvEventType_Off=internal_dpg.mvEventType_Off +mvEventType_Enter=internal_dpg.mvEventType_Enter +mvEventType_On=internal_dpg.mvEventType_On +mvEventType_Leave=internal_dpg.mvEventType_Leave +mvSetScrollFlags_Now=internal_dpg.mvSetScrollFlags_Now +mvSetScrollFlags_Delayed=internal_dpg.mvSetScrollFlags_Delayed +mvSetScrollFlags_Both=internal_dpg.mvSetScrollFlags_Both +mvScrollDirection_XAxis=internal_dpg.mvScrollDirection_XAxis +mvScrollDirection_YAxis=internal_dpg.mvScrollDirection_YAxis +mvScrollDirection_Horizontal=internal_dpg.mvScrollDirection_Horizontal +mvScrollDirection_Vertical=internal_dpg.mvScrollDirection_Vertical +mvLoadInd_DottedCircle=internal_dpg.mvLoadInd_DottedCircle +mvLoadInd_Ring=internal_dpg.mvLoadInd_Ring mvPlatform_Windows=internal_dpg.mvPlatform_Windows mvPlatform_Apple=internal_dpg.mvPlatform_Apple mvPlatform_Linux=internal_dpg.mvPlatform_Linux @@ -10297,6 +10486,7 @@ def unstage(item : Union[int, str], **kwargs) -> None: mvTable=internal_dpg.mvTable mvTableColumn=internal_dpg.mvTableColumn mvTableRow=internal_dpg.mvTableRow +mvSyncedTables=internal_dpg.mvSyncedTables mvDrawLine=internal_dpg.mvDrawLine mvDrawArrow=internal_dpg.mvDrawArrow mvDrawTriangle=internal_dpg.mvDrawTriangle @@ -10376,6 +10566,7 @@ def unstage(item : Union[int, str], **kwargs) -> None: mvToggledOpenHandler=internal_dpg.mvToggledOpenHandler mvClickedHandler=internal_dpg.mvClickedHandler mvDoubleClickedHandler=internal_dpg.mvDoubleClickedHandler +mvScrollHandler=internal_dpg.mvScrollHandler mvDragPayload=internal_dpg.mvDragPayload mvResizeHandler=internal_dpg.mvResizeHandler mvFont=internal_dpg.mvFont diff --git a/dearpygui/demo.py b/dearpygui/demo.py index 08208442b..679c7a26b 100644 --- a/dearpygui/demo.py +++ b/dearpygui/demo.py @@ -10,12 +10,11 @@ def _help(message): last_item = dpg.last_item() - group = dpg.add_group(horizontal=True) - dpg.move_item(last_item, parent=group) - dpg.capture_next_item(lambda s: dpg.move_item(s, parent=group)) - t = dpg.add_text("(?)", color=[0, 255, 0]) - with dpg.tooltip(t): - dpg.add_text(message) + with dpg.group(horizontal=True) as group: + dpg.move_item(last_item, parent=group) + t = dpg.add_text("(?)", color=[0, 255, 0]) + with dpg.tooltip(t): + dpg.add_text(message) def _hyperlink(text, address): b = dpg.add_button(label=text, callback=lambda:webbrowser.open(address)) @@ -245,7 +244,7 @@ def _log(sender, app_data, user_data): dpg.add_menu_item(label="Option 2", check=True, callback=_log) dpg.add_menu_item(label="Option 3", check=True, default_value=True, callback=_log) - with dpg.child_window(height=60, autosize_x=True, delay_search=True): + with dpg.child_window(height=60, autosize_x=True): for i in range(10): dpg.add_text(f"Scolling Text{i}") @@ -875,7 +874,7 @@ def _selection(sender, app_data, user_data): dpg.add_button(label="Button 3") with dpg.tree_node(label="Groups"): - dpg.add_text("Groups are used to control child items placement, width, and provide a hit box for things like is the set of items are hovered, ect...") + dpg.add_text("Groups are used to control child items placement, width, and provide a hit box for things like is the set of items are hovered, etc...") with dpg.group(horizontal=True): dpg.add_button(label="Button 1") dpg.add_button(label="Button 2") @@ -1047,7 +1046,7 @@ def _update_yscroll_info(sender, app_data, user_data): for i in range(5): with dpg.table_cell(): dpg.add_text(text_items[i]) - with dpg.child_window(height=200, delay_search=True) as _child_id: + with dpg.child_window(height=200) as _child_id: for j in range(25): if j == 13: dpg.add_text("Item " + str(j), color=(255, 255, 0), tracked=True, track_offset=track_items[i]) @@ -1062,7 +1061,7 @@ def _update_yscroll_info(sender, app_data, user_data): for i in range(5): dpg.add_text(text_items[i]) with dpg.group(horizontal=True): - with dpg.child_window(height=50, horizontal_scrollbar=True, width=-200, delay_search=True) as _child_id: + with dpg.child_window(height=50, horizontal_scrollbar=True, width=-200) as _child_id: with dpg.group(horizontal=True): for j in range(25): if j == 13: @@ -1288,7 +1287,7 @@ def _scroll_programmatically(sender, app_data, user_data): with dpg.table(header_row=False, row_background=True, borders_innerH=True, borders_outerH=True, borders_innerV=True, - borders_outerV=True, delay_search=True) as table_id: + borders_outerV=True) as table_id: dpg.add_table_column(label="Header 1") dpg.add_table_column(label="Header 2") @@ -1306,8 +1305,7 @@ def _scroll_programmatically(sender, app_data, user_data): with dpg.tree_node(label="Colors"): dpg.add_text("Highlighting Rows, Columns, Cells:") - with dpg.table(header_row=False, row_background=True, - delay_search=True) as table_id: + with dpg.table(header_row=False, row_background=True) as table_id: dpg.add_table_column() dpg.add_table_column() @@ -1334,8 +1332,7 @@ def _scroll_programmatically(sender, app_data, user_data): _add_config_options(table_id, 1, "row_background", before=table_id) dpg.add_text("Coloring rows:") - with dpg.table(header_row=False, row_background=True, - delay_search=True) as table_id: + with dpg.table(header_row=False, row_background=True) as table_id: dpg.add_table_column() dpg.add_table_column() @@ -1359,7 +1356,7 @@ def _scroll_programmatically(sender, app_data, user_data): with dpg.tree_node(label="Resizable, stretch"): - with dpg.table(header_row=False, resizable=True, delay_search=True, + with dpg.table(header_row=False, resizable=True, borders_outerH=True, borders_innerV=True, borders_outerV=True) as table_id: dpg.add_table_column(label="Header 1") @@ -1378,7 +1375,7 @@ def _scroll_programmatically(sender, app_data, user_data): dpg.add_text("Only available if scrollX/scrollY are disabled and stretch columns are not used") with dpg.table(header_row=False, policy=dpg.mvTable_SizingFixedFit, resizable=True, no_host_extendX=False, - borders_innerV=True, delay_search=True, borders_outerV=True,borders_outerH=True) as table_id: + borders_innerV=True, borders_outerV=True,borders_outerH=True) as table_id: dpg.add_table_column(label="Header 1") dpg.add_table_column(label="Header 2") @@ -1395,7 +1392,7 @@ def _scroll_programmatically(sender, app_data, user_data): with dpg.table(header_row=True, policy=dpg.mvTable_SizingFixedFit, row_background=True, reorderable=True, resizable=True, no_host_extendX=False, hideable=True, - borders_innerV=True, delay_search=True, borders_outerV=True, borders_innerH=True, borders_outerH=True): + borders_innerV=True, borders_outerV=True, borders_innerH=True, borders_outerH=True): dpg.add_table_column(label="AAA", width_fixed=True) dpg.add_table_column(label="BBB", width_fixed=True) @@ -1411,7 +1408,7 @@ def _scroll_programmatically(sender, app_data, user_data): with dpg.table(header_row=True, policy=dpg.mvTable_SizingFixedFit, row_background=True, reorderable=True, resizable=True, no_host_extendX=False, hideable=True, - borders_innerV=True, delay_search=True, borders_outerV=True, borders_innerH=True, borders_outerH=True): + borders_innerV=True, borders_outerV=True, borders_innerH=True, borders_outerH=True): dpg.add_table_column(label="AAA", width_fixed=True) dpg.add_table_column(label="BBB", width_fixed=True) @@ -1432,7 +1429,7 @@ def _scroll_programmatically(sender, app_data, user_data): borders_innerH=True, borders_outerH=True, borders_innerV=True, borders_outerV=True, row_background=True, hideable=True, reorderable=True, resizable=True, sortable=True, policy=dpg.mvTable_SizingFixedFit, - scrollX=True, delay_search=True, scrollY=True): + scrollX=True, scrollY=True): c1 = dpg.add_table_column(label="One", default_sort=True) c2 = dpg.add_table_column(label="Two") @@ -1482,7 +1479,7 @@ def _scroll_programmatically(sender, app_data, user_data): with dpg.table(header_row=True, resizable=True, borders_outerH=True, borders_innerH=True, - borders_outerV=True, delay_search=True): + borders_outerV=True): dpg.add_table_column(label="One") dpg.add_table_column(label="Two") @@ -1500,7 +1497,7 @@ def _scroll_programmatically(sender, app_data, user_data): for j in range(3): dpg.add_text(f"Hello {i}, {j}") - with dpg.table(header_row=False, delay_search=True) as table_id: + with dpg.table(header_row=False) as table_id: dpg.add_table_column(width_fixed=True, init_width_or_weight=100) dpg.add_table_column(width_fixed=True, init_width_or_weight=200) @@ -1524,7 +1521,7 @@ def _scroll_programmatically(sender, app_data, user_data): with dpg.tree_node(label="Row height"): - with dpg.table(header_row=False, borders_outerH=True, borders_outerV=True, delay_search=True): + with dpg.table(header_row=False, borders_outerH=True, borders_outerV=True): dpg.add_table_column() @@ -1534,7 +1531,7 @@ def _scroll_programmatically(sender, app_data, user_data): with dpg.tree_node(label="Padding"): - with dpg.table(header_row=False, resizable=True, delay_search=True, + with dpg.table(header_row=False, resizable=True, hideable=True, reorderable=True, borders_outerV=True, borders_innerH=True) as table_id: dpg.add_table_column(label="One") @@ -1552,7 +1549,7 @@ def _scroll_programmatically(sender, app_data, user_data): with dpg.tree_node(label="Angled headers"): - with dpg.table(header_row=True, resizable=True, delay_search=True, + with dpg.table(header_row=True, resizable=True, reorderable=True) as table_id: dpg.add_table_column(label="One", angled_header=True) @@ -1566,7 +1563,7 @@ def _scroll_programmatically(sender, app_data, user_data): with dpg.tree_node(label="Reorderable, hideable, with headers"): - with dpg.table(header_row=True, resizable=True, delay_search=True, + with dpg.table(header_row=True, resizable=True, hideable=True, reorderable=True) as table_id: dpg.add_table_column(label="One") @@ -1583,7 +1580,7 @@ def _scroll_programmatically(sender, app_data, user_data): with dpg.tree_node(label="Outer Size"): - with dpg.table(header_row=False, no_host_extendX=True, delay_search=True, + with dpg.table(header_row=False, no_host_extendX=True, borders_innerH=True, borders_outerH=True, borders_innerV=True, borders_outerV=True, context_menu_in_body=True, row_background=True, policy=dpg.mvTable_SizingFixedFit, height=150) as table_id: @@ -1601,7 +1598,7 @@ def _scroll_programmatically(sender, app_data, user_data): "no_host_extendX", "no_host_extendY", "resizable", before=table_id) dpg.add_text("Using explicit size:") - with dpg.table(header_row=False, no_host_extendX=True, delay_search=True, + with dpg.table(header_row=False, no_host_extendX=True, borders_innerH=True, borders_outerH=True, borders_innerV=True, borders_outerV=True, context_menu_in_body=True, row_background=True, policy=dpg.mvTable_SizingFixedFit, height=300, width=300): @@ -1619,7 +1616,7 @@ def _scroll_programmatically(sender, app_data, user_data): # without clipping dpg.add_text("Without Clipper") - with dpg.table(header_row=True, no_host_extendX=True, delay_search=True, + with dpg.table(header_row=True, no_host_extendX=True, borders_innerH=True, borders_outerH=True, borders_innerV=True, borders_outerV=True, context_menu_in_body=True, row_background=True, policy=dpg.mvTable_SizingFixedFit, height=300, @@ -1637,7 +1634,7 @@ def _scroll_programmatically(sender, app_data, user_data): # with clipping dpg.add_text("Using Clipper") - with dpg.table(header_row=True, no_host_extendX=True, delay_search=True, + with dpg.table(header_row=True, no_host_extendX=True, borders_innerH=True, borders_outerH=True, borders_innerV=True, borders_outerV=True, context_menu_in_body=True, row_background=True, policy=dpg.mvTable_SizingFixedFit, height=300, @@ -1659,7 +1656,7 @@ def _scroll_programmatically(sender, app_data, user_data): dpg.add_text("Freezing rows/columns") with dpg.table(header_row=True, borders_innerH=True, borders_outerH=True, borders_innerV=True, borders_outerV=True, row_background=True, height=300, freeze_rows=1, freeze_columns=1, - scrollY=True, scrollX=True, policy=dpg.mvTable_SizingFixedFit, delay_search=True): + scrollY=True, scrollX=True, policy=dpg.mvTable_SizingFixedFit): dpg.add_table_column(label="1", width=50) dpg.add_table_column(label="2", width=50) @@ -1685,7 +1682,7 @@ def _scroll_programmatically(sender, app_data, user_data): dpg.add_text("Using Filter (column 3)") _filter_table_id = dpg.generate_uuid() dpg.add_input_text(label="Filter (inc, -exc)", user_data=_filter_table_id, callback=lambda s, a, u: dpg.set_value(u, dpg.get_value(s))) - with dpg.table(header_row=True, no_host_extendX=True, delay_search=True, + with dpg.table(header_row=True, no_host_extendX=True, borders_innerH=True, borders_outerH=True, borders_innerV=True, borders_outerV=True, context_menu_in_body=True, row_background=True, policy=dpg.mvTable_SizingFixedFit, height=300, @@ -1744,7 +1741,7 @@ def _sorter(e): borders_innerH=True, borders_outerH=True, borders_innerV=True, borders_outerV=True, context_menu_in_body=True, row_background=True, policy=dpg.mvTable_SizingFixedFit, height=500, sortable=True, callback=_sort_callback, - scrollY=True, delay_search=True, tag="__demo_sorting_table"): + scrollY=True, tag="__demo_sorting_table"): dpg.add_table_column(label="One") dpg.add_table_column(label="Two", no_sort=True) @@ -1829,7 +1826,7 @@ def callback(sender, value, user_data): def create_table_set(policy): - with dpg.table(header_row=False, policy=policy, delay_search=True, + with dpg.table(header_row=False, policy=policy, borders_innerH=True, borders_outerH=True, borders_innerV=True, borders_outerV=True, row_background=True) as table_id1: @@ -2142,9 +2139,9 @@ def _callback_stacked(sender, app_data, user_data): def divergent_stack_cb(sender, app_data, user_data): if app_data: - dpg.configure_item("divergent_stack_series", values=data_div, label_ids=labels_div, group_size=len(labels_reg), group_width=0.75, shift=0, stacked=True, horizontal=True) + dpg.configure_item("divergent_stack_series", values=data_div, label_ids=labels_div, group_size=len(labels_div), group_width=0.75, shift=0, stacked=True, horizontal=True) else: - dpg.configure_item("divergent_stack_series", values=data_reg, label_ids=labels_reg, group_size=len(labels_div), group_width=0.75, shift=0, stacked=True, horizontal=True) + dpg.configure_item("divergent_stack_series", values=data_reg, label_ids=labels_reg, group_size=len(labels_reg), group_width=0.75, shift=0, stacked=True, horizontal=True) dpg.add_checkbox(label="Divergent", tag="divergent_stack_cb", default_value=True, callback=divergent_stack_cb) with dpg.plot(label="PolitiFact: Who Lies More?", height=400, width=-1): diff --git a/docs/source/conf.py b/docs/source/conf.py index aebf6928a..15260b499 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -16,7 +16,7 @@ # -- Project information ----------------------------------------------------- project = 'Dear PyGui' -copyright = '2024, Jonathan Hoffstadt and Preston Cothren' +copyright = '2025, Jonathan Hoffstadt and Preston Cothren' author = 'Jonathan Hoffstadt and Preston Cothren' diff --git a/docs/source/documentation/plots.rst b/docs/source/documentation/plots.rst index fa6a43ee2..07489fb2a 100644 --- a/docs/source/documentation/plots.rst +++ b/docs/source/documentation/plots.rst @@ -342,14 +342,23 @@ Querying -------- Querying allows the user to select a region of the plot by -holding with the right mouse button and clicking with the left one. +**Ctrl + dragging the right mouse button** and dragging five +circles of the query rectangle with left mouse button. + +Double left click inside a drag rect will remove it (if *min_query_rects* allows). +If number of rects exceed *max_query_rects* when create new drag rect, it will replace the last one. + +Since DearPyGui 2.0, *query_mod* changes to *query_toggle_mod* for swapping the Ctrl key above. +*query_button* is removed, so **dragging the right mouse button** is hardcoded. +*min_query_rects, max_query_rects* limit the number of drag rects. Querying requires setting *query* to **True** when creating the plot. -The callback of the plot will run when the plot is being queried. +The callback of the plot will run when the plot is being queried (dragging five circles). +Or not using plot's callback but drag rect's callback *dpg.add_drag_rect(callback=...)*. All the query areas are sent through the *app_data* argument as -*[(x_min, x_max, y_min, y_max), (x_min, x_max, y_min, y_max), ...]*. +*((x_min, y_min, x_max, y_max), (x_min, y_min, x_max, y_max), ...)*. It is also possible to poll the plot for the query areas by calling: :py:func:`get_plot_query_rects ` and @@ -370,16 +379,22 @@ Below is an example using the callback sindatay.append(0.5 + 0.5 * sin(50 * i / 100)) with dpg.window(label="Tutorial", width=400, height=600): - dpg.add_text("Click and drag the middle mouse button over the top plot!") + dpg.add_text("Ctrl and drag the right mouse button over the top plot!") def query(sender, app_data, user_data): - dpg.set_axis_limits("xaxis_tag2", app_data[0], app_data[1]) - dpg.set_axis_limits("yaxis_tag2", app_data[2], app_data[3]) + # TODO: handle for when app_data is empty - IndexError: tuple index out of range. + rect_0 = app_data[0] + # other_rects = app_data[1:] + dpg.set_axis_limits("xaxis_tag2", rect_0[0], rect_0[2]) + dpg.set_axis_limits("yaxis_tag2", rect_0[1], rect_0[3]) # plot 1 - with dpg.plot(no_title=True, height=200, callback=query, query=True, no_menus=True, width=-1): + with dpg.plot( + no_title=True, height=200, callback=query, query=True, no_menus=True, width=-1, + min_query_rects=0, max_query_rects=3, + ): dpg.add_plot_axis(dpg.mvXAxis, label="x") dpg.add_plot_axis(dpg.mvYAxis, label="y") dpg.add_line_series(sindatax, sindatay, parent=dpg.last_item()) @@ -593,4 +608,4 @@ Gallery .. image:: https://raw.githubusercontent.com/wiki/epezent/implot/screenshots3/heat.gif -.. image:: https://raw.githubusercontent.com/wiki/epezent/implot/screenshots3/tables.gif \ No newline at end of file +.. image:: https://raw.githubusercontent.com/wiki/epezent/implot/screenshots3/tables.gif diff --git a/docs/source/documentation/tables.rst b/docs/source/documentation/tables.rst index e703d819c..1d444a833 100644 --- a/docs/source/documentation/tables.rst +++ b/docs/source/documentation/tables.rst @@ -252,7 +252,7 @@ You can also set columns individually by using the with dpg.table(header_row=True, policy=dpg.mvTable_SizingFixedFit, row_background=True, reorderable=True, resizable=True, no_host_extendX=False, hideable=True, - borders_innerV=True, delay_search=True, borders_outerV=True, borders_innerH=True, + borders_innerV=True, borders_outerV=True, borders_innerH=True, borders_outerH=True): dpg.add_table_column(label="AAA", width_fixed=True) diff --git a/docs/source/extra/video-tutorials.rst b/docs/source/extra/video-tutorials.rst index a10f48482..9ba6582ba 100644 --- a/docs/source/extra/video-tutorials.rst +++ b/docs/source/extra/video-tutorials.rst @@ -221,15 +221,15 @@ with a callback close_popup("popup1"). The docking feature enables the user to dock windows to each other and the viewport. -The docking feature is not documented yet (as of January 2021). +The docking feature is not documented yet (as of September 2025). -enable_docking() will enable experimental docking. +Setting the `docking` argument to `True` in `configure_app()` will enable experimental docking. By default, the user needs to hold the shift key to enable docking. -The keyword shift_only = False enables docking without holding the shift key. +Setting `docking_shift_only = False` enables docking without holding the shift key. -The keyword dock_space = True enables docking windows to the viewport. +Setting `docking_space = True` enables docking windows to the viewport. The docking feature is experimental because you cannot programmatically set up the docking positions. diff --git a/setup.py b/setup.py index 8350a9607..c8d3c0523 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ import shutil import subprocess -wip_version = "2.0.0" +wip_version = "2.1.1" def version_number(): """This function reads the version number which is populated by github actions""" @@ -65,10 +65,10 @@ def run(self): return if get_platform() == "Windows": - command = [r'set PATH="C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin";"C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin";"C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin";%PATH% && '] + command = [r'set PATH="C:\Program Files (x86)\Microsoft Visual Studio\2022\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin";"C:\Program Files (x86)\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin";"C:\Program Files (x86)\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin";%PATH% && '] command.append("mkdir cmake-build-local && ") command.append("cd cmake-build-local && ") - command.append('cmake .. -G "Visual Studio 16 2019" -A "x64" -DMVDIST_ONLY=True -DMVDPG_VERSION=') + command.append('cmake .. -G "Visual Studio 17 2022" -A "x64" -DMVDIST_ONLY=True -DMVDPG_VERSION=') command.append(version_number() + " -DMV_PY_VERSION=") command.append(str(sys.version_info[0]) + "." + str(sys.version_info[1]) + " && ") command.append("cd .. && cmake --build cmake-build-local --config Release") @@ -186,6 +186,7 @@ def setup_package(): 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.12', 'Programming Language :: Python :: 3.13', + 'Programming Language :: Python :: 3.14', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: 3 :: Only', 'Topic :: Software Development :: User Interfaces', diff --git a/src/dearpygui.cpp b/src/dearpygui.cpp index 867d382cb..d2bdc28c3 100644 --- a/src/dearpygui.cpp +++ b/src/dearpygui.cpp @@ -69,6 +69,24 @@ GetModuleConstants() ModuleConstants.push_back({"mvComboHeight_Large", 2L }); ModuleConstants.push_back({"mvComboHeight_Largest", 3L }); + ModuleConstants.push_back({"mvEventType_Off", mvEventType_Off }); + ModuleConstants.push_back({"mvEventType_Enter", mvEventType_Enter }); + ModuleConstants.push_back({"mvEventType_On", mvEventType_On }); + ModuleConstants.push_back({"mvEventType_Leave", mvEventType_Leave }); + + // We're not adding 'None' because it's useless in the API + ModuleConstants.push_back({"mvSetScrollFlags_Now", mvSetScrollFlags_Now }); + ModuleConstants.push_back({"mvSetScrollFlags_Delayed", mvSetScrollFlags_Delayed }); + ModuleConstants.push_back({"mvSetScrollFlags_Both", mvSetScrollFlags_Both }); + + ModuleConstants.push_back({"mvScrollDirection_XAxis", mvScrollDirection_XAxis }); + ModuleConstants.push_back({"mvScrollDirection_YAxis", mvScrollDirection_YAxis }); + ModuleConstants.push_back({"mvScrollDirection_Horizontal", mvScrollDirection_Horizontal }); + ModuleConstants.push_back({"mvScrollDirection_Vertical", mvScrollDirection_Vertical }); + + ModuleConstants.push_back({"mvLoadInd_DottedCircle", mvLoadingIndicator::Style_DottedCircle }); + ModuleConstants.push_back({"mvLoadInd_Ring", mvLoadingIndicator::Style_Ring }); + ModuleConstants.push_back({"mvPlatform_Windows", 0L }); ModuleConstants.push_back({"mvPlatform_Apple", 1L }); ModuleConstants.push_back({"mvPlatform_Linux", 2L }); @@ -495,6 +513,8 @@ common_constructor(const char* command, mvAppItemType type, PyObject* self, PyOb AddItemWithRuntimeChecks((*GContext->itemRegistry), item, parent, before); + GContext->itemRegistry->allItems[id] = item.get(); + // return raw UUID if alias not used if (item->config.alias.empty()) return Py_BuildValue("K", id); diff --git a/src/dearpygui_commands.h b/src/dearpygui_commands.h index 457f2884b..06ab363ce 100644 --- a/src/dearpygui_commands.h +++ b/src/dearpygui_commands.h @@ -24,9 +24,9 @@ bind_colormap(PyObject* self, PyObject* args, PyObject* kwargs) PyObject* sourceraw; if (!Parse((GetParsers())["bind_colormap"], args, kwargs, __FUNCTION__, &itemraw, &sourceraw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); mvUUID source = GetIDFromPyObject(sourceraw); @@ -36,7 +36,7 @@ bind_colormap(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "bind_colormap", "Item not found: " + std::to_string(item), nullptr); - return GetPyNone(); + return nullptr; } if (source > 15) @@ -46,7 +46,7 @@ bind_colormap(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "bind_colormap", "Source Item not found: " + std::to_string(source), nullptr); - return GetPyNone(); + return nullptr; } if (asource->type == mvAppItemType::mvColorMap) @@ -86,7 +86,7 @@ bind_colormap(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "bind_colormap", "Incompatible type. Expected types include: mvPlot, mvColorMapScale, mvColorMapButton", aitem); - return GetPyNone(); + return nullptr; } @@ -100,9 +100,9 @@ sample_colormap(PyObject* self, PyObject* args, PyObject* kwargs) float t; if (!Parse((GetParsers())["sample_colormap"], args, kwargs, __FUNCTION__, &itemraw, &t)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); @@ -113,7 +113,7 @@ sample_colormap(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "sample_colormap", "Source Item not found: " + std::to_string(item), nullptr); - return GetPyNone(); + return nullptr; } if (asource->type == mvAppItemType::mvColorMap) @@ -127,7 +127,7 @@ sample_colormap(PyObject* self, PyObject* args, PyObject* kwargs) if (!GContext->started) { mvThrowPythonError(mvErrorCode::mvNone, "sample_colormap", "This command can only be ran once the app is started.", nullptr); - return GetPyNone(); + return nullptr; } ImVec4 result = ImPlot::SampleColormap(t, (ImPlotColormap)item); @@ -142,9 +142,9 @@ get_colormap_color(PyObject* self, PyObject* args, PyObject* kwargs) int index; if (!Parse((GetParsers())["get_colormap_color"], args, kwargs, __FUNCTION__, &itemraw, &index)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); @@ -155,7 +155,7 @@ get_colormap_color(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "get_colormap_color", "Source Item not found: " + std::to_string(item), nullptr); - return GetPyNone(); + return nullptr; } if (asource->type == mvAppItemType::mvColorMap) @@ -177,9 +177,9 @@ get_file_dialog_info(PyObject* self, PyObject* args, PyObject* kwargs) PyObject* file_dialog_raw; if (!Parse((GetParsers())["get_file_dialog_info"], args, kwargs, __FUNCTION__, &file_dialog_raw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID file_dialog = GetIDFromPyObject(file_dialog_raw); @@ -187,13 +187,13 @@ get_file_dialog_info(PyObject* self, PyObject* args, PyObject* kwargs) if (aplot == nullptr) { mvThrowPythonError(mvErrorCode::mvNone, std::to_string(file_dialog) + " plot does not exist."); - return GetPyNone(); + return nullptr; } if (aplot->type != mvAppItemType::mvFileDialog) { mvThrowPythonError(mvErrorCode::mvNone, std::to_string(file_dialog) + " is not a plot."); - return GetPyNone(); + return nullptr; } mvFileDialog* graph = static_cast(aplot); @@ -207,12 +207,13 @@ set_x_scroll(PyObject* self, PyObject* args, PyObject* kwargs) PyObject* itemraw; float value; + int when = (int)mvSetScrollFlags_Delayed; if (!Parse((GetParsers())["set_x_scroll"], args, kwargs, __FUNCTION__, - &itemraw, &value)) - return GetPyNone(); + &itemraw, &value, &when)) + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); @@ -221,33 +222,19 @@ set_x_scroll(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "set_x_scroll", "Item not found: " + std::to_string(item), nullptr); - return GetPyNone(); + return nullptr; } - if (window->type == mvAppItemType::mvWindowAppItem) + if (DearPyGui::GetApplicableState(window->type) & MV_STATE_SCROLL) { - - auto pWindow = static_cast(window); - - pWindow->configData.scrollX = value; - pWindow->configData._scrollXSet = true; - } - else if (window->type == mvAppItemType::mvChildWindow) - { - auto pChild = static_cast(window); - pChild->configData.scrollX = value; - pChild->configData._scrollXSet = true; - } - else if (window->type == mvAppItemType::mvTable) - { - auto pChild = static_cast(window); - pChild->_scrollX = value; - pChild->_scrollXSet = true; + window->config.scrollX = value; + window->config.scrollXFlags = (mvSetScrollFlags)when; } else { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "set_x_scroll", "Incompatible type. Expected types include: mvWindowAppItem, mvChildWindow, mvTable", window); + return nullptr; } return GetPyNone(); @@ -259,12 +246,13 @@ set_y_scroll(PyObject* self, PyObject* args, PyObject* kwargs) PyObject* itemraw; float value; + int when = (int)mvSetScrollFlags_Delayed; if (!Parse((GetParsers())["set_y_scroll"], args, kwargs, __FUNCTION__, - &itemraw, &value)) - return GetPyNone(); + &itemraw, &value, &when)) + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); @@ -273,33 +261,19 @@ set_y_scroll(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "set_y_scroll", "Item not found: " + std::to_string(item), nullptr); - return GetPyNone(); + return nullptr; } - if (window->type == mvAppItemType::mvWindowAppItem) - { - - auto pWindow = static_cast(window); - - pWindow->configData.scrollY = value; - pWindow->configData._scrollYSet = true; - } - else if (window->type == mvAppItemType::mvChildWindow) + if (DearPyGui::GetApplicableState(window->type) & MV_STATE_SCROLL) { - auto pChild = static_cast(window); - pChild->configData.scrollY = value; - pChild->configData._scrollYSet = true; - } - else if (window->type == mvAppItemType::mvTable) - { - auto pChild = static_cast(window); - pChild->_scrollY = value; - pChild->_scrollYSet = true; + window->config.scrollY = value; + window->config.scrollYFlags = (mvSetScrollFlags)when; } else { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "set_y_scroll", "Incompatible type. Expected types include: mvWindowAppItem, mvChildWindow, mvTable", window); + return nullptr; } return GetPyNone(); @@ -313,9 +287,9 @@ get_x_scroll(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["get_x_scroll"], args, kwargs, __FUNCTION__, &itemraw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); @@ -324,32 +298,18 @@ get_x_scroll(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "get_x_scroll", "Item not found: " + std::to_string(item), nullptr); - return GetPyNone(); + return nullptr; } - if (window->type == mvAppItemType::mvWindowAppItem) + if (DearPyGui::GetApplicableState(window->type) & MV_STATE_SCROLL) { - - auto pWindow = static_cast(window); - - return ToPyFloat(pWindow->configData.scrollX); - } - else if (window->type == mvAppItemType::mvChildWindow) - { - auto pChild = static_cast(window); - - return ToPyFloat(pChild->configData.scrollX); - } - else if (window->type == mvAppItemType::mvTable) - { - auto pTable = static_cast(window); - - return ToPyFloat(pTable->_scrollX); + return ToPyFloat(window->state.scrollPos.x); } else { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "get_x_scroll", "Incompatible type. Expected types include: mvWindowAppItem, mvChildWindow, mvTable", window); + return nullptr; } return GetPyNone(); @@ -363,9 +323,9 @@ get_y_scroll(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["get_y_scroll"], args, kwargs, __FUNCTION__, &itemraw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); @@ -374,32 +334,18 @@ get_y_scroll(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "get_y_scroll", "Item not found: " + std::to_string(item), nullptr); - return GetPyNone(); + return nullptr; } - if (window->type == mvAppItemType::mvWindowAppItem) + if (DearPyGui::GetApplicableState(window->type) & MV_STATE_SCROLL) { - - auto pWindow = static_cast(window); - - return ToPyFloat(pWindow->configData.scrollY); - } - else if (window->type == mvAppItemType::mvChildWindow) - { - auto pChild = static_cast(window); - - return ToPyFloat(pChild->configData.scrollY); - } - else if (window->type == mvAppItemType::mvTable) - { - auto pTable = static_cast(window); - - return ToPyFloat(pTable->_scrollY); + return ToPyFloat(window->state.scrollPos.y); } else { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "get_y_scroll", "Incompatible type. Expected types include: mvWindowAppItem, mvChildWindow, mvTable", window); + return nullptr; } return GetPyNone(); @@ -413,9 +359,9 @@ get_x_scroll_max(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["get_x_scroll_max"], args, kwargs, __FUNCTION__, &itemraw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); @@ -424,32 +370,18 @@ get_x_scroll_max(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "get_x_scroll_max", "Item not found: " + std::to_string(item), nullptr); - return GetPyNone(); + return nullptr; } - if (window->type == mvAppItemType::mvWindowAppItem) + if (DearPyGui::GetApplicableState(window->type) & MV_STATE_SCROLL) { - - auto pWindow = static_cast(window); - - return ToPyFloat(pWindow->configData.scrollMaxX); - } - else if (window->type == mvAppItemType::mvChildWindow) - { - auto pChild = static_cast(window); - - return ToPyFloat(pChild->configData.scrollMaxX); - } - else if (window->type == mvAppItemType::mvTable) - { - auto pTable = static_cast(window); - - return ToPyFloat(pTable->_scrollMaxX); + return ToPyFloat(window->state.scrollMax.x); } else { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "get_x_scroll_max", "Incompatible type. Expected types include: mvWindowAppItem, mvChildWindow, mvTable", window); + return nullptr; } return GetPyNone(); @@ -463,9 +395,9 @@ get_y_scroll_max(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["get_y_scroll_max"], args, kwargs, __FUNCTION__, &itemraw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); @@ -474,32 +406,18 @@ get_y_scroll_max(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "get_y_scroll_max", "Item not found: " + std::to_string(item), nullptr); - return GetPyNone(); + return nullptr; } - if (window->type == mvAppItemType::mvWindowAppItem) - { - - auto pWindow = static_cast(window); - - return ToPyFloat(pWindow->configData.scrollMaxY); - } - else if (window->type == mvAppItemType::mvChildWindow) - { - auto pChild = static_cast(window); - - return ToPyFloat(pChild->configData.scrollMaxY); - } - else if (window->type == mvAppItemType::mvTable) + if (DearPyGui::GetApplicableState(window->type) & MV_STATE_SCROLL) { - auto pTable = static_cast(window); - - return ToPyFloat(pTable->_scrollMaxY); + return ToPyFloat(window->state.scrollMax.y); } else { - mvThrowPythonError(mvErrorCode::mvIncompatibleType, "set_y_scroll_max", + mvThrowPythonError(mvErrorCode::mvIncompatibleType, "get_y_scroll_max", "Incompatible type. Expected types include: mvWindowAppItem, mvChildWindow, mvTable", window); + return nullptr; } return GetPyNone(); @@ -518,9 +436,9 @@ set_clip_space(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["set_clip_space"], args, kwargs, __FUNCTION__, &itemraw, &topleftx, &toplefty, &width, &height, &mindepth, &maxdepth)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); @@ -529,7 +447,7 @@ set_clip_space(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "apply_transform", "Item not found: " + std::to_string(item), nullptr); - return GetPyNone(); + return nullptr; } if (aitem->type == mvAppItemType::mvDrawLayer) @@ -554,7 +472,7 @@ set_clip_space(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "applydrawInfo->transform", "Incompatible type. Expected types include: mvDrawLayer", aitem); - return GetPyNone(); + return nullptr; } @@ -568,9 +486,9 @@ apply_transform(PyObject* self, PyObject* args, PyObject* kwargs) PyObject* transform; if (!Parse((GetParsers())["apply_transform"], args, kwargs, __FUNCTION__, &itemraw, &transform)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); @@ -581,7 +499,7 @@ apply_transform(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "apply_transform", "Item not found: " + std::to_string(item), nullptr); - return GetPyNone(); + return nullptr; } if (aitem->type == mvAppItemType::mvDrawNode) @@ -594,7 +512,7 @@ apply_transform(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "apply_transform", "Incompatible type. Expected types include: mvDrawNode", aitem); - return GetPyNone(); + return nullptr; } @@ -609,9 +527,9 @@ create_rotation_matrix(PyObject* self, PyObject* args, PyObject* kwargs) PyObject* axis; if (!Parse((GetParsers())["create_rotation_matrix"], args, kwargs, __FUNCTION__, &angle, &axis)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvVec4 aaxis = ToVec4(axis); @@ -635,9 +553,9 @@ create_perspective_matrix(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["create_perspective_matrix"], args, kwargs, __FUNCTION__, &fov, &aspect, &zNear, &zFar)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); PyObject* newbuffer = nullptr; PymvMat4* newbufferview = nullptr; @@ -661,9 +579,9 @@ create_orthographic_matrix(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["create_orthographic_matrix"], args, kwargs, __FUNCTION__, &left, &right, &bottom, &top, &zNear, &zFar)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); PyObject* newbuffer = nullptr; PymvMat4* newbufferview = nullptr; @@ -682,9 +600,9 @@ create_translation_matrix(PyObject* self, PyObject* args, PyObject* kwargs) PyObject* axis; if (!Parse((GetParsers())["create_translation_matrix"], args, kwargs, __FUNCTION__, &axis)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvVec4 aaxis = ToVec4(axis); @@ -705,9 +623,9 @@ create_scale_matrix(PyObject* self, PyObject* args, PyObject* kwargs) PyObject* axis; if (!Parse((GetParsers())["create_scale_matrix"], args, kwargs, __FUNCTION__, &axis)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvVec4 aaxis = ToVec4(axis); @@ -731,9 +649,9 @@ create_lookat_matrix(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["create_lookat_matrix"], args, kwargs, __FUNCTION__, &eye, ¢er, &up)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvVec4 aeye = ToVec4(eye); mvVec4 acenter = ToVec4(center); @@ -759,9 +677,9 @@ create_fps_matrix(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["create_fps_matrix"], args, kwargs, __FUNCTION__, &eye, &pitch, &yaw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvVec4 aeye = ToVec4(eye); PyObject* newbuffer = nullptr; @@ -782,9 +700,9 @@ bind_font(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["bind_font"], args, kwargs, __FUNCTION__, &itemraw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); @@ -800,14 +718,14 @@ bind_font(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "bind_font", "Item not found: " + std::to_string(item), nullptr); - return GetPyNone(); + return nullptr; } if (aplot->type != mvAppItemType::mvFont) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "bind_font", "Incompatible type. Expected types include: mvFont", aplot); - return GetPyNone(); + return nullptr; } mvFont* graph = static_cast(aplot); @@ -828,9 +746,9 @@ get_text_size(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["get_text_size"], args, kwargs, __FUNCTION__, &text, &wrap_width, &fontRaw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID font = GetIDFromPyObject(fontRaw); @@ -848,14 +766,14 @@ get_text_size(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "get_text_size", "Item not found: " + std::to_string(font), nullptr); - return GetPyNone(); + return nullptr; } if (afont->type != mvAppItemType::mvFont) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "get_text_size", "Incompatible type. Expected types include: mvFont", afont); - return GetPyNone(); + return nullptr; } mvFont* graph = static_cast(afont); @@ -885,7 +803,7 @@ get_selected_nodes(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["get_selected_nodes"], args, kwargs, __FUNCTION__, &node_editor_raw)) return ToPyBool(false); - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID node_editor = GetIDFromPyObject(node_editor_raw); @@ -894,14 +812,14 @@ get_selected_nodes(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "get_selected_nodes", "Item not found: " + std::to_string(node_editor), nullptr); - return GetPyNone(); + return nullptr; } if (anode_editor->type != mvAppItemType::mvNodeEditor) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "get_selected_nodes", "Incompatible type. Expected types include: mvNodeEditor", anode_editor); - return GetPyNone(); + return nullptr; } mvNodeEditor* editor = static_cast(anode_editor); @@ -920,7 +838,7 @@ get_selected_links(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["get_selected_links"], args, kwargs, __FUNCTION__, &node_editor_raw)) return ToPyBool(false); - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID node_editor = GetIDFromPyObject(node_editor_raw); @@ -929,14 +847,14 @@ get_selected_links(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "get_selected_links", "Item not found: " + std::to_string(node_editor), nullptr); - return GetPyNone(); + return nullptr; } if (anode_editor->type != mvAppItemType::mvNodeEditor) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "get_selected_links", "Incompatible type. Expected types include: mvNodeEditor", anode_editor); - return GetPyNone(); + return nullptr; } mvNodeEditor* editor = static_cast(anode_editor); @@ -954,7 +872,7 @@ clear_selected_links(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["clear_selected_links"], args, kwargs, __FUNCTION__, &node_editor_raw)) return ToPyBool(false); - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID node_editor = GetIDFromPyObject(node_editor_raw); @@ -963,14 +881,14 @@ clear_selected_links(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "clear_selected_links", "Item not found: " + std::to_string(node_editor), nullptr); - return GetPyNone(); + return nullptr; } if (anode_editor->type != mvAppItemType::mvNodeEditor) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "clear_selected_links", "Incompatible type. Expected types include: mvNodeEditor", anode_editor); - return GetPyNone(); + return nullptr; } mvNodeEditor* editor = static_cast(anode_editor); @@ -988,7 +906,7 @@ clear_selected_nodes(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["clear_selected_nodes"], args, kwargs, __FUNCTION__, &node_editor_raw)) return ToPyBool(false); - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID node_editor = GetIDFromPyObject(node_editor_raw); @@ -997,14 +915,14 @@ clear_selected_nodes(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "clear_selected_nodes", "Item not found: " + std::to_string(node_editor), nullptr); - return GetPyNone(); + return nullptr; } if (anode_editor->type != mvAppItemType::mvNodeEditor) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "clear_selected_nodes", "Incompatible type. Expected types include: mvNodeEditor", anode_editor); - return GetPyNone(); + return nullptr; } mvNodeEditor* editor = static_cast(anode_editor); @@ -1021,9 +939,9 @@ get_plot_query_rects(PyObject* self, PyObject* args, PyObject* kwargs) auto tag = "get_plot_query_rects"; if (!Parse((GetParsers())[tag], args, kwargs, __FUNCTION__, &plotraw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID plot = GetIDFromPyObject(plotraw); @@ -1031,13 +949,13 @@ get_plot_query_rects(PyObject* self, PyObject* args, PyObject* kwargs) if (aplot == nullptr) { mvThrowPythonError(mvErrorCode::mvItemNotFound, tag, "Item not found: " + std::to_string(plot), nullptr); - return GetPyNone(); + return nullptr; } if (aplot->type != mvAppItemType::mvPlot) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, tag, "Incompatible type. Expected types include: mvPlot", aplot); - return GetPyNone(); + return nullptr; } mvPlot* graph = static_cast(aplot); @@ -1059,11 +977,11 @@ set_axis_ticks(PyObject* self, PyObject* args, PyObject* kwargs) PyObject* label_pairs; if (!Parse((GetParsers())["set_axis_ticks"], args, kwargs, __FUNCTION__, &plotraw, &label_pairs)) - return GetPyNone(); + return nullptr; auto mlabel_pairs = ToVectPairStringFloat(label_pairs); - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID plot = GetIDFromPyObject(plotraw); @@ -1072,14 +990,14 @@ set_axis_ticks(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "set_axis_ticks", "Item not found: " + std::to_string(plot), nullptr); - return GetPyNone(); + return nullptr; } if (aplot->type != mvAppItemType::mvPlotAxis) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "set_axis_ticks", "Incompatible type. Expected types include: mvPlotAxis", aplot); - return GetPyNone(); + return nullptr; } mvPlotAxis* graph = static_cast(aplot); @@ -1114,9 +1032,9 @@ set_axis_limits_constraints(PyObject* self, PyObject* args, PyObject* kwargs) auto tag = "set_axis_limits_constraints"; if (!Parse((GetParsers())[tag], args, kwargs, __FUNCTION__, &axisraw, &vmin, &vmax)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID axis = GetIDFromPyObject(axisraw); @@ -1125,14 +1043,14 @@ set_axis_limits_constraints(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, tag, "Item not found: " + std::to_string(axis), nullptr); - return GetPyNone(); + return nullptr; } if (aplot->type != mvAppItemType::mvPlotAxis) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, tag, "Incompatible type. Expected types include: mvPlotAxis", aplot); - return GetPyNone(); + return nullptr; } mvPlotAxis* graph = static_cast(aplot); @@ -1148,9 +1066,9 @@ reset_axis_limits_constraints(PyObject* self, PyObject* args, PyObject* kwargs) auto tag = "reset_axis_limits_constraints"; if (!Parse((GetParsers())[tag], args, kwargs, __FUNCTION__, &axisraw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID axis = GetIDFromPyObject(axisraw); @@ -1159,14 +1077,14 @@ reset_axis_limits_constraints(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, tag, "Item not found: " + std::to_string(axis), nullptr); - return GetPyNone(); + return nullptr; } if (aplot->type != mvAppItemType::mvPlotAxis) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, tag, "Incompatible type. Expected types include: mvPlotAxis", aplot); - return GetPyNone(); + return nullptr; } mvPlotAxis* graph = static_cast(aplot); @@ -1183,9 +1101,9 @@ set_axis_zoom_constraints(PyObject* self, PyObject* args, PyObject* kwargs) auto tag = "set_axis_zoom_constraints"; if (!Parse((GetParsers())[tag], args, kwargs, __FUNCTION__, &axisraw, &vmin, &vmax)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID axis = GetIDFromPyObject(axisraw); @@ -1194,14 +1112,14 @@ set_axis_zoom_constraints(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, tag, "Item not found: " + std::to_string(axis), nullptr); - return GetPyNone(); + return nullptr; } if (aplot->type != mvAppItemType::mvPlotAxis) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, tag, "Incompatible type. Expected types include: mvPlotAxis", aplot); - return GetPyNone(); + return nullptr; } mvPlotAxis* graph = static_cast(aplot); @@ -1218,9 +1136,9 @@ reset_axis_zoom_constraints(PyObject* self, PyObject* args, PyObject* kwargs) auto tag = "reset_axis_zoom_constraints"; if (!Parse((GetParsers())[tag], args, kwargs, __FUNCTION__, &axisraw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID axis = GetIDFromPyObject(axisraw); @@ -1229,14 +1147,14 @@ reset_axis_zoom_constraints(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, tag, "Item not found: " + std::to_string(axis), nullptr); - return GetPyNone(); + return nullptr; } if (aplot->type != mvAppItemType::mvPlotAxis) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, tag, "Incompatible type. Expected types include: mvPlotAxis", aplot); - return GetPyNone(); + return nullptr; } mvPlotAxis* graph = static_cast(aplot); @@ -1253,9 +1171,9 @@ set_axis_limits(PyObject* self, PyObject* args, PyObject* kwargs) float ymax; if (!Parse((GetParsers())["set_axis_limits"], args, kwargs, __FUNCTION__, &axisraw, &ymin, &ymax)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID axis = GetIDFromPyObject(axisraw); @@ -1264,14 +1182,14 @@ set_axis_limits(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "set_axis_limits", "Item not found: " + std::to_string(axis), nullptr); - return GetPyNone(); + return nullptr; } if (aplot->type != mvAppItemType::mvPlotAxis) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "set_axis_limits", "Incompatible type. Expected types include: mvPlotAxis", aplot); - return GetPyNone(); + return nullptr; } mvPlotAxis* graph = static_cast(aplot); @@ -1286,9 +1204,9 @@ set_axis_limits_auto(PyObject* self, PyObject* args, PyObject* kwargs) PyObject* axisraw; if (!Parse((GetParsers())["set_axis_limits_auto"], args, kwargs, __FUNCTION__, &axisraw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID axis = GetIDFromPyObject(axisraw); @@ -1297,14 +1215,14 @@ set_axis_limits_auto(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "set_axis_limits", "Item not found: " + std::to_string(axis), nullptr); - return GetPyNone(); + return nullptr; } if (aplot->type != mvAppItemType::mvPlotAxis) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "set_axis_limits", "Incompatible type. Expected types include: mvPlotAxis", aplot); - return GetPyNone(); + return nullptr; } mvPlotAxis* graph = static_cast(aplot); @@ -1320,9 +1238,9 @@ fit_axis_data(PyObject* self, PyObject* args, PyObject* kwargs) PyObject* axisraw; if (!Parse((GetParsers())["fit_axis_data"], args, kwargs, __FUNCTION__, &axisraw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID axis = GetIDFromPyObject(axisraw); @@ -1331,14 +1249,14 @@ fit_axis_data(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "fit_axis_data", "Item not found: " + std::to_string(axis), nullptr); - return GetPyNone(); + return nullptr; } if (aplot->type != mvAppItemType::mvPlotAxis) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "fit_axis_data", "Incompatible type. Expected types include: mvPlotAxis", aplot); - return GetPyNone(); + return nullptr; } mvPlotAxis* graph = static_cast(aplot); @@ -1356,9 +1274,9 @@ get_axis_limits(PyObject* self, PyObject* args, PyObject* kwargs) PyObject* plotraw; if (!Parse((GetParsers())["get_axis_limits"], args, kwargs, __FUNCTION__, &plotraw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID plot = GetIDFromPyObject(plotraw); @@ -1367,14 +1285,14 @@ get_axis_limits(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "get_axis_limits", "Item not found: " + std::to_string(plot), nullptr); - return GetPyNone(); + return nullptr; } if (aplot->type != mvAppItemType::mvPlotAxis) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "get_axis_limits", "Incompatible type. Expected types include: mvPlotAxis", aplot); - return GetPyNone(); + return nullptr; } mvPlotAxis* graph = static_cast(aplot); @@ -1389,9 +1307,9 @@ reset_axis_ticks(PyObject* self, PyObject* args, PyObject* kwargs) PyObject* plotraw; if (!Parse((GetParsers())["reset_axis_ticks"], args, kwargs, __FUNCTION__, &plotraw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID plot = GetIDFromPyObject(plotraw); @@ -1400,14 +1318,14 @@ reset_axis_ticks(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "reset_axis_ticks", "Item not found: " + std::to_string(plot), nullptr); - return GetPyNone(); + return nullptr; } if (aplot->type != mvAppItemType::mvPlotAxis) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "reset_axis_ticks", "Incompatible type. Expected types include: mvPlotAxis", aplot); - return GetPyNone(); + return nullptr; } mvPlotAxis* graph = static_cast(aplot); @@ -1427,9 +1345,9 @@ highlight_table_column(PyObject* self, PyObject* args, PyObject* kwargs) PyObject* color; if (!Parse((GetParsers())["highlight_table_column"], args, kwargs, __FUNCTION__, &tableraw, &column, &color)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID table = GetIDFromPyObject(tableraw); @@ -1438,14 +1356,14 @@ highlight_table_column(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "highlight_table_column", "Item not found: " + std::to_string(table), nullptr); - return GetPyNone(); + return nullptr; } if (atable->type != mvAppItemType::mvTable) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "highlight_table_column", "Incompatible type. Expected types include: mvTable", atable); - return GetPyNone(); + return nullptr; } mvTable* tablecast = static_cast(atable); @@ -1454,7 +1372,7 @@ highlight_table_column(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvNone, "highlight_table_column", "Column out of range", tablecast); - return GetPyNone(); + return nullptr; } mvColor finalColor = ToColor(color); @@ -1471,9 +1389,9 @@ unhighlight_table_column(PyObject* self, PyObject* args, PyObject* kwargs) int column = 0; if (!Parse((GetParsers())["unhighlight_table_column"], args, kwargs, __FUNCTION__, &tableraw, &column)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID table = GetIDFromPyObject(tableraw); @@ -1482,14 +1400,14 @@ unhighlight_table_column(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "unhighlight_table_column", "Item not found: " + std::to_string(table), nullptr); - return GetPyNone(); + return nullptr; } if (atable->type != mvAppItemType::mvTable) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "unhighlight_table_column", "Incompatible type. Expected types include: mvTable", atable); - return GetPyNone(); + return nullptr; } mvTable* tablecast = static_cast(atable); @@ -1498,7 +1416,7 @@ unhighlight_table_column(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvNone, "unhighlight_table_column", "Column out of range", tablecast); - return GetPyNone(); + return nullptr; } tablecast->_columnColorsSet[column] = false; @@ -1514,9 +1432,9 @@ set_table_row_color(PyObject* self, PyObject* args, PyObject* kwargs) PyObject* color; if (!Parse((GetParsers())["set_table_row_color"], args, kwargs, __FUNCTION__, &tableraw, &row, &color)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID table = GetIDFromPyObject(tableraw); @@ -1525,14 +1443,14 @@ set_table_row_color(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "set_table_row_color", "Item not found: " + std::to_string(table), nullptr); - return GetPyNone(); + return nullptr; } if (atable->type != mvAppItemType::mvTable) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "set_table_row_color", "Incompatible type. Expected types include: mvTable", atable); - return GetPyNone(); + return nullptr; } mvTable* tablecast = static_cast(atable); @@ -1541,7 +1459,7 @@ set_table_row_color(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvNone, "set_table_row_color", "Row out of range", tablecast); - return GetPyNone(); + return nullptr; } mvColor finalColor = ToColor(color); @@ -1558,9 +1476,9 @@ unset_table_row_color(PyObject* self, PyObject* args, PyObject* kwargs) int row = 0; if (!Parse((GetParsers())["unset_table_row_color"], args, kwargs, __FUNCTION__, &tableraw, &row)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID table = GetIDFromPyObject(tableraw); @@ -1569,14 +1487,14 @@ unset_table_row_color(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "unset_table_row_color", "Item not found: " + std::to_string(table), nullptr); - return GetPyNone(); + return nullptr; } if (atable->type != mvAppItemType::mvTable) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "unset_table_row_color", "Incompatible type. Expected types include: mvTable", atable); - return GetPyNone(); + return nullptr; } mvTable* tablecast = static_cast(atable); @@ -1585,7 +1503,7 @@ unset_table_row_color(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvNone, "set_table_row_color", "Row out of range", tablecast); - return GetPyNone(); + return nullptr; } tablecast->_rowColorsSet[row] = false; @@ -1600,9 +1518,9 @@ highlight_table_row(PyObject* self, PyObject* args, PyObject* kwargs) PyObject* color; if (!Parse((GetParsers())["highlight_table_row"], args, kwargs, __FUNCTION__, &tableraw, &row, &color)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID table = GetIDFromPyObject(tableraw); @@ -1611,14 +1529,14 @@ highlight_table_row(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "highlight_table_row", "Item not found: " + std::to_string(table), nullptr); - return GetPyNone(); + return nullptr; } if (atable->type != mvAppItemType::mvTable) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "highlight_table_row", "Incompatible type. Expected types include: mvTable", atable); - return GetPyNone(); + return nullptr; } mvTable* tablecast = static_cast(atable); @@ -1627,7 +1545,7 @@ highlight_table_row(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvNone, "highlight_table_row", "Row out of range", tablecast); - return GetPyNone(); + return nullptr; } mvColor finalColor = ToColor(color); @@ -1644,9 +1562,9 @@ unhighlight_table_row(PyObject* self, PyObject* args, PyObject* kwargs) int row = 0; if (!Parse((GetParsers())["unhighlight_table_row"], args, kwargs, __FUNCTION__, &tableraw, &row)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID table = GetIDFromPyObject(tableraw); @@ -1655,14 +1573,14 @@ unhighlight_table_row(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "unhighlight_table_row", "Item not found: " + std::to_string(table), nullptr); - return GetPyNone(); + return nullptr; } if (atable->type != mvAppItemType::mvTable) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "unhighlight_table_row", "Incompatible type. Expected types include: mvTable", atable); - return GetPyNone(); + return nullptr; } mvTable* tablecast = static_cast(atable); @@ -1671,7 +1589,7 @@ unhighlight_table_row(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvNone, "unselect_table_row", "Row out of range", tablecast); - return GetPyNone(); + return nullptr; } tablecast->_rowSelectionColorsSet[row] = false; @@ -1688,9 +1606,9 @@ highlight_table_cell(PyObject* self, PyObject* args, PyObject* kwargs) PyObject* color; if (!Parse((GetParsers())["highlight_table_cell"], args, kwargs, __FUNCTION__, &tableraw, &row, &column, &color)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID table = GetIDFromPyObject(tableraw); @@ -1699,14 +1617,14 @@ highlight_table_cell(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "highlight_table_cell", "Item not found: " + std::to_string(table), nullptr); - return GetPyNone(); + return nullptr; } if (atable->type != mvAppItemType::mvTable) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "highlight_table_cell", "Incompatible type. Expected types include: mvTable", atable); - return GetPyNone(); + return nullptr; } mvTable* tablecast = static_cast(atable); @@ -1715,7 +1633,7 @@ highlight_table_cell(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvNone, "highlight_table_cell", "Row/Column out of range", tablecast); - return GetPyNone(); + return nullptr; } mvColor finalColor = ToColor(color); @@ -1733,9 +1651,9 @@ unhighlight_table_cell(PyObject* self, PyObject* args, PyObject* kwargs) int column = 0; if (!Parse((GetParsers())["unhighlight_table_cell"], args, kwargs, __FUNCTION__, &tableraw, &row, &column)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID table = GetIDFromPyObject(tableraw); @@ -1744,14 +1662,14 @@ unhighlight_table_cell(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "unhighlight_table_cell", "Item not found: " + std::to_string(table), nullptr); - return GetPyNone(); + return nullptr; } if (atable->type != mvAppItemType::mvTable) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "unhighlight_table_cell", "Incompatible type. Expected types include: mvTable", atable); - return GetPyNone(); + return nullptr; } mvTable* tablecast = static_cast(atable); @@ -1760,7 +1678,7 @@ unhighlight_table_cell(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvNone, "unhighlight_table_cell", "Row/Column out of range", tablecast); - return GetPyNone(); + return nullptr; } tablecast->_cellColorsSet[row][column] = false; @@ -1776,9 +1694,9 @@ is_table_cell_highlighted(PyObject* self, PyObject* args, PyObject* kwargs) int column = 0; if (!Parse((GetParsers())["is_table_cell_highlighted"], args, kwargs, __FUNCTION__, &tableraw, &row, &column)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID table = GetIDFromPyObject(tableraw); @@ -1787,14 +1705,14 @@ is_table_cell_highlighted(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "is_table_cell_highlighted", "Item not found: " + std::to_string(table), nullptr); - return GetPyNone(); + return nullptr; } if (atable->type != mvAppItemType::mvTable) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "is_table_cell_highlighted", "Incompatible type. Expected types include: mvTable", atable); - return GetPyNone(); + return nullptr; } mvTable* tablecast = static_cast(atable); @@ -1803,7 +1721,7 @@ is_table_cell_highlighted(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvNone, "is_table_cell_highlighted", "Row/Column out of range", tablecast); - return GetPyNone(); + return nullptr; } if (tablecast->_cellColorsSet[row][column]) @@ -1823,9 +1741,9 @@ is_table_row_highlighted(PyObject* self, PyObject* args, PyObject* kwargs) int row = 0; if (!Parse((GetParsers())["is_table_row_highlighted"], args, kwargs, __FUNCTION__, &tableraw, &row)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID table = GetIDFromPyObject(tableraw); @@ -1834,14 +1752,14 @@ is_table_row_highlighted(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "is_table_row_highlighted", "Item not found: " + std::to_string(table), nullptr); - return GetPyNone(); + return nullptr; } if (atable->type != mvAppItemType::mvTable) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "is_table_row_highlighted", "Incompatible type. Expected types include: mvTable", atable); - return GetPyNone(); + return nullptr; } mvTable* tablecast = static_cast(atable); @@ -1850,7 +1768,7 @@ is_table_row_highlighted(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvNone, "is_table_row_highlighted", "Row out of range", tablecast); - return GetPyNone(); + return nullptr; } return ToPyBool(tablecast->_rowSelectionColorsSet[row]); @@ -1863,9 +1781,9 @@ is_table_column_highlighted(PyObject* self, PyObject* args, PyObject* kwargs) int column = 0; if (!Parse((GetParsers())["is_table_column_highlighted"], args, kwargs, __FUNCTION__, &tableraw, &column)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID table = GetIDFromPyObject(tableraw); @@ -1874,14 +1792,14 @@ is_table_column_highlighted(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "is_table_column_highlighted", "Item not found: " + std::to_string(table), nullptr); - return GetPyNone(); + return nullptr; } if (atable->type != mvAppItemType::mvTable) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "is_table_column_highlighted", "Incompatible type. Expected types include: mvTable", atable); - return GetPyNone(); + return nullptr; } mvTable* tablecast = static_cast(atable); @@ -1890,7 +1808,7 @@ is_table_column_highlighted(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvNone, "is_table_column_highlighted", "Column out of range", tablecast); - return GetPyNone(); + return nullptr; } return ToPyBool(tablecast->_columnColorsSet[column]); @@ -1904,9 +1822,9 @@ bind_theme(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["bind_theme"], args, kwargs, __FUNCTION__, &itemraw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); @@ -1922,14 +1840,14 @@ bind_theme(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "bind_theme", "Item not found: " + std::to_string(item), nullptr); - return GetPyNone(); + return nullptr; } if (aplot->type != mvAppItemType::mvTheme) { mvThrowPythonError(mvErrorCode::mvIncompatibleType, "bind_theme", "Incompatible type. Expected types include: mvTheme", aplot); - return GetPyNone(); + return nullptr; } mvTheme* graph = static_cast(aplot); @@ -1947,9 +1865,9 @@ set_global_font_scale(PyObject* self, PyObject* args, PyObject* kwargs) float scale; if (!Parse((GetParsers())["set_global_font_scale"], args, kwargs, __FUNCTION__, &scale)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvToolManager::GetFontManager().setGlobalFontScale(scale); return GetPyNone(); @@ -1968,7 +1886,7 @@ show_tool(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["show_tool"], args, kwargs, __FUNCTION__, &toolraw)) - return GetPyNone(); + return nullptr; mvUUID tool = GetIDFromPyObject(toolraw); @@ -1987,7 +1905,7 @@ set_decimal_point(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["set_decimal_point"], args, kwargs, __FUNCTION__, &point, &from_locale)) return GetPyNone(); - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); GContext->IO.decimalPoint = *point; ImGui::GetIO().PlatformLocaleDecimalPoint = GContext->IO.decimalPoint; @@ -2004,21 +1922,15 @@ set_frame_callback(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["set_frame_callback"], args, kwargs, __FUNCTION__, &frame, &callback, &user_data)) - return GetPyNone(); + return nullptr; + + mvPySafeLockGuard lk(GContext->mutex); if (frame > GContext->callbackRegistry->highestFrame) GContext->callbackRegistry->highestFrame = frame; - // TODO: check previous entry and deprecate if existing - Py_XINCREF(callback); - - if(user_data) - Py_XINCREF(user_data); - mvSubmitCallback([=]() - { - GContext->callbackRegistry->frameCallbacks[frame] = callback; - GContext->callbackRegistry->frameCallbacksUserData[frame] = user_data; - }); + GContext->callbackRegistry->frameCallbacks.insert_or_assign(frame, mvPyObject(callback, true)); + GContext->callbackRegistry->frameCallbacksUserData.insert_or_assign(frame, mvPyObject(user_data, true)); return GetPyNone(); } @@ -2031,16 +1943,11 @@ set_exit_callback(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["set_exit_callback"], args, kwargs, __FUNCTION__, &callback, &user_data)) - return GetPyNone(); + return nullptr; + + *GContext->callbackRegistry->onCloseCallback = mvPyObject(callback == Py_None? nullptr : callback, true); + *GContext->callbackRegistry->onCloseCallbackUserData = mvPyObject(user_data, true); - Py_XINCREF(callback); - if(user_data) - Py_XINCREF(user_data); - mvSubmitCallback([=]() - { - GContext->callbackRegistry->onCloseCallback = SanitizeCallback(callback); - GContext->callbackRegistry->onCloseCallbackUserData = user_data; - }); return GetPyNone(); } @@ -2052,19 +1959,10 @@ set_viewport_resize_callback(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["set_viewport_resize_callback"], args, kwargs, __FUNCTION__, &callback, &user_data)) - return GetPyNone(); - - if (callback) - Py_XINCREF(callback); + return nullptr; - if (user_data) - Py_XINCREF(user_data); - - mvSubmitCallback([=]() - { - GContext->callbackRegistry->resizeCallback = SanitizeCallback(callback); - GContext->callbackRegistry->resizeCallbackUserData = user_data; - }); + *GContext->callbackRegistry->resizeCallback = mvPyObject(callback == Py_None? nullptr : callback, true); + *GContext->callbackRegistry->resizeCallbackUserData = mvPyObject(user_data, true); return GetPyNone(); } @@ -2073,35 +1971,36 @@ static PyObject* get_viewport_configuration(PyObject* self, PyObject* args, PyObject* kwargs) { - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); - PyObject* pdict = PyDict_New(); mvViewport* viewport = GContext->viewport; - if (viewport) + if (!viewport) { - PyDict_SetItemString(pdict, "clear_color", mvPyObject(ToPyColor(viewport->clearColor))); - PyDict_SetItemString(pdict, "small_icon", mvPyObject(ToPyString(viewport->small_icon))); - PyDict_SetItemString(pdict, "large_icon", mvPyObject(ToPyString(viewport->large_icon))); - PyDict_SetItemString(pdict, "x_pos", mvPyObject(ToPyInt(viewport->xpos))); - PyDict_SetItemString(pdict, "y_pos", mvPyObject(ToPyInt(viewport->ypos))); - PyDict_SetItemString(pdict, "width", mvPyObject(ToPyInt(viewport->actualWidth))); - PyDict_SetItemString(pdict, "height", mvPyObject(ToPyInt(viewport->actualHeight))); - PyDict_SetItemString(pdict, "client_width", mvPyObject(ToPyInt(viewport->clientWidth))); - PyDict_SetItemString(pdict, "client_height", mvPyObject(ToPyInt(viewport->clientHeight))); - PyDict_SetItemString(pdict, "resizable", mvPyObject(ToPyBool(viewport->resizable))); - PyDict_SetItemString(pdict, "vsync", mvPyObject(ToPyBool(viewport->vsync))); - PyDict_SetItemString(pdict, "min_width", mvPyObject(ToPyInt(viewport->minwidth))); - PyDict_SetItemString(pdict, "max_width", mvPyObject(ToPyInt(viewport->maxwidth))); - PyDict_SetItemString(pdict, "min_height", mvPyObject(ToPyInt(viewport->minheight))); - PyDict_SetItemString(pdict, "max_height", mvPyObject(ToPyInt(viewport->maxheight))); - PyDict_SetItemString(pdict, "always_on_top", mvPyObject(ToPyBool(viewport->alwaysOnTop))); - PyDict_SetItemString(pdict, "decorated", mvPyObject(ToPyBool(viewport->decorated))); - PyDict_SetItemString(pdict, "title", mvPyObject(ToPyString(viewport->title))); - PyDict_SetItemString(pdict, "disable_close", mvPyObject(ToPyBool(viewport->disableClose))); - } - else mvThrowPythonError(mvErrorCode::mvNone, "No viewport created"); + return nullptr; + } + + PyObject* pdict = PyDict_New(); + + PyDict_SetItemString(pdict, "clear_color", mvPyObject(ToPyColor(viewport->clearColor))); + PyDict_SetItemString(pdict, "small_icon", mvPyObject(ToPyString(viewport->small_icon))); + PyDict_SetItemString(pdict, "large_icon", mvPyObject(ToPyString(viewport->large_icon))); + PyDict_SetItemString(pdict, "x_pos", mvPyObject(ToPyInt(viewport->xpos))); + PyDict_SetItemString(pdict, "y_pos", mvPyObject(ToPyInt(viewport->ypos))); + PyDict_SetItemString(pdict, "width", mvPyObject(ToPyInt(viewport->actualWidth))); + PyDict_SetItemString(pdict, "height", mvPyObject(ToPyInt(viewport->actualHeight))); + PyDict_SetItemString(pdict, "client_width", mvPyObject(ToPyInt(viewport->clientWidth))); + PyDict_SetItemString(pdict, "client_height", mvPyObject(ToPyInt(viewport->clientHeight))); + PyDict_SetItemString(pdict, "resizable", mvPyObject(ToPyBool(viewport->resizable))); + PyDict_SetItemString(pdict, "vsync", mvPyObject(ToPyBool(viewport->vsync))); + PyDict_SetItemString(pdict, "min_width", mvPyObject(ToPyInt(viewport->minwidth))); + PyDict_SetItemString(pdict, "max_width", mvPyObject(ToPyInt(viewport->maxwidth))); + PyDict_SetItemString(pdict, "min_height", mvPyObject(ToPyInt(viewport->minheight))); + PyDict_SetItemString(pdict, "max_height", mvPyObject(ToPyInt(viewport->maxheight))); + PyDict_SetItemString(pdict, "always_on_top", mvPyObject(ToPyBool(viewport->alwaysOnTop))); + PyDict_SetItemString(pdict, "decorated", mvPyObject(ToPyBool(viewport->decorated))); + PyDict_SetItemString(pdict, "title", mvPyObject(ToPyString(viewport->title))); return pdict; } @@ -2110,7 +2009,7 @@ static PyObject* is_viewport_ok(PyObject* self, PyObject* args, PyObject* kwargs) { - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvViewport* viewport = GContext->viewport; if (viewport) @@ -2154,9 +2053,9 @@ create_viewport(PyObject* self, PyObject* args, PyObject* kwargs) &title, &small_icon, &large_icon, &width, &height, &x_pos, &y_pos, &min_width, &max_width, &min_height, &max_height, &resizable, &vsync, &always_on_top, &decorated, &color, &disable_close )) - return GetPyNone(); + return nullptr; - mvViewport* viewport = mvCreateViewport(width, height); + mvViewport* viewport = mvCreateViewport(); if (PyObject* item = PyDict_GetItemString(kwargs, "clear_color")) viewport->clearColor = ToColor(item); if (PyObject* item = PyDict_GetItemString(kwargs, "small_icon")) viewport->small_icon = ToString(item); if (PyObject* item = PyDict_GetItemString(kwargs, "large_icon")) viewport->large_icon = ToString(item); @@ -2188,7 +2087,7 @@ show_viewport(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["show_viewport"], args, kwargs, __FUNCTION__, &minimized, &maximized)) - return GetPyNone(); + return nullptr; mvViewport* viewport = GContext->viewport; if (viewport) @@ -2198,14 +2097,19 @@ show_viewport(PyObject* self, PyObject* args, PyObject* kwargs) viewport->shown = true; } else + { mvThrowPythonError(mvErrorCode::mvNone, "No viewport created"); + return nullptr; + } + return GetPyNone(); } static PyObject* configure_viewport(PyObject* self, PyObject* args, PyObject* kwargs) { - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); + mvViewport* viewport = GContext->viewport; if (viewport) { @@ -2230,7 +2134,10 @@ configure_viewport(PyObject* self, PyObject* args, PyObject* kwargs) } else + { mvThrowPythonError(mvErrorCode::mvNone, "No viewport created"); + return nullptr; + } return GetPyNone(); } @@ -2238,7 +2145,7 @@ configure_viewport(PyObject* self, PyObject* args, PyObject* kwargs) static PyObject* maximize_viewport(PyObject* self, PyObject* args, PyObject* kwargs) { - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvSubmitTask([=]() { mvMaximizeViewport(*GContext->viewport); @@ -2250,7 +2157,7 @@ maximize_viewport(PyObject* self, PyObject* args, PyObject* kwargs) static PyObject* minimize_viewport(PyObject* self, PyObject* args, PyObject* kwargs) { - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvSubmitTask([=]() { mvMinimizeViewport(*GContext->viewport); @@ -2262,7 +2169,7 @@ minimize_viewport(PyObject* self, PyObject* args, PyObject* kwargs) static PyObject* toggle_viewport_fullscreen(PyObject* self, PyObject* args, PyObject* kwargs) { - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvSubmitTask([=]() { mvToggleFullScreen(*GContext->viewport); @@ -2277,12 +2184,15 @@ save_init_file(PyObject* self, PyObject* args, PyObject* kwargs) const char* file; if (!Parse((GetParsers())["save_init_file"], args, kwargs, __FUNCTION__, &file)) - return GetPyNone(); + return nullptr; if (GContext->started) ImGui::SaveIniSettingsToDisk(file); else + { mvThrowPythonError(mvErrorCode::mvNone, "Dear PyGui must be started to use \"save_init_file\"."); + return nullptr; + } return GetPyNone(); } @@ -2290,19 +2200,26 @@ save_init_file(PyObject* self, PyObject* args, PyObject* kwargs) static PyObject* split_frame(PyObject* self, PyObject* args, PyObject* kwargs) { - i32 delay = 32; + if (!Parse((GetParsers())["split_frame"], args, kwargs, __FUNCTION__)) + return nullptr; - if (!Parse((GetParsers())["split_frame"], args, kwargs, __FUNCTION__, - &delay)) - return GetPyNone(); + if (GContext->running) + { + Py_BEGIN_ALLOW_THREADS; + std::unique_lock lk(GContext->frameEndedMutex); + GContext->frameEnded = false; + GContext->frameEndedEvent.wait(lk, []{return GContext->frameEnded;}); + lk.unlock(); - // std::lock_guard lk(GContext->mutex); + Py_END_ALLOW_THREADS; + } - Py_BEGIN_ALLOW_THREADS; - GContext->waitOneFrame = true; - while (GContext->waitOneFrame) - std::this_thread::sleep_for(std::chrono::milliseconds(delay)); - Py_END_ALLOW_THREADS; + // Now let's see if it was successful (there's a chance that DPG got stopped while we were waiting) + if (!GContext->running) + { + mvThrowPythonError(mvErrorCode::mvNone, "split_frame is exiting: there is no active rendering loop."); + return nullptr; + } return GetPyNone(); } @@ -2310,7 +2227,13 @@ split_frame(PyObject* self, PyObject* args, PyObject* kwargs) static PyObject* lock_mutex(PyObject* self, PyObject* args, PyObject* kwargs) { + // Since we may enter waiting state on mutex.lock(), we must release the + // GIL while attempting to lock the mutex; otherwise, we'd risk getting + // into a deadlock. + Py_BEGIN_ALLOW_THREADS; GContext->mutex.lock(); + Py_END_ALLOW_THREADS; + return GetPyNone(); } @@ -2324,7 +2247,7 @@ unlock_mutex(PyObject* self, PyObject* args, PyObject* kwargs) static PyObject* get_frame_count(PyObject* self, PyObject* args, PyObject* kwargs) { - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); return ToPyInt(GContext->frame); } @@ -2337,7 +2260,7 @@ load_image(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["load_image"], args, kwargs, __FUNCTION__, &file, &gamma, &gamma_scale)) - return GetPyNone(); + return nullptr; // Vout = (Vin / 255)^v; Where v = gamma @@ -2408,7 +2331,7 @@ save_image(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["save_image"], args, kwargs, __FUNCTION__, &file, &width, &height, &data, &components, &quality)) - return GetPyNone(); + return nullptr; enum ImageType_ { @@ -2432,19 +2355,19 @@ save_image(PyObject* self, PyObject* args, PyObject* kwargs) if (filepathLength < 5) { mvThrowPythonError(mvErrorCode::mvNone, "File path for 'save_image(...)' must be of the form 'name.png'."); - return GetPyNone(); + return nullptr; } if (components > 4 || components < 1) { mvThrowPythonError(mvErrorCode::mvNone, "Component count for 'save_image(...)' must be between 1 and 4."); - return GetPyNone(); + return nullptr; } if (quality < 1 || quality > 100) { mvThrowPythonError(mvErrorCode::mvNone, "Quality must be between 1 and 100."); - return GetPyNone(); + return nullptr; } // TODO: support other formats @@ -2471,7 +2394,7 @@ save_image(PyObject* self, PyObject* args, PyObject* kwargs) else { mvThrowPythonError(mvErrorCode::mvNone, "File path for 'save_image(...)' must be of the form 'name.png'."); - return GetPyNone(); + return nullptr; } switch (imageType) @@ -2520,21 +2443,33 @@ output_frame_buffer(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["output_frame_buffer"], args, kwargs, __FUNCTION__, &file, &callback)) - return GetPyNone(); + return nullptr; size_t filepathLength = strlen(file); if (filepathLength == 0 && callback) // not specified, return array instead { - //Py_XINCREF(callback); PyObject* newbuffer = nullptr; PymvBuffer* newbufferview = PyObject_New(PymvBuffer, &PymvBufferType); newbuffer = PyObject_Init((PyObject*)newbufferview, &PymvBufferType); - mvSubmitTask([newbuffer, callback, newbufferview]() { + + // Making an owned ref while we're still holding GIL (can't do this within mvSubmitTask). + auto stored_callback = std::make_shared(callback, true); + // We need to schedule this into the rendering thread because OutputFrameBufferArray + // accesses the rendering API, which might well have thread-local things in the context. + mvSubmitTask([stored_callback, newbuffer, newbufferview]() { OutputFrameBufferArray(newbufferview); - mvAddCallback(callback, 0, newbuffer, nullptr, false); - }); + mvAddOwnerlessCallback( + stored_callback, std::make_shared(nullptr), + 0, "", + // Note: the callback queue will DECREF the value returned by this + // lambda, effectively deleting `newbuffer` so that we don't need + // to perform any special cleanup. We just pass the value as it is, + // keeping a refcount of 1 all the time until the callback is done. + [=]() { return newbuffer; } + ); + }); return GetPyNone(); } @@ -2546,7 +2481,7 @@ output_frame_buffer(PyObject* self, PyObject* args, PyObject* kwargs) if (filepathLength < 5) { mvThrowPythonError(mvErrorCode::mvNone, "File path for 'output_frame_buffer(...)' must be of the form 'name.png'."); - return GetPyNone(); + return nullptr; } // TODO: support other formats @@ -2561,7 +2496,7 @@ output_frame_buffer(PyObject* self, PyObject* args, PyObject* kwargs) else { mvThrowPythonError(mvErrorCode::mvNone, "File path for 'output_frame_buffer(...)' must be of the form 'name.png'."); - return GetPyNone(); + return nullptr; } return GetPyNone(); @@ -2571,26 +2506,27 @@ output_frame_buffer(PyObject* self, PyObject* args, PyObject* kwargs) static PyObject* is_dearpygui_running(PyObject* self, PyObject* args, PyObject* kwargs) { - return ToPyBool(GContext->started); + return ToPyBool(GContext->running); } static PyObject* setup_dearpygui(PyObject* self, PyObject* args, PyObject* kwargs) { - std::lock_guard lk(GContext->mutex); - Py_BEGIN_ALLOW_THREADS; + std::lock_guard lk(GContext->mutex); + if (GContext->started) { mvThrowPythonError(mvErrorCode::mvNone, "Cannot call \"setup_dearpygui\" while a Dear PyGUI app is already running."); - return GetPyNone(); + return nullptr; } while (!GContext->itemRegistry->containers.empty()) GContext->itemRegistry->containers.pop(); GContext->started = true; + GContext->running = true; GContext->future = std::async(std::launch::async, []() {return mvRunCallbacks(); }); Py_END_ALLOW_THREADS; return GetPyNone(); @@ -2646,10 +2582,6 @@ create_context(PyObject* self, PyObject* args, PyObject* kwargs) static PyObject* destroy_context(PyObject* self, PyObject* args, PyObject* kwargs) { - // std::lock_guard lk(GContext->mutex); - - Py_BEGIN_ALLOW_THREADS; - if (GContext == nullptr) { assert(false); @@ -2657,47 +2589,57 @@ destroy_context(PyObject* self, PyObject* args, PyObject* kwargs) else { - // hacky fix, started was set to false - // to exit the event loop, but needs to be - // true in order to run DPG commands for the - // exit callback. - GContext->started = true; - mvSubmitCallback([=]() { - mvRunCallback(GContext->callbackRegistry->onCloseCallback, 0, nullptr, GContext->callbackRegistry->onCloseCallbackUserData); - GContext->started = false; // return to false after - }); - - if (GContext->viewport != nullptr) - mvCleanupViewport(*GContext->viewport); - - ImNodes::DestroyContext(); - ImPlot::DestroyContext(); - ImGui::DestroyContext(); - - mvToolManager::Reset(); - ClearItemRegistry(*GContext->itemRegistry); - + // Make sure everyone knows we're shutting down, even if stop_dearpygui + // was not called. This also releases any waiting split_frame calls. + StopRendering(); + Py_BEGIN_ALLOW_THREADS; - //#define X(el) el::s_class_theme_component = nullptr; el::s_class_theme_disabled_component = nullptr; - #define X(el) DearPyGui::GetClassThemeComponent(mvAppItemType::el) = nullptr; DearPyGui::GetDisabledClassThemeComponent(mvAppItemType::el) = nullptr; - MV_ITEM_TYPES - #undef X + // Queue the close callback, if any. The environment is still healthy enough + // for it to run, except that no more frames will be rendered with the current GContext. + mvAddOwnerlessCallback(GContext->callbackRegistry->onCloseCallback, GContext->callbackRegistry->onCloseCallbackUserData); - mvSubmitCallback([=]() { + // Shutting down the callback loop - this will run right after the close callback + mvSubmitCallback([]() { GContext->callbackRegistry->running = false; - }); + }, true); + // Waiting for it to complete all tasks and shut down if (GContext->future.valid()) GContext->future.get(); - if (GContext->viewport) - delete GContext->viewport; - delete GContext->itemRegistry; - delete GContext->callbackRegistry; - delete GContext; - GContext = nullptr; + // The rest of cleanup must be done with GIL locked because it might lead + // to occasional DECREFs on Python objects (e.g. a callback or user_data). + Py_END_ALLOW_THREADS; + + mvContext* context_to_delete = nullptr; + { + // Even though the handlers thread is down, there's still a chance that + // the user calls DPG from another Python thread. We'd better lock the + // mutex while we're tinkering with all the global structures. + mvPySafeLockGuard lk(GContext->mutex); + + mvToolManager::Reset(); + ClearItemRegistry(*GContext->itemRegistry); + + ImNodes::DestroyContext(); + ImPlot::DestroyContext(); + ImGui::DestroyContext(); + + #define X(el) DearPyGui::GetClassThemeComponent(mvAppItemType::el) = nullptr; DearPyGui::GetDisabledClassThemeComponent(mvAppItemType::el) = nullptr; + MV_ITEM_TYPES + X(All) + #undef X + + if (GContext->viewport) + delete GContext->viewport; + + delete GContext->itemRegistry; + delete GContext->callbackRegistry; + context_to_delete = GContext; + GContext = nullptr; + } + delete context_to_delete; } - Py_END_ALLOW_THREADS; return GetPyNone(); } @@ -2705,8 +2647,8 @@ destroy_context(PyObject* self, PyObject* args, PyObject* kwargs) static PyObject* stop_dearpygui(PyObject* self, PyObject* args, PyObject* kwargs) { - std::lock_guard lk(GContext->mutex); - GContext->started = false; + StopRendering(); + mvPySafeLockGuard lk(GContext->mutex); auto viewport = GContext->viewport; if (viewport) viewport->running = false; @@ -2716,14 +2658,14 @@ stop_dearpygui(PyObject* self, PyObject* args, PyObject* kwargs) static PyObject* get_total_time(PyObject* self, PyObject* args, PyObject* kwargs) { - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); return ToPyFloat((f32)GContext->time); } static PyObject* get_delta_time(PyObject* self, PyObject* args, PyObject* kwargs) { - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); return ToPyFloat(GContext->deltaTime); } @@ -2731,7 +2673,7 @@ get_delta_time(PyObject* self, PyObject* args, PyObject* kwargs) static PyObject* get_frame_rate(PyObject* self, PyObject* args, PyObject* kwargs) { - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); return ToPyFloat((f32)GContext->framerate); } @@ -2755,10 +2697,10 @@ configure_app(PyObject* self, PyObject* args, PyObject* kwargs) { assert(false); mvThrowPythonError(mvErrorCode::mvNone, "Dictionary keywords must be strings"); - return GetPyNone(); + return nullptr; } - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); if (PyObject* item = PyDict_GetItemString(kwargs, "auto_device")) GContext->IO.info_auto_device = ToBool(item); if (PyObject* item = PyDict_GetItemString(kwargs, "docking")) GContext->IO.docking = ToBool(item); @@ -2797,7 +2739,7 @@ configure_app(PyObject* self, PyObject* args, PyObject* kwargs) static PyObject* get_app_configuration(PyObject* self, PyObject* args, PyObject* kwargs) { - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); PyObject* pdict = PyDict_New(); PyDict_SetItemString(pdict, "auto_device", mvPyObject(ToPyBool(GContext->IO.info_auto_device))); PyDict_SetItemString(pdict, "docking", mvPyObject(ToPyBool(GContext->IO.docking))); @@ -2835,7 +2777,7 @@ get_mouse_pos(PyObject* self, PyObject* args, PyObject* kwargs) b32 local = true; if (!Parse((GetParsers())["get_mouse_pos"], args, kwargs, __FUNCTION__, &local)) - return GetPyNone(); + return nullptr; auto pos = mvVec2(); @@ -2852,7 +2794,7 @@ get_plot_mouse_pos(PyObject* self, PyObject* args, PyObject* kwargs) { if (!Parse((GetParsers())["get_plot_mouse_pos"], args, kwargs, __FUNCTION__)) - return GetPyNone(); + return nullptr; mvVec2 pos = { (f32)GContext->input.mousePlotPos.x, (f32)GContext->input.mousePlotPos.y }; @@ -2864,7 +2806,7 @@ get_drawing_mouse_pos(PyObject* self, PyObject* args, PyObject* kwargs) { if (!Parse((GetParsers())["get_drawing_mouse_pos"], args, kwargs, __FUNCTION__)) - return GetPyNone(); + return nullptr; mvVec2 pos = { (f32)GContext->input.mouseDrawingPos.x, (f32)GContext->input.mouseDrawingPos.y }; @@ -2885,7 +2827,7 @@ is_key_pressed(PyObject* self, PyObject* args, PyObject* kwargs) ImGuiKey key; if (!Parse((GetParsers())["is_key_pressed"], args, kwargs, __FUNCTION__, &key)) - return GetPyNone(); + return nullptr; return ToPyBool(ImGui::IsKeyPressed(key)); } @@ -2896,7 +2838,7 @@ is_key_released(PyObject* self, PyObject* args, PyObject* kwargs) ImGuiKey key; if (!Parse((GetParsers())["is_key_released"], args, kwargs, __FUNCTION__, &key)) - return GetPyNone(); + return nullptr; return ToPyBool(ImGui::IsKeyReleased(key)); } @@ -2907,7 +2849,7 @@ is_key_down(PyObject* self, PyObject* args, PyObject* kwargs) ImGuiKey key; if (!Parse((GetParsers())["is_key_down"], args, kwargs, __FUNCTION__, &key)) - return GetPyNone(); + return nullptr; return ToPyBool(ImGui::IsKeyDown(key)); } @@ -2919,7 +2861,7 @@ is_mouse_button_dragging(PyObject* self, PyObject* args, PyObject* kwargs) f32 threshold; if (!Parse((GetParsers())["is_mouse_button_dragging"], args, kwargs, __FUNCTION__, &button, &threshold)) - return GetPyNone(); + return nullptr; // TODO: Can this be changed? return ToPyBool((f32)ImGui::GetIO().MouseDownDuration[button] >= threshold); @@ -2931,7 +2873,7 @@ is_mouse_button_down(PyObject* self, PyObject* args, PyObject* kwargs) i32 button; if (!Parse((GetParsers())["is_mouse_button_down"], args, kwargs, __FUNCTION__, &button)) - return GetPyNone(); + return nullptr; return ToPyBool(ImGui::IsMouseDown(button)); } @@ -2942,7 +2884,7 @@ is_mouse_button_clicked(PyObject* self, PyObject* args, PyObject* kwargs) i32 button; if (!Parse((GetParsers())["is_mouse_button_clicked"], args, kwargs, __FUNCTION__, &button)) - return GetPyNone(); + return nullptr; return ToPyBool(ImGui::IsMouseClicked(button)); } @@ -2953,7 +2895,7 @@ is_mouse_button_double_clicked(PyObject* self, PyObject* args, PyObject* kwargs) i32 button; if (!Parse((GetParsers())["is_mouse_button_double_clicked"], args, kwargs, __FUNCTION__, &button)) - return GetPyNone(); + return nullptr; return ToPyBool(ImGui::IsMouseDoubleClicked(button)); } @@ -2964,7 +2906,7 @@ is_mouse_button_released(PyObject* self, PyObject* args, PyObject* kwargs) i32 button; if (!Parse((GetParsers())["is_mouse_button_released"], args, kwargs, __FUNCTION__, &button)) - return GetPyNone(); + return nullptr; return ToPyBool(ImGui::IsMouseReleased(button)); } @@ -2973,13 +2915,13 @@ static PyObject* pop_container_stack(PyObject* self, PyObject* args, PyObject* kwargs) { - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); if (GContext->itemRegistry->containers.empty()) { mvThrowPythonError(mvErrorCode::mvContainerStackEmpty, "No container to pop."); assert(false); - return GetPyNone(); + return nullptr; } mvAppItem* item = GContext->itemRegistry->containers.top(); @@ -2995,7 +2937,7 @@ pop_container_stack(PyObject* self, PyObject* args, PyObject* kwargs) static PyObject* empty_container_stack(PyObject* self, PyObject* args, PyObject* kwargs) { - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); while (!GContext->itemRegistry->containers.empty()) GContext->itemRegistry->containers.pop(); return GetPyNone(); @@ -3004,7 +2946,7 @@ empty_container_stack(PyObject* self, PyObject* args, PyObject* kwargs) static PyObject* top_container_stack(PyObject* self, PyObject* args, PyObject* kwargs) { - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvAppItem* item = nullptr; if (!GContext->itemRegistry->containers.empty()) @@ -3019,7 +2961,7 @@ top_container_stack(PyObject* self, PyObject* args, PyObject* kwargs) static PyObject* last_item(PyObject* self, PyObject* args, PyObject* kwargs) { - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); return ToPyUUID(GContext->itemRegistry->lastItemAdded); } @@ -3027,7 +2969,7 @@ last_item(PyObject* self, PyObject* args, PyObject* kwargs) static PyObject* last_container(PyObject* self, PyObject* args, PyObject* kwargs) { - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); return ToPyUUID(GContext->itemRegistry->lastContainerAdded); } @@ -3035,7 +2977,7 @@ last_container(PyObject* self, PyObject* args, PyObject* kwargs) static PyObject* last_root(PyObject* self, PyObject* args, PyObject* kwargs) { - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); return ToPyUUID(GContext->itemRegistry->lastRootAdded); } @@ -3046,9 +2988,9 @@ push_container_stack(PyObject* self, PyObject* args, PyObject* kwargs) PyObject* itemraw; if (!Parse((GetParsers())["push_container_stack"], args, kwargs, __FUNCTION__, &itemraw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); @@ -3071,19 +3013,26 @@ set_primary_window(PyObject* self, PyObject* args, PyObject* kwargs) i32 value; if (!VerifyRequiredArguments(GetParsers()["set_primary_window"], args)) - return GetPyNone(); + return GetPyNoneOrError(); if (!Parse((GetParsers())["set_primary_window"], args, kwargs, __FUNCTION__, &itemraw, &value)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); { mvWindowAppItem* window = GetWindow(*GContext->itemRegistry, item); - if (window) + if (!window) + { + mvThrowPythonError(mvErrorCode::mvItemNotFound, "set_primary_window", + "Item not found: " + std::to_string(item), nullptr); + assert(false); + return nullptr; + } + else { if (window->configData.mainWindow == (bool)value) return GetPyNone(); @@ -3119,12 +3068,6 @@ set_primary_window(PyObject* self, PyObject* args, PyObject* kwargs) } } } - else - { - mvThrowPythonError(mvErrorCode::mvItemNotFound, "set_primary_window", - "Item not found: " + std::to_string(item), nullptr); - assert(false); - } } // reset other windows @@ -3154,7 +3097,7 @@ set_primary_window(PyObject* self, PyObject* args, PyObject* kwargs) static PyObject* get_active_window(PyObject* self, PyObject* args, PyObject* kwargs) { - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); return ToPyUUID(GContext->activeWindow); } @@ -3162,7 +3105,7 @@ get_active_window(PyObject* self, PyObject* args, PyObject* kwargs) static PyObject* get_focused_item(PyObject* self, PyObject* args, PyObject* kwargs) { - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); return ToPyUUID(GContext->focusedItem); } @@ -3177,15 +3120,23 @@ move_item(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["move_item"], args, kwargs, __FUNCTION__, &itemraw, &parentraw, &beforeraw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); mvUUID parent = GetIDFromPyObject(parentraw); mvUUID before = GetIDFromPyObject(beforeraw); - MoveItem((*GContext->itemRegistry), item, parent, before); + if (before == 0 && parent == 0) + { + mvThrowPythonError(mvErrorCode::mvItemNotFound, "move_item", + "move_item requires either `parent` or `before` to be specified.", nullptr); + return nullptr; + } + + if (!MoveItem((*GContext->itemRegistry), item, parent, before)) + return nullptr; return GetPyNone(); } @@ -3199,9 +3150,9 @@ delete_item(PyObject* self, PyObject* args, PyObject* kwargs) i32 slot = -1; if (!Parse((GetParsers())["delete_item"], args, kwargs, __FUNCTION__, &itemraw, &childrenOnly, &slot)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); @@ -3219,9 +3170,9 @@ does_item_exist(PyObject* self, PyObject* args, PyObject* kwargs) PyObject* itemraw; if (!Parse((GetParsers())["does_item_exist"], args, kwargs, __FUNCTION__, &itemraw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); @@ -3237,13 +3188,14 @@ move_item_up(PyObject* self, PyObject* args, PyObject* kwargs) PyObject* itemraw; if (!Parse((GetParsers())["move_item_up"], args, kwargs, __FUNCTION__, &itemraw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); - MoveItemUp((*GContext->itemRegistry), item); + if (!MoveItemUp((*GContext->itemRegistry), item)) + return nullptr; return GetPyNone(); @@ -3256,13 +3208,14 @@ move_item_down(PyObject* self, PyObject* args, PyObject* kwargs) PyObject* itemraw; if (!Parse((GetParsers())["move_item_down"], args, kwargs, __FUNCTION__, &itemraw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); - MoveItemDown((*GContext->itemRegistry), item); + if (!MoveItemDown((*GContext->itemRegistry), item)) + return nullptr; return GetPyNone(); } @@ -3277,33 +3230,16 @@ reorder_items(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["reorder_items"], args, kwargs, __FUNCTION__, &containerraw, &slot, &new_order)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); auto anew_order = ToUUIDVect(new_order); mvUUID container = GetIDFromPyObject(containerraw); - mvAppItem* parent = GetItem((*GContext->itemRegistry), container); - - std::vector>& children = parent->childslots[slot]; + if (!ReorderChildren(*GContext->itemRegistry, container, slot, anew_order)) + return nullptr; - std::vector> newchildren; - newchildren.reserve(children.size()); - - // todo: better sorting algorithm - for (const auto& item : anew_order) - { - for (auto& child : children) - { - if (child->uuid == item) - { - newchildren.emplace_back(child); - break; - } - } - } - children = newchildren; return GetPyNone(); } @@ -3314,9 +3250,9 @@ unstage(PyObject* self, PyObject* args, PyObject* kwargs) PyObject* itemraw = nullptr; if (!Parse((GetParsers())["unstage"], args, kwargs, __FUNCTION__, &itemraw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); @@ -3337,16 +3273,13 @@ unstage(PyObject* self, PyObject* args, PyObject* kwargs) } if (item_found) - { - CleanUpItem(*GContext->itemRegistry, item); return GetPyNone(); - } mvThrowPythonError(mvErrorCode::mvItemNotFound, "unstage", "Stage not found: " + std::to_string(item), nullptr); assert(false); - return GetPyNone(); + return nullptr; } static PyObject* @@ -3356,9 +3289,9 @@ show_item_debug(PyObject* self, PyObject* args, PyObject* kwargs) PyObject* itemraw = nullptr; if (!Parse((GetParsers())["show_item_debug"], args, kwargs, __FUNCTION__, &itemraw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); @@ -3372,6 +3305,7 @@ show_item_debug(PyObject* self, PyObject* args, PyObject* kwargs) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "show_item_debug", "Item not found: " + std::to_string(item), nullptr); + return nullptr; } return GetPyNone(); @@ -3421,7 +3355,7 @@ static PyObject* get_all_items(PyObject* self, PyObject* args, PyObject* kwargs) { - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); std::vector childList; @@ -3446,7 +3380,7 @@ static PyObject* show_imgui_demo(PyObject* self, PyObject* args, PyObject* kwargs) { - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); GContext->itemRegistry->showImGuiDebug = true; return GetPyNone(); @@ -3456,7 +3390,7 @@ static PyObject* show_implot_demo(PyObject* self, PyObject* args, PyObject* kwargs) { - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); GContext->itemRegistry->showImPlotDebug = true; return GetPyNone(); @@ -3466,7 +3400,7 @@ static PyObject* get_windows(PyObject* self, PyObject* args, PyObject* kwargs) { - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); std::vector childList; for (auto& root : GContext->itemRegistry->colormapRoots) childList.emplace_back(root->uuid); @@ -3494,9 +3428,9 @@ add_alias(PyObject* self, PyObject* args, PyObject* kwargs) PyObject* itemraw; if (!Parse((GetParsers())["add_alias"], args, kwargs, __FUNCTION__, &alias, &itemraw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); @@ -3513,9 +3447,9 @@ remove_alias(PyObject* self, PyObject* args, PyObject* kwargs) const char* alias; if (!Parse((GetParsers())["remove_alias"], args, kwargs, __FUNCTION__, &alias)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); RemoveAlias((*GContext->itemRegistry), alias); @@ -3530,9 +3464,9 @@ does_alias_exist(PyObject* self, PyObject* args, PyObject* kwargs) const char* alias; if (!Parse((GetParsers())["does_alias_exist"], args, kwargs, __FUNCTION__, &alias)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); bool result = GContext->itemRegistry->aliases.count(alias) != 0; @@ -3546,9 +3480,9 @@ get_alias_id(PyObject* self, PyObject* args, PyObject* kwargs) const char* alias; if (!Parse((GetParsers())["get_alias_id"], args, kwargs, __FUNCTION__, &alias)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID result = GetIdFromAlias((*GContext->itemRegistry), alias); @@ -3559,7 +3493,7 @@ static PyObject* get_aliases(PyObject* self, PyObject* args, PyObject* kwargs) { - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); std::vector aliases; @@ -3575,9 +3509,9 @@ focus_item(PyObject* self, PyObject* args, PyObject* kwargs) PyObject* itemraw; if (!Parse((GetParsers())["focus_item"], args, kwargs, __FUNCTION__, &itemraw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); @@ -3604,8 +3538,11 @@ focus_item(PyObject* self, PyObject* args, PyObject* kwargs) parent->info.focusNextFrame = true; } else + { mvThrowPythonError(mvErrorCode::mvItemNotFound, "focus_item", "Item not found: " + std::to_string(item), nullptr); + return nullptr; + } return GetPyNone(); } @@ -3648,81 +3585,76 @@ get_item_info(PyObject* self, PyObject* args, PyObject* kwargs) PyObject* itemraw; if (!Parse((GetParsers())["get_item_info"], args, kwargs, __FUNCTION__, &itemraw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); mvAppItem* appitem = GetItem((*GContext->itemRegistry), item); - PyObject* pdict = PyDict_New(); - if (appitem) + if (!appitem) { + mvThrowPythonError(mvErrorCode::mvItemNotFound, "get_item_info", + "Item not found: " + std::to_string(item), nullptr); + return nullptr; + } - std::string parserCommand = GetEntityCommand(appitem->type); + PyObject* pdict = PyDict_New(); - auto children = GetItemChildren(*GContext->itemRegistry, appitem->uuid); - if (children.empty()) - PyDict_SetItemString(pdict, "children", mvPyObject(GetPyNone())); - else + std::string parserCommand = GetEntityCommand(appitem->type); + + auto children = GetItemChildren(*GContext->itemRegistry, appitem->uuid); + if (children.empty()) + PyDict_SetItemString(pdict, "children", mvPyObject(GetPyNone())); + else + { + PyObject* pyChildren = PyDict_New(); + i32 i = 0; + for (const auto& slot : children) { - PyObject* pyChildren = PyDict_New(); - i32 i = 0; - for (const auto& slot : children) - { - PyDict_SetItem(pyChildren, ToPyInt(i), mvPyObject(ToPyList(slot))); - i++; - } - PyDict_SetItemString(pdict, "children", mvPyObject(pyChildren)); + PyDict_SetItem(pyChildren, ToPyInt(i), mvPyObject(ToPyList(slot))); + i++; } + PyDict_SetItemString(pdict, "children", mvPyObject(pyChildren)); + } - PyDict_SetItemString(pdict, "type", mvPyObject(ToPyString(DearPyGui::GetEntityTypeString(appitem->type)))); - PyDict_SetItemString(pdict, "target", mvPyObject(ToPyInt(DearPyGui::GetEntityTargetSlot(appitem->type)))); - - if (appitem->info.parentPtr) - PyDict_SetItemString(pdict, "parent", mvPyObject(ToPyUUID(appitem->info.parentPtr->uuid))); - else - PyDict_SetItemString(pdict, "parent", mvPyObject(GetPyNone())); - - if (appitem->theme) - PyDict_SetItemString(pdict, "theme", mvPyObject(ToPyUUID(appitem->theme->uuid))); - else - PyDict_SetItemString(pdict, "theme", mvPyObject(GetPyNone())); + PyDict_SetItemString(pdict, "type", mvPyObject(ToPyString(DearPyGui::GetEntityTypeString(appitem->type)))); + PyDict_SetItemString(pdict, "target", mvPyObject(ToPyInt(DearPyGui::GetEntityTargetSlot(appitem->type)))); - if (appitem->handlerRegistry) - PyDict_SetItemString(pdict, "handlers", mvPyObject(ToPyUUID(appitem->handlerRegistry->uuid))); - else - PyDict_SetItemString(pdict, "handlers", mvPyObject(GetPyNone())); + if (appitem->info.parentPtr) + PyDict_SetItemString(pdict, "parent", mvPyObject(ToPyUUID(appitem->info.parentPtr->uuid))); + else + PyDict_SetItemString(pdict, "parent", mvPyObject(GetPyNone())); - if (appitem->font) - PyDict_SetItemString(pdict, "font", mvPyObject(ToPyUUID(appitem->font->uuid))); - else - PyDict_SetItemString(pdict, "font", mvPyObject(GetPyNone())); + if (appitem->theme) + PyDict_SetItemString(pdict, "theme", mvPyObject(ToPyUUID(appitem->theme->uuid))); + else + PyDict_SetItemString(pdict, "theme", mvPyObject(GetPyNone())); - if (DearPyGui::GetEntityDesciptionFlags(appitem->type) & MV_ITEM_DESC_CONTAINER) - PyDict_SetItemString(pdict, "container", mvPyObject(ToPyBool(true))); - else - PyDict_SetItemString(pdict, "container", mvPyObject(ToPyBool(false))); - - i32 applicableState = DearPyGui::GetApplicableState(appitem->type); - PyDict_SetItemString(pdict, "hover_handler_applicable", mvPyObject(ToPyBool(applicableState & MV_STATE_HOVER))); - PyDict_SetItemString(pdict, "active_handler_applicable", mvPyObject(ToPyBool(applicableState & MV_STATE_ACTIVE))); - PyDict_SetItemString(pdict, "focus_handler_applicable", mvPyObject(ToPyBool(applicableState & MV_STATE_FOCUSED))); - PyDict_SetItemString(pdict, "clicked_handler_applicable", mvPyObject(ToPyBool(applicableState & MV_STATE_CLICKED))); - PyDict_SetItemString(pdict, "visible_handler_applicable", mvPyObject(ToPyBool(applicableState & MV_STATE_VISIBLE))); - PyDict_SetItemString(pdict, "edited_handler_applicable", mvPyObject(ToPyBool(applicableState & MV_STATE_EDITED))); - PyDict_SetItemString(pdict, "activated_handler_applicable", mvPyObject(ToPyBool(applicableState & MV_STATE_ACTIVATED))); - PyDict_SetItemString(pdict, "deactivated_handler_applicable", mvPyObject(ToPyBool(applicableState & MV_STATE_DEACTIVATED))); - PyDict_SetItemString(pdict, "deactivatedae_handler_applicable", mvPyObject(ToPyBool(applicableState & MV_STATE_DEACTIVATEDAE))); - PyDict_SetItemString(pdict, "toggled_open_handler_applicable", mvPyObject(ToPyBool(applicableState & MV_STATE_TOGGLED_OPEN))); - PyDict_SetItemString(pdict, "resized_handler_applicable", mvPyObject(ToPyBool(applicableState & MV_STATE_RECT_SIZE))); - - } + if (appitem->font) + PyDict_SetItemString(pdict, "font", mvPyObject(ToPyUUID(appitem->font->uuid))); + else + PyDict_SetItemString(pdict, "font", mvPyObject(GetPyNone())); + if (DearPyGui::GetEntityDesciptionFlags(appitem->type) & MV_ITEM_DESC_CONTAINER) + PyDict_SetItemString(pdict, "container", mvPyObject(ToPyBool(true))); else - mvThrowPythonError(mvErrorCode::mvItemNotFound, "get_item_info", - "Item not found: " + std::to_string(item), nullptr); + PyDict_SetItemString(pdict, "container", mvPyObject(ToPyBool(false))); + + i32 applicableState = DearPyGui::GetApplicableState(appitem->type); + PyDict_SetItemString(pdict, "hover_handler_applicable", mvPyObject(ToPyBool(applicableState & MV_STATE_HOVER))); + PyDict_SetItemString(pdict, "active_handler_applicable", mvPyObject(ToPyBool(applicableState & MV_STATE_ACTIVE))); + PyDict_SetItemString(pdict, "focus_handler_applicable", mvPyObject(ToPyBool(applicableState & MV_STATE_FOCUSED))); + PyDict_SetItemString(pdict, "clicked_handler_applicable", mvPyObject(ToPyBool(applicableState & MV_STATE_CLICKED))); + PyDict_SetItemString(pdict, "visible_handler_applicable", mvPyObject(ToPyBool(applicableState & MV_STATE_VISIBLE))); + PyDict_SetItemString(pdict, "edited_handler_applicable", mvPyObject(ToPyBool(applicableState & MV_STATE_EDITED))); + PyDict_SetItemString(pdict, "activated_handler_applicable", mvPyObject(ToPyBool(applicableState & MV_STATE_ACTIVATED))); + PyDict_SetItemString(pdict, "deactivated_handler_applicable", mvPyObject(ToPyBool(applicableState & MV_STATE_DEACTIVATED))); + PyDict_SetItemString(pdict, "deactivatedae_handler_applicable", mvPyObject(ToPyBool(applicableState & MV_STATE_DEACTIVATEDAE))); + PyDict_SetItemString(pdict, "toggled_open_handler_applicable", mvPyObject(ToPyBool(applicableState & MV_STATE_TOGGLED_OPEN))); + PyDict_SetItemString(pdict, "resized_handler_applicable", mvPyObject(ToPyBool(applicableState & MV_STATE_RECT_SIZE))); + PyDict_SetItemString(pdict, "scroll_handler_applicable", mvPyObject(ToPyBool(applicableState & MV_STATE_SCROLL))); return pdict; } @@ -3733,81 +3665,62 @@ get_item_configuration(PyObject* self, PyObject* args, PyObject* kwargs) PyObject* itemraw; if (!Parse((GetParsers())["get_item_configuration"], args, kwargs, __FUNCTION__, &itemraw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); mvAppItem* appitem = GetItem((*GContext->itemRegistry), item); - PyObject* pdict = PyDict_New(); - - if (appitem) + if (!appitem) { - // config py objects - mvPyObject py_filter_key = ToPyString(appitem->config.filter); - mvPyObject py_payload_type = ToPyString(appitem->config.payloadType); - mvPyObject py_label = ToPyString(appitem->config.specifiedLabel); - mvPyObject py_use_internal_label = ToPyBool(appitem->config.useInternalLabel); - mvPyObject py_source = ToPyUUID(appitem->config.source); - mvPyObject py_show = ToPyBool(appitem->config.show); - mvPyObject py_enabled = ToPyBool(appitem->config.enabled); - mvPyObject py_tracked = ToPyBool(appitem->config.tracked); - mvPyObject py_width = ToPyInt(appitem->config.width); - mvPyObject py_track_offset = ToPyFloat(appitem->config.trackOffset); - mvPyObject py_height = ToPyInt(appitem->config.height); - mvPyObject py_indent = ToPyInt((i32)appitem->config.indent); - - PyDict_SetItemString(pdict, "filter_key", py_filter_key); - PyDict_SetItemString(pdict, "payload_type", py_payload_type); - PyDict_SetItemString(pdict, "label", py_label); - PyDict_SetItemString(pdict, "use_internal_label", py_use_internal_label); - PyDict_SetItemString(pdict, "source", py_source); - PyDict_SetItemString(pdict, "show", py_show); - PyDict_SetItemString(pdict, "enabled", py_enabled); - PyDict_SetItemString(pdict, "tracked", py_tracked); - PyDict_SetItemString(pdict, "width", py_width); - PyDict_SetItemString(pdict, "track_offset", py_track_offset); - PyDict_SetItemString(pdict, "height", py_height); - PyDict_SetItemString(pdict, "indent", py_indent); - - if (appitem->config.callback) - { - Py_XINCREF(appitem->config.callback); - PyDict_SetItemString(pdict, "callback", appitem->config.callback); - } - else - PyDict_SetItemString(pdict, "callback", GetPyNone()); - - if (appitem->config.dropCallback) - { - Py_XINCREF(appitem->config.dropCallback); - PyDict_SetItemString(pdict, "drop_callback", appitem->config.dropCallback); - } - else - PyDict_SetItemString(pdict, "drop_callback", GetPyNone()); - - if (appitem->config.dragCallback) - { - Py_XINCREF(appitem->config.dragCallback); - PyDict_SetItemString(pdict, "drag_callback", appitem->config.dragCallback); - } - else - PyDict_SetItemString(pdict, "drag_callback", GetPyNone()); - - if (appitem->config.user_data) - { - Py_XINCREF(appitem->config.user_data); - PyDict_SetItemString(pdict, "user_data", appitem->config.user_data); - } - else - PyDict_SetItemString(pdict, "user_data", GetPyNone()); - - appitem->getSpecificConfiguration(pdict); - } - else mvThrowPythonError(mvErrorCode::mvItemNotFound, "get_item_configuration", "Item not found: " + std::to_string(item), nullptr); + return nullptr; + } + + PyObject* pdict = PyDict_New(); + + // config py objects + mvPyObject py_filter_key = ToPyString(appitem->config.filter); + mvPyObject py_payload_type = ToPyString(appitem->config.payloadType); + mvPyObject py_label = ToPyString(appitem->config.specifiedLabel); + mvPyObject py_use_internal_label = ToPyBool(appitem->config.useInternalLabel); + mvPyObject py_source = ToPyUUID(appitem->config.source); + mvPyObject py_show = ToPyBool(appitem->config.show); + mvPyObject py_enabled = ToPyBool(appitem->config.enabled); + mvPyObject py_tracked = ToPyBool(appitem->config.tracked); + mvPyObject py_width = ToPyInt(appitem->config.width); + mvPyObject py_track_offset = ToPyFloat(appitem->config.trackOffset); + mvPyObject py_height = ToPyInt(appitem->config.height); + mvPyObject py_indent = ToPyInt((i32)appitem->config.indent); + + PyDict_SetItemString(pdict, "filter_key", py_filter_key); + PyDict_SetItemString(pdict, "payload_type", py_payload_type); + PyDict_SetItemString(pdict, "label", py_label); + PyDict_SetItemString(pdict, "use_internal_label", py_use_internal_label); + PyDict_SetItemString(pdict, "source", py_source); + PyDict_SetItemString(pdict, "show", py_show); + PyDict_SetItemString(pdict, "enabled", py_enabled); + PyDict_SetItemString(pdict, "tracked", py_tracked); + PyDict_SetItemString(pdict, "width", py_width); + PyDict_SetItemString(pdict, "track_offset", py_track_offset); + PyDict_SetItemString(pdict, "height", py_height); + PyDict_SetItemString(pdict, "indent", py_indent); + + PyObject* callback = appitem->config.callback; + PyDict_SetItemString(pdict, "callback", callback? callback : Py_None); + + PyObject* dropCallback = appitem->config.dropCallback; + PyDict_SetItemString(pdict, "drop_callback", dropCallback? dropCallback : Py_None); + + PyObject* dragCallback = appitem->config.dragCallback; + PyDict_SetItemString(pdict, "drag_callback", dragCallback? dragCallback : Py_None); + + PyObject* user_data = *(appitem->config.user_data); + PyDict_SetItemString(pdict, "user_data", user_data? user_data : Py_None); + + appitem->getSpecificConfiguration(pdict); return pdict; } @@ -3821,9 +3734,9 @@ set_item_children(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["set_item_children"], args, kwargs, __FUNCTION__, &itemraw, &sourceraw, &slot)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); mvUUID source = GetIDFromPyObject(sourceraw); @@ -3849,7 +3762,7 @@ set_item_children(PyObject* self, PyObject* args, PyObject* kwargs) mvThrowPythonError(mvErrorCode::mvItemNotFound, "set_item_children", "Stage item not found: " + std::to_string(item), nullptr); assert(false); - return GetPyNone(); + return nullptr; } @@ -3876,8 +3789,11 @@ set_item_children(PyObject* self, PyObject* args, PyObject* kwargs) } } else + { mvThrowPythonError(mvErrorCode::mvItemNotFound, "set_item_children", "Item not found: " + std::to_string(item), nullptr); + return nullptr; + } DeleteItem(*GContext->itemRegistry, source); @@ -3892,9 +3808,9 @@ bind_item_font(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["bind_item_font"], args, kwargs, __FUNCTION__, &itemraw, &fontraw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); mvUUID font = GetIDFromPyObject(fontraw); @@ -3912,6 +3828,7 @@ bind_item_font(PyObject* self, PyObject* args, PyObject* kwargs) if (appfont) { appitem->font = appfont; + return GetPyNone(); } else { @@ -3923,7 +3840,7 @@ bind_item_font(PyObject* self, PyObject* args, PyObject* kwargs) mvThrowPythonError(mvErrorCode::mvItemNotFound, "bind_item_font", "Item not found: " + std::to_string(item), nullptr); - return GetPyNone(); + return nullptr; } static PyObject* @@ -3934,9 +3851,9 @@ bind_item_theme(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["bind_item_theme"], args, kwargs, __FUNCTION__, &itemraw, &themeraw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); mvUUID theme = GetIDFromPyObject(themeraw); @@ -3954,13 +3871,14 @@ bind_item_theme(PyObject* self, PyObject* args, PyObject* kwargs) if (apptheme) { - if (apptheme->type != mvAppItemType::mvTheme) + if (apptheme->type == mvAppItemType::mvTheme) { + appitem->theme = *(std::shared_ptr*)(&apptheme); + return GetPyNone(); + } + else mvThrowPythonError(mvErrorCode::mvIncompatibleType, "bind_item_theme", "Item not a theme: " + std::to_string(theme), nullptr); - } - appitem->theme = *(std::shared_ptr*)(&apptheme); - return GetPyNone(); } else mvThrowPythonError(mvErrorCode::mvItemNotFound, "bind_item_theme", @@ -3970,7 +3888,7 @@ bind_item_theme(PyObject* self, PyObject* args, PyObject* kwargs) mvThrowPythonError(mvErrorCode::mvItemNotFound, "bind_item_theme", "Item not found: " + std::to_string(item), nullptr); - return GetPyNone(); + return nullptr; } static PyObject* @@ -3981,9 +3899,9 @@ bind_item_handler_registry(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["bind_item_handler_registry"], args, kwargs, __FUNCTION__, &itemraw, ®raw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); mvUUID reg = GetIDFromPyObject(regraw); @@ -3997,18 +3915,19 @@ bind_item_handler_registry(PyObject* self, PyObject* args, PyObject* kwargs) return GetPyNone(); } - auto apptheme = GetRefItem(*GContext->itemRegistry, reg); + auto handler_registry = GetRefItem(*GContext->itemRegistry, reg); - if (apptheme) + if (handler_registry) { - if (apptheme->type != mvAppItemType::mvItemHandlerRegistry) + if (handler_registry->type == mvAppItemType::mvItemHandlerRegistry) { + appitem->handlerRegistry = *(std::shared_ptr*)(&handler_registry); + appitem->handlerRegistry->onBind(appitem); + return GetPyNoneOrError(); + } + else mvThrowPythonError(mvErrorCode::mvIncompatibleType, "bind_item_handler_registry", "Item not handler registry: " + std::to_string(reg), nullptr); - } - appitem->handlerRegistry = *(std::shared_ptr*)(&apptheme); - appitem->handlerRegistry->onBind(appitem); - return GetPyNone(); } else mvThrowPythonError(mvErrorCode::mvItemNotFound, "bind_item_handler_registry", @@ -4018,7 +3937,7 @@ bind_item_handler_registry(PyObject* self, PyObject* args, PyObject* kwargs) mvThrowPythonError(mvErrorCode::mvItemNotFound, "bind_item_handler_registry", "Item not found: " + std::to_string(item), nullptr); - return GetPyNone(); + return nullptr; } static PyObject* @@ -4028,9 +3947,9 @@ reset_pos(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["reset_pos"], args, kwargs, __FUNCTION__, &itemraw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); mvAppItem* appitem = GetItem((*GContext->itemRegistry), item); @@ -4038,8 +3957,11 @@ reset_pos(PyObject* self, PyObject* args, PyObject* kwargs) if (appitem) appitem->info.dirtyPos = false; else + { mvThrowPythonError(mvErrorCode::mvItemNotFound, "reset_pos", "Item not found: " + std::to_string(item), nullptr); + return nullptr; + } return GetPyNone(); } @@ -4050,20 +3972,22 @@ get_item_state(PyObject* self, PyObject* args, PyObject* kwargs) PyObject* itemraw; if (!Parse((GetParsers())["get_item_state"], args, kwargs, __FUNCTION__, &itemraw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); mvAppItem* appitem = GetItem((*GContext->itemRegistry), item); - PyObject* pdict = PyDict_New(); - - if (appitem) - FillAppItemState(pdict, appitem->state, DearPyGui::GetApplicableState(appitem->type)); - else + if (!appitem) + { mvThrowPythonError(mvErrorCode::mvItemNotFound, "get_item_state", "Item not found: " + std::to_string(item), nullptr); + return nullptr; + } + + PyObject* pdict = PyDict_New(); + FillAppItemState(pdict, appitem->state, DearPyGui::GetApplicableState(appitem->type)); return pdict; } @@ -4072,7 +3996,7 @@ static PyObject* get_item_types(PyObject* self, PyObject* args, PyObject* kwargs) { - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); PyObject* pdict = PyDict_New(); #define X(el) PyDict_SetItemString(pdict, #el, PyLong_FromLong((int)mvAppItemType::el)); @@ -4086,7 +4010,7 @@ static PyObject* configure_item(PyObject* self, PyObject* args, PyObject* kwargs) { - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(PyTuple_GetItem(args, 0)); mvAppItem* appitem = GetItem((*GContext->itemRegistry), item); @@ -4097,8 +4021,11 @@ configure_item(PyObject* self, PyObject* args, PyObject* kwargs) appitem->handleKeywordArgs(kwargs, GetEntityCommand(appitem->type)); } else + { mvThrowPythonError(mvErrorCode::mvItemNotFound, "configure_item", "Item not found: " + std::to_string(item), nullptr); + return nullptr; + } return GetPyNone(); } @@ -4109,9 +4036,9 @@ get_value(PyObject* self, PyObject* args, PyObject* kwargs) PyObject* nameraw; if (!Parse((GetParsers())["get_value"], args, kwargs, __FUNCTION__, &nameraw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID name = GetIDFromPyObject(nameraw); mvAppItem* item = GetItem(*GContext->itemRegistry, name); @@ -4127,9 +4054,9 @@ get_values(PyObject* self, PyObject* args, PyObject* kwargs) PyObject* items; if (!Parse((GetParsers())["get_values"], args, kwargs, __FUNCTION__, &items)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); auto aitems = ToUUIDVect(items); PyObject* pyvalues = PyList_New(aitems.size()); @@ -4141,6 +4068,9 @@ get_values(PyObject* self, PyObject* args, PyObject* kwargs) PyList_SetItem(pyvalues, i, item->getPyValue()); else { + // TODO: decide whether we want to raise an exception or return None's. + // These two variants are mutually exclusive. If we raise an exception, + // we must return nullptr, not pyvalues. mvThrowPythonError(mvErrorCode::mvItemNotFound, "get_values", "Item not found: " + std::to_string(aitems[i]), nullptr); PyList_SetItem(pyvalues, i, GetPyNone()); @@ -4157,24 +4087,22 @@ set_value(PyObject* self, PyObject* args, PyObject* kwargs) PyObject* value; if (!Parse((GetParsers())["set_value"], args, kwargs, __FUNCTION__, &nameraw, &value)) - return GetPyNone(); + return nullptr; - if (value) - Py_XINCREF(value); - - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID name = GetIDFromPyObject(nameraw); mvAppItem* item = GetItem(*GContext->itemRegistry, name); - if (item) - item->setPyValue(value); - else + if (!item) { mvThrowPythonError(mvErrorCode::mvItemNotFound, "set_value", "Item not found: " + std::to_string(name), nullptr); + return nullptr; } + Py_XINCREF(value); + item->setPyValue(value); Py_XDECREF(value); return GetPyNone(); @@ -4188,9 +4116,9 @@ set_item_alias(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["set_item_alias"], args, kwargs, __FUNCTION__, &itemraw, &alias)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); mvAppItem* appitem = GetItem((*GContext->itemRegistry), item); @@ -4206,9 +4134,9 @@ get_item_alias(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["get_item_alias"], args, kwargs, __FUNCTION__, &itemraw)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); mvUUID item = GetIDFromPyObject(itemraw); mvAppItem* appitem = GetItem((*GContext->itemRegistry), item); @@ -4225,25 +4153,12 @@ capture_next_item(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["capture_next_item"], args, kwargs, __FUNCTION__, &callable, &user_data)) - return GetPyNone(); - - std::lock_guard lk(GContext->mutex); - - if (GContext->itemRegistry->captureCallback) - Py_XDECREF(GContext->itemRegistry->captureCallback); - - if (GContext->itemRegistry->captureCallbackUserData) - Py_XDECREF(GContext->itemRegistry->captureCallbackUserData); + return nullptr; - Py_XINCREF(callable); - if(user_data) - Py_XINCREF(user_data); - if (callable == Py_None) - GContext->itemRegistry->captureCallback = nullptr; - else - GContext->itemRegistry->captureCallback = callable; + mvPySafeLockGuard lk(GContext->mutex); - GContext->itemRegistry->captureCallbackUserData = user_data; + GContext->itemRegistry->captureCallback = mvPyObject(callable == Py_None? nullptr : callable, true); + GContext->itemRegistry->captureCallbackUserData = mvPyObject(user_data, true); return GetPyNone(); } @@ -4254,29 +4169,44 @@ get_callback_queue(PyObject* self, PyObject* args, PyObject* kwargs) if (GContext->callbackRegistry->jobs.empty()) return GetPyNone(); + mvPySafeLockGuard lk(GContext->mutex); + PyObject* pArgs = PyTuple_New(GContext->callbackRegistry->jobs.size()); for (int i = 0; i < GContext->callbackRegistry->jobs.size(); i++) { PyObject* job = PyTuple_New(4); - if (GContext->callbackRegistry->jobs[i].callback) - PyTuple_SetItem(job, 0, GContext->callbackRegistry->jobs[i].callback); - else - PyTuple_SetItem(job, 0, GetPyNone()); + const mvCallbackJob& cur_entry = GContext->callbackRegistry->jobs[i]; - if(GContext->callbackRegistry->jobs[i].sender == 0) - PyTuple_SetItem(job, 1, ToPyString(GContext->callbackRegistry->jobs[i].sender_str)); + PyObject* callback; + if (cur_entry.ownerless_callback) + { + callback = *cur_entry.ownerless_callback; + Py_XINCREF(callback); + } else - PyTuple_SetItem(job, 1, ToPyUUID(GContext->callbackRegistry->jobs[i].sender)); + { + auto liveOwner = cur_entry.owner.lock(); + // If the owner of this entry is gone, we'll just set the callback to None. + // This lets us create the output list right away, without the need to collect + // valid callbacks first. Also, this mimicks the behavior of widgets without + // a `callback` set on them, which in the "manual" mode put null callbacks into + // the queue. It's mostly a debug/diagnostic mode anyway - captures everything. + callback = liveOwner? cur_entry.callback : nullptr; + // Must only be done while we own liveOwner. + Py_XINCREF(callback); + } + PyTuple_SetItem(job, 0, callback? callback : GetPyNone()); - if (GContext->callbackRegistry->jobs[i].app_data) - PyTuple_SetItem(job, 2, GContext->callbackRegistry->jobs[i].app_data); // steals data, so don't deref - else - PyTuple_SetItem(job, 2, GetPyNone()); + PyTuple_SetItem(job, 1, ToPyUUID(cur_entry.sender, cur_entry.alias)); - if (GContext->callbackRegistry->jobs[i].user_data) - PyTuple_SetItem(job, 3, GContext->callbackRegistry->jobs[i].user_data); // steals data, so don't deref - else - PyTuple_SetItem(job, 3, GetPyNone()); + // app_data_func() returns a new PyObject reference (passing ownership to us), + // therefore we don't need to INCREF it. + PyObject* app_data = cur_entry.app_data_func(); + PyTuple_SetItem(job, 2, app_data? app_data : GetPyNone()); + + PyObject* user_data = *cur_entry.user_data; + Py_XINCREF(user_data); + PyTuple_SetItem(job, 3, user_data? user_data : GetPyNone()); PyTuple_SetItem(pArgs, i, job); } @@ -4293,9 +4223,9 @@ set_clipboard_text(PyObject* self, PyObject* args, PyObject* kwargs) if (!Parse((GetParsers())["set_clipboard_text"], args, kwargs, __FUNCTION__, &text)) - return GetPyNone(); + return nullptr; - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); ImGui::SetClipboardText(text); @@ -4306,7 +4236,7 @@ static PyObject* get_clipboard_text(PyObject* self, PyObject* args, PyObject* kwargs) { - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); const char* text = ImGui::GetClipboardText(); @@ -4317,7 +4247,7 @@ static PyObject* get_platform(PyObject* self, PyObject* args, PyObject* kwargs) { - std::lock_guard lk(GContext->mutex); + mvPySafeLockGuard lk(GContext->mutex); #ifdef _WIN32 return ToPyInt(0L); diff --git a/src/dearpygui_parsers.h b/src/dearpygui_parsers.h index ef229ae01..8446225ed 100644 --- a/src/dearpygui_parsers.h +++ b/src/dearpygui_parsers.h @@ -564,7 +564,7 @@ InsertParser_Block1(std::map& parsers) { std::vector args; - args.push_back({ mvPyDataType::Integer, "delay", mvArgType::KEYWORD_ARG, "32", "Minimal delay in in milliseconds" }); + args.push_back({ mvPyDataType::Integer, "delay", mvArgType::DEPRECATED_REMOVE_KEYWORD_ARG, "32", "Do not use it anymore, it has no effect." }); mvPythonParserSetup setup; setup.about = "Waits one frame."; @@ -1784,9 +1784,15 @@ InsertParser_Block4(std::map& parsers) { std::vector args; args.push_back({ mvPyDataType::UUID, "item" }); - args.push_back({ mvPyDataType::Float, "value" }); + args.push_back({ mvPyDataType::Float, "value", mvArgType::REQUIRED_ARG, "", "Scroll position"}); + args.push_back({ mvPyDataType::Integer, "when", mvArgType::KEYWORD_ARG, "internal_dpg.mvSetScrollFlags_Delayed", + "Specifies whether the scroll position will be set in the nearest frame (mvSetScrollFlags_Now) or with " + "a 1-frame delay (mvSetScrollFlags_Delayed). The former prevents flickering, the latter works better " + "if contents change in the same frame as when set_x_scroll called. mvSetScrollFlags_Both can also be used " + "to set the position twice." }); mvPythonParserSetup setup; + setup.about = "Sets horizontal scroll position."; mvPythonParser parser = FinalizeParser(setup, args); parsers.insert({ "set_x_scroll", parser }); @@ -1795,8 +1801,16 @@ InsertParser_Block4(std::map& parsers) { std::vector args; args.push_back({ mvPyDataType::UUID, "item" }); - args.push_back({ mvPyDataType::Float, "value" }); + args.push_back({ mvPyDataType::Float, "value", mvArgType::REQUIRED_ARG, "", "Scroll position"}); + args.push_back({ mvPyDataType::Integer, "when", mvArgType::KEYWORD_ARG, "internal_dpg.mvSetScrollFlags_Delayed", + "Specifies whether the scroll position will be set in the nearest frame (mvSetScrollFlags_Now) or with " + "a 1-frame delay (mvSetScrollFlags_Delayed). The former prevents flickering, the latter works better " + "if contents change in the same frame as when set_x_scroll called. mvSetScrollFlags_Both can also be used " + "to set the position twice." }); + mvPythonParserSetup setup; + setup.about = "Sets vertical scroll position."; + mvPythonParser parser = FinalizeParser(setup, args); parsers.insert({ "set_y_scroll", parser }); } diff --git a/src/mvAppItem.cpp b/src/mvAppItem.cpp index b5f393057..eed1026f3 100644 --- a/src/mvAppItem.cpp +++ b/src/mvAppItem.cpp @@ -36,12 +36,6 @@ mvAppItem::~mvAppItem() if (type == mvAppItemType::mvTable) static_cast(this)->onChildrenRemoved(); - mvGlobalIntepreterLock gil; - if (config.callback) Py_DECREF(config.callback); - if (config.user_data) Py_DECREF(config.user_data); - if (config.dragCallback) Py_DECREF(config.dragCallback); - if (config.dropCallback) Py_DECREF(config.dropCallback); - // in case item registry is destroyed if (GContext->itemRegistry) { @@ -50,17 +44,91 @@ mvAppItem::~mvAppItem() if (!GContext->IO.manualAliasManagement) GContext->itemRegistry->aliases.erase(config.alias); } - CleanUpItem(*GContext->itemRegistry, uuid); + GContext->itemRegistry->allItems.erase(uuid); } } -PyObject* -mvAppItem::getCallback(bool ignore_enabled) +void mvAppItem::submitCallback() +{ + submitCallbackEx([]() -> PyObject* { return nullptr; }); +} + +template<> +void mvAppItem::submitCallback(std::string app_data) +{ + submitCallbackEx([app_data=std::move(app_data)]() { return ToPyString(app_data); }); +} + +template<> +void mvAppItem::submitCallback(bool app_data) +{ + submitCallbackEx([=]() { return ToPyBool(app_data); }); +} + +template<> +void mvAppItem::submitCallback(float app_data) +{ + submitCallbackEx([=]() { return ToPyFloat(app_data); }); +} + +template<> +void mvAppItem::submitCallback(double app_data) +{ + submitCallbackEx([=]() { return ToPyDouble(app_data); }); +} + +template<> +void mvAppItem::submitCallback(int app_data) +{ + submitCallbackEx([=]() { return ToPyInt(app_data); }); +} + +template<> +void mvAppItem::submitCallback(std::array app_data) +{ + submitCallbackEx([app_data=std::move(app_data)]() { return ToPyIntList(app_data.data(), (int) app_data.size()); }); +} + +template<> +void mvAppItem::submitCallback(std::array app_data) +{ + submitCallbackEx([app_data=std::move(app_data)]() { return ToPyFloatList(app_data.data(), (int) app_data.size()); }); +} + +template<> +void mvAppItem::submitCallback(std::array app_data) +{ + submitCallbackEx([app_data=std::move(app_data)]() { return ToPyFloatList(app_data.data(), (int) app_data.size()); }); +} + +template<> +void mvAppItem::submitCallback(mvColor app_data) { - if (config.enabled) - return config.callback; + submitCallbackEx([=]() { return ToPyColor(app_data); }); +} - return ignore_enabled ? config.callback : nullptr; +template<> +void mvAppItem::submitCallback(mvUUID app_data) +{ + submitCallbackEx([=]() { return ToPyUUID(app_data); }); +} + +template<> +void mvAppItem::submitCallback(tm app_data) +{ + submitCallbackEx([=]() { return ToPyTime(app_data); }); +} + +template<> +void mvAppItem::submitCallback(ImVec2 app_data) +{ + submitCallbackEx([=]() { return ToPyPair(app_data.x, app_data.y); }); +} + +template<> +void mvAppItem::submitCallback(ImGuiKey app_data) +{ + submitCallbackEx([=]() { return ToPyInt(app_data); }); } void @@ -150,7 +218,6 @@ mvAppItem::handleKeywordArgs(PyObject* dict, const std::string& parser) } } if (PyObject* item = PyDict_GetItemString(dict, "tracked")) config.tracked = ToBool(item); - if (PyObject* item = PyDict_GetItemString(dict, "delay_search")) config.searchLast = ToBool(item); if (PyObject* item = PyDict_GetItemString(dict, "track_offset")) { config.trackOffset = ToFloat(item); @@ -163,52 +230,22 @@ mvAppItem::handleKeywordArgs(PyObject* dict, const std::string& parser) if (PyObject* item = PyDict_GetItemString(dict, "callback")) { - if (config.callback) - Py_XDECREF(config.callback); - - // TODO: investigate if PyNone should be increffed - Py_XINCREF(item); - if (item == Py_None) - config.callback = nullptr; - else - config.callback = item; + config.callback = mvPyObject(item == Py_None? nullptr : item, true); } if (PyObject* item = PyDict_GetItemString(dict, "drag_callback")) { - if (config.dragCallback) - Py_XDECREF(config.dragCallback); - - Py_XINCREF(item); - if (item == Py_None) - config.dragCallback = nullptr; - else - config.dragCallback = item; + config.dragCallback = mvPyObject(item == Py_None? nullptr : item, true); } if (PyObject* item = PyDict_GetItemString(dict, "drop_callback")) { - if (config.dropCallback) - Py_XDECREF(config.dropCallback); - - Py_XINCREF(item); - - if (item == Py_None) - config.dropCallback = nullptr; - else - config.dropCallback = item; + config.dropCallback = mvPyObject(item == Py_None? nullptr : item, true); } if (PyObject* item = PyDict_GetItemString(dict, "user_data")) { - if (config.user_data) - Py_XDECREF(config.user_data); - - Py_XINCREF(item); - if (item == Py_None) - config.user_data = nullptr; - else - config.user_data = item; + *config.user_data = mvPyObject(item == Py_None? nullptr : item, true); } handleSpecificKeywordArgs(dict); @@ -220,6 +257,37 @@ mvAppItem::setDataSource(mvUUID value) config.source = value; } +void +mvAppItem::handleImmediateScroll() +{ + if (!((config.scrollXFlags | config.scrollYFlags) & mvSetScrollFlags_Now)) + return; + + ImVec2 scroll = { (config.scrollXFlags & mvSetScrollFlags_Now)? config.scrollX : -1, + (config.scrollYFlags & mvSetScrollFlags_Now)? config.scrollY : -1 }; + ImGui::SetNextWindowScroll(scroll); +} + +void +mvAppItem::handleDelayedScroll() +{ + if (config.scrollXFlags & mvSetScrollFlags_Delayed) + { + if (config.scrollX < 0.0f) + ImGui::SetScrollHereX(1.0f); + else + ImGui::SetScrollX(config.scrollX); + } + + if (config.scrollYFlags & mvSetScrollFlags_Delayed) + { + if (config.scrollY < 0.0f) + ImGui::SetScrollHereY(1.0f); + else + ImGui::SetScrollY(config.scrollY); + } +} + static bool CanItemTypeBeHovered(mvAppItemType type) { @@ -497,6 +565,7 @@ CanItemTypeBeVisible(mvAppItemType type) case mvAppItemType::mvTable: case mvAppItemType::mvTableColumn: case mvAppItemType::mvTableRow: + case mvAppItemType::mvSyncedTables: case mvAppItemType::mvButton: return true; default: return false; } @@ -812,6 +881,7 @@ CanItemTypeHaveRectSize(mvAppItemType type) case mvAppItemType::mvNode: case mvAppItemType::mvNodeEditor: case mvAppItemType::mvPlot: + case mvAppItemType::mvTableColumn: case mvAppItemType::mvButton: return true; default: return false; } @@ -874,6 +944,19 @@ CanItemTypeHaveContAvail(mvAppItemType type) } +static bool +CanItemTypeBeScrolled(mvAppItemType type) +{ + switch (type) + { + case mvAppItemType::mvWindowAppItem: + case mvAppItemType::mvChildWindow: + case mvAppItemType::mvTable: return true; + default: return false; + } + +} + int DearPyGui::GetApplicableState(mvAppItemType type) { @@ -892,6 +975,7 @@ DearPyGui::GetApplicableState(mvAppItemType type) if(CanItemTypeHaveRectMax(type)) applicableState |= MV_STATE_RECT_MAX; if(CanItemTypeHaveRectSize(type)) applicableState |= MV_STATE_RECT_SIZE; if(CanItemTypeHaveContAvail(type)) applicableState |= MV_STATE_CONT_AVAIL; + if(CanItemTypeBeScrolled(type)) applicableState |= MV_STATE_SCROLL; return applicableState; } @@ -925,6 +1009,7 @@ DearPyGui::GetEntityDesciptionFlags(mvAppItemType type) case mvAppItemType::mvTable: case mvAppItemType::mvTableCell: case mvAppItemType::mvTableRow: + case mvAppItemType::mvSyncedTables: case mvAppItemType::mv2dHistogramSeries: case mvAppItemType::mvAreaSeries: case mvAppItemType::mvBarSeries: @@ -974,6 +1059,7 @@ DearPyGui::GetEntityDesciptionFlags(mvAppItemType type) case mvAppItemType::mvHoverHandler: case mvAppItemType::mvResizeHandler: case mvAppItemType::mvToggledOpenHandler: + case mvAppItemType::mvScrollHandler: case mvAppItemType::mvVisibleHandler: return MV_ITEM_DESC_HANDLER; case mvAppItemType::mvTooltip: @@ -1189,6 +1275,7 @@ DearPyGui::GetAllowableParents(mvAppItemType type) case mvAppItemType::mvHoverHandler: case mvAppItemType::mvResizeHandler: case mvAppItemType::mvToggledOpenHandler: + case mvAppItemType::mvScrollHandler: case mvAppItemType::mvVisibleHandler: MV_START_PARENTS MV_ADD_PARENT(mvAppItemType::mvStage), @@ -1507,7 +1594,8 @@ DearPyGui::GetAllowableChildren(mvAppItemType type) MV_ADD_CHILD(mvAppItemType::mvHoverHandler), MV_ADD_CHILD(mvAppItemType::mvResizeHandler), MV_ADD_CHILD(mvAppItemType::mvToggledOpenHandler), - MV_ADD_CHILD(mvAppItemType::mvVisibleHandler) + MV_ADD_CHILD(mvAppItemType::mvVisibleHandler), + MV_ADD_CHILD(mvAppItemType::mvScrollHandler), MV_END_CHILDREN case mvAppItemType::mvValueRegistry: @@ -2999,7 +3087,7 @@ DearPyGui::GetEntityParser(mvAppItemType type) args.push_back({ mvPyDataType::Dict, "default_value", mvArgType::KEYWORD_ARG, "{'month_day': 14, 'year':20, 'month':5}" }); args.push_back({ mvPyDataType::Integer, "level", mvArgType::KEYWORD_ARG, "0", "Use avaliable constants. mvDatePickerLevel_Day, mvDatePickerLevel_Month, mvDatePickerLevel_Year" }); - setup.about = "Adds a data picker."; + setup.about = "Adds a date picker."; break; } case mvAppItemType::mvColorButton: @@ -3264,6 +3352,24 @@ DearPyGui::GetEntityParser(mvAppItemType type) setup.createContextManager = true; break; } + case mvAppItemType::mvSyncedTables: + { + AddCommonArgs(args, (CommonParserArgs)( + MV_PARSER_ARG_ID | + MV_PARSER_ARG_PARENT | + MV_PARSER_ARG_BEFORE | + MV_PARSER_ARG_FILTER | + MV_PARSER_ARG_SHOW) + ); + + setup.about = + "Links all tables that are immediate children of this container so that they share " + "their state (mostly column sizes). Other children are rendered as is. This is " + "an experimental feature, use with caution."; + setup.category = { "Tables", "Containers", "Widgets" }; + setup.createContextManager = true; + break; + } case mvAppItemType::mvDrawLine: { AddCommonArgs(args, (CommonParserArgs)( @@ -4456,13 +4562,13 @@ DearPyGui::GetEntityParser(mvAppItemType type) MV_PARSER_ARG_POS) ); - args.push_back({ mvPyDataType::Integer, "style", mvArgType::KEYWORD_ARG, "0", "0 is rotating dots style, 1 is rotating bar style." }); - args.push_back({ mvPyDataType::Integer, "circle_count", mvArgType::KEYWORD_ARG, "8", "Number of dots show if dots or size of circle if circle." }); - args.push_back({ mvPyDataType::Float, "speed", mvArgType::KEYWORD_ARG, "1.0", "Speed the anamation will rotate." }); - args.push_back({ mvPyDataType::Float, "radius", mvArgType::KEYWORD_ARG, "3.0", "Radius size of the loading indicator." }); - args.push_back({ mvPyDataType::Float, "thickness", mvArgType::KEYWORD_ARG, "1.0", "Thickness of the circles or line." }); - args.push_back({ mvPyDataType::IntList, "color", mvArgType::KEYWORD_ARG, "(51, 51, 55, 255)", "Color of the growing center circle." }); - args.push_back({ mvPyDataType::IntList, "secondary_color", mvArgType::KEYWORD_ARG, "(29, 151, 236, 103)", "Background of the dots in dot mode." }); + args.push_back({ mvPyDataType::Integer, "style", mvArgType::KEYWORD_ARG, "0", "mvLoadInd_DottedCircle is rotating dots style, mvLoadInd_Ring is rotating bar style." }); + args.push_back({ mvPyDataType::Integer, "circle_count", mvArgType::KEYWORD_ARG, "8", "DottedCircle style: number of dots to show." }); + args.push_back({ mvPyDataType::Float, "speed", mvArgType::KEYWORD_ARG, "1.0", "Speed with which the animation will rotate." }); + args.push_back({ mvPyDataType::Float, "radius", mvArgType::KEYWORD_ARG, "3.0", "Scale factor for the loading indicator radius. The size of the indicator is determined by font size and this scale factor." }); + args.push_back({ mvPyDataType::Float, "thickness", mvArgType::KEYWORD_ARG, "1.0", "Ring style: scale factor of line thickness; thickness=1 corresponds to line width being 1/8 of the ring diameter." }); + args.push_back({ mvPyDataType::IntList, "color", mvArgType::KEYWORD_ARG, "None", "Main color of the indicator. If omitted, the color for mvThemeCol_Button will be used." }); + args.push_back({ mvPyDataType::IntList, "secondary_color", mvArgType::KEYWORD_ARG, "None", "DottedCircle style: color of 'inactive' dots. If omitted, the color for mvThemeCol_ButtonHovered will be used." }); setup.about = "Adds a rotating animated loading symbol."; break; @@ -4817,6 +4923,8 @@ DearPyGui::GetEntityParser(mvAppItemType type) MV_PARSER_ARG_CALLBACK) ); + args.push_back({ mvPyDataType::Integer, "event_type", mvArgType::KEYWORD_ARG, "None", "What kind of events to track: mouse-in (mvEventType_Enter), mouse-over (mvEventType_On), mouse-out (mvEventType_Leave). Can be a combination of these flags. Defaults to mouse-over." }); + setup.about = "Adds a hover handler."; setup.category = { "Widgets", "Events" }; break; @@ -4843,6 +4951,8 @@ DearPyGui::GetEntityParser(mvAppItemType type) MV_PARSER_ARG_CALLBACK) ); + args.push_back({ mvPyDataType::Integer, "event_type", mvArgType::KEYWORD_ARG, "None", "What kind of events to track: just got focus (mvEventType_Enter), currently having focus (mvEventType_On), lost focus (mvEventType_Leave). Can be a combination of these flags. Defaults to mvEventType_On." }); + setup.about = "Adds a focus handler."; setup.category = { "Widgets", "Events" }; break; @@ -4985,6 +5095,19 @@ DearPyGui::GetEntityParser(mvAppItemType type) setup.category = { "Widgets", "Events" }; break; } + case mvAppItemType::mvScrollHandler: + { + AddCommonArgs(args, (CommonParserArgs)( + MV_PARSER_ARG_ID | + MV_PARSER_ARG_SHOW | + MV_PARSER_ARG_PARENT | + MV_PARSER_ARG_CALLBACK) + ); + + setup.about = "Adds a scroll handler."; + setup.category = { "Widgets", "Events" }; + break; + } case mvAppItemType::mvFont: { AddCommonArgs(args, (CommonParserArgs)( diff --git a/src/mvAppItem.h b/src/mvAppItem.h index b8711a95d..2c576d454 100644 --- a/src/mvAppItem.h +++ b/src/mvAppItem.h @@ -109,6 +109,14 @@ struct mvAppItemInfo bool dirtyPos = false; }; +enum mvSetScrollFlags +{ + mvSetScrollFlags_None = 0, + mvSetScrollFlags_Now = 1 << 0, + mvSetScrollFlags_Delayed = 1 << 1, + mvSetScrollFlags_Both = mvSetScrollFlags_Now | mvSetScrollFlags_Delayed +}; + struct mvAppItemConfig { mvUUID source = 0; @@ -123,14 +131,19 @@ struct mvAppItemConfig float trackOffset = 0.5f; // 0.0f:top, 0.5f:center, 1.0f:bottom bool show = true; bool enabled = true; - bool searchLast = false; - bool searchDelayed = false; bool useInternalLabel = true; // when false, will use specificed label bool tracked = false; - PyObject* callback = nullptr; - PyObject* user_data = nullptr; - PyObject* dragCallback = nullptr; - PyObject* dropCallback = nullptr; + mvPyObject callback = nullptr; + mvPyObject dragCallback = nullptr; + mvPyObject dropCallback = nullptr; + // We store user_data as a pointer because that's how we'll need it when submitting + // the callback. This is to pass user_data into mvAddCallback that comes from a + // different source than the callback owner (required for the drag callback). + std::shared_ptr user_data = std::make_shared(nullptr); + float scrollX = 0.0f; + float scrollY = 0.0f; + mvSetScrollFlags scrollXFlags = mvSetScrollFlags_None; + mvSetScrollFlags scrollYFlags = mvSetScrollFlags_None; }; struct mvAppItemDrawInfo @@ -146,7 +159,7 @@ struct mvAppItemDrawInfo //----------------------------------------------------------------------------- // mvAppItem //----------------------------------------------------------------------------- -class mvAppItem +class mvAppItem : public std::enable_shared_from_this { public: @@ -207,13 +220,46 @@ class mvAppItem //----------------------------------------------------------------------------- // callbacks //----------------------------------------------------------------------------- - [[nodiscard]] PyObject* getCallback(b8 ignore_enabled = true); // returns the callback. If ignore_enable false and item is disabled then no callback will be returned. + // Submits the specified callback, if any, with user_data from the item config + // and app_data created by app_data_func (typically a lambda). + // Note: `callback` must be a member of `this` (or of a nested object, like `config`). + // It does *not* check if the item is enabled or disabled, because some "custom" + // callbacks historically run even on disabled items. + template + void submitCallbackEx(PyObject* callback, AppDataFunc app_data_func) + { + // The current `mvAppItem` becomes the owner of this callback, and as soon + // as it gets deleted, the callback entry will be thrown away. + mvAddCallback(weak_from_this(), callback, config.user_data, uuid, config.alias, app_data_func); + } + + // Submits the mvAppItem's "default" callback, if any, with user_data from + // the item config and app_data created by app_data_func (typically a lambda). + // The callback is only submitted if the item is enabled; on a disabled item, + // the call is effectively ignored. + template + void submitCallbackEx(AppDataFunc app_data_func) + { + if (!config.enabled) + return; + submitCallbackEx(config.callback, app_data_func); + } + + template + void submitCallback(AppDataType app_data); // submits the callback, if any, passing it app_data, and also user_data from the item config + + void submitCallback(); // submits the callback with app_data=None //----------------------------------------------------------------------------- // config setters //----------------------------------------------------------------------------- virtual void setDataSource(mvUUID value); - + + //----------------------------------------------------------------------------- + // scrolling support + //----------------------------------------------------------------------------- + void handleImmediateScroll(); + void handleDelayedScroll(); }; inline bool mvClipPoint(float clipViewport[6], mvVec4& point) @@ -290,6 +336,7 @@ GetEntityCommand(mvAppItemType type) case mvAppItemType::mvTable: return "add_table"; case mvAppItemType::mvTableColumn: return "add_table_column"; case mvAppItemType::mvTableRow: return "add_table_row"; + case mvAppItemType::mvSyncedTables: return "add_synced_tables"; case mvAppItemType::mvDrawLine: return "draw_line"; case mvAppItemType::mvDrawArrow: return "draw_arrow"; case mvAppItemType::mvDrawTriangle: return "draw_triangle"; @@ -375,6 +422,7 @@ GetEntityCommand(mvAppItemType type) case mvAppItemType::mvDoubleClickedHandler: return "add_item_double_clicked_handler"; case mvAppItemType::mvDragPayload: return "add_drag_payload"; case mvAppItemType::mvResizeHandler: return "add_item_resize_handler"; + case mvAppItemType::mvScrollHandler: return "add_item_scroll_handler"; case mvAppItemType::mvFont: return "add_font"; case mvAppItemType::mvFontRegistry: return "add_font_registry"; case mvAppItemType::mvTheme: return "add_theme"; diff --git a/src/mvAppItemState.cpp b/src/mvAppItemState.cpp index da166671b..4c636a5ae 100644 --- a/src/mvAppItemState.cpp +++ b/src/mvAppItemState.cpp @@ -8,8 +8,10 @@ void ResetAppItemState(mvAppItemState& state) { state.hovered = false; + state.prevHovered = false; state.active = false; state.focused = false; + state.prevFocused = false; state.leftclicked = false; state.rightclicked = false; state.middleclicked = false; @@ -21,14 +23,18 @@ ResetAppItemState(mvAppItemState& state) state.deactivatedAfterEdit = false; state.toggledOpen = false; state.mvRectSizeResized = false; + state.scrolledX = state.scrolledY = false; + state.isScrollingX = state.isScrollingY = false; } void UpdateAppItemState(mvAppItemState& state) { state.lastFrameUpdate = GContext->frame; + state.prevHovered = state.hovered; state.hovered = ImGui::IsItemHovered(); state.active = ImGui::IsItemActive(); + state.prevFocused = state.focused; state.focused = ImGui::IsItemFocused(); if (state.focused) { @@ -57,6 +63,17 @@ UpdateAppItemState(mvAppItemState& state) state.mvPrevRectSize = state.rectSize; } +void +UpdateAppItemScrollInfo(mvAppItemState& state) +{ + float scrollX = ImGui::GetScrollX(); + float scrollY = ImGui::GetScrollY(); + state.scrolledX = (scrollX != state.scrollPos.x); + state.scrolledY = (scrollY != state.scrollPos.y); + state.scrollPos = { scrollX, scrollY }; + state.scrollMax = { ImGui::GetScrollMaxX(), ImGui::GetScrollMaxY() }; +} + void FillAppItemState(PyObject* dict, mvAppItemState& state, i32 applicableState) { @@ -93,6 +110,14 @@ FillAppItemState(PyObject* dict, mvAppItemState& state, i32 applicableState) } if(applicableState & MV_STATE_CONT_AVAIL) PyDict_SetItemString(dict, "content_region_avail", mvPyObject(ToPyPairII((i32)state.contextRegionAvail.x, (i32)state.contextRegionAvail.y))); + if(applicableState & MV_STATE_SCROLL) + { + PyDict_SetItemString(dict, "scrolled", mvPyObject(ToPyTPair(valid && state.scrolledX, valid && state.scrolledY))); + PyDict_SetItemString(dict, "is_scrolling", mvPyObject(ToPyTPair(valid && state.isScrollingX, valid && state.isScrollingY))); + PyDict_SetItemString(dict, "scroll_pos", mvPyObject(ToPyPair(state.scrollPos.x, state.scrollPos.y))); + PyDict_SetItemString(dict, "scroll_max", mvPyObject(ToPyPair(state.scrollMax.x, state.scrollMax.y))); + } + } b8 diff --git a/src/mvAppItemState.h b/src/mvAppItemState.h index b635645a7..d22d90c41 100644 --- a/src/mvAppItemState.h +++ b/src/mvAppItemState.h @@ -31,8 +31,9 @@ enum mvStateItems MV_STATE_RECT_MAX = 1 << 12, MV_STATE_RECT_SIZE = 1 << 13, MV_STATE_CONT_AVAIL = 1 << 14, + MV_STATE_SCROLL = 1 << 15, MV_STATE_ALL = MV_STATE_HOVER |MV_STATE_ACTIVE |MV_STATE_FOCUSED |MV_STATE_CLICKED |MV_STATE_VISIBLE |MV_STATE_EDITED |MV_STATE_ACTIVATED |MV_STATE_DEACTIVATED |MV_STATE_DEACTIVATEDAE | - MV_STATE_TOGGLED_OPEN | MV_STATE_RECT_MIN |MV_STATE_RECT_MAX |MV_STATE_RECT_SIZE |MV_STATE_CONT_AVAIL + MV_STATE_TOGGLED_OPEN | MV_STATE_RECT_MIN |MV_STATE_RECT_MAX |MV_STATE_RECT_SIZE |MV_STATE_CONT_AVAIL |MV_STATE_SCROLL }; //----------------------------------------------------------------------------- @@ -42,6 +43,10 @@ enum mvStateItems void FillAppItemState (PyObject* dict, mvAppItemState& state, i32 applicableState); // fills python dict with applicable state values void ResetAppItemState (mvAppItemState& state); // reset values to false void UpdateAppItemState(mvAppItemState& state); // standard imgui update +// Retrieves scroll info; only applicable to containers. Does NOT update state.lastFrameUpdate +// and therefore MUST be called in the same branch where that variable is updated +// by the caller (or where UpdateAppItemState() gets called). +void UpdateAppItemScrollInfo(mvAppItemState& state); // return actual value if frame is active b8 IsItemHovered (mvAppItemState& state, i32 frameDelay = 0); @@ -66,8 +71,10 @@ inline b8 IsItemDoubleClicked(ImGuiMouseButton mouse_button) struct mvAppItemState { b8 hovered = false; + b8 prevHovered = false; b8 active = false; b8 focused = false; + b8 prevFocused = false; b8 leftclicked = false; b8 rightclicked = false; b8 middleclicked = false; @@ -79,12 +86,20 @@ struct mvAppItemState b8 deactivatedAfterEdit = false; b8 toggledOpen = false; b8 mvRectSizeResized = false; + b8 scrolledX = false; + b8 scrolledY = false; + // isScrolling flags are not implemented yet - we need support on ImGui side. + // They are here just as a reserved placeholder for future implementation. + b8 isScrollingX = false; + b8 isScrollingY = false; mvVec2 rectMin = { 0.0f, 0.0f }; mvVec2 rectMax = { 0.0f, 0.0f }; mvVec2 rectSize = { 0.0f, 0.0f }; mvVec2 mvPrevRectSize = { 0.0f, 0.0f }; mvVec2 pos = { 0.0f, 0.0f }; mvVec2 contextRegionAvail = { 0.0f, 0.0f }; + mvVec2 scrollPos = { 0.0f, 0.0f }; + mvVec2 scrollMax = { 0.0f, 0.0f }; b8 ok = true; i32 lastFrameUpdate = 0; // last frame update occured mvAppItem* parent = nullptr; // hacky, but quick fix for widget handlers diff --git a/src/mvAppItemTypes.inc b/src/mvAppItemTypes.inc index 249db0b13..88c48f07e 100644 --- a/src/mvAppItemTypes.inc +++ b/src/mvAppItemTypes.inc @@ -51,6 +51,7 @@ X( mvTable ) \ X( mvTableColumn ) \ X( mvTableRow ) \ + X( mvSyncedTables ) \ X( mvDrawLine ) \ X( mvDrawArrow ) \ X( mvDrawTriangle ) \ @@ -130,6 +131,7 @@ X( mvToggledOpenHandler ) \ X( mvClickedHandler ) \ X( mvDoubleClickedHandler ) \ + X( mvScrollHandler ) \ X( mvDragPayload ) \ X( mvResizeHandler ) \ X( mvFont ) \ diff --git a/src/mvBasicWidgets.cpp b/src/mvBasicWidgets.cpp index ab9ef1d9c..6cf58f269 100644 --- a/src/mvBasicWidgets.cpp +++ b/src/mvBasicWidgets.cpp @@ -2642,6 +2642,7 @@ DearPyGui::draw_simple_plot(ImDrawList* drawlist, mvAppItem& item, const mvSimpl // * only update if applicable //----------------------------------------------------------------------------- item.state.lastFrameUpdate = GContext->frame; + item.state.prevHovered = item.state.hovered; item.state.hovered = ImGui::IsItemHovered(); item.state.leftclicked = ImGui::IsItemClicked(); item.state.rightclicked = ImGui::IsItemClicked(1); @@ -2749,10 +2750,7 @@ DearPyGui::draw_button(ImDrawList* drawlist, mvAppItem& item, const mvButtonConf if (activated) { - if (item.config.alias.empty()) - mvAddCallback(item.getCallback(false), item.uuid, nullptr, item.config.user_data); - else - mvAddCallback(item.getCallback(false), item.config.alias, nullptr, item.config.user_data); + item.submitCallback(); } } @@ -2857,12 +2855,7 @@ DearPyGui::draw_combo(ImDrawList* drawlist, mvAppItem& item, mvComboConfig& conf { if (item.config.enabled) { *config.value = name; } - auto value = *config.value; - - if (item.config.alias.empty()) - mvSubmitCallback([&item, value]() {mvAddCallback(item.getCallback(false), item.uuid, ToPyString(value), item.config.user_data);}); - else - mvSubmitCallback([&item, value]() { mvAddCallback(item.getCallback(false), item.config.alias, ToPyString(value), item.config.user_data);}); + item.submitCallback(*config.value); } item.state.edited = ImGui::IsItemEdited(); @@ -2959,12 +2952,7 @@ DearPyGui::draw_checkbox(ImDrawList* drawlist, mvAppItem& item, mvCheckboxConfig if (ImGui::Checkbox(item.info.internalLabel.c_str(), item.config.enabled ? config.value.get() : &config.disabled_value)) { - bool value = *config.value; - - if (item.config.alias.empty()) - mvSubmitCallback([&item, value]() { mvAddCallback(item.getCallback(false), item.uuid, ToPyBool(value), item.config.user_data);}); - else - mvSubmitCallback([&item, value]() { mvAddCallback(item.getCallback(false), item.config.alias, ToPyBool(value), item.config.user_data);}); + item.submitCallback(*config.value); } } @@ -3056,12 +3044,7 @@ DearPyGui::draw_drag_float(ImDrawList* drawlist, mvAppItem& item, mvDragFloatCon item.config.enabled ? config.value.get() : &config.disabled_value, config.speed, config.minv, config.maxv, config.format.c_str(), config.flags)) { - auto value = *config.value; - - if (item.config.alias.empty()) - mvSubmitCallback([&item, value]() {mvAddCallback(item.getCallback(false), item.uuid, ToPyFloat(value), item.config.user_data);}); - else - mvSubmitCallback([&item, value]() { mvAddCallback(item.getCallback(false), item.config.alias, ToPyFloat(value), item.config.user_data);}); + item.submitCallback(*config.value); } } @@ -3154,12 +3137,7 @@ DearPyGui::draw_drag_double(ImDrawList* drawlist, mvAppItem& item, mvDragDoubleC item.config.enabled ? config.value.get() : &config.disabled_value, config.speed, &config.minv, &config.maxv, config.format.c_str(), config.flags)) { - auto value = *config.value; - - if (item.config.alias.empty()) - mvSubmitCallback([&item, value]() {mvAddCallback(item.getCallback(false), item.uuid, ToPyDouble(value), item.config.user_data); }); - else - mvSubmitCallback([&item, value]() { mvAddCallback(item.getCallback(false), item.config.alias, ToPyDouble(value), item.config.user_data); }); + item.submitCallback(*config.value); } } @@ -3252,15 +3230,7 @@ DearPyGui::draw_drag_int(ImDrawList* drawlist, mvAppItem& item, mvDragIntConfig& item.config.enabled ? config.value.get() : &config.disabled_value, config.speed, config.minv, config.maxv, config.format.c_str(), config.flags)) { - auto value = *config.value; - if (item.config.alias.empty()) - mvSubmitCallback([&item, value]() { - mvAddCallback(item.getCallback(false), item.uuid, ToPyInt(value), item.config.user_data); - }); - else - mvSubmitCallback([&item, value]() { - mvAddCallback(item.getCallback(false), item.config.alias, ToPyInt(value), item.config.user_data); - }); + item.submitCallback(*config.value); } } @@ -3369,15 +3339,7 @@ DearPyGui::draw_drag_intx(ImDrawList* drawlist, mvAppItem& item, mvDragIntMultiC if (activated) { - auto value = *config.value; - if (item.config.alias.empty()) - mvSubmitCallback([&item, value]() { - mvAddCallback(item.getCallback(false), item.uuid, ToPyIntList(value.data(), (int)value.size()), item.config.user_data); - }); - else - mvSubmitCallback([&item, value]() { - mvAddCallback(item.getCallback(false), item.config.alias, ToPyIntList(value.data(), (int)value.size()), item.config.user_data); - }); + item.submitCallback(*config.value); } } @@ -3484,15 +3446,7 @@ DearPyGui::draw_drag_floatx(ImDrawList* drawlist, mvAppItem& item, mvDragFloatMu if (activated) { - auto value = *config.value; - if (item.config.alias.empty()) - mvSubmitCallback([&item, value]() { - mvAddCallback(item.getCallback(false), item.uuid, ToPyFloatList(value.data(), (int)value.size()), item.config.user_data); - }); - else - mvSubmitCallback([&item, value]() { - mvAddCallback(item.getCallback(false), item.config.alias, ToPyFloatList(value.data(), (int)value.size()), item.config.user_data); - }); + item.submitCallback(*config.value); } } //----------------------------------------------------------------------------- @@ -3586,15 +3540,7 @@ DearPyGui::draw_drag_doublex(ImDrawList* drawlist, mvAppItem& item, mvDragDouble if (activated) { - auto value = *config.value; - if (item.config.alias.empty()) - mvSubmitCallback([&item, value]() { - mvAddCallback(item.getCallback(false), item.uuid, ToPyFloatList(value.data(), (int)value.size()), item.config.user_data); - }); - else - mvSubmitCallback([&item, value]() { - mvAddCallback(item.getCallback(false), item.config.alias, ToPyFloatList(value.data(), (int)value.size()), item.config.user_data); - }); + item.submitCallback(*config.value); } } //----------------------------------------------------------------------------- @@ -3690,12 +3636,7 @@ DearPyGui::draw_slider_float(ImDrawList* drawlist, mvAppItem& item, mvSliderFloa if (ImGui::VSliderFloat(item.info.internalLabel.c_str(), ImVec2((float)item.config.width, (float)item.config.height), item.config.enabled ? config.value.get() : &config.disabled_value, config.minv, config.maxv, config.format.c_str())) { - auto value = *config.value; - - if (item.config.alias.empty()) - mvSubmitCallback([&item, value]() { mvAddCallback(item.getCallback(false), item.uuid, ToPyFloat(value), item.config.user_data);}); - else - mvSubmitCallback([&item, value]() { mvAddCallback(item.getCallback(false), item.config.alias, ToPyFloat(value), item.config.user_data);}); + item.submitCallback(*config.value); } } @@ -3703,11 +3644,7 @@ DearPyGui::draw_slider_float(ImDrawList* drawlist, mvAppItem& item, mvSliderFloa { if (ImGui::SliderFloat(item.info.internalLabel.c_str(), item.config.enabled ? config.value.get() : &config.disabled_value, config.minv, config.maxv, config.format.c_str(), config.flags)) { - auto value = *config.value; - if (item.config.alias.empty()) - mvSubmitCallback([&item, value]() {mvAddCallback(item.getCallback(false), item.uuid, ToPyFloat(value), item.config.user_data);}); - else - mvSubmitCallback([&item, value]() {mvAddCallback(item.getCallback(false), item.config.alias, ToPyFloat(value), item.config.user_data);}); + item.submitCallback(*config.value); } } @@ -3806,12 +3743,7 @@ DearPyGui::draw_slider_double(ImDrawList* drawlist, mvAppItem& item, mvSliderDou if (ImGui::VSliderScalar(item.info.internalLabel.c_str(), ImVec2((float)item.config.width, (float)item.config.height), ImGuiDataType_Double, item.config.enabled ? config.value.get() : &config.disabled_value, &config.minv, &config.maxv, config.format.c_str())) { - auto value = *config.value; - - if (item.config.alias.empty()) - mvSubmitCallback([&item, value]() { mvAddCallback(item.getCallback(false), item.uuid, ToPyDouble(value), item.config.user_data); }); - else - mvSubmitCallback([&item, value]() { mvAddCallback(item.getCallback(false), item.config.alias, ToPyDouble(value), item.config.user_data); }); + item.submitCallback(*config.value); } } @@ -3819,11 +3751,7 @@ DearPyGui::draw_slider_double(ImDrawList* drawlist, mvAppItem& item, mvSliderDou { if (ImGui::SliderScalar(item.info.internalLabel.c_str(), ImGuiDataType_Double, item.config.enabled ? config.value.get() : &config.disabled_value, &config.minv, &config.maxv, config.format.c_str(), config.flags)) { - auto value = *config.value; - if (item.config.alias.empty()) - mvSubmitCallback([&item, value]() {mvAddCallback(item.getCallback(false), item.uuid, ToPyDouble(value), item.config.user_data); }); - else - mvSubmitCallback([&item, value]() {mvAddCallback(item.getCallback(false), item.config.alias, ToPyDouble(value), item.config.user_data); }); + item.submitCallback(*config.value); } } @@ -3932,12 +3860,7 @@ DearPyGui::draw_slider_floatx(ImDrawList* drawlist, mvAppItem& item, mvSliderFlo if (activated) { - auto value = *config.value; - - if (item.config.alias.empty()) - mvSubmitCallback([&item, value]() {mvAddCallback(item.getCallback(false), item.uuid, ToPyFloatList(value.data(), (int)value.size()), item.config.user_data);}); - else - mvSubmitCallback([&item, value]() {mvAddCallback(item.getCallback(false), item.config.alias, ToPyFloatList(value.data(), (int)value.size()), item.config.user_data);}); + item.submitCallback(*config.value); } } @@ -4032,12 +3955,7 @@ DearPyGui::draw_slider_doublex(ImDrawList* drawlist, mvAppItem& item, mvSliderDo if (activated) { - auto value = *config.value; - - if (item.config.alias.empty()) - mvSubmitCallback([&item, value]() {mvAddCallback(item.getCallback(false), item.uuid, ToPyFloatList(value.data(), (int)value.size()), item.config.user_data); }); - else - mvSubmitCallback([&item, value]() {mvAddCallback(item.getCallback(false), item.config.alias, ToPyFloatList(value.data(), (int)value.size()), item.config.user_data); }); + item.submitCallback(*config.value); } } @@ -4134,12 +4052,7 @@ DearPyGui::draw_slider_int(ImDrawList* drawlist, mvAppItem& item, mvSliderIntCon if (ImGui::VSliderInt(item.info.internalLabel.c_str(), ImVec2((float)item.config.width, (float)item.config.height), item.config.enabled ? config.value.get() : &config.disabled_value, config.minv, config.maxv, config.format.c_str())) { - auto value = *config.value; - - if (item.config.alias.empty()) - mvSubmitCallback([&item, value]() { mvAddCallback(item.getCallback(false), item.uuid, ToPyInt(value), item.config.user_data);}); - else - mvSubmitCallback([&item, value]() { mvAddCallback(item.getCallback(false), item.config.alias, ToPyInt(value), item.config.user_data);}); + item.submitCallback(*config.value); } } @@ -4147,11 +4060,7 @@ DearPyGui::draw_slider_int(ImDrawList* drawlist, mvAppItem& item, mvSliderIntCon { if (ImGui::SliderInt(item.info.internalLabel.c_str(), item.config.enabled ? config.value.get() : &config.disabled_value, config.minv, config.maxv, config.format.c_str(), config.flags)) { - auto value = *config.value; - if (item.config.alias.empty()) - mvSubmitCallback([&item, value]() {mvAddCallback(item.getCallback(false), item.uuid, ToPyInt(value), item.config.user_data);}); - else - mvSubmitCallback([&item, value]() {mvAddCallback(item.getCallback(false), item.config.alias, ToPyInt(value), item.config.user_data);}); + item.submitCallback(*config.value); } } @@ -4260,12 +4169,7 @@ DearPyGui::draw_slider_intx(ImDrawList* drawlist, mvAppItem& item, mvSliderIntMu if (activated) { - auto value = *config.value; - - if (item.config.alias.empty()) - mvSubmitCallback([&item, value]() {mvAddCallback(item.getCallback(false), item.uuid, ToPyIntList(value.data(), (int)value.size()), item.config.user_data); }); - else - mvSubmitCallback([&item, value]() {mvAddCallback(item.getCallback(false), item.config.alias, ToPyIntList(value.data(), (int)value.size()), item.config.user_data); }); + item.submitCallback(*config.value); } } @@ -4366,16 +4270,7 @@ DearPyGui::draw_listbox(ImDrawList *drawlist, mvAppItem &item, mvListboxConfig & { *config.value = config.names[config.index]; config.disabled_value = config.names[config.index]; - auto value = *config.value; - - if(item.config.alias.empty()) - mvSubmitCallback([&item, value]() { - mvAddCallback(item.getCallback(false), item.uuid, ToPyString(value), item.config.user_data); - }); - else - mvSubmitCallback([&item, value]() { - mvAddCallback(item.getCallback(false), item.config.alias, ToPyString(value), item.config.user_data); - }); + item.submitCallback(*config.value); } ImGui::PopStyleColor(); @@ -4481,12 +4376,7 @@ DearPyGui::draw_radio_button(ImDrawList* drawlist, mvAppItem& item, mvRadioButto { *config.value = config.itemnames[config.index]; config.disabled_value = config.itemnames[config.index]; - auto value = *config.value; - - if (item.config.alias.empty()) - mvSubmitCallback([&item, value]() {mvAddCallback(item.getCallback(false), item.uuid, ToPyString(value), item.config.user_data);}); - else - mvSubmitCallback([&item, value]() { mvAddCallback(item.getCallback(false), item.config.alias, ToPyString(value), item.config.user_data);}); + item.submitCallback(*config.value); } item.state.edited = ImGui::IsItemEdited(); @@ -4499,26 +4389,7 @@ DearPyGui::draw_radio_button(ImDrawList* drawlist, mvAppItem& item, mvRadioButto //----------------------------------------------------------------------------- // update state //----------------------------------------------------------------------------- - item.state.lastFrameUpdate = GContext->frame; - item.state.hovered = ImGui::IsItemHovered(); - item.state.active = ImGui::IsItemActive(); - item.state.focused = ImGui::IsItemFocused(); - item.state.leftclicked = ImGui::IsItemClicked(); - item.state.rightclicked = ImGui::IsItemClicked(1); - item.state.middleclicked = ImGui::IsItemClicked(2); - for (int i = 0; i < item.state.doubleclicked.size(); i++) - { - item.state.doubleclicked[i] = IsItemDoubleClicked(i); - } - item.state.visible = ImGui::IsItemVisible(); - item.state.activated = ImGui::IsItemActivated(); - item.state.deactivated = ImGui::IsItemDeactivated(); - item.state.deactivatedAfterEdit = ImGui::IsItemDeactivatedAfterEdit(); - item.state.toggledOpen = ImGui::IsItemToggledOpen(); - item.state.rectMin = { ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y }; - item.state.rectMax = { ImGui::GetItemRectMax().x, ImGui::GetItemRectMax().y }; - item.state.rectSize = { ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y }; - item.state.contextRegionAvail = { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }; + UpdateAppItemState(item.state); //----------------------------------------------------------------------------- // post draw @@ -4615,15 +4486,7 @@ DearPyGui::draw_input_text(ImDrawList* drawlist, mvAppItem& item, mvInputTextCon if (activated) { - auto value = *config.value; - if (item.config.alias.empty()) - mvSubmitCallback([&item, value]() { - mvAddCallback(item.getCallback(false), item.uuid, ToPyString(value), item.config.user_data); - }); - else - mvSubmitCallback([&item, value]() { - mvAddCallback(item.getCallback(false), item.config.alias, ToPyString(value), item.config.user_data); - }); + item.submitCallback(*config.value); } } @@ -4735,16 +4598,7 @@ DearPyGui::draw_input_int(ImDrawList* drawlist, mvAppItem& item, mvInputIntConfi if (config.last_value != *config.value) { config.last_value = *config.value; - auto value = *config.value; - - if (item.config.alias.empty()) - mvSubmitCallback([&item, value]() { - mvAddCallback(item.getCallback(false), item.uuid, ToPyInt(value), item.config.user_data); - }); - else - mvSubmitCallback([&item, value]() { - mvAddCallback(item.getCallback(false), item.config.alias, ToPyInt(value), item.config.user_data); - }); + item.submitCallback(*config.value); } } @@ -4884,16 +4738,7 @@ DearPyGui::draw_input_floatx(ImDrawList* drawlist, mvAppItem& item, mvInputFloat if (config.last_value != *config.value) { config.last_value = *config.value; - auto value = *config.value; - - if (item.config.alias.empty()) - mvSubmitCallback([&item, value]() { - mvAddCallback(item.getCallback(false), item.uuid, ToPyFloatList(value.data(), (int)value.size()), item.config.user_data); - }); - else - mvSubmitCallback([&item, value]() { - mvAddCallback(item.getCallback(false), item.config.alias, ToPyFloatList(value.data(), (int)value.size()), item.config.user_data); - }); + item.submitCallback(*config.value); } } @@ -5007,16 +4852,7 @@ DearPyGui::draw_input_float(ImDrawList* drawlist, mvAppItem& item, mvInputFloatC if (config.last_value != *config.value) { config.last_value = *config.value; - auto value = *config.value; - - if (item.config.alias.empty()) - mvSubmitCallback([&item, value]() { - mvAddCallback(item.getCallback(false), item.uuid, ToPyFloat(value), item.config.user_data); - }); - else - mvSubmitCallback([&item, value]() { - mvAddCallback(item.getCallback(false), item.config.alias, ToPyFloat(value), item.config.user_data); - }); + item.submitCallback(*config.value); } } } @@ -5108,13 +4944,7 @@ DearPyGui::draw_knob_float(ImDrawList* drawlist, mvAppItem& item, mvKnobFloatCon if (KnobFloat(item.config.specifiedLabel.c_str(), item.config.enabled ? config.value.get() : &config.disabled_value, config.minv, config.maxv, config.step)) { - auto value = *config.value; - mvSubmitCallback([&item, value]() { - if (item.config.alias.empty()) - mvAddCallback(item.getCallback(false), item.uuid, ToPyFloat(value), item.config.user_data); - else - mvAddCallback(item.getCallback(false), item.config.alias, ToPyFloat(value), item.config.user_data); - }); + item.submitCallback(*config.value); } } @@ -5225,16 +5055,7 @@ DearPyGui::draw_input_double(ImDrawList* drawlist, mvAppItem& item, mvInputDoubl if (config.last_value != *config.value) { config.last_value = *config.value; - auto value = *config.value; - - if (item.config.alias.empty()) - mvSubmitCallback([&item, value]() { - mvAddCallback(item.getCallback(false), item.uuid, ToPyDouble(value), item.config.user_data); - }); - else - mvSubmitCallback([&item, value]() { - mvAddCallback(item.getCallback(false), item.config.alias, ToPyDouble(value), item.config.user_data); - }); + item.submitCallback(*config.value); } } } @@ -5361,16 +5182,7 @@ DearPyGui::draw_input_doublex(ImDrawList* drawlist, mvAppItem& item, mvInputDoub if (config.last_value != *config.value) { config.last_value = *config.value; - auto value = *config.value; - - if (item.config.alias.empty()) - mvSubmitCallback([&item, value]() { - mvAddCallback(item.getCallback(false), item.uuid, ToPyFloatList(value.data(), (int)value.size()), item.config.user_data); - }); - else - mvSubmitCallback([&item, value]() { - mvAddCallback(item.getCallback(false), item.config.alias, ToPyFloatList(value.data(), (int)value.size()), item.config.user_data); - }); + item.submitCallback(*config.value); } } @@ -5511,16 +5323,7 @@ DearPyGui::draw_input_intx(ImDrawList* drawlist, mvAppItem& item, mvInputIntMult { config.last_value = *config.value; - auto value = *config.value; - - if (item.config.alias.empty()) - mvSubmitCallback([&item, value]() { - mvAddCallback(item.getCallback(false), item.uuid, ToPyIntList(value.data(), (int)value.size()), item.config.user_data); - }); - else - mvSubmitCallback([&item, value]() { - mvAddCallback(item.getCallback(false), item.config.alias, ToPyIntList(value.data(), (int)value.size()), item.config.user_data); - }); + item.submitCallback(*config.value); } } } @@ -5743,12 +5546,7 @@ DearPyGui::draw_selectable(ImDrawList* drawlist, mvAppItem& item, mvSelectableCo if (ImGui::Selectable(item.info.internalLabel.c_str(), config.value.get(), config.flags, ImVec2((float)item.config.width, (float)item.config.height))) { - auto value = *config.value; - - if (item.config.alias.empty()) - mvSubmitCallback([&item, value]() { mvAddCallback(item.getCallback(false), item.uuid, ToPyBool(value), item.config.user_data);}); - else - mvSubmitCallback([&item, value]() {mvAddCallback(item.getCallback(false), item.config.alias, ToPyBool(value), item.config.user_data);}); + item.submitCallback(*config.value); } } @@ -5836,10 +5634,7 @@ DearPyGui::draw_tab_button(ImDrawList* drawlist, mvAppItem& item, mvTabButtonCon if (ImGui::TabItemButton(item.info.internalLabel.c_str(), config.flags)) { - if (item.config.alias.empty()) - mvAddCallback(item.getCallback(false), item.uuid, nullptr, item.config.user_data); - else - mvAddCallback(item.getCallback(false), item.config.alias, nullptr, item.config.user_data); + item.submitCallback(); } } @@ -5934,12 +5729,7 @@ DearPyGui::draw_menu_item(ImDrawList* drawlist, mvAppItem& item, mvMenuItemConfi // create menu item and see if its selected if (ImGui::MenuItem(item.info.internalLabel.c_str(), config.shortcut.c_str(), config.check ? config.value.get() : nullptr, item.config.enabled)) { - bool value = *config.value; - - if (item.config.alias.empty()) - mvAddCallback(item.config.callback, item.uuid, ToPyBool(value), item.config.user_data); - else - mvAddCallback(item.config.callback, item.config.alias, ToPyBool(value), item.config.user_data); + item.submitCallback(*config.value); } ImGui::PopStyleColor(); @@ -6259,10 +6049,7 @@ DearPyGui::draw_image_button(ImDrawList* drawlist, mvAppItem& item, mvImageButto ImVec2(config.uv_min.x, config.uv_min.y), ImVec2(config.uv_max.x, config.uv_max.y), config.backgroundColor, config.tintColor)) { - if (item.config.alias.empty()) - mvAddCallback(item.getCallback(false), item.uuid, nullptr, item.config.user_data); - else - mvAddCallback(item.getCallback(false), item.config.alias, nullptr, item.config.user_data); + item.submitCallback(); } ImGui::PopID(); @@ -6349,6 +6136,8 @@ DearPyGui::draw_separator(ImDrawList* drawlist, mvAppItem& item) void DearPyGui::draw_spacer(ImDrawList* drawlist, mvAppItem& item) { + if (!item.config.show) + return; if (item.config.width == 0 && item.config.height == 0) ImGui::Spacing(); else @@ -6466,7 +6255,11 @@ DearPyGui::draw_tooltip(ImDrawList* drawlist, mvAppItem& item) { tooltip->hovered_last_frame = false; item.state.visible = false; + item.state.lastFrameUpdate = GContext->frame; + // TODO: should we reset rectSize and contextRegionAvail? } + if (item.handlerRegistry) + item.handlerRegistry->checkEvents(&item.state); } void diff --git a/src/mvCallbackRegistry.cpp b/src/mvCallbackRegistry.cpp index 079b1a338..c28943f74 100644 --- a/src/mvCallbackRegistry.cpp +++ b/src/mvCallbackRegistry.cpp @@ -19,15 +19,27 @@ void mvRunTasks() void mvFrameCallback(i32 frame) { + auto callbackRegistry = GContext->callbackRegistry; // for brevity - if (frame > GContext->callbackRegistry->highestFrame) + if (frame > callbackRegistry->highestFrame) return; - if (GContext->callbackRegistry->frameCallbacks.count(frame) == 0) + if (callbackRegistry->frameCallbacks.count(frame) == 0) return; - mvAddCallback(GContext->callbackRegistry->frameCallbacks[frame], frame, nullptr, - GContext->callbackRegistry->frameCallbacksUserData[frame]); + // We have to use `std::unordered_map::at()` instead of indexing it with `[]`: + // `mvPyObject` has no default constructor, whereas `operator[]` can insert + // a new value into the map and therefore requires a default constructor. + + auto callback = std::make_shared(std::move(callbackRegistry->frameCallbacks.at(frame))); + auto user_data = std::make_shared(std::move(callbackRegistry->frameCallbacksUserData.at(frame))); + + // Since mvPyObject objects remaining in the maps are now "empty", it's safe to + // delete them right here even though we don't own the GIL. + callbackRegistry->frameCallbacks.erase(frame); + callbackRegistry->frameCallbacksUserData.erase(frame); + + mvAddOwnerlessCallback(callback, user_data, (mvUUID)frame, "", []() -> PyObject* { return nullptr; }); } bool mvRunCallbacks() @@ -49,314 +61,114 @@ bool mvRunCallbacks() return true; } -void mvAddCallback(PyObject* callable, mvUUID sender, PyObject* app_data, PyObject* user_data, bool decrementAppData) +void mvAddCallback(const std::weak_ptr& owner, + PyObject* callback, + const std::shared_ptr& user_data, + mvUUID sender, + const std::string& alias) { - - if (GContext->callbackRegistry->callCount > GContext->callbackRegistry->maxNumberOfCalls) - { - if (app_data != nullptr) - Py_XDECREF(app_data); - if (user_data != nullptr) - Py_XDECREF(user_data); - assert(false); - return; - } - - if (GContext->IO.manualCallbacks) - { - if (callable != nullptr) - Py_XINCREF(callable); - if (app_data != nullptr) - Py_XINCREF(app_data); - if (user_data != nullptr) - Py_XINCREF(user_data); - GContext->callbackRegistry->jobs.push_back({ sender, callable, app_data, user_data }); - return; - } - - mvSubmitCallback([=]() { - mvRunCallback(callable, sender, app_data, user_data, decrementAppData); - }); + mvAddCallback(owner, callback, user_data, sender, alias, []() -> PyObject* { return nullptr; }); } -void mvAddCallback(PyObject* callable, const std::string& sender, PyObject* app_data, PyObject* user_data) +void mvAddOwnerlessCallback(const std::shared_ptr& callback, + const std::shared_ptr& user_data, + mvUUID sender, + const std::string& alias) { - - if (GContext->callbackRegistry->callCount > GContext->callbackRegistry->maxNumberOfCalls) - { - - if (app_data != nullptr) - Py_XDECREF(app_data); - if (user_data != nullptr) - Py_XDECREF(user_data); - assert(false); - return; - } - - if (GContext->IO.manualCallbacks) - { - if (callable != nullptr) - Py_XINCREF(callable); - if (app_data != nullptr) - Py_XINCREF(app_data); - if (user_data != nullptr) - Py_XINCREF(user_data); - GContext->callbackRegistry->jobs.push_back({ 0, callable, app_data, user_data, sender }); - return; - } - - mvSubmitCallback([=]() { - mvRunCallback(callable, sender, app_data, user_data); - }); + mvAddOwnerlessCallback(callback, user_data, sender, alias, []() -> PyObject* { return nullptr; }); } -void mvRunCallback(PyObject* callable, const std::string& sender, PyObject* app_data, PyObject* user_data) +void mvRunOwnedCallback(const std::weak_ptr& owner, PyObject* callback, PyObject* user_data, mvUUID sender /* = 0 */, const std::string& sender_alias /* = "" */, PyObject* app_data /* = nullptr */) { - - if (callable == nullptr) + auto liveOwner = owner.lock(); + if (liveOwner) { - //if (data != nullptr) - // Py_XDECREF(data); - return; - } - - if (!PyCallable_Check(callable)) - { - if (app_data != nullptr) - Py_XDECREF(app_data); - if (user_data != nullptr) - Py_XDECREF(user_data); - mvThrowPythonError(mvErrorCode::mvNone, "Callable not callable."); - PyErr_Print(); - return; - } - - if (app_data == nullptr) - { - app_data = Py_None; - Py_XINCREF(app_data); - } - Py_XINCREF(app_data); - - if (user_data == nullptr) - { - user_data = Py_None; - Py_XINCREF(user_data); - } - Py_XINCREF(user_data); - - //PyErr_Clear(); - if (PyErr_Occurred()) - PyErr_Print(); - - if (PyErr_Occurred()) - PyErr_Print(); - - PyObject* fc = PyObject_GetAttrString(callable, "__code__"); - if (fc) { - PyObject* ac = PyObject_GetAttrString(fc, "co_argcount"); - if (ac) { - i32 count = PyLong_AsLong(ac); - - if (PyMethod_Check(callable)) - count--; - - if (count > 3) - { - mvPyObject pArgs(PyTuple_New(count)); - PyTuple_SetItem(pArgs, 0, ToPyString(sender)); - PyTuple_SetItem(pArgs, 1, app_data); // steals data, so don't deref - PyTuple_SetItem(pArgs, 2, user_data); // steals data, so don't deref - - for (int i = 3; i < count; i++) - PyTuple_SetItem(pArgs, i, GetPyNone()); - - mvPyObject result(PyObject_CallObject(callable, pArgs)); - - // check if call succeeded - if (!result.isOk()) - PyErr_Print(); - - } - else if (count == 3) - { - mvPyObject pArgs(PyTuple_New(3)); - PyTuple_SetItem(pArgs, 0, ToPyString(sender)); - PyTuple_SetItem(pArgs, 1, app_data); // steals data, so don't deref - PyTuple_SetItem(pArgs, 2, user_data); // steals data, so don't deref - - mvPyObject result(PyObject_CallObject(callable, pArgs)); - - pArgs.delRef(); - // check if call succeeded - if (!result.isOk()) - PyErr_Print(); - - } - else if (count == 2) - { - mvPyObject pArgs(PyTuple_New(2)); - PyTuple_SetItem(pArgs, 0, ToPyString(sender)); - PyTuple_SetItem(pArgs, 1, app_data); // steals data, so don't deref - - mvPyObject result(PyObject_CallObject(callable, pArgs)); - - pArgs.delRef(); - // check if call succeeded - if (!result.isOk()) - PyErr_Print(); - - } - else if (count == 1) - { - mvPyObject pArgs(PyTuple_New(1)); - PyTuple_SetItem(pArgs, 0, ToPyString(sender)); - - mvPyObject result(PyObject_CallObject(callable, pArgs)); - - // check if call succeeded - if (!result.isOk()) - PyErr_Print(); - } - else - { - mvPyObject result(PyObject_CallObject(callable, nullptr)); - - // check if call succeeded - if (!result.isOk()) - PyErr_Print(); - - - } - Py_DECREF(ac); + // Make our own callback ref + mvPyObject ownCallback(callback, true); + { + // We need to lock the mutex while releasing the `owner` pointer. When `liveOwner` + // goes out of scope, the mvAppItem that it holds might get deleted, thus + // invalidating all mvAppItem* pointers that we might be holding in various DPG functions + // e.g. in another thread. By locking the mutex and explicitly resetting + // `liveOwner`, we guarantee that destruction of mvAppItem only occurs with + // the mutex locked, and thus cannot happen in the middle of an API function + // that also locks the mutex. + mvPySafeLockGuard lk(GContext->mutex); + liveOwner.reset(); } - Py_DECREF(fc); + mvRunCallback(ownCallback, user_data, sender, sender_alias, app_data); } - } -void mvRunCallback(PyObject* callable, mvUUID sender, PyObject* app_data, PyObject* user_data, bool decrementAppData) +void mvRunCallback(PyObject* callback, PyObject* user_data, mvUUID sender, const std::string& sender_alias, PyObject* app_data) { - if (callable == nullptr) - { - //if (data != nullptr) - // Py_XDECREF(data); + if (callback == nullptr) return; - } - if (!PyCallable_Check(callable)) + if (!PyCallable_Check(callback)) { - if (app_data != nullptr) - Py_XDECREF(app_data); - if (user_data != nullptr) - Py_XDECREF(user_data); mvThrowPythonError(mvErrorCode::mvNone, "Callable not callable."); PyErr_Print(); return; } - if (app_data == nullptr) - { - app_data = Py_None; - Py_XINCREF(app_data); - } - if(decrementAppData) - Py_XINCREF(app_data); - - if (user_data == nullptr) - { - user_data = Py_None; - Py_XINCREF(user_data); - } - Py_XINCREF(user_data); - //PyErr_Clear(); if (PyErr_Occurred()) PyErr_Print(); - if (PyErr_Occurred()) - PyErr_Print(); - - PyObject* fc = PyObject_GetAttrString(callable, "__code__"); + PyObject* fc = PyObject_GetAttrString(callback, "__code__"); if (fc) { PyObject* ac = PyObject_GetAttrString(fc, "co_argcount"); if (ac) { i32 count = PyLong_AsLong(ac); - if (PyMethod_Check(callable)) + if (PyMethod_Check(callback)) count--; - if (count > 3) - { - mvPyObject pArgs(PyTuple_New(count)); - PyTuple_SetItem(pArgs, 0, ToPyUUID(sender)); - PyTuple_SetItem(pArgs, 1, app_data); // steals data, so don't deref - PyTuple_SetItem(pArgs, 2, user_data); // steals data, so don't deref - - for (int i = 3; i < count; i++) - PyTuple_SetItem(pArgs, i, GetPyNone()); - - mvPyObject result(PyObject_CallObject(callable, pArgs)); - - // check if call succeeded - if (!result.isOk()) - PyErr_Print(); + mvPyObject pArgs(count > 0 ? PyTuple_New(count) : nullptr); - } - else if (count == 3) + if (count > 0) { - mvPyObject pArgs(PyTuple_New(3)); - PyTuple_SetItem(pArgs, 0, ToPyUUID(sender)); - PyTuple_SetItem(pArgs, 1, app_data); // steals data, so don't deref - PyTuple_SetItem(pArgs, 2, user_data); // steals data, so don't deref - - mvPyObject result(PyObject_CallObject(callable, pArgs)); - - pArgs.delRef(); - // check if call succeeded - if (!result.isOk()) - PyErr_Print(); - + PyTuple_SetItem(pArgs, 0, sender_alias.empty()? + ToPyUUID(sender) : + ToPyString(sender_alias)); + + if (count > 1) + { + if (app_data == nullptr) + app_data = Py_None; + // Need an owned ref here: PyTuple_SetItem takes ownership; + // this also handles Py_None correctly (need to incref it). + Py_INCREF(app_data); + PyTuple_SetItem(pArgs, 1, app_data); + + if (count > 2) + { + if (user_data == nullptr) + user_data = Py_None; + // Need an owned ref here: PyTuple_SetItem takes ownership; + // this also handles Py_None correctly (need to incref it). + Py_INCREF(user_data); + PyTuple_SetItem(pArgs, 2, user_data); + + // If the callback takes more parms, just pass None in there + for (int i = 3; i < count; i++) + PyTuple_SetItem(pArgs, i, GetPyNone()); + } + } } - else if (count == 2) - { - mvPyObject pArgs(PyTuple_New(2)); - PyTuple_SetItem(pArgs, 0, ToPyUUID(sender)); - PyTuple_SetItem(pArgs, 1, app_data); // steals data, so don't deref - mvPyObject result(PyObject_CallObject(callable, pArgs)); + // perform the actual call + mvPyObject result(PyObject_CallObject(callback, pArgs)); - pArgs.delRef(); - // check if call succeeded - if (!result.isOk()) - PyErr_Print(); + // check if call succeeded + if (!result.isOk()) + PyErr_Print(); - } - else if(count == 1) - { - mvPyObject pArgs(PyTuple_New(1)); - PyTuple_SetItem(pArgs, 0, ToPyUUID(sender)); - - mvPyObject result(PyObject_CallObject(callable, pArgs)); - - // check if call succeeded - if (!result.isOk()) - PyErr_Print(); - } - else - { - mvPyObject result(PyObject_CallObject(callable, nullptr)); - - // check if call succeeded - if (!result.isOk()) - PyErr_Print(); - - - } Py_DECREF(ac); } Py_DECREF(fc); } -} \ No newline at end of file +} diff --git a/src/mvCallbackRegistry.h b/src/mvCallbackRegistry.h index 1c84f78ae..701aa419e 100644 --- a/src/mvCallbackRegistry.h +++ b/src/mvCallbackRegistry.h @@ -193,26 +193,25 @@ class mvQueue }; -static PyObject* SanitizeCallback(PyObject* callback) -{ - if (callback == Py_None) - return nullptr; - - return callback; -} - struct mvCallbackJob { - mvUUID sender = 0; - PyObject* callback = nullptr; - PyObject* app_data = nullptr; - PyObject* user_data = nullptr; - std::string sender_str; + std::weak_ptr owner; + // Only valid if `owner` is alive; one must lock() the owner before accessing + // the callback. + PyObject* callback = nullptr; + std::shared_ptr user_data; + mvUUID sender = 0; + std::string alias; + std::function app_data_func; + // Either `callback` (and `owner`) or `ownerless_callback` must be set, + // but not both - otherwise one of them will be ignored. + std::shared_ptr ownerless_callback = nullptr; }; struct mvCallbackRegistry { - const i32 maxNumberOfCalls = 50; + // TODO: ideally, it should be configurable (e.g. via configure_app) + const i32 maxNumberOfCalls = 500; std::vector jobs; mvQueue tasks; @@ -221,22 +220,92 @@ struct mvCallbackRegistry std::atomic callCount = 0; // callbacks - PyObject* resizeCallback = nullptr; - PyObject* onCloseCallback = nullptr; - PyObject* resizeCallbackUserData = nullptr; - PyObject* onCloseCallbackUserData = nullptr; + std::shared_ptr resizeCallback = std::make_shared(nullptr); + std::shared_ptr resizeCallbackUserData = std::make_shared(nullptr); + std::shared_ptr onCloseCallback = std::make_shared(nullptr); + std::shared_ptr onCloseCallbackUserData = std::make_shared(nullptr); i32 highestFrame = 0; - std::unordered_map frameCallbacks; - std::unordered_map frameCallbacksUserData; + std::unordered_map frameCallbacks; + std::unordered_map frameCallbacksUserData; }; void mvFrameCallback(i32 frame); void mvRunTasks(); -void mvRunCallback(PyObject* callback, mvUUID sender, PyObject* app_data, PyObject* user_data, bool decrementAppData = true); -void mvRunCallback(PyObject* callback, const std::string& sender, PyObject* app_data, PyObject* user_data); -void mvAddCallback(PyObject* callback, mvUUID sender, PyObject* app_data, PyObject* user_data, bool decrementAppData = true); -void mvAddCallback(PyObject* callback, const std::string& sender, PyObject* app_data, PyObject* user_data); +// All PyObject references here are borrowed references - caller must release them after this call +void mvRunCallback(PyObject* callback, PyObject* user_data, mvUUID sender = 0, const std::string& sender_alias = "", PyObject* app_data = nullptr); +// This version checks if owner is still alive (by obtaining shared_ptr), and if it is, +// INCREFs the callback and releases the owner. The owner is released under mvContext::mutex. +// All PyObject references except `callback` are borrowed references - the caller must release +// them after this call. +void mvRunOwnedCallback(const std::weak_ptr& owner, PyObject* callback, PyObject* user_data, mvUUID sender = 0, const std::string& sender_alias = "", PyObject* app_data = nullptr); + +// Note: We pass the `callback` and its `user_data` as two separate arguments (rather +// than a single object) because, even though they only make sense together, `mvAppItem` may +// combine the same `user_data` with different callbacks. We don't want to spread `user_data` +// instances all across `mvAppItem`. +// The `callback` must be valid all the time while `owner` is alive. This works for +// the fields of `owner`; if `callback` is not a field of `owner`, the caller must make +// sure that `callback`'s lifetime is at least as long as `owner`'s. +// When the callback is about to be executed on the handlers thread, the callback queue +// acquires a shared_ptr to `owner` and holds it while the callback is being executed. +// If the `owner` is already lost by the moment the callback is fetched from the +// queue, the callback will be silently ignored. This effectively cleans the queue +// from irrelevant callbacks - lingering there after `mvAppItem` deletion and such. +template +void mvAddCallback(const std::weak_ptr& owner, + PyObject* callback, + const std::shared_ptr& user_data, + mvUUID sender, + const std::string& alias, + AppDataFunc&& app_data_func) +{ + if (GContext->IO.manualCallbacks) + { + GContext->callbackRegistry->jobs.push_back({owner, callback, user_data, sender, alias, std::forward(app_data_func)}); + return; + } + mvSubmitCallback([=, app_data_func = std::forward(app_data_func)] () { + mvRunOwnedCallback(owner, callback, *user_data, sender, alias, mvPyObject(app_data_func())); + }); +} + +// This overload exists purely to provide default argument values - we can't do this +// directly on the template version above because the compiler won't be able to deduce +// `app_data_func` type if `app_data_func` is omitted (that is, we can't really use +// the default on `app_data_func`). +void mvAddCallback(const std::weak_ptr& owner, + PyObject* callback, + const std::shared_ptr& user_data, + mvUUID sender = 0, + const std::string& alias = ""); + +template +void mvAddOwnerlessCallback(const std::shared_ptr& callback, + const std::shared_ptr& user_data, + mvUUID sender, + const std::string& alias, + AppDataFunc&& app_data_func) +{ + if (GContext->IO.manualCallbacks) + { + GContext->callbackRegistry->jobs.push_back({{}, nullptr, user_data, sender, alias, std::forward(app_data_func), callback}); + return; + } + mvSubmitCallback([=, app_data_func = std::forward(app_data_func)]() { + mvRunCallback(*callback, *user_data, sender, alias, mvPyObject(app_data_func())); + }); +} + +// This overload exists purely to provide default argument values - we can't do this +// directly on the template version above because the compiler won't be able to deduce +// `app_data_func` type if `app_data_func` is omitted (that is, we can't really use +// the default on `app_data_func`). +void mvAddOwnerlessCallback(const std::shared_ptr& callback, + const std::shared_ptr& user_data, + mvUUID sender = 0, + const std::string& alias = ""); + bool mvRunCallbacks(); template @@ -247,7 +316,7 @@ std::future::type> mvSubmitTask(F f) std::packaged_task task(std::move(f)); std::future res(task.get_future()); - if (GContext->started) + if (GContext->running) GContext->callbackRegistry->tasks.push(std::move(task)); else task(); @@ -256,11 +325,12 @@ std::future::type> mvSubmitTask(F f) } template -std::future::type> mvSubmitCallback(F f) +std::future::type> mvSubmitCallback(F f, bool ignore_limit = false) { - if (GContext->callbackRegistry->callCount > GContext->callbackRegistry->maxNumberOfCalls) + if (GContext->callbackRegistry->callCount > GContext->callbackRegistry->maxNumberOfCalls && !ignore_limit) { + assert(false); return {}; } diff --git a/src/mvColors.cpp b/src/mvColors.cpp index 2916cdacd..beffd8572 100644 --- a/src/mvColors.cpp +++ b/src/mvColors.cpp @@ -66,10 +66,7 @@ DearPyGui::draw_color_button(ImDrawList* drawlist, mvAppItem& item, mvColorButto if (ImGui::ColorButton(item.info.internalLabel.c_str(), col, config.flags, ImVec2((float)item.config.width, (float)item.config.height))) { - if(item.config.alias.empty()) - mvAddCallback(item.getCallback(false), item.uuid, nullptr, item.config.user_data); - else - mvAddCallback(item.getCallback(false), item.config.alias, nullptr, item.config.user_data); + item.submitCallback(); } } @@ -161,11 +158,7 @@ DearPyGui::draw_color_edit(ImDrawList* drawlist, mvAppItem& item, mvColorEditCon if (ImGui::ColorEdit4(item.info.internalLabel.c_str(), item.config.enabled ? config.value->data() : &config.disabled_value[0], config.flags)) { mvColor color = mvColor((*config.value)[0], (*config.value)[1], (*config.value)[2], (*config.value)[3]); - - if (item.config.alias.empty()) - mvSubmitCallback([&item, color]() { mvAddCallback(item.getCallback(false), item.uuid, ToPyColor(color), item.config.user_data); }); - else - mvSubmitCallback([&item, color]() { mvAddCallback(item.getCallback(false), item.config.alias, ToPyColor(color), item.config.user_data); }); + item.submitCallback(color); } } @@ -261,10 +254,7 @@ DearPyGui::draw_color_map_button(ImDrawList* drawlist, mvAppItem& item, mvColorM ScopedID id(item.uuid); if (ImPlot::ColormapButton(item.info.internalLabel.c_str(), ImVec2((float)item.config.width, (float)item.config.height), config.colorMap)) { - if (item.config.alias.empty()) - mvAddCallback(item.getCallback(false), item.uuid, nullptr, item.config.user_data); - else - mvAddCallback(item.getCallback(false), item.config.alias, nullptr, item.config.user_data); + item.submitCallback(); } } @@ -442,11 +432,7 @@ DearPyGui::draw_color_picker(ImDrawList* drawlist, mvAppItem& item, mvColorPicke if (ImGui::ColorPicker4(item.info.internalLabel.c_str(), item.config.enabled ? config.value->data() : &config.disabled_value[0], config.flags)) { mvColor color = mvColor((*config.value)[0], (*config.value)[1], (*config.value)[2], (*config.value)[3]); - - if (item.config.alias.empty()) - mvSubmitCallback([&item, color]() { mvAddCallback(item.getCallback(false), item.uuid, ToPyColor(color), item.config.user_data); }); - else - mvSubmitCallback([&item, color]() { mvAddCallback(item.getCallback(false), item.config.alias, ToPyColor(color), item.config.user_data); }); + item.submitCallback(color); } } @@ -535,12 +521,7 @@ DearPyGui::draw_color_map_slider(ImDrawList* drawlist, mvAppItem& item, mvColorM if (ImPlot::ColormapSlider(item.info.internalLabel.c_str(), config.value.get(), &config.color, "", config.colorMap)) { - auto value = *config.value; - - if (item.config.alias.empty()) - mvSubmitCallback([&item, value]() { mvAddCallback(item.getCallback(false), item.uuid, ToPyFloat(value), item.config.user_data); }); - else - mvSubmitCallback([&item, value]() { mvAddCallback(item.getCallback(false), item.config.alias, ToPyFloat(value), item.config.user_data); }); + item.submitCallback(*config.value); } } diff --git a/src/mvContainers.cpp b/src/mvContainers.cpp index 045dc662d..367c9f39c 100644 --- a/src/mvContainers.cpp +++ b/src/mvContainers.cpp @@ -98,21 +98,11 @@ DearPyGui::fill_configuration_dict(const mvDragPayloadConfig& inConfig, PyObject if (outDict == nullptr) return; - if (inConfig.dragData) - { - Py_XINCREF(inConfig.dragData); - PyDict_SetItemString(outDict, "drag_data", inConfig.dragData); - } - else - PyDict_SetItemString(outDict, "drag_data", GetPyNone()); + PyObject* dragData = *(inConfig.dragData); + PyDict_SetItemString(outDict, "drag_data", dragData? dragData : Py_None); - if (inConfig.dropData) - { - Py_XINCREF(inConfig.dropData); - PyDict_SetItemString(outDict, "drop_data", inConfig.dropData); - } - else - PyDict_SetItemString(outDict, "drop_data", GetPyNone()); + PyObject* dropData = *(inConfig.dropData); + PyDict_SetItemString(outDict, "drop_data", dropData? dropData : Py_None); } void @@ -190,13 +180,9 @@ DearPyGui::fill_configuration_dict(const mvWindowAppItemConfig& inConfig, PyObje PyDict_SetItemString(outDict, "collapsed", mvPyObject(ToPyBool(inConfig.collapsed))); PyDict_SetItemString(outDict, "min_size", mvPyObject(ToPyPairII(inConfig.min_size.x, inConfig.min_size.y))); PyDict_SetItemString(outDict, "max_size", mvPyObject(ToPyPairII(inConfig.max_size.x, inConfig.max_size.y))); - if (inConfig.on_close) - { - Py_XINCREF(inConfig.on_close); - PyDict_SetItemString(outDict, "on_close", inConfig.on_close); - } - else - PyDict_SetItemString(outDict, "on_close", GetPyNone()); + + PyObject* on_close = inConfig.on_close; + PyDict_SetItemString(outDict, "on_close", on_close? on_close : Py_None); // helper to check and set bit auto checkbitset = [outDict](const char* keyword, int flag, const int& flags) @@ -322,20 +308,12 @@ DearPyGui::set_configuration(PyObject* inDict, mvDragPayloadConfig& outConfig) if (PyObject* item = PyDict_GetItemString(inDict, "drag_data")) { - if (outConfig.dragData) - Py_XDECREF(outConfig.dragData); - - Py_XINCREF(item); - outConfig.dragData = item; + *outConfig.dragData = mvPyObject(item == Py_None? nullptr : item, true); } if (PyObject* item = PyDict_GetItemString(inDict, "drop_data")) { - if (outConfig.dropData) - Py_XDECREF(outConfig.dropData); - - Py_XINCREF(item); - outConfig.dropData = item; + *outConfig.dropData = mvPyObject(item == Py_None? nullptr : item, true); } } @@ -449,12 +427,7 @@ DearPyGui::set_configuration(PyObject* inDict, mvAppItem& itemc, mvWindowAppItem if (PyObject* item = PyDict_GetItemString(inDict, "on_close")) { - if (outConfig.on_close) - Py_XDECREF(outConfig.on_close); - item = SanitizeCallback(item); - if (item) - Py_XINCREF(item); - outConfig.on_close = item; + outConfig.on_close = mvPyObject(item == Py_None? nullptr : item, true); } // helper for bit flipping @@ -666,7 +639,9 @@ DearPyGui::draw_menu(ImDrawList* drawlist, mvAppItem& item, mvMenuConfig& config item.state.active = ImGui::IsItemActive(); item.state.activated = ImGui::IsItemActivated(); item.state.deactivated = ImGui::IsItemDeactivated(); + item.state.prevFocused = item.state.focused; item.state.focused = ImGui::IsWindowFocused(); + item.state.prevHovered = item.state.hovered; item.state.hovered = ImGui::IsWindowHovered(); item.state.rectSize = { ImGui::GetWindowWidth(), ImGui::GetWindowHeight() }; item.state.contextRegionAvail = { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }; @@ -709,7 +684,9 @@ DearPyGui::draw_menu(ImDrawList* drawlist, mvAppItem& item, mvMenuConfig& config item.state.active = ImGui::IsItemActive(); item.state.activated = ImGui::IsItemActivated(); item.state.deactivated = ImGui::IsItemDeactivated(); + item.state.prevFocused = item.state.focused; item.state.focused = false; + item.state.prevHovered = item.state.hovered; item.state.hovered = false; item.state.rectSize = { 0.0f, 0.0f }; item.state.contextRegionAvail = { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }; @@ -806,6 +783,7 @@ DearPyGui::draw_tab(ImDrawList* drawlist, mvAppItem& item, mvTabConfig& config) } item.state.lastFrameUpdate = GContext->frame; + item.state.prevHovered = item.state.hovered; // create tab item and see if it is selected if (ImGui::BeginTabItem(item.info.internalLabel.c_str(), config.closable ? &item.config.show : nullptr, config._flags)) { @@ -840,12 +818,7 @@ DearPyGui::draw_tab(ImDrawList* drawlist, mvAppItem& item, mvTabConfig& config) // run call back if it exists if (parent->getSpecificValue() != item.uuid) { - mvSubmitCallback([=, &item]() { - if (parent->config.alias.empty()) - mvAddCallback(parent->getCallback(), parent->uuid, ToPyUUID(item.uuid), parent->config.user_data); - else - mvAddCallback(parent->getCallback(), parent->config.alias, ToPyUUID(item.uuid), parent->config.user_data); - }); + parent->submitCallback(item.uuid); } parent->setValue(item.uuid); @@ -954,12 +927,16 @@ DearPyGui::draw_child_window(ImDrawList* drawlist, mvAppItem& item, mvChildWindo { ScopedID id(item.uuid); + item.handleImmediateScroll(); + // TODO: Do we want to put an if statement to prevent further drawing if not shown? ImGui::BeginChild(item.info.internalLabel.c_str(), ImVec2(config.autosize_x ? 0 : (float)item.config.width, config.autosize_y ? 0 : (float)item.config.height), config.childFlags, config.windowflags); item.state.lastFrameUpdate = GContext->frame; item.state.active = ImGui::IsItemActive(); item.state.deactivated = ImGui::IsItemDeactivated(); + item.state.prevFocused = item.state.focused; item.state.focused = ImGui::IsWindowFocused(); + item.state.prevHovered = item.state.hovered; item.state.hovered = ImGui::IsWindowHovered(); item.state.rectSize = { ImGui::GetWindowWidth(), ImGui::GetWindowHeight() }; item.state.contextRegionAvail = { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y }; @@ -976,23 +953,8 @@ DearPyGui::draw_child_window(ImDrawList* drawlist, mvAppItem& item, mvChildWindo } - if (config._scrollXSet) - { - if (config.scrollX < 0.0f) - ImGui::SetScrollHereX(1.0f); - else - ImGui::SetScrollX(config.scrollX); - config._scrollXSet = false; - } - - if (config._scrollYSet) - { - if (config.scrollY < 0.0f) - ImGui::SetScrollHereY(1.0f); - else - ImGui::SetScrollY(config.scrollY); - config._scrollYSet = false; - } + item.handleDelayedScroll(); + item.config.scrollXFlags = item.config.scrollYFlags = mvSetScrollFlags_None; // allows this item to have a render callback if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) @@ -1009,10 +971,7 @@ DearPyGui::draw_child_window(ImDrawList* drawlist, mvAppItem& item, mvChildWindo } - config.scrollX = ImGui::GetScrollX(); - config.scrollY = ImGui::GetScrollY(); - config.scrollMaxX = ImGui::GetScrollMaxX(); - config.scrollMaxY = ImGui::GetScrollMaxY(); + UpdateAppItemScrollInfo(item.state); ImGui::EndChild(); } @@ -1163,14 +1122,31 @@ DearPyGui::draw_drag_payload(ImDrawList* drawlist, mvAppItem& item, mvDragPayloa { if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID)) { - ImGui::SetDragDropPayload(config.payloadType.c_str(), &item, sizeof(mvDragPayload)); - - if (item.info.parentPtr->config.dragCallback) + // ImGui uses memcpy to store the drag data, and the only thing we can + // store this way more ore less safely is the numeric UUID. Worst case if + // the payload gets deleted during drag'n'drop, we'll simply abandon + // the drop callback. + ImGui::SetDragDropPayload(config.payloadType.c_str(), &item.uuid, sizeof(item.uuid)); + + // The mvDragPayload item is a bit peculiar: historically, it uses its own user_data + // to pass to the parent item's drag callback. That's why we can't directly + // call parentPtr->submitCallback(), as it would take user_data from the parent + // instead of mvDragPayload. + mvAppItem* parent = item.info.parentPtr; + if (parent->config.dragCallback) { - if (item.info.parentPtr->config.alias.empty()) - mvAddCallback(item.info.parentPtr->config.dragCallback, item.config.parent, config.dragData, item.config.user_data); - else - mvAddCallback(item.info.parentPtr->config.dragCallback, item.info.parentPtr->config.alias, config.dragData, item.config.user_data); + // We can't use mvAppItem::submitCallbackEx here because we need custom user_data. + mvAddCallback( + parent->weak_from_this(), + parent->config.dragCallback, + item.config.user_data, + parent->uuid, parent->config.alias, + [dragData=config.dragData] () { + PyObject* pyDragData = *dragData; + Py_XINCREF(pyDragData); + return pyDragData; + } + ); } for (auto& childset : item.childslots) @@ -1510,6 +1486,8 @@ DearPyGui::draw_window(ImDrawList* drawlist, mvAppItem& item, mvWindowAppItemCon ImGui::SetNextWindowSizeConstraints(config.min_size, config.max_size); + item.handleImmediateScroll(); + if (config.modal) { if (item.info.shownLastFrame) @@ -1526,15 +1504,14 @@ DearPyGui::draw_window(ImDrawList* drawlist, mvAppItem& item, mvWindowAppItemCon // shouldn't have to do this but do. Fix later item.config.show = false; item.state.lastFrameUpdate = GContext->frame; + item.state.prevHovered = item.state.hovered; item.state.hovered = false; + item.state.prevFocused = item.state.focused; item.state.focused = false; item.state.toggledOpen = false; item.state.visible = false; - if (item.config.alias.empty()) - mvAddCallback(config.on_close, item.uuid, nullptr, item.config.user_data); - else - mvAddCallback(config.on_close, item.config.alias, nullptr, item.config.user_data); + item.submitCallbackEx(config.on_close, []() -> PyObject* { return nullptr; }); // handle popping themes cleanup_local_theming(&item); @@ -1558,6 +1535,25 @@ DearPyGui::draw_window(ImDrawList* drawlist, mvAppItem& item, mvWindowAppItemCon // handle popping themes cleanup_local_theming(&item); + + // See if it's just been closed (can't rely on BeginPopup == false here + // because BeginPopup can, even if only theoretically, return false for + // an open popup - e.g. when it has zero size). + if (!ImGui::IsPopupOpen(item.info.internalLabel.c_str())) + { + // Hide it so that the callback doesn't fire at the next frame + item.config.show = false; + // Update item state so that get_item_state is valid + item.state.lastFrameUpdate = GContext->frame; + item.state.prevHovered = item.state.hovered; + item.state.hovered = false; + item.state.prevFocused = item.state.focused; + item.state.focused = false; + item.state.toggledOpen = false; + item.state.visible = false; + // Fire the close callback, if any + item.submitCallbackEx(config.on_close, []() -> PyObject* { return nullptr; }); + } return; } } @@ -1630,28 +1626,10 @@ DearPyGui::draw_window(ImDrawList* drawlist, mvAppItem& item, mvWindowAppItemCon // handle popping themes cleanup_local_theming(&item); - if (config._scrollXSet) - { - if (config.scrollX < 0.0f) - ImGui::SetScrollHereX(1.0f); - else - ImGui::SetScrollX(config.scrollX); - config._scrollXSet = false; - } + item.handleDelayedScroll(); + item.config.scrollXFlags = item.config.scrollYFlags = mvSetScrollFlags_None; - if (config._scrollYSet) - { - if (config.scrollY < 0.0f) - ImGui::SetScrollHereY(1.0f); - else - ImGui::SetScrollY(config.scrollY); - config._scrollYSet = false; - } - - config.scrollX = ImGui::GetScrollX(); - config.scrollY = ImGui::GetScrollY(); - config.scrollMaxX = ImGui::GetScrollMaxX(); - config.scrollMaxY = ImGui::GetScrollMaxY(); + UpdateAppItemScrollInfo(item.state); //----------------------------------------------------------------------------- // update state @@ -1659,7 +1637,9 @@ DearPyGui::draw_window(ImDrawList* drawlist, mvAppItem& item, mvWindowAppItemCon item.state.lastFrameUpdate = GContext->frame; item.state.visible = true; + item.state.prevHovered = item.state.hovered; item.state.hovered = ImGui::IsWindowHovered(); + item.state.prevFocused = item.state.focused; item.state.focused = ImGui::IsWindowFocused(); item.state.rectSize = { ImGui::GetWindowSize().x, ImGui::GetWindowSize().y }; item.state.toggledOpen = ImGui::IsWindowCollapsed(); @@ -1706,21 +1686,52 @@ DearPyGui::draw_window(ImDrawList* drawlist, mvAppItem& item, mvWindowAppItemCon if (!item.config.show) { item.state.lastFrameUpdate = GContext->frame; + item.state.prevHovered = item.state.hovered; item.state.hovered = false; + item.state.prevFocused = item.state.focused; item.state.focused = false; item.state.toggledOpen = false; item.state.visible = false; - if (item.config.alias.empty()) - mvAddCallback(config.on_close, item.uuid, nullptr, item.config.user_data); - else - mvAddCallback(config.on_close, item.config.alias, nullptr, item.config.user_data); + item.submitCallbackEx(config.on_close, []() -> PyObject* { return nullptr; }); } if (item.handlerRegistry) item.handlerRegistry->checkEvents(&item.state); } +void +check_drop_event(mvAppItem* item) +{ + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(item->config.payloadType.c_str())) + { + IM_ASSERT(payload->DataSize == sizeof(mvUUID) && "Unexpected drag payload data size."); + mvUUID payloadUUID = *(mvUUID*)payload->Data; + // Let's see if the payload still exists. + auto payloadItem = GetItem(*GContext->itemRegistry, payloadUUID); + if (payloadItem && payloadItem->type == mvAppItemType::mvDragPayload) + { + auto payloadActual = static_cast(payloadItem); + // Note: we're passing None in user_data for backward compatibility + // (mvAddCallback will derive None from the mvPyObject that stores nullptr). + // One day this may change, but we need to decide which of the user_data's + // (parent's or payload's) we're going to pass here. + // We can't use mvAppItem::submitCallbackEx here because we need custom user_data. + mvAddCallback( + item->weak_from_this(), + item->config.dropCallback, + std::make_shared(nullptr), + item->uuid, item->config.alias, + [dragData = payloadActual->configData.dragData] () { + PyObject* pyDragData = *dragData; + Py_XINCREF(pyDragData); + return pyDragData; + } + ); + } + } +} + void apply_drag_drop(mvAppItem* item) { @@ -1732,15 +1743,7 @@ apply_drag_drop(mvAppItem* item) ScopedID id(item->uuid); if (ImGui::BeginDragDropTarget()) { - if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(item->config.payloadType.c_str())) - { - auto payloadActual = static_cast(payload->Data); - if (item->config.alias.empty()) - mvAddCallback(item->config.dropCallback, item->uuid, payloadActual->configData.dragData, nullptr); - else - mvAddCallback(item->config.dropCallback, item->config.alias, payloadActual->configData.dragData, nullptr); - } - + check_drop_event(item); ImGui::EndDragDropTarget(); } } @@ -1754,15 +1757,7 @@ apply_drag_drop_nodraw(mvAppItem* item) ScopedID id(item->uuid); if (ImGui::BeginDragDropTarget()) { - if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(item->config.payloadType.c_str())) - { - auto payloadActual = static_cast(payload->Data); - if (item->config.alias.empty()) - mvAddCallback(item->config.dropCallback, item->uuid, payloadActual->configData.dragData, nullptr); - else - mvAddCallback(item->config.dropCallback, item->config.alias, payloadActual->configData.dragData, nullptr); - } - + check_drop_event(item); ImGui::EndDragDropTarget(); } } diff --git a/src/mvContainers.h b/src/mvContainers.h index bc205f918..a5390c7fc 100644 --- a/src/mvContainers.h +++ b/src/mvContainers.h @@ -3,6 +3,15 @@ #include "mvItemRegistry.h" #include +// check_drop_event() implements the typical contents of Dear ImGui's drop target +// (ImGui::BeginDragDropTarget()) tied to DearPyGui's drop callback. You usually +// don't need to call it directly, but it can be used need to implement custom +// drag'n'drop mechanics. +// To implement drag'n'drop in an arbitrary ImGui item, use `apply_drag_drop()` - +// it both implements the entire drop target and renders the drag payload. +void check_drop_event(mvAppItem* item); +// During drag'n'drop, renders drag payload and checks whether it's time to call +// the drop callback. void apply_drag_drop(mvAppItem* item); void apply_drag_drop_nodraw(mvAppItem* item); @@ -92,12 +101,6 @@ struct mvChildWindowConfig bool autosize_x = false; bool autosize_y = false; ImGuiWindowFlags windowflags = ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_NavFlattened; - float scrollX = 0.0f; - float scrollY = 0.0f; - float scrollMaxX = 0.0f; - float scrollMaxY = 0.0f; - bool _scrollXSet = false; - bool _scrollYSet = false; }; struct mvTreeNodeConfig @@ -118,8 +121,8 @@ struct mvGroupConfig struct mvDragPayloadConfig { std::string payloadType = "$$DPG_PAYLOAD"; - PyObject* dragData = nullptr; - PyObject* dropData = nullptr; + std::shared_ptr dragData = std::make_shared(nullptr); + std::shared_ptr dropData = std::make_shared(nullptr); }; struct mvCollapsingHeaderConfig @@ -161,16 +164,10 @@ struct mvWindowAppItemConfig bool no_background = false; bool collapsed = false; bool no_open_over_existing_popup = true; - PyObject* on_close = nullptr; + mvPyObject on_close = nullptr; mvVec2 min_size = { 100.0f, 100.0f }; mvVec2 max_size = { 30000.0f, 30000.0f }; - float scrollX = 0.0f; - float scrollY = 0.0f; - float scrollMaxX = 0.0f; - float scrollMaxY = 0.0f; bool _collapsedDirty = true; - bool _scrollXSet = false; - bool _scrollYSet = false; ImGuiWindowFlags _oldWindowflags = ImGuiWindowFlags_None; float _oldxpos = 200; float _oldypos = 200; @@ -288,5 +285,4 @@ class mvWindowAppItem : public mvAppItem void draw(ImDrawList* drawlist, float x, float y) override { DearPyGui::draw_window(drawlist, *this, configData); } void handleSpecificKeywordArgs(PyObject* dict) override { DearPyGui::set_configuration(dict, *this, configData); } void getSpecificConfiguration(PyObject* dict) override { DearPyGui::fill_configuration_dict(configData, dict); } - ~mvWindowAppItem() { PyObject* callback = configData.on_close; mvSubmitCallback([callback]() { if (callback) Py_XDECREF(callback);});} }; \ No newline at end of file diff --git a/src/mvContext.cpp b/src/mvContext.cpp index db10dd2c2..cc41d22bc 100644 --- a/src/mvContext.cpp +++ b/src/mvContext.cpp @@ -160,6 +160,9 @@ SetDefaultTheme() void Render() { + // We lock the mutex from the very start so that frame count is kept valid + // for API calls. + std::lock_guard lk(GContext->mutex); // update timing GContext->deltaTime = ImGui::GetIO().DeltaTime; @@ -179,21 +182,22 @@ Render() mvToolManager::Draw(); + if (GContext->resetTheme) { - std::lock_guard lk(GContext->mutex); - if (GContext->resetTheme) - { - SetDefaultTheme(); - GContext->resetTheme = false; - } - - mvRunTasks(); - RenderItemRegistry(*GContext->itemRegistry); - mvRunTasks(); + SetDefaultTheme(); + GContext->resetTheme = false; } - if (GContext->waitOneFrame == true) - GContext->waitOneFrame = false; + mvRunTasks(); + RenderItemRegistry(*GContext->itemRegistry); + mvRunTasks(); + + // release split_frame if it's waiting for the frame end + { + std::lock_guard lk(GContext->frameEndedMutex); + GContext->frameEnded = true; + } + GContext->frameEndedEvent.notify_all(); } std::map& @@ -202,6 +206,24 @@ GetParsers() return const_cast&>(GetModuleParsers()); } +void StopRendering() +{ + // While it may seem reasonable to set it to false with frameEndedMutex locked + // (to set it simultaneously with frameEnded), we don't want to spur another + // race condition between split_frame() and is_dearpygui_running() in the + // rendering loop. Let's trigger it as early as possible. + GContext->running = false; + + // Unblock handlers (or other code) that might be waiting in `split_frame()` + { + std::lock_guard lk(GContext->frameEndedMutex); + // Simulate an end of frame even though there's no real frame this time. + // Otherwise split_frame will continue waiting. + GContext->frameEnded = true; + } + GContext->frameEndedEvent.notify_all(); +} + void InsertConstants_mvContext(std::vector>& constants) { @@ -298,6 +320,8 @@ InsertConstants_mvContext(std::vector>& constants) constants.emplace_back("mvKey_NumPad7", ImGuiKey_Keypad7); constants.emplace_back("mvKey_NumPad8", ImGuiKey_Keypad8); constants.emplace_back("mvKey_NumPad9", ImGuiKey_Keypad9); + constants.emplace_back("mvKey_NumPadEnter", ImGuiKey_KeypadEnter); + constants.emplace_back("mvKey_NumPadEqual", ImGuiKey_KeypadEqual); constants.emplace_back("mvKey_Subtract", ImGuiKey_KeypadSubtract); constants.emplace_back("mvKey_Decimal", ImGuiKey_KeypadDecimal); constants.emplace_back("mvKey_Divide", ImGuiKey_KeypadDivide); diff --git a/src/mvContext.h b/src/mvContext.h index 10ac7106c..cb2bc864e 100644 --- a/src/mvContext.h +++ b/src/mvContext.h @@ -34,6 +34,8 @@ mvUUID GenerateUUID(); void SetDefaultTheme(); void Render(); std::map& GetParsers(); +// Signals the rendering loop via GContext->running to quit. +void StopRendering(); struct mvInput { @@ -100,8 +102,14 @@ struct mvIO struct mvContext { - std::atomic_bool waitOneFrame = false; + std::mutex frameEndedMutex; + std::condition_variable frameEndedEvent; + bool frameEnded = false; + // Indicates whether DPG has started at least once in this context, i.e. whether + // associated Dear ImGui contexts exist and can be read from. std::atomic_bool started = false; + // If true, more frames are going to be rendered. Goes back to false on shutdown. + std::atomic_bool running = false; std::recursive_mutex mutex; std::future future; float deltaTime = 0.0f; // time since last frame diff --git a/src/mvDatePicker.cpp b/src/mvDatePicker.cpp index ef309c623..82dab312a 100644 --- a/src/mvDatePicker.cpp +++ b/src/mvDatePicker.cpp @@ -67,13 +67,7 @@ void mvDatePicker::draw(ImDrawList* drawlist, float x, float y) { ImPlot::GetGmtTime(*_imvalue, _value.get()); { - auto value = *_value; - mvSubmitCallback([=]() { - if(config.alias.empty()) - mvAddCallback(getCallback(false), uuid, ToPyTime(value), config.user_data); - else - mvAddCallback(getCallback(false), config.alias, ToPyTime(value), config.user_data); - }); + submitCallback(*_value); } } } diff --git a/src/mvDrawings.cpp b/src/mvDrawings.cpp index c24cc61a6..bb5d082d1 100644 --- a/src/mvDrawings.cpp +++ b/src/mvDrawings.cpp @@ -952,10 +952,7 @@ void mvDrawlist::draw(ImDrawList* drawlist, float x, float y) if (ImGui::InvisibleButton(info.internalLabel.c_str(), ImVec2((float)config.width, (float)config.height), ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight | ImGuiButtonFlags_MouseButtonMiddle)) { - if (config.alias.empty()) - mvAddCallback(getCallback(false), uuid, nullptr, config.user_data); - else - mvAddCallback(getCallback(false), config.alias, nullptr, config.user_data); + submitCallback(); } UpdateAppItemState(state); diff --git a/src/mvFileDialog.cpp b/src/mvFileDialog.cpp index 7eef5a3c1..5f9d7fb8e 100644 --- a/src/mvFileDialog.cpp +++ b/src/mvFileDialog.cpp @@ -103,25 +103,21 @@ void mvFileDialog::draw(ImDrawList* drawlist, float x, float y) // action if OK clicked or if cancel clicked and cancel callback provided if (_instance.IsOk() || _cancelCallback) { - mvSubmitCallback([&]() + submitCallbackEx( + _instance.IsOk()? config.callback : _cancelCallback, + // We're capturing a weak reference to mvFileDialog, so that the dialog can + // be safely deleted even if there's a callback still waiting in the queue. + [weakThis=weak_from_this()] () -> PyObject* { - PyObject* callback; - PyObject* appData; - - if(_instance.IsOk()) + auto liveThis = weakThis.lock(); + if (liveThis) { - callback = config.callback; - appData = getInfoDict(); - } else { - callback = _cancelCallback; - appData = getInfoDict(); + mvFileDialog* dlg = static_cast(liveThis.get()); + return dlg->getInfoDict(); } - - if(config.alias.empty()) - mvRunCallback(callback, uuid, appData, config.user_data); - else - mvRunCallback(callback, config.alias, appData, config.user_data); - }); + return nullptr; + } + ); } // close @@ -189,15 +185,7 @@ void mvFileDialog::handleSpecificKeywordArgs(PyObject* dict) if (PyObject* item = PyDict_GetItemString(dict, "cancel_callback")) { - Py_XDECREF(_cancelCallback); - - if (item == Py_None) - _cancelCallback = nullptr; - else - { - Py_XINCREF(item); - _cancelCallback = item; - } + _cancelCallback = mvPyObject(item == Py_None? nullptr : item, true); } } diff --git a/src/mvFileDialog.h b/src/mvFileDialog.h index 3b034a4a3..547c22021 100644 --- a/src/mvFileDialog.h +++ b/src/mvFileDialog.h @@ -46,5 +46,5 @@ class mvFileDialog final : public mvAppItem bool _directory = false; mvVec2 _min_size = { 100.0f, 100.0f }; mvVec2 _max_size = { 30000.0f, 30000.0f }; - PyObject* _cancelCallback = nullptr; + mvPyObject _cancelCallback = nullptr; }; \ No newline at end of file diff --git a/src/mvFontManager.cpp b/src/mvFontManager.cpp index 8ff88fa94..a6e2e6437 100644 --- a/src/mvFontManager.cpp +++ b/src/mvFontManager.cpp @@ -168,6 +168,10 @@ mvFontManager::rebuildAtlas() { item->customAction(nullptr); } + + // Just to make sure g.Font doesn't point to a font already deleted by + // io.Fonts->Clear(), though ideally ImGui should be doing it on its own. + ImGui::SetCurrentFont(ImGui::GetDefaultFont()); } _dirty = false; diff --git a/src/mvGlobalHandlers.cpp b/src/mvGlobalHandlers.cpp index 791e1126e..5382f37c0 100644 --- a/src/mvGlobalHandlers.cpp +++ b/src/mvGlobalHandlers.cpp @@ -19,26 +19,14 @@ void mvKeyDownHandler::draw(ImDrawList* drawlist, float x, float y) auto key = ImGui::GetKeyData(static_cast(i)); if (key->Down) { - mvSubmitCallback([=]() - { - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, ToPyMPair(i, key->DownDuration), config.user_data); - else - mvRunCallback(getCallback(false), config.alias, ToPyMPair(i, key->DownDuration), config.user_data); - }); + submitCallbackEx([=]() { return ToPyMPair(i, key->DownDuration); }); } } } else if (ImGui::IsKeyDown(_key)) { - mvSubmitCallback([=]() - { - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, ToPyMPair(_key, ImGui::GetKeyData(_key)->DownDuration), config.user_data); - else - mvRunCallback(getCallback(false), config.alias, ToPyMPair(_key, ImGui::GetKeyData(_key)->DownDuration), config.user_data); - }); + submitCallbackEx([=]() { return ToPyMPair(_key, ImGui::GetKeyData(_key)->DownDuration); }); } } @@ -74,26 +62,14 @@ void mvKeyPressHandler::draw(ImDrawList* drawlist, float x, float y) { if (ImGui::IsKeyPressed(static_cast(i))) { - mvSubmitCallback([=]() - { - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, ToPyInt(i), config.user_data); - else - mvRunCallback(getCallback(false), config.alias, ToPyInt(i), config.user_data); - }); + submitCallback(i); } } } else if (ImGui::IsKeyPressed(_key)) { - mvSubmitCallback([=]() - { - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, ToPyInt(_key), config.user_data); - else - mvRunCallback(getCallback(false), config.alias, ToPyInt(_key), config.user_data); - }); + submitCallback(_key); } } @@ -141,26 +117,14 @@ void mvKeyReleaseHandler::draw(ImDrawList* drawlist, float x, float y) { if (ImGui::IsKeyReleased(static_cast(i))) { - mvSubmitCallback([=]() - { - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, ToPyInt(i), config.user_data); - else - mvRunCallback(getCallback(false), config.alias, ToPyInt(i), config.user_data); - }); + submitCallback(i); } } } else if (ImGui::IsKeyReleased(_key)) { - mvSubmitCallback([=]() - { - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, ToPyInt(_key), config.user_data); - else - mvRunCallback(getCallback(false), config.alias, ToPyInt(_key), config.user_data); - }); + submitCallback(_key); } } @@ -208,26 +172,14 @@ void mvMouseClickHandler::draw(ImDrawList* drawlist, float x, float y) { if (ImGui::IsMouseClicked(i)) { - mvSubmitCallback([=]() - { - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, ToPyInt(i), config.user_data); - else - mvRunCallback(getCallback(false), config.alias, ToPyInt(i), config.user_data); - }); + submitCallback(i); } } } else if (ImGui::IsMouseClicked(_button)) { - mvSubmitCallback([=]() - { - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, ToPyInt(_button), config.user_data); - else - mvRunCallback(getCallback(false), config.alias, ToPyInt(_button), config.user_data); - }); + submitCallback(_button); } } @@ -275,26 +227,14 @@ void mvMouseDoubleClickHandler::draw(ImDrawList* drawlist, float x, float y) { if (ImGui::IsMouseDoubleClicked(i)) { - mvSubmitCallback([=]() - { - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, ToPyInt(i), config.user_data); - else - mvRunCallback(getCallback(false), config.alias, ToPyInt(i), config.user_data); - }); + submitCallback(i); } } } else if (ImGui::IsMouseDoubleClicked(_button)) { - mvSubmitCallback([=]() - { - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, ToPyInt(_button), config.user_data); - else - mvRunCallback(getCallback(false), config.alias, ToPyInt(_button), config.user_data); - }); + submitCallback(_button); } } @@ -342,26 +282,14 @@ void mvMouseDownHandler::draw(ImDrawList* drawlist, float x, float y) { if (ImGui::GetIO().MouseDown[i]) { - mvSubmitCallback([=]() - { - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, ToPyMPair(i, ImGui::GetIO().MouseDownDuration[i]), config.user_data); - else - mvRunCallback(getCallback(false), config.alias, ToPyMPair(i, ImGui::GetIO().MouseDownDuration[i]), config.user_data); - }); + submitCallbackEx([=]() { return ToPyMPair(i, ImGui::GetIO().MouseDownDuration[i]); }); } } } else if (ImGui::GetIO().MouseDown[_button]) { - mvSubmitCallback([=]() - { - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, ToPyMPair(_button, ImGui::GetIO().MouseDownDuration[_button]), config.user_data); - else - mvRunCallback(getCallback(false), config.alias, ToPyMPair(_button, ImGui::GetIO().MouseDownDuration[_button]), config.user_data); - }); + submitCallbackEx([=]() { return ToPyMPair(_button, ImGui::GetIO().MouseDownDuration[_button]); }); } } @@ -412,15 +340,7 @@ void mvMouseDragHandler::draw(ImDrawList* drawlist, float x, float y) if (ImGui::IsMouseDragging(i, _threshold)) { - mvSubmitCallback([=]() - { - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, - ToPyMTrip(i, ImGui::GetMouseDragDelta(i).x, ImGui::GetMouseDragDelta(i).y), config.user_data); - else - mvRunCallback(getCallback(false), config.alias, - ToPyMTrip(i, ImGui::GetMouseDragDelta(i).x, ImGui::GetMouseDragDelta(i).y), config.user_data); - }); + submitCallbackEx([=]() { return ToPyMTrip(i, ImGui::GetMouseDragDelta(i).x, ImGui::GetMouseDragDelta(i).y); }); } } } @@ -429,15 +349,8 @@ void mvMouseDragHandler::draw(ImDrawList* drawlist, float x, float y) { if (ImGui::IsMouseReleased(_button)) ImGui::ResetMouseDragDelta(_button); - mvSubmitCallback([=]() - { - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, - ToPyMTrip(_button, ImGui::GetMouseDragDelta(_button).x, ImGui::GetMouseDragDelta(_button).y), config.user_data); - else - mvRunCallback(getCallback(false), config.alias, - ToPyMTrip(_button, ImGui::GetMouseDragDelta(_button).x, ImGui::GetMouseDragDelta(_button).y), config.user_data); - }); + + submitCallbackEx([=]() { return ToPyMTrip(_button, ImGui::GetMouseDragDelta(_button).x, ImGui::GetMouseDragDelta(_button).y); }); } } @@ -495,13 +408,7 @@ void mvMouseMoveHandler::draw(ImDrawList* drawlist, float x, float y) { _oldPos = mousepos; - mvSubmitCallback([=]() - { - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, ToPyPair(mousepos.x, mousepos.y), config.user_data); - else - mvRunCallback(getCallback(false), config.alias, ToPyPair(mousepos.x, mousepos.y), config.user_data); - }); + submitCallback(mousepos); } } } @@ -514,26 +421,14 @@ void mvMouseReleaseHandler::draw(ImDrawList* drawlist, float x, float y) { if (ImGui::IsMouseReleased(i)) { - mvSubmitCallback([=]() - { - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, ToPyInt(i), config.user_data); - else - mvRunCallback(getCallback(false), config.alias, ToPyInt(i), config.user_data); - }); + submitCallback(i); } } } else if (ImGui::IsMouseReleased(_button)) { - mvSubmitCallback([=]() - { - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, ToPyInt(_button), config.user_data); - else - mvRunCallback(getCallback(false), config.alias, ToPyInt(_button), config.user_data); - }); + submitCallback(_button); } } @@ -578,14 +473,6 @@ void mvMouseWheelHandler::draw(ImDrawList* drawlist, float x, float y) int wheel = (int)ImGui::GetIO().MouseWheel; if (wheel) { - - mvSubmitCallback([=]() - { - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, ToPyInt(wheel), config.user_data); - else - mvRunCallback(getCallback(false), config.alias, ToPyInt(wheel), config.user_data); - }); - + submitCallback(wheel); } } \ No newline at end of file diff --git a/src/mvItemHandlers.cpp b/src/mvItemHandlers.cpp index 93e79a2ad..2c77ac5b7 100644 --- a/src/mvItemHandlers.cpp +++ b/src/mvItemHandlers.cpp @@ -119,24 +119,67 @@ void mvItemHandlerRegistry::onBind(mvAppItem* item) break; } + case mvAppItemType::mvScrollHandler: + { + if (!(applicableState & ~MV_STATE_SCROLL)) + mvThrowPythonError(mvErrorCode::mvNone, "bind_item_handler_registry", + "Item Handler Registry includes inapplicable handler: mvScrollHandler", item); + break; + } + default: break; } } } +void mvItemHandler::submitHandler(mvAppItem* parent) +{ + submitCallbackEx([uuid=parent->uuid, alias=parent->config.alias] () { + return ToPyUUID(uuid, alias); + }); +} + +void mvBoolStateHandler::checkEvent(bool curState, bool prevState, mvAppItem* parent) +{ + mvEventType eventType = curState? + (prevState? mvEventType_On : mvEventType_EnterAndOn) : + (prevState? mvEventType_LeaveAndOff : mvEventType_Off); + + if (trackedEventType & eventType) + { + // We do not pass eventType to callback yet in order to keep it compatible + // with the old version. + submitHandler(parent); + } +} + +void mvBoolStateHandler::handleSpecificKeywordArgs(PyObject* dict) +{ + if (dict == nullptr) + return; + + if (PyObject* item = PyDict_GetItemString(dict, "event_type")) + { + if (item != Py_None) + trackedEventType = static_cast(ToInt(item)); + } +} + +void mvBoolStateHandler::getSpecificConfiguration(PyObject* dict) +{ + if (dict == nullptr) + return; + + PyDict_SetItemString(dict, "event_type", mvPyObject(ToPyInt(trackedEventType))); +} + void mvActivatedHandler::customAction(void* data) { mvAppItemState* state = static_cast(data); if (state->activated) { - mvSubmitCallback([=]() - { - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, ToPyUUID(state->parent), config.user_data); - else - mvRunCallback(getCallback(false), config.alias, ToPyUUID(state->parent), config.user_data); - }); + submitHandler(state->parent); } } @@ -146,13 +189,7 @@ void mvActiveHandler::customAction(void* data) mvAppItemState* state = static_cast(data); if (state->active) { - mvSubmitCallback([=]() - { - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, ToPyUUID(state->parent), config.user_data); - else - mvRunCallback(getCallback(false), config.alias, ToPyUUID(state->parent), config.user_data); - }); + submitHandler(state->parent); } } @@ -160,51 +197,25 @@ void mvClickedHandler::customAction(void* data) { mvAppItemState* state = static_cast(data); - if (_button == -1 || _button == 0) - if (state->leftclicked) - { - mvSubmitCallback([=]() - { - mvPyObject pArgs(PyTuple_New(2)); - PyTuple_SetItem(pArgs, 0, ToPyInt(0)); - PyTuple_SetItem(pArgs, 1, ToPyUUID(state->parent)); // steals data, so don't deref - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, pArgs, config.user_data); - else - mvRunCallback(getCallback(false), config.alias, pArgs, config.user_data); - }); - } - if (_button == -1 || _button == 1) - if (state->rightclicked) - { - mvSubmitCallback([=]() - { - mvPyObject pArgs(PyTuple_New(2)); - PyTuple_SetItem(pArgs, 0, ToPyInt(1)); - PyTuple_SetItem(pArgs, 1, ToPyUUID(state->parent)); // steals data, so don't deref - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, pArgs, config.user_data); - else - mvRunCallback(getCallback(false), config.alias, pArgs, config.user_data); - }); - } + b8 clicked[] = {state->leftclicked, state->rightclicked, state->middleclicked}; + + int i = (_button < 0)? 0 : _button ; + int end = (_button < 0)? (int)std::size(clicked) : (i + 1); - if (_button == -1 || _button == 2) - if (state->middleclicked) + for (; i < end; i++) + { + if (clicked[i]) { - mvSubmitCallback([=]() - { - mvPyObject pArgs(PyTuple_New(2)); - PyTuple_SetItem(pArgs, 0, ToPyInt(2)); - PyTuple_SetItem(pArgs, 1, ToPyUUID(state->parent)); // steals data, so don't deref - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, pArgs, config.user_data); - else - mvRunCallback(getCallback(false), config.alias, pArgs, config.user_data); - }); + mvAppItem* parent = state->parent; + submitCallbackEx([i, uuid=parent->uuid, alias=parent->config.alias] () { + PyObject* app_data = PyTuple_New(2); + PyTuple_SetItem(app_data, 0, ToPyInt(i)); + PyTuple_SetItem(app_data, 1, ToPyUUID(uuid, alias)); + return app_data; + }); } - + } } void mvClickedHandler::handleSpecificRequiredArgs(PyObject* dict) @@ -242,16 +253,13 @@ void mvDoubleClickedHandler::customAction(void* data) { if (state->doubleclicked[i]) { - mvSubmitCallback([=]() - { - mvPyObject pArgs(PyTuple_New(2)); - PyTuple_SetItem(pArgs, 0, ToPyInt(i)); - PyTuple_SetItem(pArgs, 1, ToPyUUID(state->parent)); // steals data, so don't deref - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, pArgs, config.user_data); - else - mvRunCallback(getCallback(false), config.alias, pArgs, config.user_data); - }); + mvAppItem* parent = state->parent; + submitCallbackEx([i, uuid=parent->uuid, alias=parent->config.alias] () { + PyObject* app_data = PyTuple_New(2); + PyTuple_SetItem(app_data, 0, ToPyInt(i)); + PyTuple_SetItem(app_data, 1, ToPyUUID(uuid, alias)); + return app_data; + }); } } } @@ -286,13 +294,7 @@ void mvDeactivatedAfterEditHandler::customAction(void* data) mvAppItemState* state = static_cast(data); if (state->deactivatedAfterEdit) { - mvSubmitCallback([=]() - { - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, ToPyUUID(state->parent), config.user_data); - else - mvRunCallback(getCallback(false), config.alias, ToPyUUID(state->parent), config.user_data); - }); + submitHandler(state->parent); } } @@ -301,13 +303,7 @@ void mvDeactivatedHandler::customAction(void* data) mvAppItemState* state = static_cast(data); if (state->deactivated) { - mvSubmitCallback([=]() - { - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, ToPyUUID(state->parent), config.user_data); - else - mvRunCallback(getCallback(false), config.alias, ToPyUUID(state->parent), config.user_data); - }); + submitHandler(state->parent); } } @@ -317,45 +313,20 @@ void mvEditedHandler::customAction(void* data) mvAppItemState* state = static_cast(data); if (state->edited) { - mvSubmitCallback([=]() - { - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, ToPyUUID(state->parent), config.user_data); - else - mvRunCallback(getCallback(false), config.alias, ToPyUUID(state->parent), config.user_data); - }); + submitHandler(state->parent); } } void mvFocusHandler::customAction(void* data) { - mvAppItemState* state = static_cast(data); - if (state->focused) - { - mvSubmitCallback([=]() - { - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, ToPyUUID(state->parent), config.user_data); - else - mvRunCallback(getCallback(false), config.alias, ToPyUUID(state->parent), config.user_data); - }); - } + checkEvent(state->focused, state->prevFocused, state->parent); } void mvHoverHandler::customAction(void* data) { mvAppItemState* state = static_cast(data); - if (state->hovered) - { - mvSubmitCallback([=]() - { - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, ToPyUUID(state->parent), config.user_data); - else - mvRunCallback(getCallback(false), config.alias, ToPyUUID(state->parent), config.user_data); - }); - } + checkEvent(state->hovered, state->prevHovered, state->parent); } void mvResizeHandler::customAction(void* data) @@ -363,42 +334,66 @@ void mvResizeHandler::customAction(void* data) mvAppItemState* state = static_cast(data); if (state->mvRectSizeResized) { - mvSubmitCallback([=]() - { - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, ToPyUUID(state->parent), config.user_data); - else - mvRunCallback(getCallback(false), config.alias, ToPyUUID(state->parent), config.user_data); - }); + submitHandler(state->parent); } } void mvToggledOpenHandler::customAction(void* data) { - - if (static_cast(data)->toggledOpen) + mvAppItemState* state = static_cast(data); + if (state->toggledOpen) { - mvSubmitCallback([=]() - { - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, GetPyNone(), config.user_data); - else - mvRunCallback(getCallback(false), config.alias, GetPyNone(), config.user_data); - }); + submitHandler(state->parent); } } void mvVisibleHandler::customAction(void* data) { - + mvAppItemState* state = static_cast(data); if (static_cast(data)->visible) { - mvSubmitCallback([=]() - { - if (config.alias.empty()) - mvRunCallback(getCallback(false), uuid, GetPyNone(), config.user_data); - else - mvRunCallback(getCallback(false), config.alias, GetPyNone(), config.user_data); - }); + submitHandler(state->parent); + } +} + +PyObject* mvScrollHandler::makeAppData(mvUUID uuid, const std::string& alias, mvScrollDirection dir, bool isScrolling, float pos, float max) +{ + PyObject* app_data = PyTuple_New(5); + PyTuple_SetItem(app_data, 0, ToPyUUID(uuid, alias)); + PyTuple_SetItem(app_data, 1, ToPyInt(dir)); + PyTuple_SetItem(app_data, 2, ToPyFloat(pos)); + PyTuple_SetItem(app_data, 3, ToPyFloat(max)); + PyTuple_SetItem(app_data, 4, ToPyBool(isScrolling)); + return app_data; +} + +void mvScrollHandler::customAction(void* data) +{ + mvAppItemState* state = static_cast(data); + mvAppItem* parent = state->parent; + if (state->scrolledX) + { + submitCallbackEx([=, + uuid=parent->uuid, + alias=parent->config.alias, + isScrolling=state->isScrollingX, + pos=state->scrollPos.x, + max=state->scrollMax.x] () + { + return makeAppData(uuid, alias, mvScrollDirection_XAxis, isScrolling, pos, max); + }); } -} \ No newline at end of file + + if (state->scrolledY) + { + submitCallbackEx([=, + uuid=parent->uuid, + alias=parent->config.alias, + isScrolling=state->isScrollingY, + pos=state->scrollPos.y, + max=state->scrollMax.y] () + { + return makeAppData(uuid, alias, mvScrollDirection_YAxis, isScrolling, pos, max); + }); + } +} diff --git a/src/mvItemHandlers.h b/src/mvItemHandlers.h index be2823245..08f59bca2 100644 --- a/src/mvItemHandlers.h +++ b/src/mvItemHandlers.h @@ -14,29 +14,71 @@ class mvItemHandlerRegistry : public mvAppItem void onBind(mvAppItem* item); }; -class mvActivatedHandler : public mvAppItem +class mvItemHandler : public mvAppItem { public: - explicit mvActivatedHandler(mvUUID uuid) : mvAppItem(uuid) {} + explicit mvItemHandler(mvUUID uuid) : mvAppItem(uuid) {} + +protected: + void submitHandler(mvAppItem* parent); +}; + +enum mvEventType +{ + // These constants can be used as a combination of flags + mvEventType_None = 0, + mvEventType_Off = 1 << 1, + mvEventType_Enter = 1 << 2, + mvEventType_On = 1 << 3, + mvEventType_Leave = 1 << 4, + // When the state changes, we observe two events in a single frame: + // both "enter" and "on" or both "leave" and "off". We need to define + // these flags here so that they can be used as a mask later on. + mvEventType_EnterAndOn = mvEventType_Enter | mvEventType_On, + mvEventType_LeaveAndOff = mvEventType_Leave | mvEventType_Off, + // This is the state the handler will react to by default + mvEventType_Default = mvEventType_On +}; + +// This is a base class for handlers that monitor a single bool variable +// that can switch on or off and reflects the item state, like "focused" +// or "hovered". +class mvBoolStateHandler : public mvItemHandler +{ +public: + explicit mvBoolStateHandler(mvUUID uuid) : mvItemHandler(uuid) {} + void draw(ImDrawList* drawlist, float x, float y) override {} + void checkEvent(bool curState, bool prevState, mvAppItem* parent); + void handleSpecificKeywordArgs(PyObject* dict) override; + void getSpecificConfiguration(PyObject* dict) override; + +protected: + mvEventType trackedEventType = mvEventType_Default; +}; + +class mvActivatedHandler : public mvItemHandler +{ +public: + explicit mvActivatedHandler(mvUUID uuid) : mvItemHandler(uuid) {} void draw(ImDrawList* drawlist, float x, float y) override {} void customAction(void* data = nullptr) override; }; -class mvActiveHandler : public mvAppItem +class mvActiveHandler : public mvItemHandler { public: - explicit mvActiveHandler(mvUUID uuid) : mvAppItem(uuid) {} + explicit mvActiveHandler(mvUUID uuid) : mvItemHandler(uuid) {} void draw(ImDrawList* drawlist, float x, float y) override {} void customAction(void* data = nullptr) override; }; -class mvClickedHandler : public mvAppItem +class mvClickedHandler : public mvItemHandler { public: int _button = -1; - explicit mvClickedHandler(mvUUID uuid) : mvAppItem(uuid) {} + explicit mvClickedHandler(mvUUID uuid) : mvItemHandler(uuid) {} void draw(ImDrawList* drawlist, float x, float y) override {} void customAction(void* data = nullptr) override; void handleSpecificRequiredArgs(PyObject* dict) override; @@ -44,11 +86,11 @@ class mvClickedHandler : public mvAppItem void getSpecificConfiguration(PyObject* dict) override; }; -class mvDoubleClickedHandler : public mvAppItem +class mvDoubleClickedHandler : public mvItemHandler { public: int _button = -1; - explicit mvDoubleClickedHandler(mvUUID uuid) : mvAppItem(uuid) {} + explicit mvDoubleClickedHandler(mvUUID uuid) : mvItemHandler(uuid) {} void draw(ImDrawList* drawlist, float x, float y) override {} void customAction(void* data = nullptr) override; void handleSpecificRequiredArgs(PyObject* dict) override; @@ -56,66 +98,84 @@ class mvDoubleClickedHandler : public mvAppItem void getSpecificConfiguration(PyObject* dict) override; }; -class mvDeactivatedAfterEditHandler : public mvAppItem +class mvDeactivatedAfterEditHandler : public mvItemHandler { public: - explicit mvDeactivatedAfterEditHandler(mvUUID uuid) : mvAppItem(uuid) {} + explicit mvDeactivatedAfterEditHandler(mvUUID uuid) : mvItemHandler(uuid) {} void draw(ImDrawList* drawlist, float x, float y) override {} void customAction(void* data = nullptr) override; }; -class mvDeactivatedHandler : public mvAppItem +class mvDeactivatedHandler : public mvItemHandler { public: - explicit mvDeactivatedHandler(mvUUID uuid) : mvAppItem(uuid) {} + explicit mvDeactivatedHandler(mvUUID uuid) : mvItemHandler(uuid) {} void draw(ImDrawList* drawlist, float x, float y) override {} void customAction(void* data = nullptr) override; }; -class mvEditedHandler : public mvAppItem +class mvEditedHandler : public mvItemHandler { public: - explicit mvEditedHandler(mvUUID uuid) : mvAppItem(uuid) {} + explicit mvEditedHandler(mvUUID uuid) : mvItemHandler(uuid) {} void draw(ImDrawList* drawlist, float x, float y) override {} void customAction(void* data = nullptr) override; }; -class mvFocusHandler : public mvAppItem +class mvFocusHandler : public mvBoolStateHandler { public: - explicit mvFocusHandler(mvUUID uuid) : mvAppItem(uuid) {} - void draw(ImDrawList* drawlist, float x, float y) override {} + explicit mvFocusHandler(mvUUID uuid) : mvBoolStateHandler(uuid) {} void customAction(void* data = nullptr) override; }; -class mvHoverHandler : public mvAppItem +class mvHoverHandler : public mvBoolStateHandler { public: - explicit mvHoverHandler(mvUUID uuid) : mvAppItem(uuid) {} + explicit mvHoverHandler(mvUUID uuid) : mvBoolStateHandler(uuid) {} + void customAction(void* data = nullptr) override; +}; + +class mvResizeHandler : public mvItemHandler +{ +public: + explicit mvResizeHandler(mvUUID uuid) : mvItemHandler(uuid) {} void draw(ImDrawList* drawlist, float x, float y) override {} void customAction(void* data = nullptr) override; }; -class mvResizeHandler : public mvAppItem +class mvToggledOpenHandler : public mvItemHandler { public: - explicit mvResizeHandler(mvUUID uuid) : mvAppItem(uuid) {} + explicit mvToggledOpenHandler(mvUUID uuid) : mvItemHandler(uuid) {} void draw(ImDrawList* drawlist, float x, float y) override {} void customAction(void* data = nullptr) override; }; -class mvToggledOpenHandler : public mvAppItem +class mvVisibleHandler : public mvItemHandler { public: - explicit mvToggledOpenHandler(mvUUID uuid) : mvAppItem(uuid) {} + explicit mvVisibleHandler(mvUUID uuid) : mvItemHandler(uuid) {} void draw(ImDrawList* drawlist, float x, float y) override {} void customAction(void* data = nullptr) override; }; -class mvVisibleHandler : public mvAppItem +enum mvScrollDirection +{ + // These constants can be used as a combination of flags + mvScrollDirection_XAxis = 1, + mvScrollDirection_Horizontal = 1, + mvScrollDirection_YAxis = 2, + mvScrollDirection_Vertical = 2, +}; + +class mvScrollHandler : public mvItemHandler { public: - explicit mvVisibleHandler(mvUUID uuid) : mvAppItem(uuid) {} + explicit mvScrollHandler(mvUUID uuid) : mvItemHandler(uuid) {} void draw(ImDrawList* drawlist, float x, float y) override {} void customAction(void* data = nullptr) override; -}; \ No newline at end of file + +private: + static PyObject* makeAppData(mvUUID uuid, const std::string& alias, mvScrollDirection dir, bool isScrolling, float pos, float max); +}; diff --git a/src/mvItemRegistry.cpp b/src/mvItemRegistry.cpp index ceecd0412..2bca82d58 100644 --- a/src/mvItemRegistry.cpp +++ b/src/mvItemRegistry.cpp @@ -8,14 +8,11 @@ mvItemRegistry::mvItemRegistry() { - // prefill cached containers - for (i32 i = 0; i < CachedContainerCount; i++) - { - cachedContainersID[i] = 0; - cachedContainersPTR[i] = nullptr; - cachedItemsID[i] = 0; - cachedItemsPTR[i] = nullptr; - } + // We seldom need to do a GetItem(0), and an explicit check for uuid == 0 in GetItem + // slows it down. Instead of this, we add a fake entry to the allItems map, + // mapping 0 to nullptr. This entry will never go away because map items are only + // removed in the mvAppItem destructor. + allItems[0] = nullptr; } static b8 @@ -47,25 +44,6 @@ TopParent(mvItemRegistry& registry) return nullptr; } -static void -CacheItem(mvItemRegistry& registry, mvAppItem* item) -{ - if (DearPyGui::GetEntityDesciptionFlags(item->type) & MV_ITEM_DESC_CONTAINER) - { - registry.cachedContainersID[registry.cachedContainerIndex] = item->uuid; - registry.cachedContainersPTR[registry.cachedContainerIndex] = item; - registry.cachedContainerIndex++; - if (registry.cachedContainerIndex == registry.CachedContainerCount) - registry.cachedContainerIndex = 0; - } - - registry.cachedItemsID[registry.cachedItemsIndex] = item->uuid; - registry.cachedItemsPTR[registry.cachedItemsIndex] = item; - registry.cachedItemsIndex++; - if (registry.cachedItemsIndex == registry.CachedContainerCount) - registry.cachedItemsIndex = 0; -} - static void UpdateChildLocations(std::vector>* children, i32 slots) { @@ -84,683 +62,114 @@ UpdateChildLocations(std::vector>* children, i32 slot } static b8 -DeleteChild(mvAppItem* item, mvUUID uuid) +AddRuntimeChild(mvAppItem* rootitem, mvUUID before, std::shared_ptr item) { - for (auto& childset : item->childslots) + if (before == 0) { - b8 childfound = false; - b8 itemDeleted = false; - - for (auto& child : childset) - { - if (child) - { - if (child->uuid == uuid) - { - childfound = true; - break; - } - - itemDeleted = DeleteChild(child.get(), uuid); - if (itemDeleted) - break; - } - } - - if (childfound) - { - std::vector> oldchildren = childset; - - childset.clear(); - - for (auto& child : oldchildren) - { - if (child) - { - if (child->uuid == uuid) - { - itemDeleted = true; - DearPyGui::OnChildRemoved(item, child); - continue; - } - } - - childset.push_back(child); - } - } - - if (itemDeleted) - { - UpdateChildLocations(item->childslots, 4); - return true; - } - } - - return false; -} - -static b8 -DeleteRoot(std::vector>& roots, mvUUID uuid) -{ - b8 deletedItem = false; - - // try to delete build-in item - for (auto& root : roots) - { - deletedItem = DeleteChild(root.get(), uuid); - if (deletedItem) - break; - } - - if (deletedItem) - return true; - - b8 rootDeleting = false; - - // check if attempting to delete a window - for (auto& window : roots) - { - if (window->uuid == uuid) - { - rootDeleting = true; - break; - } - } - - // delete window and update window vector - // this should be changed to a different data - // structure - if (rootDeleting) - { - std::vector> oldroots = roots; - - roots.clear(); - - for (auto& root : oldroots) - { - if (root->uuid == uuid) - { - deletedItem = true; - continue; - } - roots.push_back(root); - } - + i32 targetSlot = DearPyGui::GetEntityTargetSlot(item->type); + item->info.location = (i32)rootitem->childslots[targetSlot].size(); + rootitem->childslots[targetSlot].push_back(item); + item->info.parentPtr = rootitem; + item->config.parent = rootitem->uuid; + DearPyGui::OnChildAdded(rootitem, item); return true; } - - return false; -} - -static std::shared_ptr -StealChild(mvAppItem* item, mvUUID uuid) -{ - std::shared_ptr stolenChild = nullptr; - - for (auto& childset : item->childslots) - { - b8 childfound = false; - - for (auto& child : childset) - { - if (!child) - continue; - - if (child->uuid == uuid) - { - childfound = true; - break; - } - - if (DearPyGui::GetEntityDesciptionFlags(child->type) & MV_ITEM_DESC_CONTAINER) - { - stolenChild = StealChild(child.get(), uuid); - if (stolenChild) - return stolenChild; - } - } - - if (childfound) - { - std::vector> oldchildren = childset; - - childset.clear(); - - for (auto& child : oldchildren) - { - if (child->uuid == uuid) - { - stolenChild = child; - DearPyGui::OnChildRemoved(item, child); - continue; - } - - childset.push_back(child); - } - - UpdateChildLocations(item->childslots, 4); - - return stolenChild; - } - - - //return static_cast>(std::make_shared("Not possible")); - } - - return stolenChild; -} - -static b8 -MoveRoot(std::vector>& roots, mvUUID uuid, std::shared_ptr& item) -{ - - for (auto& window : roots) - { - item = StealChild(window.get(), uuid); - if (item) - return true; - } - return false; -} - -static b8 -MoveChildUp(mvAppItem* item, mvUUID uuid) -{ - b8 found = false; - i32 index = 0; - - for (auto& childset : item->childslots) - { - // check children - for (size_t i = 0; i < childset.size(); i++) - { - - if (childset[i]->uuid == uuid) - { - found = true; - index = (i32)i; - break; - } - - if (DearPyGui::GetEntityDesciptionFlags(childset[i]->type) & MV_ITEM_DESC_CONTAINER) - { - found = MoveChildUp(childset[i].get(), uuid); - if (found) - return true; - } - - } - - if (found) - { - if (index > 0) - { - auto upperitem = childset[index - 1]; - auto loweritem = childset[index]; - - childset[index] = upperitem; - childset[index - 1] = loweritem; - - UpdateChildLocations(item->childslots, 4); - } - - return true; - } - } - - return false; -} - -static b8 -MoveUpRoot(std::vector>& roots, mvUUID uuid) -{ - for (auto& window : roots) - { - if (MoveChildUp(window.get(), uuid)) - return true; - } - return false; -} - -static b8 -MoveChildDown(mvAppItem* item, mvUUID uuid) -{ - b8 found = false; - size_t index = 0; - - for (auto& childset : item->childslots) - { - // check children - for (size_t i = 0; i < childset.size(); i++) - { - - if (childset[i]->uuid == uuid) - { - found = true; - index = i; - break; - } - - if (DearPyGui::GetEntityDesciptionFlags(childset[i]->type) & MV_ITEM_DESC_CONTAINER) - { - found = MoveChildDown(childset[i].get(), uuid); - if (found) - return true; - } - - } - - if (found) - { - if (index < childset.size() - 1) - { - auto upperitem = childset[index]; - auto loweritem = childset[index + 1]; - - childset[index] = loweritem; - childset[index + 1] = upperitem; - - UpdateChildLocations(item->childslots, 4); - } - - return true; - } - - - } - - return false; -} - -static b8 -MoveDownRoot(std::vector>& roots, mvUUID uuid) -{ - for (auto& window : roots) - { - if (MoveChildDown(window.get(), uuid)) - return true; - } - return false; -} - -static b8 -AddRuntimeChild(mvAppItem* rootitem, mvUUID parent, mvUUID before, std::shared_ptr item) -{ - if (before == 0 && parent == 0) - return false; - - for (auto& children : rootitem->childslots) + else { - //this is the container, add item to end. - if (before == 0) - { - - if (rootitem->uuid == parent) - { - i32 targetSlot = DearPyGui::GetEntityTargetSlot(item->type); - item->info.location = (i32)rootitem->childslots[targetSlot].size(); - rootitem->childslots[targetSlot].push_back(item); - DearPyGui::OnChildAdded(rootitem, item); - item->info.parentPtr = rootitem; - item->config.parent = rootitem->uuid; - return true; - } - - // check children - for (auto& childslot : rootitem->childslots) - { - for (auto& child : childslot) - { - - if (!child) - continue; - - if (DearPyGui::GetEntityDesciptionFlags(child->type) & MV_ITEM_DESC_CONTAINER - || DearPyGui::GetEntityDesciptionFlags(item->type) & MV_ITEM_DESC_HANDLER) - { - // parent found - if (AddRuntimeChild(child.get(), parent, before, item)) - return true; - } - } - } - } - - // this is the container, add item to beginning. - else + for (auto& childslot : rootitem->childslots) { - bool beforeFound = false; - - // check children - for (auto& child : children) + for (auto it = childslot.begin(); it != childslot.end(); ++it) { + auto child = *it; if (!child) continue; if (child->uuid == before) { - beforeFound = true; - break; - } - } - - - // after item is in this container - if (beforeFound) - { - item->info.parentPtr = rootitem; - - std::vector> oldchildren = children; - children.clear(); - - int location = 0; - for (auto& child : oldchildren) - { - if (!child) - continue; - - if (child->uuid == before) - { - children.push_back(item); - item->info.location = location; - DearPyGui::OnChildAdded(rootitem, item); - ++location; - } - children.push_back(child); - ++location; - - } - - // TODO: maybe remove this call since location gets updated inside the loop - UpdateChildLocations(rootitem->childslots, 4); - - return true; - } - } - - // check children - for (auto& child : children) - { - if (!child) - continue; - - if (DearPyGui::GetEntityDesciptionFlags(child->type) & MV_ITEM_DESC_CONTAINER - || DearPyGui::GetEntityDesciptionFlags(item->type) & MV_ITEM_DESC_HANDLER) - { - // parent found - if (AddRuntimeChild(child.get(), parent, before, item)) + childslot.insert(it, item); + item->info.parentPtr = rootitem; + item->config.parent = rootitem->uuid; + // TODO: this one can be optimized by updating locations in the tail + // of the `childslot` only + UpdateChildLocations(&childslot, 1); + DearPyGui::OnChildAdded(rootitem, item); return true; + } } } - - }; - - return false; -} - -static b8 -AddRuntimeChildRoot(std::vector>& roots, mvUUID parent, mvUUID before, std::shared_ptr item) -{ - for (auto& root : roots) - { - if (AddRuntimeChild(root.get(), parent, before, item)) - return true; } + IM_ASSERT(false && "We could not find `before` in its parent's childslots."); return false; - } static b8 -AddChildAfter(mvAppItem* parent, mvUUID prev, std::shared_ptr item) +AddItemAfter(mvItemRegistry& registry, mvUUID prev, std::shared_ptr item) { - if (prev == 0) - return false; - - b8 prevFound = false; - // check children - for (auto& childslot : parent->childslots) + mvAppItem* prevItem = GetItem(registry, prev); + if (!prevItem) { - for (auto& child : childslot) - { - if (!child) - continue; - - if (child->uuid == prev) - { - item->info.parentPtr = parent; - prevFound = true; - break; - } - - } + IM_ASSERT(false && "AddItemAfter could not find prev."); + return false; } - // prev item is in this container - if (prevFound) + mvAppItem* parent = prevItem->info.parentPtr; + if (parent) { - i32 targetSlot = DearPyGui::GetEntityTargetSlot(item->type); - std::vector> oldchildren = parent->childslots[targetSlot]; - parent->childslots[targetSlot].clear(); - - for (auto& child : oldchildren) + for (auto& childset : parent->childslots) { - parent->childslots[targetSlot].push_back(child); - if (child->uuid == prev) + for (auto it = childset.begin(); it != childset.end(); ++it) { - parent->childslots[targetSlot].push_back(item); - DearPyGui::OnChildAdded(parent, item); + if (it->get() == prevItem) + { + ++it; + childset.insert(it, item); + item->info.parentPtr = parent; + item->config.parent = parent->uuid; + UpdateChildLocations(&childset, 1); + DearPyGui::OnChildAdded(parent, item); + return true; + } } } - - return true; - } - - - // check children - for (auto& childslot : parent->childslots) - { - for (auto& child : childslot) - { - if (!child) - continue; - - // parent found - if (AddChildAfter(child.get(), prev, item)) - return true; - } - } - - return false; -} - -static b8 -AddItemAfterRoot(std::vector>& roots, mvUUID prev, std::shared_ptr item) -{ - for (auto& root : roots) - { - if (AddChildAfter(root.get(), prev, item)) - return true; + // This must never happen + IM_ASSERT(false && "Could not find item in parent's childslots."); + return false; } - - return false; -} - -static b8 -AddItemAfter(mvItemRegistry& registry, mvUUID prev, std::shared_ptr item) -{ - - if (AddItemAfterRoot(registry.colormapRoots, prev, item)) return true; - else if (AddItemAfterRoot(registry.filedialogRoots, prev, item)) return true; - else if (AddItemAfterRoot(registry.stagingRoots, prev, item)) return true; - else if (AddItemAfterRoot(registry.viewportMenubarRoots, prev, item)) return true; - else if (AddItemAfterRoot(registry.fontRegistryRoots, prev, item)) return true; - else if (AddItemAfterRoot(registry.handlerRegistryRoots, prev, item)) return true; - else if (AddItemAfterRoot(registry.textureRegistryRoots, prev, item)) return true; - else if (AddItemAfterRoot(registry.valueRegistryRoots, prev, item)) return true; - else if (AddItemAfterRoot(registry.windowRoots, prev, item)) return true; - else if (AddItemAfterRoot(registry.themeRegistryRoots, prev, item)) return true; - else if (AddItemAfterRoot(registry.itemTemplatesRoots, prev, item)) return true; - else if (AddItemAfterRoot(registry.itemHandlerRegistryRoots, prev, item)) return true; - else if (AddItemAfterRoot(registry.viewportDrawlistRoots, prev, item)) return true; - + assert(false); return false; } -static b8 -AddItem(mvItemRegistry& registry, std::shared_ptr item) -{ - mvAppItem* parentitem = TopParent(registry); - item->info.parentPtr = parentitem; - i32 targetSlot = DearPyGui::GetEntityTargetSlot(item->type); - item->info.location = (i32)parentitem->childslots[targetSlot].size(); - parentitem->childslots[targetSlot].push_back(item); - DearPyGui::OnChildAdded(parentitem, item); - return true; -} - -static b8 -AddRuntimeItem(mvItemRegistry& registry, mvUUID parent, mvUUID before, std::shared_ptr item) -{ - - if (AddRuntimeChildRoot(registry.colormapRoots, parent, before, item)) return true; - else if (AddRuntimeChildRoot(registry.filedialogRoots, parent, before, item)) return true; - else if (AddRuntimeChildRoot(registry.stagingRoots, parent, before, item)) return true; - else if (AddRuntimeChildRoot(registry.viewportMenubarRoots, parent, before, item)) return true; - else if (AddRuntimeChildRoot(registry.fontRegistryRoots, parent, before, item)) return true; - else if (AddRuntimeChildRoot(registry.handlerRegistryRoots, parent, before, item)) return true; - else if (AddRuntimeChildRoot(registry.textureRegistryRoots, parent, before, item)) return true; - else if (AddRuntimeChildRoot(registry.valueRegistryRoots, parent, before, item)) return true; - else if (AddRuntimeChildRoot(registry.windowRoots, parent, before, item)) return true; - else if (AddRuntimeChildRoot(registry.themeRegistryRoots, parent, before, item)) return true; - else if (AddRuntimeChildRoot(registry.itemTemplatesRoots, parent, before, item)) return true; - else if (AddRuntimeChildRoot(registry.itemHandlerRegistryRoots, parent, before, item)) return true; - else if (AddRuntimeChildRoot(registry.viewportDrawlistRoots, parent, before, item)) return true; - - return false; -} - -static b8 -AddRoot(mvItemRegistry& registry, std::shared_ptr item) -{ - - if (item->type == mvAppItemType::mvWindowAppItem) registry.windowRoots.push_back(item); - if (item->type == mvAppItemType::mvColorMapRegistry) registry.colormapRoots.push_back(item); - if (item->type == mvAppItemType::mvFileDialog) registry.filedialogRoots.push_back(item); - if (item->type == mvAppItemType::mvStage) registry.stagingRoots.push_back(item); - if (item->type == mvAppItemType::mvViewportMenuBar) registry.viewportMenubarRoots.push_back(item); - if (item->type == mvAppItemType::mvFontRegistry) registry.fontRegistryRoots.push_back(item); - if (item->type == mvAppItemType::mvHandlerRegistry) registry.handlerRegistryRoots.push_back(item); - if (item->type == mvAppItemType::mvTextureRegistry) registry.textureRegistryRoots.push_back(item); - if (item->type == mvAppItemType::mvValueRegistry) registry.valueRegistryRoots.push_back(item); - if (item->type == mvAppItemType::mvTheme) registry.themeRegistryRoots.push_back(item); - if (item->type == mvAppItemType::mvTemplateRegistry) registry.itemTemplatesRoots.push_back(item); - if (item->type == mvAppItemType::mvItemHandlerRegistry) registry.itemHandlerRegistryRoots.push_back(item); - if (item->type == mvAppItemType::mvViewportDrawlist) registry.viewportDrawlistRoots.push_back(item); - - return true; -} - -static mvAppItem* -GetChild(mvAppItem* rootitem, mvUUID uuid) -{ - - if (rootitem->uuid == uuid) - return rootitem; - - if (rootitem->config.searchLast) - { - if (rootitem->config.searchDelayed) - rootitem->config.searchDelayed = false; - else - { - rootitem->config.searchDelayed = true; - DelaySearch(*GContext->itemRegistry, rootitem); - } - } - - for (auto& childset : rootitem->childslots) - { - for (auto& childitem : childset) - { - if (!childitem) - continue; - - if (childitem->uuid == uuid) - return childitem.get(); - - auto child = GetChild(childitem.get(), uuid); - if (child) - return child; - } - } - - return nullptr; -} - -static std::shared_ptr -GetChildRef(mvAppItem* rootitem, mvUUID uuid) +static std::vector>& +GetRootsList(mvItemRegistry& registry, mvAppItemType type) { - - for (auto& childset : rootitem->childslots) + switch (type) { - for (auto& item : childset) - { - - if (!item) - continue; - - if (item->uuid == uuid) - return item; - - auto child = GetChildRef(item.get(), uuid); - if (child) - return child; - } + case mvAppItemType::mvWindowAppItem: return registry.windowRoots; + case mvAppItemType::mvColorMapRegistry: return registry.colormapRoots; + case mvAppItemType::mvFileDialog: return registry.filedialogRoots; + case mvAppItemType::mvStage: return registry.stagingRoots; + case mvAppItemType::mvViewportMenuBar: return registry.viewportMenubarRoots; + case mvAppItemType::mvFontRegistry: return registry.fontRegistryRoots; + case mvAppItemType::mvHandlerRegistry: return registry.handlerRegistryRoots; + case mvAppItemType::mvTextureRegistry: return registry.textureRegistryRoots; + case mvAppItemType::mvValueRegistry: return registry.valueRegistryRoots; + case mvAppItemType::mvTheme: return registry.themeRegistryRoots; + case mvAppItemType::mvTemplateRegistry: return registry.itemTemplatesRoots; + case mvAppItemType::mvItemHandlerRegistry: return registry.itemHandlerRegistryRoots; + case mvAppItemType::mvViewportDrawlist: return registry.viewportDrawlistRoots; } - - return nullptr; + // We must never end up here + IM_ASSERT(false && "A root container does not have a corresponding list in GetRootsList."); + return registry.windowRoots; } -static mvAppItem* -GetItemRoot(mvItemRegistry& registry, std::vector>& roots, mvUUID uuid) +static void +AddRoot(mvItemRegistry& registry, std::shared_ptr item) { - for (auto& root : roots) - { - if (root->uuid == uuid) - { - CacheItem(registry, root.get()); - return root.get(); - } - - mvAppItem* child = GetChild(root.get(), uuid); - if (child) - { - CacheItem(registry, child); - registry.delayedSearch.clear(); - return child; - } - } - - return nullptr; -} - -static std::shared_ptr -GetRefItemRoot(std::vector>& roots, mvUUID uuid) -{ - - for (auto& root : roots) - { - if (root->uuid == uuid) - return root; - - auto child = GetChildRef(root.get(), uuid); - if (child) - return child; - } - - return nullptr; + auto& roots = GetRootsList(registry, item->type); + roots.push_back(item); } static void @@ -826,63 +235,105 @@ GetItemRoot(mvItemRegistry& registry, mvUUID uuid) return nullptr; } -b8 -DeleteItem(mvItemRegistry& registry, mvUUID uuid, b8 childrenOnly, i32 slot) +// Disconnects the item from its parent by removing it from the parent's childslot. +// For root items, removes it from the "parent" list of roots. +// When called on an item that's in the tree, must never return false. The return +// value is only intended to catch internal errors when the item registry is broken. +// Note: it does *not* reset item->info.parentPtr! +static bool +RemoveItemFromTree(mvItemRegistry& registry, mvAppItem* item) { - - CleanUpItem(registry, uuid); - - // delete item's children only - if(childrenOnly) + mvAppItem* parent = item->info.parentPtr; + if (parent) { - auto item = GetItem(registry, uuid); - if (item) + for (auto& childset : parent->childslots) { - if (slot > -1 && slot < 4) - { - item->childslots[slot].clear(); - } - else + for (auto it = childset.begin(); it != childset.end(); ++it) { - for(size_t i = 0; i < 4; i++) + if (it->get() == item) { - item->childslots[i].clear(); + auto child = *it; + childset.erase(it); + // TODO: this one can be optimized by updating locations in the tail + // of the `childset` only + UpdateChildLocations(&childset, 1); + DearPyGui::OnChildRemoved(parent, child); + return true; } } - - if(item->type == mvAppItemType::mvTable) - static_cast(item)->onChildrenRemoved(); + } + // This must never happen + IM_ASSERT(false && "Could not find item in parent's childslots."); + return false; + } + // Now this is a root item + IM_ASSERT((DearPyGui::GetEntityDesciptionFlags(item->type) & MV_ITEM_DESC_ROOT) && "Item is neither a child nor a root."); + + auto& roots = GetRootsList(registry, item->type); + for (auto it = roots.begin(); it != roots.end(); ++it) + { + if (it->get() == item) + { + roots.erase(it); return true; } } - bool deletedItem = false; - - if (DeleteRoot(registry.colormapRoots, uuid)) deletedItem = true; - else if (DeleteRoot(registry.filedialogRoots, uuid)) deletedItem = true; - else if (DeleteRoot(registry.stagingRoots, uuid)) deletedItem = true; - else if (DeleteRoot(registry.viewportMenubarRoots, uuid)) deletedItem = true; - else if (DeleteRoot(registry.fontRegistryRoots, uuid)) deletedItem = true; - else if (DeleteRoot(registry.handlerRegistryRoots, uuid)) deletedItem = true; - else if (DeleteRoot(registry.textureRegistryRoots, uuid)) deletedItem = true; - else if (DeleteRoot(registry.valueRegistryRoots, uuid)) deletedItem = true; - else if (DeleteRoot(registry.windowRoots, uuid)) deletedItem = true; - else if (DeleteRoot(registry.themeRegistryRoots, uuid)) deletedItem = true; - else if (DeleteRoot(registry.itemTemplatesRoots, uuid)) deletedItem = true; - else if (DeleteRoot(registry.itemHandlerRegistryRoots, uuid)) deletedItem = true; - else if (DeleteRoot(registry.viewportDrawlistRoots, uuid)) deletedItem = true; - - if (deletedItem) + // This must never happen + IM_ASSERT(false && "Could not find a root item in the corresponding roots list."); + return false; +} + +b8 +DeleteItem(mvItemRegistry& registry, mvUUID uuid, b8 childrenOnly, i32 slot) +{ + mvAppItem* item = GetItem(registry, uuid); + if (!item) { - RemoveDebugWindow(registry, uuid); - } - else mvThrowPythonError(mvErrorCode::mvItemNotFound, "delete_item", "Item not found: " + std::to_string(uuid), nullptr); + return false; + } + + // delete item's children only + if (childrenOnly) + { + if (slot > -1 && slot < 4) + { + item->childslots[slot].clear(); + } + else + { + for(size_t i = 0; i < 4; i++) + { + item->childslots[i].clear(); + } + } + + if(item->type == mvAppItemType::mvTable) + static_cast(item)->onChildrenRemoved(); + + return true; + } + + // See if it is the captured item + if (registry.capturedItem && registry.capturedItem.get() == item) + { + registry.capturedItem = nullptr; + return true; + } - assert(deletedItem && "Item to delete not found"); - return deletedItem; + // Now this is just a regular item in the tree + RemoveDebugWindow(registry, uuid); + if (!RemoveItemFromTree(registry, item)) + { + mvThrowPythonError(mvErrorCode::mvItemNotFound, "delete_item", + "Unable to delete item: " + std::to_string(uuid), item); + return false; + } + + return true; } b8 @@ -891,119 +342,161 @@ MoveItem(mvItemRegistry& registry, mvUUID uuid, mvUUID parent, mvUUID before) std::shared_ptr child = nullptr; - b8 movedItem = false; - - if(registry.capturedItem) - { - if(registry.capturedItem->uuid == uuid) - { - child = registry.capturedItem; - movedItem = true; - registry.capturedItem = nullptr; - } - - } - - if(!movedItem) + if (registry.capturedItem && registry.capturedItem->uuid == uuid) { - if (MoveRoot(registry.colormapRoots, uuid, child)) movedItem = true; - else if (MoveRoot(registry.filedialogRoots, uuid, child)) movedItem = true; - else if (MoveRoot(registry.stagingRoots, uuid, child)) movedItem = true; - else if (MoveRoot(registry.viewportMenubarRoots, uuid, child)) movedItem = true; - else if (MoveRoot(registry.fontRegistryRoots, uuid, child)) movedItem = true; - else if (MoveRoot(registry.handlerRegistryRoots, uuid, child)) movedItem = true; - else if (MoveRoot(registry.textureRegistryRoots, uuid, child)) movedItem = true; - else if (MoveRoot(registry.valueRegistryRoots, uuid, child)) movedItem = true; - else if (MoveRoot(registry.windowRoots, uuid, child)) movedItem = true; - else if (MoveRoot(registry.themeRegistryRoots, uuid, child)) movedItem = true; - else if (MoveRoot(registry.itemTemplatesRoots, uuid, child)) movedItem = true; - else if (MoveRoot(registry.itemHandlerRegistryRoots, uuid, child)) movedItem = true; - else if (MoveRoot(registry.viewportDrawlistRoots, uuid, child)) movedItem = true; + child = registry.capturedItem; + registry.capturedItem = nullptr; } - - if (child == nullptr) + else { - mvThrowPythonError(mvErrorCode::mvItemNotFound, "move_item", - "Item not found: " + std::to_string(uuid), nullptr); + child = GetRefItem(registry, uuid); + if (child == nullptr) + { + mvThrowPythonError(mvErrorCode::mvItemNotFound, "move_item", + "Item not found: " + std::to_string(uuid), nullptr); + return false; + } + // Remove it from its current location in the tree + RemoveItemFromTree(registry, child.get()); } - if (child) - AddRuntimeItem(registry, parent, before, child); + // Resetting parent item or otherwise AddItemWithRuntimeChecks might fall back + // to the previously stored value. + child->config.parent = 0; - return movedItem; + // TODO: AddItemWithRuntimeChecks will refuse to add items with state.ok == false, + // which includes fonts and textures that failed to load. Fix this. + return AddItemWithRuntimeChecks(registry, child, parent, before); } b8 MoveItemUp(mvItemRegistry& registry, mvUUID uuid) { - - b8 movedItem = false; - - if (MoveUpRoot(registry.colormapRoots, uuid)) movedItem = true; - else if (MoveUpRoot(registry.filedialogRoots, uuid)) movedItem = true; - else if (MoveUpRoot(registry.stagingRoots, uuid)) movedItem = true; - else if (MoveUpRoot(registry.viewportMenubarRoots, uuid)) movedItem = true; - else if (MoveUpRoot(registry.fontRegistryRoots, uuid)) movedItem = true; - else if (MoveUpRoot(registry.handlerRegistryRoots, uuid)) movedItem = true; - else if (MoveUpRoot(registry.textureRegistryRoots, uuid)) movedItem = true; - else if (MoveUpRoot(registry.valueRegistryRoots, uuid)) movedItem = true; - else if (MoveUpRoot(registry.windowRoots, uuid)) movedItem = true; - else if (MoveUpRoot(registry.themeRegistryRoots, uuid)) movedItem = true; - else if (MoveUpRoot(registry.itemTemplatesRoots, uuid)) movedItem = true; - else if (MoveUpRoot(registry.itemHandlerRegistryRoots, uuid)) movedItem = true; - else if (MoveUpRoot(registry.viewportDrawlistRoots, uuid)) movedItem = true; - - if (!movedItem) + mvAppItem* item = GetItem(registry, uuid); + if (!item) { - mvThrowPythonError(mvErrorCode::mvItemNotFound, "move_item", + mvThrowPythonError(mvErrorCode::mvItemNotFound, "move_item_up", "Item not found: " + std::to_string(uuid), nullptr); + return false; } - assert(movedItem && "Item to move not found"); + mvAppItem* parent = item->info.parentPtr; + if (parent) + { + for (auto& childset : parent->childslots) + { + for (auto it = childset.begin(), prev_it = childset.begin(); it != childset.end(); ++it) + { + if (it->get() == item) + { + if (it != childset.begin()) + { + // Swapping locations so that we don't need to recalculate them on all children + std::swap((*prev_it)->info.location, (*it)->info.location); + // Now swap the child items themselves + std::iter_swap(prev_it, it); + } + return true; + } + prev_it = it; + } + } + // This must never happen + IM_ASSERT(false && "Could not find item in parent's childslots."); + mvThrowPythonError(mvErrorCode::mvItemNotFound, "move_item_up", + "Unable to move item: " + std::to_string(uuid), item); + return false; + } - return movedItem; + // This is probably a root item, but we don't support moving roots up/down. + // It has never worked on roots, and actually has little sense. + mvThrowPythonError(mvErrorCode::mvItemNotFound, "move_item_up", + "move_item_up for root items is not supported", item); + return false; } b8 MoveItemDown(mvItemRegistry& registry, mvUUID uuid) { - - b8 movedItem = false; - - if (MoveDownRoot(registry.colormapRoots, uuid)) movedItem = true; - else if (MoveDownRoot(registry.filedialogRoots, uuid)) movedItem = true; - else if (MoveDownRoot(registry.stagingRoots, uuid)) movedItem = true; - else if (MoveDownRoot(registry.viewportMenubarRoots, uuid)) movedItem = true; - else if (MoveDownRoot(registry.fontRegistryRoots, uuid)) movedItem = true; - else if (MoveDownRoot(registry.handlerRegistryRoots, uuid)) movedItem = true; - else if (MoveDownRoot(registry.textureRegistryRoots, uuid)) movedItem = true; - else if (MoveDownRoot(registry.valueRegistryRoots, uuid)) movedItem = true; - else if (MoveDownRoot(registry.windowRoots, uuid)) movedItem = true; - else if (MoveDownRoot(registry.themeRegistryRoots, uuid)) movedItem = true; - else if (MoveDownRoot(registry.itemTemplatesRoots, uuid)) movedItem = true; - else if (MoveDownRoot(registry.itemHandlerRegistryRoots, uuid)) movedItem = true; - else if (MoveDownRoot(registry.viewportDrawlistRoots, uuid)) movedItem = true; - - if (!movedItem) + mvAppItem* item = GetItem(registry, uuid); + if (!item) { - mvThrowPythonError(mvErrorCode::mvItemNotFound, "move_item", + mvThrowPythonError(mvErrorCode::mvItemNotFound, "move_item_down", "Item not found: " + std::to_string(uuid), nullptr); + return false; + } + + mvAppItem* parent = item->info.parentPtr; + if (parent) + { + for (auto& childset : parent->childslots) + { + for (auto it = childset.begin(); it != childset.end(); ++it) + { + if (it->get() == item) + { + auto next_it = std::next(it); + if (next_it != childset.end()) + { + // Swapping locations so that we don't need to recalculate them on all children + std::swap((*it)->info.location, (*next_it)->info.location); + // Now swap the child items themselves + std::iter_swap(it, next_it); + } + return true; + } + } + } + // This must never happen + IM_ASSERT(false && "Could not find item in parent's childslots."); + mvThrowPythonError(mvErrorCode::mvItemNotFound, "move_item_down", + "Unable to move item: " + std::to_string(uuid), item); + return false; } - assert(movedItem && "Item to move not found"); + // This is probably a root item, but we don't support moving roots up/down. + // It has never worked on roots, and actually has little sense. + mvThrowPythonError(mvErrorCode::mvItemNotFound, "move_item_down", + "move_item_down for root items is not supported", item); + return false; +} - return movedItem; +b8 +ReorderChildren(mvItemRegistry& registry, mvUUID parent, i32 slot, const std::vector& new_order) +{ + mvAppItem* parentItem = GetItem(registry, parent); + if (parentItem == nullptr) + { + mvThrowPythonError(mvErrorCode::mvItemNotFound, "reorder_items", + "Item not found: " + std::to_string(parent), nullptr); + return false; + } + + std::vector>& children = parentItem->childslots[slot]; + + std::vector> newchildren; + newchildren.reserve(children.size()); + + // todo: better sorting algorithm + for (const auto& item : new_order) + { + for (auto& child : children) + { + if (child->uuid == item) + { + newchildren.emplace_back(child); + break; + } + } + } + children = newchildren; + UpdateChildLocations(&children, 1); + return true; } void RenderItemRegistry(mvItemRegistry& registry) { - // TODO: figure out why delayedSearch can - // still have values (sometimes). - // It should be empty after every search. - if(!registry.delayedSearch.empty()) - registry.delayedSearch.clear(); - MV_PROFILE_SCOPE("Rendering") if(registry.showImGuiDebug) @@ -1120,7 +613,7 @@ RenderItemRegistry(mvItemRegistry& registry) DebugItem("Enabled:", root->config.enabled ? ts : fs); DebugItem("Tracked:", root->config.tracked ? ts : fs); DebugItem("Callback:", root->config.callback ? ts : fs); - DebugItem("User Data:", root->config.user_data ? ts : fs); + DebugItem("User Data:", *(root->config.user_data) ? ts : fs); DebugItem("Drop Callback:", root->config.dropCallback ? ts : fs); DebugItem("Drag Callback:", root->config.dragCallback ? ts : fs); @@ -1172,88 +665,22 @@ ResetTheme(mvItemRegistry& registry) root->config.show = false; } -void -DelaySearch(mvItemRegistry& registry, mvAppItem* item) -{ - registry.delayedSearch.push_back(item); -} - mvAppItem* GetItem(mvItemRegistry& registry, mvUUID uuid) { // check captured - if(registry.capturedItem) - { - if(registry.capturedItem->uuid == uuid) - return registry.capturedItem.get(); - } - - // check cache - for (i32 i = 0; i < registry.CachedContainerCount; i++) - { - if (registry.cachedContainersID[i] == uuid) - return registry.cachedContainersPTR[i]; - if (registry.cachedItemsID[i] == uuid) - return registry.cachedItemsPTR[i]; - } - - if (auto foundItem = GetItemRoot(registry, registry.colormapRoots, uuid)) return foundItem; - if (auto foundItem = GetItemRoot(registry, registry.colormapRoots, uuid)) return foundItem; - if (auto foundItem = GetItemRoot(registry, registry.filedialogRoots, uuid)) return foundItem; - if (auto foundItem = GetItemRoot(registry, registry.stagingRoots, uuid)) return foundItem; - if (auto foundItem = GetItemRoot(registry, registry.viewportMenubarRoots, uuid)) return foundItem; - if (auto foundItem = GetItemRoot(registry, registry.fontRegistryRoots, uuid)) return foundItem; - if (auto foundItem = GetItemRoot(registry, registry.handlerRegistryRoots, uuid)) return foundItem; - if (auto foundItem = GetItemRoot(registry, registry.textureRegistryRoots, uuid)) return foundItem; - if (auto foundItem = GetItemRoot(registry, registry.valueRegistryRoots, uuid)) return foundItem; - if (auto foundItem = GetItemRoot(registry, registry.windowRoots, uuid)) return foundItem; - if (auto foundItem = GetItemRoot(registry, registry.themeRegistryRoots, uuid)) return foundItem; - if (auto foundItem = GetItemRoot(registry, registry.itemTemplatesRoots, uuid)) return foundItem; - if (auto foundItem = GetItemRoot(registry, registry.itemHandlerRegistryRoots, uuid)) return foundItem; - if (auto foundItem = GetItemRoot(registry, registry.viewportDrawlistRoots, uuid)) return foundItem; - - for (auto delayedItem : registry.delayedSearch) - { - mvAppItem* child = GetChild(delayedItem, uuid); - if (child) - { - CacheItem(registry, child); - registry.delayedSearch.clear(); - return child; - } - } + if (registry.capturedItem && registry.capturedItem->uuid == uuid) + return registry.capturedItem.get(); - registry.delayedSearch.clear(); - - return nullptr; + auto found = registry.allItems.find(uuid); + return found != registry.allItems.end()? found->second : nullptr; } std::shared_ptr GetRefItem(mvItemRegistry& registry, mvUUID uuid) { - - // check captured - if(registry.capturedItem) - { - if(registry.capturedItem->uuid == uuid) - return registry.capturedItem; - } - - if (auto foundItem = GetRefItemRoot(registry.colormapRoots, uuid)) return foundItem; - else if (auto foundItem = GetRefItemRoot(registry.filedialogRoots, uuid)) return foundItem; - else if (auto foundItem = GetRefItemRoot(registry.stagingRoots, uuid)) return foundItem; - else if (auto foundItem = GetRefItemRoot(registry.viewportMenubarRoots, uuid)) return foundItem; - else if (auto foundItem = GetRefItemRoot(registry.fontRegistryRoots, uuid)) return foundItem; - else if (auto foundItem = GetRefItemRoot(registry.handlerRegistryRoots, uuid)) return foundItem; - else if (auto foundItem = GetRefItemRoot(registry.textureRegistryRoots, uuid)) return foundItem; - else if (auto foundItem = GetRefItemRoot(registry.valueRegistryRoots, uuid)) return foundItem; - else if (auto foundItem = GetRefItemRoot(registry.windowRoots, uuid)) return foundItem; - else if (auto foundItem = GetRefItemRoot(registry.themeRegistryRoots, uuid)) return foundItem; - else if (auto foundItem = GetRefItemRoot(registry.itemTemplatesRoots, uuid)) return foundItem; - else if (auto foundItem = GetRefItemRoot(registry.itemHandlerRegistryRoots, uuid)) return foundItem; - else if (auto foundItem = GetRefItemRoot(registry.viewportDrawlistRoots, uuid)) return foundItem; - - return nullptr; + mvAppItem* item = GetItem(registry, uuid); + return item? item->shared_from_this() : nullptr; } mvWindowAppItem* @@ -1270,7 +697,7 @@ GetWindow(mvItemRegistry& registry, mvUUID uuid) if (item->type == mvAppItemType::mvWindowAppItem) return static_cast(item); - assert(false && "Item is not a window not found."); + assert(false && "Item is not a window."); return nullptr; } @@ -1292,25 +719,6 @@ ClearItemRegistry(mvItemRegistry& registry) registry.viewportDrawlistRoots.clear(); } -void -CleanUpItem(mvItemRegistry& registry, mvUUID uuid) -{ - for (i32 i = 0; i < registry.CachedContainerCount; i++) - { - if (registry.cachedContainersID[i] == uuid) - { - registry.cachedContainersID[i] = 0; - registry.cachedContainersPTR[i] = nullptr; - } - - if (registry.cachedItemsID[i] == uuid) - { - registry.cachedItemsID[i] = 0; - registry.cachedItemsPTR[i] = nullptr; - } - } -} - b8 AddItemWithRuntimeChecks(mvItemRegistry& registry, std::shared_ptr item, mvUUID parent, mvUUID before) { @@ -1320,15 +728,14 @@ AddItemWithRuntimeChecks(mvItemRegistry& registry, std::shared_ptr it // this is a unique situation in that the caller always has the GIL registry.capturedItem = item; - mvRunCallback(registry.captureCallback, registry.capturedItem->uuid, nullptr, nullptr); - Py_XDECREF(registry.captureCallback); + // resetting captureCallback in advance in order to avoid recursion (if the callback + // attempts to add another item or move an item) + mvPyObject captureCallback(std::move(registry.captureCallback)); registry.captureCallback = nullptr; + mvRunCallback(captureCallback, nullptr, registry.capturedItem->uuid); return true; } - if (DearPyGui::GetEntityDesciptionFlags(item->type) & MV_ITEM_DESC_HANDLER && parent == 0) - parent = item->config.parent; - if (item == nullptr) return false; @@ -1336,8 +743,10 @@ AddItemWithRuntimeChecks(mvItemRegistry& registry, std::shared_ptr it if (!item->state.ok) return false; + mvPySafeLockGuard lk(GContext->mutex); + //--------------------------------------------------------------------------- - // STEP 0: updata "last" information + // STEP 0: update "last" information //--------------------------------------------------------------------------- if (DearPyGui::GetEntityDesciptionFlags(item->type) & MV_ITEM_DESC_ROOT) { @@ -1349,8 +758,6 @@ AddItemWithRuntimeChecks(mvItemRegistry& registry, std::shared_ptr it registry.lastItemAdded = item->uuid; - CacheItem(registry, item.get()); - //--------------------------------------------------------------------------- // STEP 1: check if an item with this name exists (NO LONGER NEEDED) //--------------------------------------------------------------------------- @@ -1362,65 +769,56 @@ AddItemWithRuntimeChecks(mvItemRegistry& registry, std::shared_ptr it // return false; //} - enum class AddTechnique - { - NONE, STAGE, BEFORE, PARENT, STACK - }; - AddTechnique technique = AddTechnique::NONE; - - std::lock_guard lk(GContext->mutex); - //--------------------------------------------------------------------------- // STEP 2: handle root case //--------------------------------------------------------------------------- if (DearPyGui::GetEntityDesciptionFlags(item->type) & MV_ITEM_DESC_ROOT) { - - if (GContext->started) - { - AddRoot(registry, item); - return true; - } - return AddRoot(registry, item); + AddRoot(registry, item); + return true; } //--------------------------------------------------------------------------- // STEP 3: attempt to deduce parent //--------------------------------------------------------------------------- + if (item->type == mvAppItemType::mvTooltip && parent == 0) + parent = item->config.parent; + mvAppItem* parentPtr = nullptr; if (before > 0) { - + // Adding it before the "before" item - let's find it! mvAppItem* beforeItem = GetItem(registry, before); - if (beforeItem) - parentPtr = beforeItem->info.parentPtr; - technique = AddTechnique::BEFORE; + if (beforeItem == nullptr) + { + mvThrowPythonError(mvErrorCode::mvItemNotFound, "add_*", "Item not found: " + std::to_string(parent), nullptr); + IM_ASSERT(false && "The 'before' item could not be found."); + return false; + } + // We'll need the parent anyway in order to check compatibility + parentPtr = beforeItem->info.parentPtr; } - else if (parent > MV_RESERVED_UUID_start + MV_RESERVED_UUIDs) + else if (parent >= MV_START_UUID) { + // Append to children of the specified parent parentPtr = GetItem(registry, parent); - technique = AddTechnique::PARENT; } else if (parent == 0) { + // Take the parent from stack and add to the end parentPtr = TopParent(registry); - technique = AddTechnique::STACK; } // reserved uuid case else { parentPtr = GetItem(registry, parent); - if (parentPtr) - technique = AddTechnique::PARENT; - - // revert to stack operation (reserved uuid not used) - else + if (!parentPtr) { + // revert to stack operation (reserved uuid not used) parentPtr = TopParent(registry); - technique = AddTechnique::STACK; } } @@ -1515,9 +913,10 @@ AddItemWithRuntimeChecks(mvItemRegistry& registry, std::shared_ptr it //--------------------------------------------------------------------------- if (item->type == mvAppItemType::mvTooltip) { - if (parentPtr->info.parentPtr->type == mvAppItemType::mvTable) + mvAppItem* prevItemParent = parentPtr->info.parentPtr; + if (prevItemParent && prevItemParent->type == mvAppItemType::mvTable) { - parentPtr->info.parentPtr->childslots[2][parentPtr->info.location] = item; + prevItemParent->childslots[2][parentPtr->info.location] = item; return true; } else @@ -1527,17 +926,9 @@ AddItemWithRuntimeChecks(mvItemRegistry& registry, std::shared_ptr it } //--------------------------------------------------------------------------- - // STEP 8: handle "before" and "after" style adding - //--------------------------------------------------------------------------- - if (technique == AddTechnique::BEFORE || technique == AddTechnique::PARENT) - return AddRuntimeChild(parentPtr, parent, before, item); // same for run/compile time - - //--------------------------------------------------------------------------- - // STEP 9: handle "stack" style adding + // STEP 8: Either append it to parent's children or insert before the "before" //--------------------------------------------------------------------------- - if(GContext->started) - return AddRuntimeChild(parentPtr, parentPtr->uuid, 0, item); - return AddItem(registry, item); + return AddRuntimeChild(parentPtr, before, item); } void diff --git a/src/mvItemRegistry.h b/src/mvItemRegistry.h index e6a30b89c..65fd44738 100644 --- a/src/mvItemRegistry.h +++ b/src/mvItemRegistry.h @@ -24,7 +24,6 @@ void RenderItemRegistry(mvItemRegistry& registry); // cleanup void ClearItemRegistry(mvItemRegistry& registry); -void CleanUpItem (mvItemRegistry& registry, mvUUID uuid); b8 DeleteItem (mvItemRegistry& registry, mvUUID uuid, b8 childrenOnly = false, i32 slot = -1); // aliases @@ -39,15 +38,17 @@ b8 MoveItemDown(mvItemRegistry& registry, mvUUID uuid); // item retrieval mvUUID GetIDFromPyObject(PyObject* item); +// Note: this function is *not* threadsafe and must be called with mvContext::mutex locked mvAppItem* GetItem (mvItemRegistry& registry, mvUUID uuid); +// Note: this function is *not* threadsafe and must be called with mvContext::mutex locked std::shared_ptr GetRefItem (mvItemRegistry& registry, mvUUID uuid); mvWindowAppItem* GetWindow (mvItemRegistry& registry, mvUUID uuid); mvAppItem* GetItemRoot (mvItemRegistry& registry, mvUUID uuid); // item operations -void DelaySearch (mvItemRegistry& registry, mvAppItem* item); b8 AddItemWithRuntimeChecks(mvItemRegistry& registry, std::shared_ptr item, mvUUID parent, mvUUID before); void ResetTheme (mvItemRegistry& registry); +b8 ReorderChildren (mvItemRegistry& registry, mvUUID parent, i32 slot, const std::vector& new_order); //----------------------------------------------------------------------------- // mvItemRegistry @@ -62,29 +63,21 @@ void ResetTheme (mvItemRegistry& registry); struct mvItemRegistry { - static constexpr i32 CachedContainerCount = 25; - - // caching + // "last item" state mvUUID lastItemAdded = 0; mvUUID lastContainerAdded = 0; mvUUID lastRootAdded = 0; - i32 cachedContainerIndex = 0; - i32 cachedItemsIndex = 0; - mvUUID cachedItemsID[CachedContainerCount]; - mvAppItem* cachedItemsPTR[CachedContainerCount]; - mvUUID cachedContainersID[CachedContainerCount]; - mvAppItem* cachedContainersPTR[CachedContainerCount]; // misc std::stack containers; // parent stack, top of stack becomes widget's parent std::unordered_map aliases; - std::vector delayedSearch; + std::unordered_map allItems; // used for quick access to items by UUID b8 showImGuiDebug = false; b8 showImPlotDebug = false; std::vector> debugWindows; std::shared_ptr capturedItem = nullptr; - PyObject* captureCallback = nullptr; - PyObject* captureCallbackUserData = nullptr; + mvPyObject captureCallback = nullptr; + mvPyObject captureCallbackUserData = nullptr; // roots std::vector> colormapRoots; diff --git a/src/mvLayoutWindow.cpp b/src/mvLayoutWindow.cpp index 54bb78eb4..1e510f0e9 100644 --- a/src/mvLayoutWindow.cpp +++ b/src/mvLayoutWindow.cpp @@ -2,6 +2,9 @@ #include #include "mvContext.h" #include "mvItemRegistry.h" +#include "mvFontItems.h" +#include "mvThemes.h" +#include static void DebugItem(const char* label, const char* item) { @@ -10,6 +13,31 @@ DebugItem(const char* label, const char* item) { ImGui::TextColored(ImVec4(1.0f, 0.0f, 1.0f, 1.0f), "%s", item); } +static void +DebugItem(const char* label, float value) { + ImGui::Text("%s", label); + ImGui::SameLine(); + ImGui::TextColored(ImVec4(1.0f, 0.0f, 1.0f, 1.0f), "%g", value); +} + +static void +DebugItem(const char* label, mvVec2 value) { + ImGui::Text("%s", label); + ImGui::SameLine(); + ImGui::TextColored(ImVec4(1.0f, 0.0f, 1.0f, 1.0f), "(%g, %g)", value.x, value.y); +} + +static void +DebugItem(const char* label, bool value) { + DebugItem(label, value? "True" : "False"); +} + +static void InfoHeader(const char* label) { + ImGui::NewLine(); + ImGui::Text("%s", label); + ImGui::Separator(); +} + mvLayoutWindow::mvLayoutWindow() { m_windowflags = ImGuiWindowFlags_NoSavedSettings; @@ -18,11 +46,30 @@ mvLayoutWindow::mvLayoutWindow() void mvLayoutWindow::renderRootCategory(const char* category, std::vector>& roots) { - const auto node_flags = ImGuiTreeNodeFlags_OpenOnArrow | (roots.empty() ? ImGuiTreeNodeFlags_Leaf : 0); + const auto node_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | (roots.empty() ? ImGuiTreeNodeFlags_Leaf : 0); ImGui::PushID(&roots); + + if (_expandToSelected) + { + for (auto& root : roots) + { + if (root->uuid == m_selectedItem || _itemsToExpand.count(root->uuid) > 0) + { + ImGui::SetNextItemOpen(true); + break; + } + } + } + const auto expanded = ImGui::TreeNodeEx(category, node_flags); + if (!roots.empty()) + { + ImGui::SameLine(); + ImGui::TextColored({0.7f, 0.7f, 0.7f, 1.0f}, "(%zd)", roots.size()); + } + if (expanded) { for (auto& root : roots) @@ -38,16 +85,32 @@ void mvLayoutWindow::renderTreeNode(std::shared_ptr& item) // build up flags for current node const auto node_flags = ImGuiTreeNodeFlags_OpenOnArrow + | ImGuiTreeNodeFlags_OpenOnDoubleClick | ((item->uuid == m_selectedItem) ? ImGuiTreeNodeFlags_Selected : 0) | (DearPyGui::GetEntityDesciptionFlags(item->type) & MV_ITEM_DESC_CONTAINER ? 0 : ImGuiTreeNodeFlags_Leaf); // render this node ImGui::PushID(item.get()); - std::string labelToShow = DearPyGui::GetEntityTypeString(item->type); + std::string labelToShow; + // Remember whether we have a custom name for this item, like a label or a tag. + // Otherwise we'll have to show its type name instead, which is not as descriptive. + bool is_labeled = true; if (!item->config.alias.empty()) labelToShow = item->config.alias; else if (!item->config.specifiedLabel.empty()) labelToShow = item->config.specifiedLabel; + else + { + is_labeled = false; + labelToShow = DearPyGui::GetEntityTypeString(item->type); + constexpr const char* prefix = "mvAppItemType::"; + // This is a cumbersome way to get string length, but it's the only way + // that provides a constexpr (note: strlen() is not a constexpr). + // Well, we could also do a `sizeof(prefix) - 1`... + constexpr size_t prefix_len = std::char_traits::length(prefix); + if (labelToShow.compare(0, prefix_len, prefix) == 0) + labelToShow.erase(0, prefix_len); + } if (!_imguiFilter.PassFilter(labelToShow.c_str()) && _startFiltering) @@ -56,8 +119,59 @@ void mvLayoutWindow::renderTreeNode(std::shared_ptr& item) return; } + bool expandThisNode = (_expandToSelected && _itemsToExpand.count(item->uuid) > 0); + if (expandThisNode) + { + ImGui::SetNextItemOpen(true); + } + + // TODO: add a flag to GetEntityDesciptionFlags for this + bool is_bindable = (item->type == mvAppItemType::mvTheme || + item->type == mvAppItemType::mvItemHandlerRegistry || + item->type == mvAppItemType::mvFont ); + + // An unused/orhpaned bindable? (note that we might be holding 1 ref to item) + bool is_lonely = (is_bindable && item.use_count() <= (1 + (item == _itemref? 1 : 0))); + + // An extra check for some elements that can have global refs *not* shared + // via shared_ptr. + // - the global theme is the only one that has config.show == true + // - the global font is the only one having _default == true + if (is_lonely && ( + (item->type == mvAppItemType::mvTheme && item->config.show) || + (item->type == mvAppItemType::mvFont && (static_cast(item.get()))->_default))) + { + // It's bound as a global entity and therefore is not lonely + is_lonely = false; + } + + if (is_lonely) + { + ImGui::PushStyleColor(ImGuiCol_Text, {1.0f, 1.0f, 1.0f, 0.5f}); + } + + if (is_labeled) + { + // We're keeping alpha because some sub-trees might be translucent + auto alpha = ImGui::GetStyleColorVec4(ImGuiCol_Text).w; + ImGui::PushStyleColor(ImGuiCol_Text, {0.7f, 0.7f, 1.0f, alpha}); + } + + // Render the node itself const auto expanded = ImGui::TreeNodeEx(labelToShow.c_str(), node_flags); + if (expandThisNode) + { + ImGui::SetScrollHereX(); + ImGui::SetScrollHereY(); + } + + if (is_labeled) + ImGui::PopStyleColor(); + + if (ImGui::IsItemHovered()) + highlightItemRect(item.get()); + if (item->uuid == m_selectedItem) _startFiltering = true; @@ -66,11 +180,18 @@ void mvLayoutWindow::renderTreeNode(std::shared_ptr& item) { m_selectedItem = item->uuid; _itemref = item; - m_dirtyNodes = true; + } + + if (is_lonely) + { + ImGui::SameLine(); + ImGui::Text("(not bound)"); } if (!(DearPyGui::GetEntityDesciptionFlags(item->type) & MV_ITEM_DESC_CONTAINER)) { + if (is_lonely) + ImGui::PopStyleColor(); if(expanded) ImGui::TreePop(); ImGui::PopID(); @@ -85,13 +206,26 @@ void mvLayoutWindow::renderTreeNode(std::shared_ptr& item) int i = 0; for (auto& childrenSet : item->childslots) { - - std::string title = "Child Slot: " + std::to_string(i++); - if (_slots) { + std::string title = "Child Slot: " + std::to_string(i++); + // Only expand a slot if there's something more to expand within it + if (expandThisNode) + { + for (auto& child : childrenSet) + { + if (child && _itemsToExpand.count(child->uuid) > 0) + { + ImGui::SetNextItemOpen(true); + break; + } + } + } - if (ImGui::TreeNodeEx(title.c_str(), childrenSet.empty() ? ImGuiTreeNodeFlags_Leaf : 0)) + ImGui::PushStyleColor(ImGuiCol_Text, {0.7f, 0.7f, 0.7f, 1.0f}); + const auto slot_expanded = ImGui::TreeNodeEx(title.c_str(), childrenSet.empty() ? ImGuiTreeNodeFlags_Leaf : 0); + ImGui::PopStyleColor(); + if (slot_expanded) { for (auto& children : childrenSet) if(children) @@ -109,6 +243,9 @@ void mvLayoutWindow::renderTreeNode(std::shared_ptr& item) ImGui::TreePop(); } + if (is_lonely) + ImGui::PopStyleColor(); + ImGui::PopID(); if (item->uuid == m_selectedItem) @@ -119,24 +256,99 @@ void mvLayoutWindow::renderTreeNode(std::shared_ptr& item) void mvLayoutWindow::drawWidgets() { - mvUUID parentName = 0; + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; - if (_itemref == nullptr && GContext->itemRegistry->windowRoots.size() > 0) - _itemref = GContext->itemRegistry->windowRoots[0]; - else if(_itemref == nullptr) - return; + bool pickerEnabled = _picker; + if (pickerEnabled) + { + ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetColorU32(ImGuiCol_ButtonHovered)); + } + if (ImGui::Button("Pick...")) + { + _picker = !_picker; + } + if (pickerEnabled) + { + ImGui::PopStyleColor(); + } + if (_picker) + { + mvUUID hoveredItem = getHoveredItem(); + if (hoveredItem) + highlightItemRect(GetItem(*GContext->itemRegistry, hoveredItem)); + + // When picker is enabled, swallow the first click we get, and look at + // what is hovered - but don't abuse our own window. + if (ImGui::IsMouseClicked(0) && !ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) + { + // Pretend that nothing happened :) + g.IO.MouseDownDuration[0] = g.IO.MouseDownDurationPrev[0] = -1.0f; + g.IO.MouseDown[0] = g.IO.MouseClicked[0] = false; + // Show that hovered item + jumpToItem(hoveredItem); + _picker = false; + } - if (_itemref->info.parentPtr) - parentName = _itemref->info.parentPtr->uuid; + } - // left side - ImGui::BeginGroup(); + ImGui::SameLine(); + + if (ImGui::Button("Focused")) + { + if (!jumpToItem(GContext->focusedItem)) + showError("No focused item."); + } + + ImGui::SameLine(); + + const char* hint = "tag or uuid"; + ImVec2 hint_size = ImGui::CalcTextSize(hint); + ImGui::SetNextItemWidth(hint_size.x + 2*style.FramePadding.x); + // This input, while it doesn't need a label, *must* use a non-empty ID due to ImGui + // restrictions. That's why we put an explicit ID here. + if (ImGui::InputTextWithHint("###uuid-search", hint, &_search_tag, ImGuiInputTextFlags_AutoSelectAll|ImGuiInputTextFlags_EnterReturnsTrue) + && _search_tag.find_first_not_of(' ') != std::string::npos) + { + mvUUID uuid = GetIdFromAlias(*GContext->itemRegistry, _search_tag); + if (!uuid) + { + try + { + size_t converted = 0; + uuid = std::stoull(_search_tag, &converted); + // Make sure we've used all non-whitespace chars, i.e. the input is a valid + // number and not something like "123die" + if (_search_tag.find_first_not_of(' ', converted) != std::string::npos) + { + // Invalid input - reset it back to 0 + uuid = 0; + } + } + catch (...) + { + uuid = 0; + } + } + if (!jumpToItem(uuid)) + showError("Item not found."); + } + + ImGui::SameLine(); + ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); + ImGui::SameLine(); + + if (_itemref == nullptr) + { + ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); + ImGui::PushStyleColor(ImGuiCol_Text, {1.0f, 1.0f, 1.0f, 0.5f}); + } if (ImGui::ArrowButton("Move Up", ImGuiDir_Up)) { - std::lock_guard lk(GContext->mutex); mvSubmitCallback([&]() { + mvPySafeLockGuard lk(GContext->mutex); MoveItemUp(*GContext->itemRegistry, m_selectedItem); }); } @@ -144,134 +356,492 @@ void mvLayoutWindow::drawWidgets() ImGui::SameLine(); if (ImGui::ArrowButton("Move Down", ImGuiDir_Down)) { - std::lock_guard lk(GContext->mutex); mvSubmitCallback([&]() { + mvPySafeLockGuard lk(GContext->mutex); MoveItemDown(*GContext->itemRegistry, m_selectedItem); }); } ImGui::SameLine(); if (ImGui::Button("Delete")) { - std::lock_guard lk(GContext->mutex); mvSubmitCallback([&]() { + mvPySafeLockGuard lk(GContext->mutex); DeleteItem(*GContext->itemRegistry, m_selectedItem, false); m_selectedItem = 0; + resetSelectedItem(); }); - - _itemref = nullptr; - _itemref = GContext->itemRegistry->windowRoots[0]; } ImGui::SameLine(); - if (ImGui::Button("Show")) + if (ImGui::Button("Show") && _itemref != nullptr) { - std::lock_guard lk(GContext->mutex); - mvAppItem* tempItem = GetItem(*GContext->itemRegistry, m_selectedItem); - tempItem->config.show = true; - tempItem->info.shownLastFrame = true; + _itemref->config.show = true; + _itemref->info.shownLastFrame = true; } ImGui::SameLine(); - if (ImGui::Button("Hide")) + if (ImGui::Button("Hide") && _itemref != nullptr) { - std::lock_guard lk(GContext->mutex); - mvAppItem* tempItem = GetItem(*GContext->itemRegistry, m_selectedItem); - tempItem->config.show = false; - tempItem->info.hiddenLastFrame = true; + _itemref->config.show = false; + _itemref->info.hiddenLastFrame = true; } + + if (_itemref == nullptr) + { + ImGui::PopStyleColor(); + ImGui::PopItemFlag(); + } + + ImGui::SameLine(); + ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); + ImGui::SameLine(); + ImGui::SameLine(); ImGui::Checkbox("Show Slots###layout", &_slots); - ImGui::BeginChild("###layoutwindow", ImVec2(400, 0)); - static char ts[6] = "True"; - static char fs[6] = "False"; - - std::string width = std::to_string(_itemref->config.width); - std::string height = std::to_string(_itemref->config.height); - - std::string sizex = std::to_string(_itemref->state.rectSize.x); - std::string sizey = std::to_string(_itemref->state.rectSize.y); - - ImGui::PushID(_itemref.get()); - DebugItem("Label:", _itemref->config.specifiedLabel.c_str()); - DebugItem("ID:", std::to_string(_itemref->uuid).c_str()); - DebugItem("Alias:", _itemref->config.alias.c_str()); - DebugItem("Type:", DearPyGui::GetEntityTypeString(_itemref->type)); - DebugItem("Filter:", _itemref->config.filter.c_str()); - DebugItem("Payload Type:", _itemref->config.payloadType.c_str()); - DebugItem("Location:", std::to_string(_itemref->info.location).c_str()); - DebugItem("Track Offset:", std::to_string(_itemref->config.trackOffset).c_str()); - DebugItem("Container:", DearPyGui::GetEntityDesciptionFlags(_itemref->type) & MV_ITEM_DESC_CONTAINER ? ts : fs); - DebugItem("Width:", width.c_str()); - DebugItem("Height:", height.c_str()); - DebugItem("Size x:", sizex.c_str()); - DebugItem("Size y:", sizey.c_str()); - DebugItem("Show:", _itemref->config.show ? ts : fs); - DebugItem("Enabled:", _itemref->config.enabled ? ts : fs); - DebugItem("Tracked:", _itemref->config.tracked ? ts : fs); - DebugItem("Callback:", _itemref->config.callback ? ts : fs); - DebugItem("User Data:", _itemref->config.user_data ? ts : fs); - DebugItem("Drop Callback:", _itemref->config.dropCallback ? ts : fs); - DebugItem("Drag Callback:", _itemref->config.dragCallback ? ts : fs); - - ImGui::Spacing(); - ImGui::Spacing(); - ImGui::Spacing(); - ImGui::Text("Bindings"); - ImGui::Separator(); - DebugItem("Theme Bound:", _itemref->theme ? ts : fs); - DebugItem("Font Bound:", _itemref->font ? ts : fs); - DebugItem("Handlers Bound:", _itemref->handlerRegistry ? ts : fs); - - int applicableState = DearPyGui::GetApplicableState(_itemref->type); - ImGui::Spacing(); - ImGui::Spacing(); - ImGui::Spacing(); - ImGui::Text("State"); ImGui::Separator(); - if (applicableState & MV_STATE_VISIBLE) DebugItem("Item Visible:", IsItemVisible(_itemref->state, 1) ? ts : fs); - if (applicableState & MV_STATE_HOVER) DebugItem("Item Hovered:", IsItemHovered(_itemref->state, 1) ? ts : fs); - if (applicableState & MV_STATE_ACTIVE) DebugItem("Item Active:", IsItemActive(_itemref->state, 1) ? ts : fs); - if (applicableState & MV_STATE_FOCUSED) DebugItem("Item Focused:", IsItemFocused(_itemref->state, 1) ? ts : fs); - if (applicableState & MV_STATE_CLICKED) - { - DebugItem("Item Left Clicked:", IsItemLeftClicked(_itemref->state, 1) ? ts : fs); - DebugItem("Item Right Clicked:", IsItemRightClicked(_itemref->state, 1) ? ts : fs); - DebugItem("Item Middle Clicked:", IsItemMiddleClicked(_itemref->state, 1) ? ts : fs); - } - if (applicableState & MV_STATE_EDITED) DebugItem("Item Edited:", IsItemEdited(_itemref->state, 1) ? ts : fs); - if (applicableState & MV_STATE_ACTIVATED) DebugItem("Item Activated:", IsItemActivated(_itemref->state, 1) ? ts : fs); - if (applicableState & MV_STATE_DEACTIVATED) DebugItem("Item Deactivated:", IsItemDeactivated(_itemref->state, 1) ? ts : fs); - if (applicableState & MV_STATE_DEACTIVATEDAE) DebugItem("Item DeactivatedAfterEdit:", IsItemDeactivatedAfterEdit(_itemref->state, 1) ? ts : fs); - if (applicableState & MV_STATE_TOGGLED_OPEN) DebugItem("Item ToggledOpen:", IsItemToogledOpen(_itemref->state, 1) ? ts : fs); - ImGui::PopID(); - ImGui::EndChild(); + ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(4, 0)); + if (ImGui::BeginTable("", 2, ImGuiTableFlags_Resizable|ImGuiTableFlags_NoSavedSettings|ImGuiTableFlags_BordersInnerV|ImGuiTableFlags_SizingFixedFit|ImGuiTableFlags_NoKeepColumnsVisible)) + { + ImGui::TableSetupColumn(""); + ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 1.0f); + + ImGui::TableNextRow(); + // left side + ImGui::TableNextColumn(); + + // We want the left side to initially be no narrower than this line + ImVec2 spacer_size = ImGui::CalcTextSize("Type:mvAppItemType::mvWindowAppItem"); + // The left size will initially have a scrollbar, so let's add some space; + // let's also account for item spacing between "type:" and its value (item spacing x), + // and add more padding on the right (let's use frame padding for now). + spacer_size.x += style.ScrollbarSize + style.ItemSpacing.x + style.FramePadding.x; + // No need for vertical offset + spacer_size.y = 0; + // Adding some fake contents that the table will use for auto-fitting + // 1st column (note that the child window below is not used for fitting: + // it itself inherits width from the column). + ImGui::Dummy(spacer_size); + + // We only render item details if there's a selected item OR if + // we've been able to select another item (i.e. there's at least + // something available in the item tree). + if (_itemref != nullptr || resetSelectedItem()) + { + ImGui::BeginChild("###layoutwindow", ImVec2(0, 0)); + static char ts[6] = "True"; + static char fs[6] = "False"; + + std::string width = std::to_string(_itemref->config.width); + std::string height = std::to_string(_itemref->config.height); + + ImGui::PushID(_itemref.get()); + DebugItem("Label:", _itemref->config.specifiedLabel.c_str()); + DebugItem("ID:", std::to_string(_itemref->uuid).c_str()); + DebugItem("Alias:", _itemref->config.alias.c_str()); + DebugItem("Type:", DearPyGui::GetEntityTypeString(_itemref->type)); + + ImGui::Spacing(); + ImGui::Spacing(); + + DebugItem("Show:", _itemref->config.show); + DebugItem("Enabled:", _itemref->config.enabled); + + DebugItem("Pos:", _itemref->state.pos); + DebugItem("Width:", width.c_str()); + DebugItem("Height:", height.c_str()); + + DebugItem("Rect:", _itemref->state.rectMin); + ImGui::SameLine(); + DebugItem("-", _itemref->state.rectMax); + DebugItem("Size:", _itemref->state.rectSize); + + ImGui::Spacing(); + ImGui::Spacing(); + + DebugItem("Container:", DearPyGui::GetEntityDesciptionFlags(_itemref->type) & MV_ITEM_DESC_CONTAINER ? ts : fs); + DebugItem("Location:", std::to_string(_itemref->info.location).c_str()); + DebugItem("Filter:", _itemref->config.filter.c_str()); + + DebugItem("Tracked:", _itemref->config.tracked); + DebugItem("Track Offset:", _itemref->config.trackOffset); + + ImGui::Spacing(); + ImGui::Spacing(); + + DebugItem("Callback:", _itemref->config.callback ? ts : fs); + DebugItem("User Data:", *(_itemref->config.user_data) ? ts : fs); + DebugItem("Drop Callback:", _itemref->config.dropCallback ? ts : fs); + DebugItem("Drag Callback:", _itemref->config.dragCallback ? ts : fs); + DebugItem("Payload Type:", _itemref->config.payloadType.c_str()); + + renderTypeSpecificInfo(); + + InfoHeader("Bindings"); + // TODO: make it a hyperlink to the theme + DebugItem("Theme Bound:", _itemref->theme ? ts : fs); + // TODO: make it a hyperlink to the font + DebugItem("Font Bound:", _itemref->font ? ts : fs); + // TODO: make it a hyperlink to the handlers + DebugItem("Handlers Bound:", _itemref->handlerRegistry ? ts : fs); + + int applicableState = DearPyGui::GetApplicableState(_itemref->type); + InfoHeader("State"); + if (applicableState & MV_STATE_VISIBLE) DebugItem("Item Visible:", IsItemVisible(_itemref->state, 1)); + if (applicableState & MV_STATE_HOVER) DebugItem("Item Hovered:", IsItemHovered(_itemref->state, 1)); + if (applicableState & MV_STATE_ACTIVE) DebugItem("Item Active:", IsItemActive(_itemref->state, 1)); + if (applicableState & MV_STATE_FOCUSED) DebugItem("Item Focused:", IsItemFocused(_itemref->state, 1)); + if (applicableState & MV_STATE_CLICKED) + { + DebugItem("Item Left Clicked:", IsItemLeftClicked(_itemref->state, 1)); + DebugItem("Item Right Clicked:", IsItemRightClicked(_itemref->state, 1)); + DebugItem("Item Middle Clicked:", IsItemMiddleClicked(_itemref->state, 1)); + } + if (applicableState & MV_STATE_EDITED) DebugItem("Item Edited:", IsItemEdited(_itemref->state, 1)); + if (applicableState & MV_STATE_ACTIVATED) DebugItem("Item Activated:", IsItemActivated(_itemref->state, 1)); + if (applicableState & MV_STATE_DEACTIVATED) DebugItem("Item Deactivated:", IsItemDeactivated(_itemref->state, 1)); + if (applicableState & MV_STATE_DEACTIVATEDAE) DebugItem("Item DeactivatedAfterEdit:", IsItemDeactivatedAfterEdit(_itemref->state, 1)); + if (applicableState & MV_STATE_TOGGLED_OPEN) DebugItem("Item ToggledOpen:", IsItemToogledOpen(_itemref->state, 1)); + + ImGui::PopID(); + ImGui::EndChild(); + } + + // right side + ImGui::TableNextColumn(); + _imguiFilter.Draw(); + _startFiltering = false; + + if (_expandToSelected) + { + mvAppItem* parent = _itemref->info.parentPtr; + while (parent) + { + _itemsToExpand.insert(parent->uuid); + parent = parent->info.parentPtr; + } + } + + ImGui::BeginChild("TreeChild", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar); + renderRootCategory("Windows", GContext->itemRegistry->windowRoots); + renderRootCategory("Themes", GContext->itemRegistry->themeRegistryRoots); + renderRootCategory("Template Registries", GContext->itemRegistry->itemTemplatesRoots); + renderRootCategory("Staging Containers", GContext->itemRegistry->stagingRoots); + renderRootCategory("Texture Registries", GContext->itemRegistry->textureRegistryRoots); + renderRootCategory("Font Registries", GContext->itemRegistry->fontRegistryRoots); + renderRootCategory("Item Handler Registries", GContext->itemRegistry->itemHandlerRegistryRoots); + renderRootCategory("Handler Registries", GContext->itemRegistry->handlerRegistryRoots); + renderRootCategory("Value Registries", GContext->itemRegistry->valueRegistryRoots); + renderRootCategory("Colormap Registries", GContext->itemRegistry->colormapRoots); + renderRootCategory("File Dialogs", GContext->itemRegistry->filedialogRoots); + renderRootCategory("Viewport Menubars", GContext->itemRegistry->viewportMenubarRoots); + renderRootCategory("Viewport Drawlists", GContext->itemRegistry->viewportDrawlistRoots); + ImGui::EndChild(); + + // No longer need to expand the tree + _expandToSelected = false; + _itemsToExpand.clear(); + + ImGui::EndTable(); + } + + ImGui::PopStyleVar(); + renderErrorMessage(); +} - ImGui::EndGroup(); +void mvLayoutWindow::renderThemeComponentInfo(mvAppItem* item) +{ + if (!item || item->type != mvAppItemType::mvThemeComponent) + return; + auto comp = static_cast(item); + DebugItem("Enabled State:", comp->_specificEnabled); + mvAppItemType target_type = (mvAppItemType)comp->_specificType; + DebugItem("Applies to:", (target_type == mvAppItemType::All)? "All item types" : DearPyGui::GetEntityTypeString(target_type)); +} + +void mvLayoutWindow::renderBindCount() +{ + auto count_str = std::to_string(_itemref.use_count() - 2); + DebugItem("Bound to:", count_str.c_str()); ImGui::SameLine(); + ImGui::Text("items"); +} +void mvLayoutWindow::renderTypeSpecificInfo() +{ + switch (_itemref->type) + { + case mvAppItemType::mvTheme: + { + InfoHeader("Theme"); + // Most themes will have False here, so let's not clutter the UI for them + if (_itemref->config.show) + { + DebugItem("Global Theme:", true); + } + renderBindCount(); + } + break; + + case mvAppItemType::mvThemeComponent: + { + InfoHeader("Theme"); + renderThemeComponentInfo(_itemref.get()); + } + break; + + case mvAppItemType::mvThemeColor: + { + InfoHeader("Theme"); + auto item = static_cast(_itemref.get()); + renderThemeComponentInfo(item->info.parentPtr); + + // TODO: add accessors for lib type and color index + // switch (item->_libType) + + // OMG. This is horrible. We might be better off having a typed + // accessor for this, too. + auto color = *static_cast>*>(item->getValue()); + + ImGui::AlignTextToFramePadding(); + ImGui::Text("Color:"); + ImGui::SameLine(); + + // Making it fixed-width so that prefixes do not show up - they look + // messy in that little space the layout window typically has. + float text_width = ImGui::CalcTextSize("255").x; + const ImGuiStyle& style = ImGui::GetStyle(); + float total_width = (text_width <= 0.0f)? -1.0f : 4*(text_width + 2*style.FramePadding.x + style.ItemInnerSpacing.x) + ImGui::GetFrameHeight(); + ImGui::SetNextItemWidth(total_width); + + ImGui::PushStyleColor(ImGuiCol_Text, {1.0f, 0.0f, 1.0f, 1.0f}); + ImGui::ColorEdit4("##color", &(*color)[0], ImGuiColorEditFlags_AlphaBar | ImGuiColorEditFlags_AlphaPreviewHalf | ImGuiColorEditFlags_NoBorder | ImGuiColorEditFlags_NoLabel); + ImGui::PopStyleColor(); + } + break; - // right side - ImGui::BeginGroup(); - _imguiFilter.Draw(); - _startFiltering = false; - ImGui::BeginChild("TreeChild", ImVec2(-1.0f, -1.0f), ImGuiChildFlags_Border); - renderRootCategory("Windows", GContext->itemRegistry->windowRoots); - renderRootCategory("Themes", GContext->itemRegistry->themeRegistryRoots); - renderRootCategory("Template Registries", GContext->itemRegistry->itemTemplatesRoots); - renderRootCategory("Staging Containers", GContext->itemRegistry->stagingRoots); - renderRootCategory("Texture Registries", GContext->itemRegistry->textureRegistryRoots); - renderRootCategory("Font Registries", GContext->itemRegistry->fontRegistryRoots); - renderRootCategory("Item Handler Registries", GContext->itemRegistry->itemHandlerRegistryRoots); - renderRootCategory("Handler Registries", GContext->itemRegistry->handlerRegistryRoots); - renderRootCategory("Value Registries", GContext->itemRegistry->valueRegistryRoots); - renderRootCategory("Colormap Registries", GContext->itemRegistry->colormapRoots); - renderRootCategory("File Dialogs", GContext->itemRegistry->filedialogRoots); - renderRootCategory("Viewport Menubars", GContext->itemRegistry->viewportMenubarRoots); - renderRootCategory("Viewport Drawlists", GContext->itemRegistry->viewportDrawlistRoots); - ImGui::EndChild(); - ImGui::EndGroup(); - - -} \ No newline at end of file + case mvAppItemType::mvThemeStyle: + { + InfoHeader("Theme"); + auto item = static_cast(_itemref.get()); + renderThemeComponentInfo(item->info.parentPtr); + + // TODO: add accessors for lib type and style index + // switch (item->_libType) + + // OMG. This is horrible. We might be better off having a typed + // accessor for this, too. + auto value = *static_cast>*>(item->getValue()); + + ImGui::AlignTextToFramePadding(); + ImGui::Text("Value:"); + ImGui::SameLine(); + ImGui::PushStyleColor(ImGuiCol_Text, {1.0f, 0.0f, 1.0f, 1.0f}); + float value_buf[2] = {(*value)[0], (*value)[1]}; + if (ImGui::DragFloat2("##style", value_buf, 1.0f, 0.0f, 100.0f, "%g")) + { + (*value)[0] = value_buf[0]; + (*value)[1] = value_buf[1]; + } + ImGui::PopStyleColor(); + } + break; + + case mvAppItemType::mvItemHandlerRegistry: + { + InfoHeader("Handler Registry"); + renderBindCount(); + } + break; + + case mvAppItemType::mvFont: + { + InfoHeader("Font"); + renderBindCount(); + } + break; + } +} + +void mvLayoutWindow::highlightItemRect(mvAppItem* item) +{ + auto rectMin = item->state.rectMin; + auto rectMax = item->state.rectMax; + if (rectMin.x == 0.0f && rectMin.y == 0.0f && rectMax.x == 0.0f && rectMax.y == 0.0f) + { + // This only works for items positioned relative to the viewport, such as + // windows and popups. Some other items, like table columns or child windows, + // will get into this branch too. + + auto pos = item->state.pos; + + // Going through the container chain, adjusting `pos` according to window positions + // that we find across the way to the root window. + mvAppItem* parent = item->info.parentPtr; + while (parent) { + // TODO: if mvTable ever starts saving its position, add it here as well. + // Item positions are relative to the table when scrolling in the table is + // enabled, because in that case it creates an internal child window. + if (parent->type == mvAppItemType::mvWindowAppItem || parent->type == mvAppItemType::mvChildWindow) + pos = pos + parent->state.pos - parent->state.scrollPos; + + parent = parent->info.parentPtr; + } + + ImGui::GetForegroundDrawList()->AddRect(pos, pos + item->state.rectSize, IM_COL32(255, 0, 0, 255)); + } + else + { + // Regular widgets that have rectMin/rectMax go here + ImGui::GetForegroundDrawList()->AddRect(rectMin, rectMax, IM_COL32(255, 255, 0, 255)); + } +} + +bool mvLayoutWindow::jumpToItem(mvUUID item) +{ + auto itemRef = GetRefItem(*GContext->itemRegistry, item); + if (!itemRef) + return false; + m_selectedItem = item; + _itemref = itemRef; + _expandToSelected = (item != 0); + return true; +} + +mvUUID mvLayoutWindow::getHoveredItem() +{ + // Surely this should belong to mvItemRegistry, but let it live here for the moment. + // The layout window will probably be the only user of this function. + + // For simplicity, we'll only check those registries that can actually capture + // hovered state. Note that they are listed here in the reverse order of their + // rendering - this way we'll get the last item that got hovered; see notes in + // findHoveredInSubTree for more info. + std::vector>* categories[] = { + &GContext->itemRegistry->viewportDrawlistRoots, + &GContext->itemRegistry->viewportMenubarRoots, + &GContext->itemRegistry->windowRoots, + &GContext->itemRegistry->filedialogRoots, + }; + for (auto category : categories) + { + mvUUID hoveredItem = findHoveredInCategory(*category); + if (hoveredItem) + return hoveredItem; + } + return 0; +} + +mvUUID mvLayoutWindow::findHoveredInCategory(std::vector>& roots) +{ + for (auto& root : roots) + { + mvUUID hoveredItem = findHoveredInSubTree(root.get()); + if (hoveredItem) + return hoveredItem; + } + return 0; +} + +mvUUID mvLayoutWindow::findHoveredInSubTree(mvAppItem* parent) +{ + // Sometimes there might be null pointers in the widgets tree. + if (!parent) + return 0; + + // Since mvLayoutWindow is rendered at the beginning of a frame, we only + // retain items state from the previous frame, therefore it's already + // 1 frame old - telling IsItemHovered to look back that far. + bool hovered = IsItemHovered(parent->state, 1); + + // If item is hoverable but not hovered, it's definitely not in the chain of hovered + // items. Let's drop the rest of sub-tree. + // + // Note: the way DPG tests for hovered state of windows - not specifying ImGuiHoveredFlags_ChildWindows - + // as soon as a child window is hovered, its parent is reported as "not hovered". + // That's why we can't skip non-hovered windows at all, otherwise we'll miss the + // beginning of the hovered chain. + if (!hovered && (DearPyGui::GetApplicableState(parent->type) & MV_STATE_HOVER) && + parent->type != mvAppItemType::mvWindowAppItem && parent->type != mvAppItemType::mvChildWindow) + return 0; + + // Now, we have three possible cases: + // + // - The item is not hoverable. It may still contain some hovered items in + // its subtree, so we check the children; worst case we'll return 0. + // + // - The item is hoverable (and therefore hovered - see the check above), + // and there's a hovered child inside. We'll search deeper because the + // current item is somewhere in the middle of the chain. + // + // - The item is hovered and it has no hovered children. This means it's + // finally the leaf, that end of the hovered chain that we're looking for. + + // Since slots and children are typicaly rendered in the first-to-last order, + // we're mainly interested in the *last* child that got the hovered status. + // This means we have to do reverse iteration, and have to resort to ugly + // iterators instead of a typical range-for loop. + for (auto itChildSet = std::crbegin(parent->childslots); itChildSet != std::crend(parent->childslots); ++itChildSet) + { + for (auto itChild = std::crbegin(*itChildSet); itChild != std::crend(*itChildSet); ++itChild) + { + mvUUID hoveredItem = findHoveredInSubTree(itChild->get()); + if (hoveredItem) + return hoveredItem; + } + } + // Finally this is the deepest item - or else something totally not hoverable. + return hovered? parent->uuid : 0; +} + +bool mvLayoutWindow::resetSelectedItem() +{ + std::array registries { + &GContext->itemRegistry->windowRoots, + &GContext->itemRegistry->themeRegistryRoots, + &GContext->itemRegistry->itemTemplatesRoots, + &GContext->itemRegistry->stagingRoots, + &GContext->itemRegistry->textureRegistryRoots, + &GContext->itemRegistry->fontRegistryRoots, + &GContext->itemRegistry->itemHandlerRegistryRoots, + &GContext->itemRegistry->handlerRegistryRoots, + &GContext->itemRegistry->valueRegistryRoots, + &GContext->itemRegistry->colormapRoots, + &GContext->itemRegistry->filedialogRoots, + &GContext->itemRegistry->viewportMenubarRoots, + &GContext->itemRegistry->viewportDrawlistRoots, + }; + + for (auto registry : registries) + { + if (!registry->empty()) + { + _itemref = (*registry)[0]; + m_selectedItem = _itemref->uuid; + _expandToSelected = true; + return true; + } + } + + // Just in case it's still holding a ref to an item that no longer exists + // (and thus keeping the item object from deletion). + _itemref = nullptr; + m_selectedItem = 0; + return false; +} + +void mvLayoutWindow::showError(const char* message) +{ + _error_message = message; + ImGui::OpenPopup("error"); +} + +void mvLayoutWindow::renderErrorMessage() +{ + if (ImGui::BeginPopup("error")) + { + ImGui::TextColored(ImVec4(1.0f, 0.3f, 0.3f, 1.0f), "%s", _error_message.c_str()); + ImGui::EndPopup(); + } +} diff --git a/src/mvLayoutWindow.h b/src/mvLayoutWindow.h index ab941463b..295e31cbc 100644 --- a/src/mvLayoutWindow.h +++ b/src/mvLayoutWindow.h @@ -2,6 +2,7 @@ #include #include +#include #include "mvToolWindow.h" class mvAppItem; @@ -24,12 +25,29 @@ class mvLayoutWindow final : public mvToolWindow void renderTreeNode(std::shared_ptr& item); void renderRootCategory(const char* category, std::vector>& roots); + void highlightItemRect(mvAppItem* item); + bool jumpToItem(mvUUID item); + void showError(const char* message); + mvUUID getHoveredItem(); + mvUUID findHoveredInSubTree(mvAppItem* parent); + mvUUID findHoveredInCategory(std::vector>& roots); + // Sets _itemref to whatever item it can find, like the first window or + // some other root (e.g. if there are no windows). Returns true if _itemref + // is valid (non-null). Can only return false if there are no any items at all. + bool resetSelectedItem(); + void renderTypeSpecificInfo(); + void renderThemeComponentInfo(mvAppItem* item); + void renderBindCount(); + void renderErrorMessage(); std::shared_ptr _itemref = nullptr; mvUUID m_selectedItem = 0; - bool m_dirtyNodes = true; - int m_selectedId = -1; + bool _expandToSelected = false; + std::unordered_set _itemsToExpand; ImGuiTextFilter _imguiFilter; bool _startFiltering = false; bool _slots = false; + bool _picker = false; + std::string _search_tag; + std::string _error_message; }; \ No newline at end of file diff --git a/src/mvLoadingIndicator.cpp b/src/mvLoadingIndicator.cpp index 173459152..4055602ec 100644 --- a/src/mvLoadingIndicator.cpp +++ b/src/mvLoadingIndicator.cpp @@ -57,10 +57,33 @@ void mvLoadingIndicator::draw(ImDrawList* drawlist, float x, float y) { ScopedID id(uuid); - if (_style == 0) + switch (_style) + { + case Style_OldDottedCircle: LoadingIndicatorCircle(config.specifiedLabel.c_str(), _radius, _mainColor, _optionalColor, _circleCount, _speed); - else + break; + case Style_OldRing: LoadingIndicatorCircle2(config.specifiedLabel.c_str(), _radius, _thickness, _mainColor); + break; + case Style_DottedCircle: + // This is to align the indicator body to text rather than to framed rect + // (can be useful with radius=1). + ImGui::AlignTextToFramePadding(); + LoadingIndicatorCircle(config.specifiedLabel.c_str(), _radius, _mainColor, _optionalColor, _circleCount, _speed); + break; + case Style_Ring: + { + const float pixSize = (_radius > 0? _radius : 1.f) * ImGui::GetTextLineHeight(); + // `thickness=1` corresponds to line thickness being 1/4 of the ring radius, + // i.e. 1/8 of the diameter (pixSize). + const float pixThickness = (_thickness > 0? _thickness : 1.f) * pixSize * 0.125f; + // This is to align the indicator body to text rather than to framed rect + // (can be useful with radius=1). + ImGui::AlignTextToFramePadding(); + LoadingIndicatorRing(config.specifiedLabel.c_str(), pixSize, pixThickness, _speed, _mainColor); + } + break; + } } //----------------------------------------------------------------------------- @@ -98,13 +121,19 @@ void mvLoadingIndicator::handleSpecificKeywordArgs(PyObject* dict) if (dict == nullptr) return; - if (PyObject* item = PyDict_GetItemString(dict, "style")) _style = ToInt(item); + if (PyObject* item = PyDict_GetItemString(dict, "style")) _style = static_cast