diff --git a/dearpygui/_dearpygui.pyi b/dearpygui/_dearpygui.pyi index 1c8ffaa5b..9701c53c9 100644 --- a/dearpygui/_dearpygui.pyi +++ b/dearpygui/_dearpygui.pyi @@ -547,7 +547,12 @@ def add_subplots(rows : int, columns : int, *, label: str ='', user_data: Any =' """Adds a collection of plots.""" ... -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 ='', tracked: bool ='', track_offset: float ='', closable: bool ='', no_tooltip: bool ='', order_mode: int ='') -> Union[int, str]: +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.""" ... @@ -1790,6 +1795,7 @@ mvNodeAttribute=0 mvTable=0 mvTableColumn=0 mvTableRow=0 +mvSyncedTables=0 mvDrawLine=0 mvDrawArrow=0 mvDrawTriangle=0 diff --git a/dearpygui/_dearpygui_RTD.py b/dearpygui/_dearpygui_RTD.py index b1db7afbf..b4e28ab8e 100644 --- a/dearpygui/_dearpygui_RTD.py +++ b/dearpygui/_dearpygui_RTD.py @@ -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. @@ -6343,6 +6367,25 @@ def add_subplots(rows, columns, **kwargs): 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. @@ -9361,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 diff --git a/dearpygui/dearpygui.py b/dearpygui/dearpygui.py index a8e6d2d9b..2699a54ad 100644 --- a/dearpygui/dearpygui.py +++ b/dearpygui/dearpygui.py @@ -2505,7 +2505,35 @@ def subplots(rows : int, columns : int, *, label: str =None, user_data: Any =Non internal_dpg.pop_container_stack() @contextmanager -def 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]: +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: + internal_dpg.pop_container_stack() + +@contextmanager +def 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]: """ Adds a tab to a tab bar. Args: @@ -10458,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 diff --git a/src/mvAppItem.cpp b/src/mvAppItem.cpp index 2bc1047da..eed1026f3 100644 --- a/src/mvAppItem.cpp +++ b/src/mvAppItem.cpp @@ -565,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; } @@ -1008,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: @@ -3350,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)( diff --git a/src/mvAppItem.h b/src/mvAppItem.h index 3d35beca8..2c576d454 100644 --- a/src/mvAppItem.h +++ b/src/mvAppItem.h @@ -336,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"; diff --git a/src/mvAppItemTypes.inc b/src/mvAppItemTypes.inc index 5ecffb450..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 ) \ diff --git a/src/mvTables.cpp b/src/mvTables.cpp index ebe9ed236..421d5966e 100644 --- a/src/mvTables.cpp +++ b/src/mvTables.cpp @@ -168,8 +168,6 @@ void mvTable::draw(ImDrawList* drawlist, float x, float y) apply_local_theming(this); { - ScopedID id(uuid); - auto row_renderer = [&](mvAppItem* row, mvAppItem* prev_visible_row=nullptr) { //TableNextRow() ends the previous row, if any, and determines background color for it. @@ -241,7 +239,14 @@ void mvTable::draw(ImDrawList* drawlist, float x, float y) handleImmediateScroll(); - if (ImGui::BeginTable(info.internalLabel.c_str(), _columns, _flags, + const char* table_id = info.internalLabel.c_str(); + // If this table is a part of a synced group, use that group's internalLabel + // instead. In most cases, it will contain UUID so that all groups are distinct + // but tables within the group are synced. + if (info.parentPtr && info.parentPtr->type == mvAppItemType::mvSyncedTables) + table_id = info.parentPtr->info.internalLabel.c_str(); + + if (ImGui::BeginTable(table_id, _columns, _flags, ImVec2((float)config.width, (float)config.height), (float)_inner_width)) { state.lastFrameUpdate = GContext->frame; @@ -670,3 +675,51 @@ void mvTable::setPyValue(PyObject* value) _imguiFilter.InputBuf[i] = 0; _imguiFilter.Build(); } + +void mvSyncedTables::draw(ImDrawList* drawlist, float x, float y) +{ + //----------------------------------------------------------------------------- + // pre draw + //----------------------------------------------------------------------------- + + // show/hide + if (!config.show) + return; + + // push font if a font object is attached + if (font) + { + ImFont* fontptr = static_cast(font.get())->getFontPtr(); + ImGui::PushFont(fontptr); + } + + // themes + apply_local_theming(this); + + //----------------------------------------------------------------------------- + // draw + //----------------------------------------------------------------------------- + { + ScopedID id(uuid); + + for (auto& child : childslots[1]) + { + child->draw(drawlist, ImGui::GetCursorPosX(), ImGui::GetCursorPosY()); + } + UpdateAppItemState(state); + } + + //----------------------------------------------------------------------------- + // post draw + //----------------------------------------------------------------------------- + + // handle popping themes + cleanup_local_theming(this); + + // pop font off stack + if (font) + ImGui::PopFont(); + + if (handlerRegistry) + handlerRegistry->checkEvents(&state); +} diff --git a/src/mvTables.h b/src/mvTables.h index 6bf137060..8d5d3330a 100644 --- a/src/mvTables.h +++ b/src/mvTables.h @@ -92,4 +92,11 @@ class mvTable : public mvAppItem int direction; }; -}; \ No newline at end of file +}; + +class mvSyncedTables : public mvAppItem +{ +public: + explicit mvSyncedTables(mvUUID uuid) : mvAppItem(uuid) {} + void draw(ImDrawList* drawlist, float x, float y) override; +};