From d7f6bf3c80deaf4a6b5dfc44770fd0fa7dc1e51f Mon Sep 17 00:00:00 2001 From: Vladimir Ein Date: Sun, 4 Jan 2026 20:39:07 +0500 Subject: [PATCH] fix (mvLoadingIndicator): Corrected size calculations for the ring-style indicator. Old indicator rendering is kept at style=1 for compatibility; new corrected rendering can be selected with style=mvLoadInd_Ring. Also, colors are taken from Button/ButtonHovered styles, as was intended in the original design. Also, the indicator should not receive navigation focus (since it's not actionable anyway). --- dearpygui/_dearpygui.pyi | 2 + dearpygui/_dearpygui_RTD.py | 16 ++++---- dearpygui/dearpygui.py | 18 +++++---- src/dearpygui.cpp | 3 ++ src/mvAppItem.cpp | 14 +++---- src/mvLoadingIndicator.cpp | 39 +++++++++++++++--- src/mvLoadingIndicator.h | 13 ++++-- src/mvLoadingIndicatorCustom.cpp | 68 ++++++++++++++++++++++++++++---- src/mvLoadingIndicatorCustom.h | 4 +- 9 files changed, 138 insertions(+), 39 deletions(-) diff --git a/dearpygui/_dearpygui.pyi b/dearpygui/_dearpygui.pyi index 3ffbd5356..0a2550da3 100644 --- a/dearpygui/_dearpygui.pyi +++ b/dearpygui/_dearpygui.pyi @@ -1445,6 +1445,8 @@ 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 diff --git a/dearpygui/_dearpygui_RTD.py b/dearpygui/_dearpygui_RTD.py index abb68f6a9..0b3f7f0ba 100644 --- a/dearpygui/_dearpygui_RTD.py +++ b/dearpygui/_dearpygui_RTD.py @@ -5222,13 +5222,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] @@ -9016,6 +9016,8 @@ def unstage(item): 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 diff --git a/dearpygui/dearpygui.py b/dearpygui/dearpygui.py index aa4c2d846..fbde8f8ce 100644 --- a/dearpygui/dearpygui.py +++ b/dearpygui/dearpygui.py @@ -5792,7 +5792,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: @@ -5809,13 +5809,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] @@ -9999,6 +9999,8 @@ def unstage(item : Union[int, str], **kwargs) -> None: 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 diff --git a/src/dearpygui.cpp b/src/dearpygui.cpp index d26509634..3a878f7a3 100644 --- a/src/dearpygui.cpp +++ b/src/dearpygui.cpp @@ -84,6 +84,9 @@ GetModuleConstants() 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 }); diff --git a/src/mvAppItem.cpp b/src/mvAppItem.cpp index 4815f8797..0cb2c948c 100644 --- a/src/mvAppItem.cpp +++ b/src/mvAppItem.cpp @@ -4542,13 +4542,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; 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