diff --git a/dearpygui/dearpygui.py b/dearpygui/dearpygui.py index aa4c2d846..3f2b8131c 100644 --- a/dearpygui/dearpygui.py +++ b/dearpygui/dearpygui.py @@ -4175,6 +4175,90 @@ def add_drag_intx(*, label: str =None, user_data: Any =None, use_internal_label: return internal_dpg.add_drag_intx(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, size=size, format=format, speed=speed, min_value=min_value, max_value=max_value, no_input=no_input, clamped=clamped, **kwargs) +def add_drag_int_range(*, 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, source: 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, default_value: Union[List[int], Tuple[int, ...]] =(0, 100), format: str ='%d', format_max: str ='', speed: float =1.0, min_value: int =0, max_value: int =100, no_input: bool =False, clamped: bool =False, **kwargs) -> Union[int, str]: + """ Adds a drag widget for a range of two int values (min and max). The min value cannot exceed max and vice versa. + + 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. + width (int, optional): Width of the item. + 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) + before (Union[int, str], optional): This item will be displayed before the specified item in the parent. + source (Union[int, str], optional): Overrides 'id' as value storage key. + payload_type (str, optional): Sender string type must be the same as the target for the target to run the payload_callback. + callback (Callable, optional): Registers a callback. + drag_callback (Callable, optional): Registers a drag callback for drag and drop. + drop_callback (Callable, optional): Registers a drop callback for drag and drop. + show (bool, optional): Attempt to render widget. + 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. + tracked (bool, optional): Scroll tracking + track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom + default_value (Union[List[int], Tuple[int, ...]], optional): Initial (min, max) range values. + format (str, optional): Determines the format the values will be displayed as. + format_max (str, optional): Format for the max value (uses format if empty). + speed (float, optional): Sets the sensitivity while dragging. + min_value (int, optional): Minimum allowed value for the range. + max_value (int, optional): Maximum allowed value for the range. + no_input (bool, optional): Disable direct entry methods. + clamped (bool, optional): Apply min/max limits to direct entry. + 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_drag_int_range(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, format=format, format_max=format_max, speed=speed, min_value=min_value, max_value=max_value, no_input=no_input, clamped=clamped, **kwargs) + +def add_drag_float_range(*, 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, source: 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, default_value: Union[List[float], Tuple[float, ...]] =(0.0, 100.0), format: str ='%.3f', format_max: str ='', speed: float =1.0, min_value: float =0.0, max_value: float =100.0, no_input: bool =False, clamped: bool =False, **kwargs) -> Union[int, str]: + """ Adds a drag widget for a range of two float values (min and max). The min value cannot exceed max and vice versa. + + 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. + width (int, optional): Width of the item. + 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) + before (Union[int, str], optional): This item will be displayed before the specified item in the parent. + source (Union[int, str], optional): Overrides 'id' as value storage key. + payload_type (str, optional): Sender string type must be the same as the target for the target to run the payload_callback. + callback (Callable, optional): Registers a callback. + drag_callback (Callable, optional): Registers a drag callback for drag and drop. + drop_callback (Callable, optional): Registers a drop callback for drag and drop. + show (bool, optional): Attempt to render widget. + 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. + tracked (bool, optional): Scroll tracking + track_offset (float, optional): 0.0f:top, 0.5f:center, 1.0f:bottom + default_value (Union[List[float], Tuple[float, ...]], optional): Initial (min, max) range values. + format (str, optional): Determines the format the values will be displayed as. + format_max (str, optional): Format for the max value (uses format if empty). + speed (float, optional): Sets the sensitivity while dragging. + min_value (float, optional): Minimum allowed value for the range. + max_value (float, optional): Maximum allowed value for the range. + no_input (bool, optional): Disable direct entry methods. + clamped (bool, optional): Apply min/max limits to direct entry. + 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_drag_float_range(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, format=format, format_max=format_max, speed=speed, min_value=min_value, max_value=max_value, no_input=no_input, clamped=clamped, **kwargs) + def add_drag_line(*, 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, callback: Callable =None, show: bool =True, default_value: float =0.0, color: Union[List[int], Tuple[int, ...]] =(0, 0, 0, -255), thickness: float =1.0, show_label: bool =True, vertical: bool =True, delayed: bool =False, no_cursor: bool =False, no_fit: bool =False, no_inputs: bool =False, **kwargs) -> Union[int, str]: """ Adds a drag line to a plot. diff --git a/src/mvAppItem.cpp b/src/mvAppItem.cpp index 4815f8797..5cb7a7392 100644 --- a/src/mvAppItem.cpp +++ b/src/mvAppItem.cpp @@ -89,12 +89,24 @@ 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 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(std::array app_data) { @@ -3731,6 +3743,70 @@ DearPyGui::GetEntityParser(mvAppItemType type) setup.about = "Adds drag input for a set of int values up to 4. Directly entry can be done with double click or CTRL+Click. Min and Max alone are a soft limit for the drag. Use clamped keyword to also apply limits to the direct entry modes."; break; } + case mvAppItemType::mvDragIntRange: + { + AddCommonArgs(args, (CommonParserArgs)( + MV_PARSER_ARG_ID | + MV_PARSER_ARG_WIDTH | + MV_PARSER_ARG_INDENT | + MV_PARSER_ARG_PARENT | + MV_PARSER_ARG_BEFORE | + MV_PARSER_ARG_SOURCE | + MV_PARSER_ARG_CALLBACK | + MV_PARSER_ARG_SHOW | + MV_PARSER_ARG_ENABLED | + MV_PARSER_ARG_FILTER | + MV_PARSER_ARG_DROP_CALLBACK | + MV_PARSER_ARG_DRAG_CALLBACK | + MV_PARSER_ARG_PAYLOAD_TYPE | + MV_PARSER_ARG_TRACKED | + MV_PARSER_ARG_POS) + ); + + args.push_back({ mvPyDataType::IntList, "default_value", mvArgType::KEYWORD_ARG, "(0, 100)", "Initial (min, max) range values." }); + args.push_back({ mvPyDataType::String, "format", mvArgType::KEYWORD_ARG, "'%d'", "Determines the format the values will be displayed as." }); + args.push_back({ mvPyDataType::String, "format_max", mvArgType::KEYWORD_ARG, "''", "Format for the max value (uses format if empty)." }); + args.push_back({ mvPyDataType::Float, "speed", mvArgType::KEYWORD_ARG, "1.0", "Sets the sensitivity while dragging." }); + args.push_back({ mvPyDataType::Integer, "min_value", mvArgType::KEYWORD_ARG, "0", "Minimum allowed value for the range." }); + args.push_back({ mvPyDataType::Integer, "max_value", mvArgType::KEYWORD_ARG, "100", "Maximum allowed value for the range." }); + args.push_back({ mvPyDataType::Bool, "no_input", mvArgType::KEYWORD_ARG, "False", "Disable direct entry methods." }); + args.push_back({ mvPyDataType::Bool, "clamped", mvArgType::KEYWORD_ARG, "False", "Apply min/max limits to direct entry." }); + + setup.about = "Adds a drag widget for a range of two int values (min and max). The min value cannot exceed max and vice versa."; + break; + } + case mvAppItemType::mvDragFloatRange: + { + AddCommonArgs(args, (CommonParserArgs)( + MV_PARSER_ARG_ID | + MV_PARSER_ARG_WIDTH | + MV_PARSER_ARG_INDENT | + MV_PARSER_ARG_PARENT | + MV_PARSER_ARG_BEFORE | + MV_PARSER_ARG_SOURCE | + MV_PARSER_ARG_CALLBACK | + MV_PARSER_ARG_SHOW | + MV_PARSER_ARG_ENABLED | + MV_PARSER_ARG_FILTER | + MV_PARSER_ARG_DROP_CALLBACK | + MV_PARSER_ARG_DRAG_CALLBACK | + MV_PARSER_ARG_PAYLOAD_TYPE | + MV_PARSER_ARG_TRACKED | + MV_PARSER_ARG_POS) + ); + + args.push_back({ mvPyDataType::FloatList, "default_value", mvArgType::KEYWORD_ARG, "(0.0, 100.0)", "Initial (min, max) range values." }); + args.push_back({ mvPyDataType::String, "format", mvArgType::KEYWORD_ARG, "'%.3f'", "Determines the format the values will be displayed as." }); + args.push_back({ mvPyDataType::String, "format_max", mvArgType::KEYWORD_ARG, "''", "Format for the max value (uses format if empty)." }); + args.push_back({ mvPyDataType::Float, "speed", mvArgType::KEYWORD_ARG, "1.0", "Sets the sensitivity while dragging." }); + args.push_back({ mvPyDataType::Float, "min_value", mvArgType::KEYWORD_ARG, "0.0", "Minimum allowed value for the range." }); + args.push_back({ mvPyDataType::Float, "max_value", mvArgType::KEYWORD_ARG, "100.0", "Maximum allowed value for the range." }); + args.push_back({ mvPyDataType::Bool, "no_input", mvArgType::KEYWORD_ARG, "False", "Disable direct entry methods." }); + args.push_back({ mvPyDataType::Bool, "clamped", mvArgType::KEYWORD_ARG, "False", "Apply min/max limits to direct entry." }); + + setup.about = "Adds a drag widget for a range of two float values (min and max). The min value cannot exceed max and vice versa."; + break; + } case mvAppItemType::mvSliderFloatMulti: { AddCommonArgs(args, (CommonParserArgs)( diff --git a/src/mvAppItem.h b/src/mvAppItem.h index aa125b789..833775978 100644 --- a/src/mvAppItem.h +++ b/src/mvAppItem.h @@ -355,6 +355,8 @@ GetEntityCommand(mvAppItemType type) case mvAppItemType::mvDragFloatMulti: return "add_drag_floatx"; case mvAppItemType::mvDragDoubleMulti: return "add_drag_doublex"; case mvAppItemType::mvDragIntMulti: return "add_drag_intx"; + case mvAppItemType::mvDragIntRange: return "add_drag_int_range"; + case mvAppItemType::mvDragFloatRange: return "add_drag_float_range"; case mvAppItemType::mvSliderFloatMulti: return "add_slider_floatx"; case mvAppItemType::mvSliderDoubleMulti: return "add_slider_doublex"; case mvAppItemType::mvSliderIntMulti: return "add_slider_intx"; diff --git a/src/mvAppItemTypes.inc b/src/mvAppItemTypes.inc index 5ecffb450..eaf80031c 100644 --- a/src/mvAppItemTypes.inc +++ b/src/mvAppItemTypes.inc @@ -168,6 +168,8 @@ X( mvInputDoubleMulti ) \ X( mvDragDouble ) \ X( mvDragDoubleMulti ) \ + X( mvDragIntRange ) \ + X( mvDragFloatRange ) \ X( mvSliderDouble ) \ X( mvSliderDoubleMulti ) \ X( mvCustomSeries ) diff --git a/src/mvBasicWidgets.cpp b/src/mvBasicWidgets.cpp index 6cf58f269..ee3c11f33 100644 --- a/src/mvBasicWidgets.cpp +++ b/src/mvBasicWidgets.cpp @@ -186,6 +186,62 @@ DearPyGui::fill_configuration_dict(const mvDragIntMultiConfig& inConfig, PyObjec checkbitset("no_input", ImGuiSliderFlags_NoInput, inConfig.flags); } +void +DearPyGui::fill_configuration_dict(const mvDragIntRangeConfig& inConfig, PyObject* outDict) +{ + if (outDict == nullptr) + return; + + mvPyObject py_format = ToPyString(inConfig.format); + mvPyObject py_format_max = ToPyString(inConfig.format_max); + mvPyObject py_speed = ToPyFloat(inConfig.speed); + mvPyObject py_min_value = ToPyInt(inConfig.minv); + mvPyObject py_max_value = ToPyInt(inConfig.maxv); + + PyDict_SetItemString(outDict, "format", py_format); + PyDict_SetItemString(outDict, "format_max", py_format_max); + PyDict_SetItemString(outDict, "speed", py_speed); + PyDict_SetItemString(outDict, "min_value", py_min_value); + PyDict_SetItemString(outDict, "max_value", py_max_value); + + auto checkbitset = [outDict](const char* keyword, int flag, const int& flags) + { + mvPyObject py_result = ToPyBool(flags & flag); + PyDict_SetItemString(outDict, keyword, py_result); + }; + + checkbitset("clamped", ImGuiSliderFlags_AlwaysClamp, inConfig.flags); + checkbitset("no_input", ImGuiSliderFlags_NoInput, inConfig.flags); +} + +void +DearPyGui::fill_configuration_dict(const mvDragFloatRangeConfig& inConfig, PyObject* outDict) +{ + if (outDict == nullptr) + return; + + mvPyObject py_format = ToPyString(inConfig.format); + mvPyObject py_format_max = ToPyString(inConfig.format_max); + mvPyObject py_speed = ToPyFloat(inConfig.speed); + mvPyObject py_min_value = ToPyFloat(inConfig.minv); + mvPyObject py_max_value = ToPyFloat(inConfig.maxv); + + PyDict_SetItemString(outDict, "format", py_format); + PyDict_SetItemString(outDict, "format_max", py_format_max); + PyDict_SetItemString(outDict, "speed", py_speed); + PyDict_SetItemString(outDict, "min_value", py_min_value); + PyDict_SetItemString(outDict, "max_value", py_max_value); + + auto checkbitset = [outDict](const char* keyword, int flag, const int& flags) + { + mvPyObject py_result = ToPyBool(flags & flag); + PyDict_SetItemString(outDict, keyword, py_result); + }; + + checkbitset("clamped", ImGuiSliderFlags_AlwaysClamp, inConfig.flags); + checkbitset("no_input", ImGuiSliderFlags_NoInput, inConfig.flags); +} + void DearPyGui::fill_configuration_dict(const mvDragFloatMultiConfig& inConfig, PyObject* outDict) { @@ -892,6 +948,78 @@ DearPyGui::set_configuration(PyObject* inDict, mvDragIntMultiConfig& outConfig, } } +void +DearPyGui::set_configuration(PyObject* inDict, mvDragIntRangeConfig& outConfig, mvAppItemInfo& info) +{ + if (inDict == nullptr) + return; + + if (PyObject* item = PyDict_GetItemString(inDict, "format")) outConfig.format = ToString(item); + if (PyObject* item = PyDict_GetItemString(inDict, "format_max")) outConfig.format_max = ToString(item); + if (PyObject* item = PyDict_GetItemString(inDict, "speed")) outConfig.speed = ToFloat(item); + if (PyObject* item = PyDict_GetItemString(inDict, "min_value")) outConfig.minv = ToInt(item); + if (PyObject* item = PyDict_GetItemString(inDict, "max_value")) outConfig.maxv = ToInt(item); + + auto flagop = [inDict](const char* keyword, int flag, int& flags) + { + if (PyObject* item = PyDict_GetItemString(inDict, keyword)) ToBool(item) ? flags |= flag : flags &= ~flag; + }; + + flagop("clamped", ImGuiSliderFlags_AlwaysClamp, outConfig.flags); + flagop("clamped", ImGuiSliderFlags_AlwaysClamp, outConfig.stor_flags); + flagop("no_input", ImGuiSliderFlags_NoInput, outConfig.flags); + flagop("no_input", ImGuiSliderFlags_NoInput, outConfig.stor_flags); + + if (info.enabledLastFrame) + { + info.enabledLastFrame = false; + outConfig.flags = outConfig.stor_flags; + } + + if (info.disabledLastFrame) + { + info.disabledLastFrame = false; + outConfig.stor_flags = outConfig.flags; + outConfig.flags |= ImGuiSliderFlags_NoInput; + } +} + +void +DearPyGui::set_configuration(PyObject* inDict, mvDragFloatRangeConfig& outConfig, mvAppItemInfo& info) +{ + if (inDict == nullptr) + return; + + if (PyObject* item = PyDict_GetItemString(inDict, "format")) outConfig.format = ToString(item); + if (PyObject* item = PyDict_GetItemString(inDict, "format_max")) outConfig.format_max = ToString(item); + if (PyObject* item = PyDict_GetItemString(inDict, "speed")) outConfig.speed = ToFloat(item); + if (PyObject* item = PyDict_GetItemString(inDict, "min_value")) outConfig.minv = ToFloat(item); + if (PyObject* item = PyDict_GetItemString(inDict, "max_value")) outConfig.maxv = ToFloat(item); + + auto flagop = [inDict](const char* keyword, int flag, int& flags) + { + if (PyObject* item = PyDict_GetItemString(inDict, keyword)) ToBool(item) ? flags |= flag : flags &= ~flag; + }; + + flagop("clamped", ImGuiSliderFlags_AlwaysClamp, outConfig.flags); + flagop("clamped", ImGuiSliderFlags_AlwaysClamp, outConfig.stor_flags); + flagop("no_input", ImGuiSliderFlags_NoInput, outConfig.flags); + flagop("no_input", ImGuiSliderFlags_NoInput, outConfig.stor_flags); + + if (info.enabledLastFrame) + { + info.enabledLastFrame = false; + outConfig.flags = outConfig.stor_flags; + } + + if (info.disabledLastFrame) + { + info.disabledLastFrame = false; + outConfig.stor_flags = outConfig.flags; + outConfig.flags |= ImGuiSliderFlags_NoInput; + } +} + void DearPyGui::set_configuration(PyObject* inDict, mvDragFloatMultiConfig& outConfig, mvAppItemInfo& info) { @@ -2108,6 +2236,50 @@ DearPyGui::set_data_source(mvAppItem& item, mvUUID dataSource, mvDragFloatMultiC outConfig.value = *static_cast>*>(srcItem->getValue()); } +void +DearPyGui::set_data_source(mvAppItem& item, mvUUID dataSource, mvDragIntRangeConfig& outConfig) +{ + if (dataSource == item.config.source) return; + item.config.source = dataSource; + + mvAppItem* srcItem = GetItem((*GContext->itemRegistry), dataSource); + if (!srcItem) + { + mvThrowPythonError(mvErrorCode::mvSourceNotFound, "set_value", + "Source item not found: " + std::to_string(dataSource), &item); + return; + } + if (DearPyGui::GetEntityValueType(srcItem->type) != DearPyGui::GetEntityValueType(item.type)) + { + mvThrowPythonError(mvErrorCode::mvSourceNotCompatible, "set_value", + "Values types do not match: " + std::to_string(dataSource), &item); + return; + } + outConfig.value = *static_cast>*>(srcItem->getValue()); +} + +void +DearPyGui::set_data_source(mvAppItem& item, mvUUID dataSource, mvDragFloatRangeConfig& outConfig) +{ + if (dataSource == item.config.source) return; + item.config.source = dataSource; + + mvAppItem* srcItem = GetItem((*GContext->itemRegistry), dataSource); + if (!srcItem) + { + mvThrowPythonError(mvErrorCode::mvSourceNotFound, "set_value", + "Source item not found: " + std::to_string(dataSource), &item); + return; + } + if (DearPyGui::GetEntityValueType(srcItem->type) != DearPyGui::GetEntityValueType(item.type)) + { + mvThrowPythonError(mvErrorCode::mvSourceNotCompatible, "set_value", + "Values types do not match: " + std::to_string(dataSource), &item); + return; + } + outConfig.value = *static_cast>*>(srcItem->getValue()); +} + void DearPyGui::set_data_source(mvAppItem& item, mvUUID dataSource, mvDragDoubleMultiConfig& outConfig) { @@ -3373,6 +3545,162 @@ DearPyGui::draw_drag_intx(ImDrawList* drawlist, mvAppItem& item, mvDragIntMultiC apply_drag_drop(&item); } +void +DearPyGui::draw_drag_int_range(ImDrawList* drawlist, mvAppItem& item, mvDragIntRangeConfig& config) +{ + // pre draw + if (!item.config.show) + return; + + if (item.info.focusNextFrame) + { + ImGui::SetKeyboardFocusHere(); + item.info.focusNextFrame = false; + } + + ImVec2 previousCursorPos = ImGui::GetCursorPos(); + + if (item.info.dirtyPos) + ImGui::SetCursorPos(item.state.pos); + + item.state.pos = { ImGui::GetCursorPosX(), ImGui::GetCursorPosY() }; + + if (item.config.width != 0) + ImGui::SetNextItemWidth((float)item.config.width); + + if (item.config.indent > 0.0f) + ImGui::Indent(item.config.indent); + + if (item.font) + { + ImFont* fontptr = static_cast(item.font.get())->getFontPtr(); + ImGui::PushFont(fontptr); + } + + apply_local_theming(&item); + + // draw + { + ScopedID id(item.uuid); + + if (!item.config.enabled) + { + config.disabled_value[0] = (*config.value)[0]; + config.disabled_value[1] = (*config.value)[1]; + } + + int* value_ptr = item.config.enabled ? config.value->data() : config.disabled_value; + const char* format_max = config.format_max.empty() ? nullptr : config.format_max.c_str(); + + bool activated = ImGui::DragIntRange2( + item.info.internalLabel.c_str(), + &value_ptr[0], &value_ptr[1], + config.speed, config.minv, config.maxv, + config.format.c_str(), format_max, config.flags); + + if (activated) + item.submitCallback(*config.value); + } + + // update state + UpdateAppItemState(item.state); + + // post draw + if (item.info.dirtyPos) + ImGui::SetCursorPos(previousCursorPos); + + if (item.config.indent > 0.0f) + ImGui::Unindent(item.config.indent); + + if (item.font) + ImGui::PopFont(); + + cleanup_local_theming(&item); + + if (item.handlerRegistry) + item.handlerRegistry->checkEvents(&item.state); + + apply_drag_drop(&item); +} + +void +DearPyGui::draw_drag_float_range(ImDrawList* drawlist, mvAppItem& item, mvDragFloatRangeConfig& config) +{ + // pre draw + if (!item.config.show) + return; + + if (item.info.focusNextFrame) + { + ImGui::SetKeyboardFocusHere(); + item.info.focusNextFrame = false; + } + + ImVec2 previousCursorPos = ImGui::GetCursorPos(); + + if (item.info.dirtyPos) + ImGui::SetCursorPos(item.state.pos); + + item.state.pos = { ImGui::GetCursorPosX(), ImGui::GetCursorPosY() }; + + if (item.config.width != 0) + ImGui::SetNextItemWidth((float)item.config.width); + + if (item.config.indent > 0.0f) + ImGui::Indent(item.config.indent); + + if (item.font) + { + ImFont* fontptr = static_cast(item.font.get())->getFontPtr(); + ImGui::PushFont(fontptr); + } + + apply_local_theming(&item); + + // draw + { + ScopedID id(item.uuid); + + if (!item.config.enabled) + { + config.disabled_value[0] = (*config.value)[0]; + config.disabled_value[1] = (*config.value)[1]; + } + + float* value_ptr = item.config.enabled ? config.value->data() : config.disabled_value; + const char* format_max = config.format_max.empty() ? nullptr : config.format_max.c_str(); + + bool activated = ImGui::DragFloatRange2( + item.info.internalLabel.c_str(), + &value_ptr[0], &value_ptr[1], + config.speed, config.minv, config.maxv, + config.format.c_str(), format_max, config.flags); + + if (activated) + item.submitCallback(*config.value); + } + + // update state + UpdateAppItemState(item.state); + + // post draw + if (item.info.dirtyPos) + ImGui::SetCursorPos(previousCursorPos); + + if (item.config.indent > 0.0f) + ImGui::Unindent(item.config.indent); + + if (item.font) + ImGui::PopFont(); + + cleanup_local_theming(&item); + + if (item.handlerRegistry) + item.handlerRegistry->checkEvents(&item.state); + + apply_drag_drop(&item); +} + void DearPyGui::draw_drag_floatx(ImDrawList* drawlist, mvAppItem& item, mvDragFloatMultiConfig& config) { @@ -6277,6 +6605,36 @@ mvDragIntMulti::setPyValue(PyObject* value) configData.value = std::make_shared>(temp_array); } +void +mvDragIntRange::setPyValue(PyObject* value) +{ + std::vector temp = ToIntVect(value); + while (temp.size() < 2) + temp.push_back(0); + std::array temp_array; + for (size_t i = 0; i < temp_array.size(); i++) + temp_array[i] = temp[i]; + if (configData.value) + *configData.value = temp_array; + else + configData.value = std::make_shared>(temp_array); +} + +void +mvDragFloatRange::setPyValue(PyObject* value) +{ + std::vector temp = ToFloatVect(value); + while (temp.size() < 2) + temp.push_back(0.0f); + std::array temp_array; + for (size_t i = 0; i < temp_array.size(); i++) + temp_array[i] = temp[i]; + if (configData.value) + *configData.value = temp_array; + else + configData.value = std::make_shared>(temp_array); +} + void mvDragFloatMulti::setPyValue(PyObject* value) { diff --git a/src/mvBasicWidgets.h b/src/mvBasicWidgets.h index 576d14239..02e87b832 100644 --- a/src/mvBasicWidgets.h +++ b/src/mvBasicWidgets.h @@ -13,6 +13,8 @@ struct mvDragDoubleConfig; struct mvDragFloatMultiConfig; struct mvDragDoubleMultiConfig; struct mvDragIntMultiConfig; +struct mvDragIntRangeConfig; +struct mvDragFloatRangeConfig; struct mvSliderIntConfig; struct mvSliderFloatConfig; struct mvSliderDoubleConfig; @@ -51,6 +53,8 @@ namespace DearPyGui void fill_configuration_dict(const mvDragDoubleMultiConfig& inConfig, PyObject* outDict); void fill_configuration_dict(const mvDragIntConfig& inConfig, PyObject* outDict); void fill_configuration_dict(const mvDragIntMultiConfig& inConfig, PyObject* outDict); + void fill_configuration_dict(const mvDragIntRangeConfig& inConfig, PyObject* outDict); + void fill_configuration_dict(const mvDragFloatRangeConfig& inConfig, PyObject* outDict); void fill_configuration_dict(const mvSliderIntConfig& inConfig, PyObject* outDict); void fill_configuration_dict(const mvSliderIntMultiConfig& inConfig, PyObject* outDict); void fill_configuration_dict(const mvSliderFloatConfig& inConfig, PyObject* outDict); @@ -86,6 +90,8 @@ namespace DearPyGui void set_configuration(PyObject* inDict, mvDragDoubleMultiConfig& outConfig, mvAppItemInfo& info); void set_configuration(PyObject* inDict, mvDragFloatMultiConfig& outConfig, mvAppItemInfo& info); void set_configuration(PyObject* inDict, mvDragIntMultiConfig& outConfig, mvAppItemInfo& info); + void set_configuration(PyObject* inDict, mvDragIntRangeConfig& outConfig, mvAppItemInfo& info); + void set_configuration(PyObject* inDict, mvDragFloatRangeConfig& outConfig, mvAppItemInfo& info); void set_configuration(PyObject* inDict, mvSliderIntConfig& outConfig, mvAppItemInfo& info); void set_configuration(PyObject* inDict, mvSliderIntMultiConfig& outConfig, mvAppItemInfo& info); void set_configuration(PyObject* inDict, mvSliderFloatConfig& outConfig, mvAppItemInfo& info); @@ -132,6 +138,8 @@ namespace DearPyGui void set_data_source(mvAppItem& item, mvUUID dataSource, mvDragIntMultiConfig& outConfig); void set_data_source(mvAppItem& item, mvUUID dataSource, mvDragDoubleConfig& outConfig); void set_data_source(mvAppItem& item, mvUUID dataSource, mvDragDoubleMultiConfig& outConfig); + void set_data_source(mvAppItem& item, mvUUID dataSource, mvDragIntRangeConfig& outConfig); + void set_data_source(mvAppItem& item, mvUUID dataSource, mvDragFloatRangeConfig& outConfig); void set_data_source(mvAppItem& item, mvUUID dataSource, mvSliderFloatConfig& outConfig); void set_data_source(mvAppItem& item, mvUUID dataSource, mvSliderFloatMultiConfig& outConfig); void set_data_source(mvAppItem& item, mvUUID dataSource, mvSliderDoubleConfig& outConfig); @@ -164,6 +172,8 @@ namespace DearPyGui void draw_drag_doublex (ImDrawList* drawlist, mvAppItem& item, mvDragDoubleMultiConfig& config); void draw_drag_int (ImDrawList* drawlist, mvAppItem& item, mvDragIntConfig& config); void draw_drag_intx (ImDrawList* drawlist, mvAppItem& item, mvDragIntMultiConfig& config); + void draw_drag_int_range(ImDrawList* drawlist, mvAppItem& item, mvDragIntRangeConfig& config); + void draw_drag_float_range(ImDrawList* drawlist, mvAppItem& item, mvDragFloatRangeConfig& config); void draw_slider_float (ImDrawList* drawlist, mvAppItem& item, mvSliderFloatConfig& config); void draw_slider_floatx(ImDrawList* drawlist, mvAppItem& item, mvSliderFloatMultiConfig& config); void draw_slider_double(ImDrawList* drawlist, mvAppItem& item, mvSliderDoubleConfig& config); @@ -314,6 +324,32 @@ struct mvDragDoubleMultiConfig double disabled_value[4]{}; }; +struct mvDragIntRangeConfig +{ + float speed = 1.0f; + int minv = 0; + int maxv = 100; + std::string format = "%d"; + std::string format_max = ""; + ImGuiInputTextFlags flags = ImGuiSliderFlags_None; + ImGuiInputTextFlags stor_flags = ImGuiSliderFlags_None; + std::shared_ptr> value = std::make_shared>(std::array{0, 100}); + int disabled_value[2]{}; +}; + +struct mvDragFloatRangeConfig +{ + float speed = 1.0f; + float minv = 0.0f; + float maxv = 100.0f; + std::string format = "%.3f"; + std::string format_max = ""; + ImGuiInputTextFlags flags = ImGuiSliderFlags_None; + ImGuiInputTextFlags stor_flags = ImGuiSliderFlags_None; + std::shared_ptr> value = std::make_shared>(std::array{0.0f, 100.0f}); + float disabled_value[2]{}; +}; + struct mvSliderIntConfig { int minv = 0; @@ -704,6 +740,34 @@ class mvDragIntMulti : public mvAppItem void setPyValue(PyObject* value) override; }; +class mvDragIntRange : public mvAppItem +{ +public: + mvDragIntRangeConfig configData{}; + explicit mvDragIntRange(mvUUID uuid) : mvAppItem(uuid) {} + void draw(ImDrawList* drawlist, float x, float y) override { DearPyGui::draw_drag_int_range(drawlist, *this, configData); } + void handleSpecificKeywordArgs(PyObject* dict) override { DearPyGui::set_configuration(dict, configData, info); } + void getSpecificConfiguration(PyObject* dict) override { DearPyGui::fill_configuration_dict(configData, dict); } + void setDataSource(mvUUID dataSource) override { DearPyGui::set_data_source(*this, dataSource, configData); } + void* getValue() override { return &configData.value; } + PyObject* getPyValue() override { return ToPyIntList(configData.value->data(), 2); } + void setPyValue(PyObject* value) override; +}; + +class mvDragFloatRange : public mvAppItem +{ +public: + mvDragFloatRangeConfig configData{}; + explicit mvDragFloatRange(mvUUID uuid) : mvAppItem(uuid) {} + void draw(ImDrawList* drawlist, float x, float y) override { DearPyGui::draw_drag_float_range(drawlist, *this, configData); } + void handleSpecificKeywordArgs(PyObject* dict) override { DearPyGui::set_configuration(dict, configData, info); } + void getSpecificConfiguration(PyObject* dict) override { DearPyGui::fill_configuration_dict(configData, dict); } + void setDataSource(mvUUID dataSource) override { DearPyGui::set_data_source(*this, dataSource, configData); } + void* getValue() override { return &configData.value; } + PyObject* getPyValue() override { return ToPyFloatList(configData.value->data(), 2); } + void setPyValue(PyObject* value) override; +}; + class mvDragFloatMulti : public mvAppItem { public: