From c3e47899c4054ef9482922f5bfcaffcf11391c96 Mon Sep 17 00:00:00 2001 From: hoffstadt Date: Tue, 17 May 2022 08:15:34 -0500 Subject: [PATCH] chore: consolidated mvPlotAxis.h to mvPlotting.h --- DearPyGui/cmake/dpg_sources.cmake | 1 - DearPyGui/src/modules/dearpygui_commands.h | 36 ++- DearPyGui/src/mvDearPyGui.h | 1 + DearPyGui/src/ui/AppItems/mvAppItem.cpp | 28 +- DearPyGui/src/ui/AppItems/mvAppItemCommons.h | 1 - DearPyGui/src/ui/AppItems/mvPlotting.cpp | 168 +++++++++++- DearPyGui/src/ui/AppItems/mvPlotting.h | 30 +++ DearPyGui/src/ui/AppItems/plots/mvPlot.cpp | 141 +++------- DearPyGui/src/ui/AppItems/plots/mvPlot.h | 20 +- .../src/ui/AppItems/plots/mvPlotAxis.cpp | 253 ------------------ DearPyGui/src/ui/AppItems/plots/mvPlotAxis.h | 42 --- 11 files changed, 274 insertions(+), 447 deletions(-) delete mode 100644 DearPyGui/src/ui/AppItems/plots/mvPlotAxis.cpp delete mode 100644 DearPyGui/src/ui/AppItems/plots/mvPlotAxis.h diff --git a/DearPyGui/cmake/dpg_sources.cmake b/DearPyGui/cmake/dpg_sources.cmake index 6f437e00b..68cea7411 100644 --- a/DearPyGui/cmake/dpg_sources.cmake +++ b/DearPyGui/cmake/dpg_sources.cmake @@ -81,7 +81,6 @@ set(MARVEL_SOURCES "src/ui/AppItems/composite/mvFileDialog.cpp" "src/ui/AppItems/composite/mvFileExtension.cpp" "src/ui/AppItems/plots/mvPlot.cpp" - "src/ui/AppItems/plots/mvPlotAxis.cpp" # imnodes "vendor/imnodes/imnodes.cpp" diff --git a/DearPyGui/src/modules/dearpygui_commands.h b/DearPyGui/src/modules/dearpygui_commands.h index 7ab687134..95c3d674f 100644 --- a/DearPyGui/src/modules/dearpygui_commands.h +++ b/DearPyGui/src/modules/dearpygui_commands.h @@ -57,7 +57,9 @@ bind_colormap(PyObject* self, PyObject* args, PyObject* kwargs) if (aitem->type == mvAppItemType::mvPlot) { mvPlot* graph = static_cast(aitem); - graph->SetColorMap((ImPlotColormap)source); + graph->_colormap = (ImPlotColormap)source; + graph->_useColorMap = true; + graph->_newColorMap = true; } else if (aitem->type == mvAppItemType::mvColorMapScale) @@ -1003,7 +1005,7 @@ is_plot_queried(PyObject* self, PyObject* args, PyObject* kwargs) mvPlot* graph = static_cast(aplot); - return ToPyBool(graph->isPlotQueried()); + return ToPyBool(graph->_queried); } mv_internal mv_python_function @@ -1035,7 +1037,7 @@ get_plot_query_area(PyObject* self, PyObject* args, PyObject* kwargs) mvPlot* graph = static_cast(aplot); - double* result = graph->getPlotQueryArea(); + double* result = graph->_queryArea; return Py_BuildValue("(dddd)", result[0], result[1], result[2], result[3]); } @@ -1079,8 +1081,15 @@ set_axis_ticks(PyObject* self, PyObject* args, PyObject* kwargs) labels.emplace_back(item.first.c_str()); locations.emplace_back((double)item.second); } - graph->resetYTicks(); - graph->setYTicks(labels, locations); + + graph->configData.labels.clear(); + graph->configData.clabels.clear(); + graph->configData.labelLocations.clear(); + graph->configData.labels = labels; + graph->configData.labelLocations = locations; + + for (const auto& item : graph->configData.labels) + graph->configData.clabels.push_back(item.data()); return GetPyNone(); } @@ -1115,9 +1124,8 @@ set_axis_limits(PyObject* self, PyObject* args, PyObject* kwargs) } mvPlotAxis* graph = static_cast(aplot); - - graph->setLimits(ymin, ymax); - + graph->configData.setLimits = true; + graph->configData.limits = ImVec2(ymin, ymax); return GetPyNone(); } @@ -1150,7 +1158,7 @@ set_axis_limits_auto(PyObject* self, PyObject* args, PyObject* kwargs) mvPlotAxis* graph = static_cast(aplot); - graph->setLimitsAuto(); + graph->configData.setLimits = false; return GetPyNone(); } @@ -1184,7 +1192,9 @@ fit_axis_data(PyObject* self, PyObject* args, PyObject* kwargs) mvPlotAxis* graph = static_cast(aplot); - graph->fitAxisData(); + // fit axis data + static_cast(graph->info.parentPtr)->_fitDirty = true; + static_cast(graph->info.parentPtr)->_axisfitDirty[graph->info.location] = true; return GetPyNone(); } @@ -1218,7 +1228,7 @@ get_axis_limits(PyObject* self, PyObject* args, PyObject* kwargs) mvPlotAxis* graph = static_cast(aplot); - const ImVec2& lim = graph->getYLimits(); + const ImVec2& lim = graph->configData.limits_actual; return ToPyPair(lim.x, lim.y); } @@ -1251,7 +1261,9 @@ reset_axis_ticks(PyObject* self, PyObject* args, PyObject* kwargs) mvPlotAxis* graph = static_cast(aplot); - graph->resetYTicks(); + graph->configData.labels.clear(); + graph->configData.clabels.clear(); + graph->configData.labelLocations.clear(); return GetPyNone(); } diff --git a/DearPyGui/src/mvDearPyGui.h b/DearPyGui/src/mvDearPyGui.h index aa2f60815..7eca30887 100644 --- a/DearPyGui/src/mvDearPyGui.h +++ b/DearPyGui/src/mvDearPyGui.h @@ -63,6 +63,7 @@ struct mvColorMapScaleConfig; struct mvColorMapSliderConfig; // plots +struct mvPlotAxisConfig; struct mvAnnotationConfig; struct mvSubPlotsConfig; struct mvPlotLegendConfig; diff --git a/DearPyGui/src/ui/AppItems/mvAppItem.cpp b/DearPyGui/src/ui/AppItems/mvAppItem.cpp index 53532d577..fdb5685fd 100644 --- a/DearPyGui/src/ui/AppItems/mvAppItem.cpp +++ b/DearPyGui/src/ui/AppItems/mvAppItem.cpp @@ -5379,14 +5379,14 @@ DearPyGui::OnChildAdded(mvAppItem* item, mvRef child) case mvAppItemType::mvPlot: { mvPlot* actualItem = (mvPlot*)item; - actualItem->onChildAdd(child); - return; - } - - case mvAppItemType::mvPlotAxis: - { - mvPlotAxis* actualItem = (mvPlotAxis*)item; - actualItem->onChildAdd(child); + if (child->type == mvAppItemType::mvPlotLegend) + actualItem->_flags &= ~ImPlotFlags_NoLegend; + + if (child->type == mvAppItemType::mvPlotAxis) + { + actualItem->updateFlags(); + actualItem->updateAxesNames(); + } return; } @@ -5429,14 +5429,10 @@ DearPyGui::OnChildRemoved(mvAppItem* item, mvRef child) case mvAppItemType::mvPlot: { mvPlot* actualItem = (mvPlot*)item; - actualItem->onChildRemoved(child); - return; - } - - case mvAppItemType::mvPlotAxis: - { - mvPlotAxis* actualItem = (mvPlotAxis*)item; - actualItem->onChildRemoved(child); + if (child->type == mvAppItemType::mvPlotLegend) + actualItem->_flags |= ImPlotFlags_NoLegend; + if (child->type == mvAppItemType::mvPlotAxis) + actualItem->updateFlags(); return; } diff --git a/DearPyGui/src/ui/AppItems/mvAppItemCommons.h b/DearPyGui/src/ui/AppItems/mvAppItemCommons.h index 24b709b91..a289f739f 100644 --- a/DearPyGui/src/ui/AppItems/mvAppItemCommons.h +++ b/DearPyGui/src/ui/AppItems/mvAppItemCommons.h @@ -33,4 +33,3 @@ #include "composite/mvFileExtension.h" #include "plots/mvPlot.h" -#include "plots/mvPlotAxis.h" diff --git a/DearPyGui/src/ui/AppItems/mvPlotting.cpp b/DearPyGui/src/ui/AppItems/mvPlotting.cpp index cb5a278bc..44235efee 100644 --- a/DearPyGui/src/ui/AppItems/mvPlotting.cpp +++ b/DearPyGui/src/ui/AppItems/mvPlotting.cpp @@ -310,6 +310,77 @@ DearPyGui::set_data_source(mvAppItem& item, mvUUID dataSource, mvRef>>*>(srcItem->getValue()); } +void +DearPyGui::draw_plot_axis(ImDrawList* drawlist, mvAppItem& item, mvPlotAxisConfig& config) +{ + if (!item.config.show) + return; + + // todo: add check + if (config.axis != 0) + ImPlot::SetPlotYAxis(item.info.location - 1); + + for (auto& item : item.childslots[1]) + item->draw(drawlist, ImPlot::GetPlotPos().x, ImPlot::GetPlotPos().y); + + // x axis + if (config.axis == 0) + { + config.limits_actual.x = (float)ImPlot::GetPlotLimits(item.info.location).X.Min; + config.limits_actual.y = (float)ImPlot::GetPlotLimits(item.info.location).X.Max; + auto context = ImPlot::GetCurrentContext(); + config.flags = context->CurrentPlot->XAxis.Flags; + + } + + // y axis + else + { + config.limits_actual.x = (float)ImPlot::GetPlotLimits(item.info.location - 1).Y.Min; + config.limits_actual.y = (float)ImPlot::GetPlotLimits(item.info.location - 1).Y.Max; + auto context = ImPlot::GetCurrentContext(); + config.flags = context->CurrentPlot->YAxis[item.info.location - 1].Flags; + } + + + UpdateAppItemState(item.state); + + if (item.font) + { + ImGui::PopFont(); + } + + if (item.theme) + { + static_cast(item.theme.get())->customAction(); + } + + if (item.config.dropCallback) + { + ScopedID id(item.uuid); + if (item.info.location == 0 && ImPlot::BeginDragDropTargetX()) + { + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(item.config.payloadType.c_str())) + { + auto payloadActual = static_cast(payload->Data); + mvAddCallback(item.config.dropCallback, item.uuid, payloadActual->getDragData(), nullptr); + } + + ImPlot::EndDragDropTarget(); + } + else if (ImPlot::BeginDragDropTargetY(item.info.location - 1)) + { + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(item.config.payloadType.c_str())) + { + auto payloadActual = static_cast(payload->Data); + mvAddCallback(item.config.dropCallback, item.uuid, payloadActual->getDragData(), nullptr); + } + + ImPlot::EndDragDropTarget(); + } + } +} + void DearPyGui::draw_subplots(ImDrawList* drawlist, mvAppItem& item, mvSubPlotsConfig& config) { @@ -1978,6 +2049,17 @@ DearPyGui::set_required_configuration(PyObject* inDict, mvCustomSeriesConfig& ou } } +void +DearPyGui::set_required_configuration(PyObject* inDict, mvPlotAxisConfig& outConfig) +{ + if (!VerifyRequiredArguments(GetParsers()[GetEntityCommand(mvAppItemType::mvPlotAxis)], inDict)) + return; + + outConfig.axis = ToInt(PyTuple_GetItem(inDict, 0)); + if (outConfig.axis > 1) + outConfig.axis = 1; +} + void DearPyGui::set_configuration(PyObject* inDict, mvDragLineConfig& outConfig) { @@ -2017,7 +2099,7 @@ DearPyGui::set_configuration(PyObject* inDict, mvPlotLegendConfig& outConfig, mv { item.info.shownLastFrame = false; if (auto plot = static_cast(item.info.parentPtr)) - plot->removeFlag(ImPlotFlags_NoLegend); + plot->_flags &= ~ImPlotFlags_NoLegend; else if (auto plot = static_cast(item.info.parentPtr)) plot->removeFlag(ImPlotSubplotFlags_NoLegend); item.config.show = true; @@ -2027,7 +2109,7 @@ DearPyGui::set_configuration(PyObject* inDict, mvPlotLegendConfig& outConfig, mv { item.info.hiddenLastFrame = false; if (auto plot = static_cast(item.info.parentPtr)) - plot->addFlag(ImPlotFlags_NoLegend); + plot->_flags |= ImPlotFlags_NoLegend; else if (auto plot = static_cast(item.info.parentPtr)) plot->addFlag(ImPlotSubplotFlags_NoLegend); item.config.show = false; @@ -2303,6 +2385,51 @@ DearPyGui::set_configuration(PyObject* inDict, mvSubPlotsConfig& outConfig) flagop("column_major", ImPlotSubplotFlags_ColMajor, outConfig.flags); } +void +DearPyGui::set_configuration(PyObject* inDict, mvPlotAxisConfig& outConfig, mvAppItem& item) +{ + if (inDict == nullptr) + return; + + // helper for bit flipping + auto flagop = [inDict](const char* keyword, int flag, int& flags) + { + if (PyObject* item = PyDict_GetItemString(inDict, keyword)) ToBool(item) ? flags |= flag : flags &= ~flag; + }; + + // axis flags + flagop("no_gridlines", ImPlotAxisFlags_NoGridLines, outConfig.flags); + flagop("no_tick_marks", ImPlotAxisFlags_NoTickMarks, outConfig.flags); + flagop("no_tick_labels", ImPlotAxisFlags_NoTickLabels, outConfig.flags); + flagop("log_scale", ImPlotAxisFlags_LogScale, outConfig.flags); + flagop("invert", ImPlotAxisFlags_Invert, outConfig.flags); + flagop("lock_min", ImPlotAxisFlags_LockMin, outConfig.flags); + flagop("lock_max", ImPlotAxisFlags_LockMax, outConfig.flags); + flagop("time", ImPlotAxisFlags_Time, outConfig.flags); + + if (item.info.parentPtr) + { + static_cast(item.info.parentPtr)->updateFlags(); + static_cast(item.info.parentPtr)->updateAxesNames(); + } + + if (item.info.shownLastFrame) + { + item.info.shownLastFrame = false; + if (auto plot = static_cast(item.info.parentPtr)) + plot->_flags &= ~ImPlotFlags_NoLegend; + item.config.show = true; + } + + if (item.info.hiddenLastFrame) + { + item.info.hiddenLastFrame = false; + if (auto plot = static_cast(item.info.parentPtr)) + plot->_flags |= ImPlotFlags_NoLegend; + item.config.show = false; + } +} + void DearPyGui::fill_configuration_dict(const mvDragLineConfig& inConfig, PyObject* outDict) { @@ -2530,6 +2657,30 @@ DearPyGui::fill_configuration_dict(const mvSubPlotsConfig& inConfig, PyObject* o checkbitset("column_major", ImPlotSubplotFlags_ColMajor, inConfig.flags); } +void +DearPyGui::fill_configuration_dict(const mvPlotAxisConfig& inConfig, PyObject* outDict) +{ + if (outDict == nullptr) + return; + + // helper to check and set bit + auto checkbitset = [outDict](const char* keyword, int flag, const int& flags) + { + mvPyObject py_result = ToPyBool(flags & flag); + PyDict_SetItemString(outDict, keyword, py_result); + }; + + // plot flags + checkbitset("no_gridlines", ImPlotAxisFlags_NoGridLines, inConfig.flags); + checkbitset("no_tick_marks", ImPlotAxisFlags_NoTickMarks, inConfig.flags); + checkbitset("no_tick_labels", ImPlotAxisFlags_NoTickLabels, inConfig.flags); + checkbitset("log_scale", ImPlotAxisFlags_LogScale, inConfig.flags); + checkbitset("invert", ImPlotAxisFlags_Invert, inConfig.flags); + checkbitset("lock_min", ImPlotAxisFlags_LockMin, inConfig.flags); + checkbitset("lock_max", ImPlotAxisFlags_LockMax, inConfig.flags); + checkbitset("time", ImPlotAxisFlags_Time, inConfig.flags); +} + void DearPyGui::apply_template(const mvSubPlotsConfig& sourceConfig, mvSubPlotsConfig& dstConfig) { @@ -2708,6 +2859,19 @@ DearPyGui::apply_template(const mvAnnotationConfig& sourceConfig, mvAnnotationCo dstConfig.pixOffset = sourceConfig.pixOffset; } +void +DearPyGui::apply_template(const mvPlotAxisConfig& sourceConfig, mvPlotAxisConfig& dstConfig) +{ + dstConfig.flags = sourceConfig.flags; + dstConfig.axis = sourceConfig.axis; + dstConfig.setLimits = sourceConfig.setLimits; + dstConfig.limits = sourceConfig.limits; + dstConfig.limits_actual = sourceConfig.limits_actual; + dstConfig.labels = sourceConfig.labels; + dstConfig.labelLocations = sourceConfig.labelLocations; + dstConfig.clabels = sourceConfig.clabels; +} + //----------------------------------------------------------------------------- // Old Classes, in the process of removing OOP crap //----------------------------------------------------------------------------- diff --git a/DearPyGui/src/ui/AppItems/mvPlotting.h b/DearPyGui/src/ui/AppItems/mvPlotting.h index b4c1f18fd..2c75516ce 100644 --- a/DearPyGui/src/ui/AppItems/mvPlotting.h +++ b/DearPyGui/src/ui/AppItems/mvPlotting.h @@ -24,6 +24,7 @@ namespace DearPyGui void fill_configuration_dict(const mvCustomSeriesConfig& inConfig, PyObject* outDict); void fill_configuration_dict(const mvAnnotationConfig& inConfig, PyObject* outDict); void fill_configuration_dict(const mvSubPlotsConfig& inConfig, PyObject* outDict); + void fill_configuration_dict(const mvPlotAxisConfig& inConfig, PyObject* outDict); // specific part of `configure_item(...)` void set_configuration(PyObject* inDict, mvPlotLegendConfig& outConfig, mvAppItem& item); @@ -43,6 +44,7 @@ namespace DearPyGui void set_configuration(PyObject* inDict, mvCustomSeriesConfig& outConfig); void set_configuration(PyObject* inDict, mvAnnotationConfig& outConfig); void set_configuration(PyObject* inDict, mvSubPlotsConfig& outConfig); + void set_configuration(PyObject* inDict, mvPlotAxisConfig& outConfig, mvAppItem& item); // positional args TODO: combine with above void set_positional_configuration(PyObject* inDict, mvBarSeriesConfig& outConfig); @@ -60,6 +62,7 @@ namespace DearPyGui void set_required_configuration(PyObject* inDict, mvAreaSeriesConfig& outConfig); void set_required_configuration(PyObject* inDict, mvCandleSeriesConfig& outConfig); void set_required_configuration(PyObject* inDict, mvCustomSeriesConfig& outConfig); + void set_required_configuration(PyObject* inDict, mvPlotAxisConfig& outConfig); // data source handling void set_data_source(mvAppItem& item, mvUUID dataSource, mvAnnotationConfig& outConfig); @@ -85,8 +88,10 @@ namespace DearPyGui void apply_template(const mvCandleSeriesConfig& sourceConfig, mvCandleSeriesConfig& dstConfig); void apply_template(const mvCustomSeriesConfig& sourceConfig, mvCustomSeriesConfig& dstConfig); void apply_template(const mvAnnotationConfig& sourceConfig, mvAnnotationConfig& dstConfig); + void apply_template(const mvPlotAxisConfig& sourceConfig, mvPlotAxisConfig& dstConfig); // draw commands + void draw_plot_axis (ImDrawList* drawlist, mvAppItem& item, mvPlotAxisConfig& config); void draw_subplots (ImDrawList* drawlist, mvAppItem& item, mvSubPlotsConfig& config); void draw_plot_legend (ImDrawList* drawlist, mvAppItem& item, mvPlotLegendConfig& config); void draw_drag_line (ImDrawList* drawlist, mvAppItem& item, mvDragLineConfig& config); @@ -339,6 +344,19 @@ struct mvSubPlotsConfig ImPlotSubplotFlags flags = ImPlotSubplotFlags_None; }; +struct mvPlotAxisConfig +{ + ImPlotAxisFlags flags = 0; + int axis = 0; + bool setLimits = false; + ImVec2 limits; + ImVec2 limits_actual; + std::vector labels; + std::vector labelLocations; + std::vector clabels; // to prevent conversion from string to char* every frame + bool _dirty = false; +}; + //----------------------------------------------------------------------------- // Old Classes, in the process of removing OOP crap //----------------------------------------------------------------------------- @@ -701,4 +719,16 @@ class mvAnnotation : public mvAppItem void* getValue() override { return &configData.value; } PyObject* getPyValue() override { return +ToPyFloatList(configData.value->data(), 4); } void setPyValue(PyObject* value) override; +}; + +class mvPlotAxis : public mvAppItem +{ +public: + mvPlotAxisConfig configData{}; + explicit mvPlotAxis(mvUUID uuid) : mvAppItem(uuid) {} + void draw(ImDrawList* drawlist, float x, float y) override { DearPyGui::draw_plot_axis(drawlist, *this, configData); } + void handleSpecificRequiredArgs(PyObject* dict) override { DearPyGui::set_required_configuration(dict, configData); } + void handleSpecificKeywordArgs(PyObject* dict) override { DearPyGui::set_configuration(dict, configData, *this); } + void getSpecificConfiguration(PyObject* dict) override { DearPyGui::fill_configuration_dict(configData, dict); } + void applySpecificTemplate(mvAppItem* item) override { auto titem = static_cast(item); DearPyGui::apply_template(titem->configData, configData); } }; \ No newline at end of file diff --git a/DearPyGui/src/ui/AppItems/plots/mvPlot.cpp b/DearPyGui/src/ui/AppItems/plots/mvPlot.cpp index b6bc868c0..c30cd1a6f 100644 --- a/DearPyGui/src/ui/AppItems/plots/mvPlot.cpp +++ b/DearPyGui/src/ui/AppItems/plots/mvPlot.cpp @@ -4,21 +4,12 @@ #include "mvContext.h" #include "mvLog.h" #include "mvPythonExceptions.h" -#include "mvPlotAxis.h" #include "mvThemes.h" #include "containers/mvDragPayload.h" #include "mvPyObject.h" #include "mvFontItems.h" #include "AppItems/mvItemHandlers.h" -mvPlot::mvPlot(mvUUID uuid) - : mvAppItem(uuid) -{ - //_label = "Plot###" + std::to_string(uuid); - config.width = -1; - config.height = -1; -} - void mvPlot::applySpecificTemplate(mvAppItem* item) { auto titem = static_cast(item); @@ -38,28 +29,6 @@ void mvPlot::applySpecificTemplate(mvAppItem* item) _vertical_mod = titem->_vertical_mod; } -void mvPlot::onChildAdd(mvRef item) -{ - if (item->type == mvAppItemType::mvPlotLegend) - _flags &= ~ImPlotFlags_NoLegend; - - if (item->type == mvAppItemType::mvPlotAxis) - { - updateFlags(); - updateAxesNames(); - } -} - -void mvPlot::onChildRemoved(mvRef item) -{ - - if (item->type == mvAppItemType::mvPlotLegend) - _flags |= ImPlotFlags_NoLegend; - - if (item->type == mvAppItemType::mvPlotAxis) - updateFlags(); -} - void mvPlot::updateFlags() { for (size_t i = 0; i < childslots[1].size(); i++) @@ -67,33 +36,11 @@ void mvPlot::updateFlags() auto child = static_cast(childslots[1][i].get()); switch (i) { - case(0): - _xflags = child->getFlags(); - break; - - case(1): - _yflags = child->getFlags(); - break; - - case(2): - _y1flags = child->getFlags(); - if (child->config.show) - addFlag(ImPlotFlags_YAxis2); - else - removeFlag(ImPlotFlags_YAxis2); - break; - - case(3): - _y2flags = child->getFlags(); - if (child->config.show) - addFlag(ImPlotFlags_YAxis3); - else - removeFlag(ImPlotFlags_YAxis3); - break; - - default: - _yflags = child->getFlags(); - break; + case(0): _xflags = child->configData.flags; break; + case(1): _yflags = child->configData.flags; break; + case(2): _y1flags = child->configData.flags; if (child->config.show) _flags |= ImPlotFlags_YAxis2; else _flags &= ~ImPlotFlags_YAxis2; break; + case(3): _y2flags = child->configData.flags; if (child->config.show) _flags |= ImPlotFlags_YAxis3; else _flags &= ~ImPlotFlags_YAxis3; break; + default: _yflags = child->configData.flags; break; } } @@ -111,37 +58,16 @@ void mvPlot::updateAxesNames() auto axis = childslots[1][i].get(); switch (i) { - case(0): - _xaxisName = axis->config.specifiedLabel; - break; - - case(1): - _y1axisName = axis->config.specifiedLabel; - break; - - case(2): - _y2axisName = axis->config.specifiedLabel; - break; - - case(3): - _y3axisName = axis->config.specifiedLabel; - break; - - default: - _y1axisName = axis->config.specifiedLabel; - break; + case(0): _xaxisName = axis->config.specifiedLabel; break; + case(1): _y1axisName = axis->config.specifiedLabel; break; + case(2): _y2axisName = axis->config.specifiedLabel; break; + case(3): _y3axisName = axis->config.specifiedLabel; break; + default: _y1axisName = axis->config.specifiedLabel; break; } } } -void mvPlot::SetColorMap(ImPlotColormap colormap) -{ - _colormap = colormap; - _useColorMap = true; - _newColorMap = true; -} - void mvPlot::draw(ImDrawList* drawlist, float x, float y) { @@ -197,7 +123,34 @@ void mvPlot::draw(ImDrawList* drawlist, float x, float y) // skip item if it's not shown if (!item->config.show) continue; - item->customAction(); + + if (item->type == mvAppItemType::mvPlotAxis) + { + auto axis = static_cast(item.get()); + if (axis->configData.setLimits || axis->configData._dirty) + { + switch (info.location) + { + case(0): ImPlot::SetNextPlotLimitsX(axis->configData.limits.x, axis->configData.limits.y, ImGuiCond_Always); break; + case(1): ImPlot::SetNextPlotLimitsY(axis->configData.limits.x, axis->configData.limits.y, ImGuiCond_Always); break; + case(2): ImPlot::SetNextPlotLimitsY(axis->configData.limits.x, axis->configData.limits.y, ImGuiCond_Always, ImPlotYAxis_2); break; + case(3): ImPlot::SetNextPlotLimitsY(axis->configData.limits.x, axis->configData.limits.y, ImGuiCond_Always, ImPlotYAxis_3); break; + default: ImPlot::SetNextPlotLimitsY(axis->configData.limits.x, axis->configData.limits.y, ImGuiCond_Always); break; + } + axis->configData._dirty = false; + } + + if (!axis->configData.labels.empty()) + { + // TODO: Checks + if (info.location == 0) + ImPlot::SetNextPlotTicksX(axis->configData.labelLocations.data(), (int)axis->configData.labels.size(), axis->configData.clabels.data()); + else + ImPlot::SetNextPlotTicksY(axis->configData.labelLocations.data(), (int)axis->configData.labels.size(), axis->configData.clabels.data()); + } + } + else + item->customAction(); } if (_fitDirty) @@ -373,25 +326,7 @@ void mvPlot::draw(ImDrawList* drawlist, float x, float y) item->draw(nullptr, ImGui::GetCursorPosX(), ImGui::GetCursorPosY()); } -bool mvPlot::isPlotQueried() const -{ - return _queried; -} - -double* mvPlot::getPlotQueryArea() -{ - return _queryArea; -} -void mvPlot::addFlag(ImPlotFlags flag) -{ - _flags |= flag; -} - -void mvPlot::removeFlag(ImPlotFlags flag) -{ - _flags &= ~flag; -} void mvPlot::handleSpecificKeywordArgs(PyObject* dict) { diff --git a/DearPyGui/src/ui/AppItems/plots/mvPlot.h b/DearPyGui/src/ui/AppItems/plots/mvPlot.h index 955bc1a85..88b257a4e 100644 --- a/DearPyGui/src/ui/AppItems/plots/mvPlot.h +++ b/DearPyGui/src/ui/AppItems/plots/mvPlot.h @@ -12,30 +12,18 @@ class mvPlot : public mvAppItem public: - explicit mvPlot(mvUUID uuid); + explicit mvPlot(mvUUID uuid) : mvAppItem(uuid) { config.width = config.height = -1; } void updateFlags(); void updateAxesNames(); // settings - void SetColorMap (ImPlotColormap colormap); - void draw (ImDrawList* drawlist, float x, float y) override; - - void addFlag (ImPlotFlags flag); - void removeFlag (ImPlotFlags flag); - - [[nodiscard]] bool isPlotQueried() const; - double* getPlotQueryArea(); - - ImPlotFlags getFlags () const { return _flags; } - - void onChildRemoved(mvRef item); - void onChildAdd(mvRef item); + void draw (ImDrawList* drawlist, float x, float y) override; void handleSpecificKeywordArgs(PyObject* dict) override; void getSpecificConfiguration(PyObject* dict) override; void applySpecificTemplate(mvAppItem* item) override; -private: +public: std::string _xaxisName; std::string _y1axisName; @@ -55,8 +43,6 @@ class mvPlot : public mvAppItem bool _fitDirty = false; bool _axisfitDirty[4] = { false, false, false, false }; - friend class mvPlotAxis; - // custom input mapping ImPlotInputMap _originalMap = ImPlotInputMap(); diff --git a/DearPyGui/src/ui/AppItems/plots/mvPlotAxis.cpp b/DearPyGui/src/ui/AppItems/plots/mvPlotAxis.cpp deleted file mode 100644 index 39756a714..000000000 --- a/DearPyGui/src/ui/AppItems/plots/mvPlotAxis.cpp +++ /dev/null @@ -1,253 +0,0 @@ -#include -#include "mvPlotAxis.h" -#include "mvContext.h" -#include "mvItemRegistry.h" -#include "mvLog.h" -#include "mvThemes.h" -#include "mvPythonExceptions.h" -#include "mvPlot.h" -#include "containers/mvDragPayload.h" - -void mvPlotAxis::customAction(void* data) -{ - if (_setLimits || _dirty) - { - switch (info.location) - { - case(0): - ImPlot::SetNextPlotLimitsX(_limits.x, _limits.y, ImGuiCond_Always); - break; - - case(1): - ImPlot::SetNextPlotLimitsY(_limits.x, _limits.y, ImGuiCond_Always); - break; - - case(2): - ImPlot::SetNextPlotLimitsY(_limits.x, _limits.y, ImGuiCond_Always, ImPlotYAxis_2); - break; - - case(3): - ImPlot::SetNextPlotLimitsY(_limits.x, _limits.y, ImGuiCond_Always, ImPlotYAxis_3); - break; - - default: - ImPlot::SetNextPlotLimitsY(_limits.x, _limits.y, ImGuiCond_Always); - break; - } - - _dirty = false; - - } - - if (!_labels.empty()) - { - // TODO: Checks - if(info.location == 0) - ImPlot::SetNextPlotTicksX(_labelLocations.data(), (int)_labels.size(), _clabels.data()); - else - ImPlot::SetNextPlotTicksY(_labelLocations.data(), (int)_labels.size(), _clabels.data()); - } -} - -void mvPlotAxis::draw(ImDrawList* drawlist, float x, float y) -{ - - if (!config.show) - return; - - // todo: add check - if(_axis != 0) - ImPlot::SetPlotYAxis(info.location - 1); - - for (auto& item : childslots[1]) - item->draw(drawlist, ImPlot::GetPlotPos().x, ImPlot::GetPlotPos().y); - - // x axis - if (_axis == 0) - { - _limits_actual.x = (float)ImPlot::GetPlotLimits(info.location).X.Min; - _limits_actual.y = (float)ImPlot::GetPlotLimits(info.location).X.Max; - auto context = ImPlot::GetCurrentContext(); - _flags = context->CurrentPlot->XAxis.Flags; - - } - - // y axis - else - { - _limits_actual.x = (float)ImPlot::GetPlotLimits(info.location -1).Y.Min; - _limits_actual.y = (float)ImPlot::GetPlotLimits(info.location -1).Y.Max; - auto context = ImPlot::GetCurrentContext(); - _flags = context->CurrentPlot->YAxis[info.location-1].Flags; - } - - - UpdateAppItemState(state); - - if (font) - { - ImGui::PopFont(); - } - - if (theme) - { - static_cast(theme.get())->customAction(); - } - - if (config.dropCallback) - { - ScopedID id(uuid); - if (info.location == 0 && ImPlot::BeginDragDropTargetX()) - { - if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(config.payloadType.c_str())) - { - auto payloadActual = static_cast(payload->Data); - mvAddCallback(config.dropCallback, uuid, payloadActual->getDragData(), nullptr); - } - - ImPlot::EndDragDropTarget(); - } - else if (ImPlot::BeginDragDropTargetY(info.location - 1)) - { - if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(config.payloadType.c_str())) - { - auto payloadActual = static_cast(payload->Data); - mvAddCallback(config.dropCallback, uuid, payloadActual->getDragData(), nullptr); - } - - ImPlot::EndDragDropTarget(); - } - } - -} - -void mvPlotAxis::fitAxisData() -{ - static_cast(info.parentPtr)->_fitDirty = true; - static_cast(info.parentPtr)->_axisfitDirty[info.location] = true; -} - -void mvPlotAxis::handleSpecificKeywordArgs(PyObject* dict) -{ - if (dict == nullptr) - return; - - // helper for bit flipping - auto flagop = [dict](const char* keyword, int flag, int& flags) - { - if (PyObject* item = PyDict_GetItemString(dict, keyword)) ToBool(item) ? flags |= flag : flags &= ~flag; - }; - - // axis flags - flagop("no_gridlines", ImPlotAxisFlags_NoGridLines, _flags); - flagop("no_tick_marks", ImPlotAxisFlags_NoTickMarks, _flags); - flagop("no_tick_labels", ImPlotAxisFlags_NoTickLabels, _flags); - flagop("log_scale", ImPlotAxisFlags_LogScale, _flags); - flagop("invert", ImPlotAxisFlags_Invert, _flags); - flagop("lock_min", ImPlotAxisFlags_LockMin, _flags); - flagop("lock_max", ImPlotAxisFlags_LockMax, _flags); - flagop("time", ImPlotAxisFlags_Time, _flags); - - if (info.parentPtr) - { - static_cast(info.parentPtr)->updateFlags(); - static_cast(info.parentPtr)->updateAxesNames(); - } - - if (info.shownLastFrame) - { - info.shownLastFrame = false; - if (auto plot = static_cast(info.parentPtr)) - plot->removeFlag(ImPlotFlags_NoLegend); - config.show = true; - } - - if (info.hiddenLastFrame) - { - info.hiddenLastFrame = false; - if (auto plot = static_cast(info.parentPtr)) - plot->addFlag(ImPlotFlags_NoLegend); - config.show = false; - } -} - -void mvPlotAxis::handleSpecificRequiredArgs(PyObject* dict) -{ - if (!VerifyRequiredArguments(GetParsers()[GetEntityCommand(type)], dict)) - return; - - _axis = ToInt(PyTuple_GetItem(dict, 0)); - if (_axis > 1) - _axis = 1; -} - -void mvPlotAxis::getSpecificConfiguration(PyObject* dict) -{ - if (dict == nullptr) - return; - - // helper to check and set bit - auto checkbitset = [dict](const char* keyword, int flag, const int& flags) - { - mvPyObject py_result = ToPyBool(flags & flag); - PyDict_SetItemString(dict, keyword, py_result); - }; - - // plot flags - checkbitset("no_gridlines", ImPlotAxisFlags_NoGridLines, _flags); - checkbitset("no_tick_marks", ImPlotAxisFlags_NoTickMarks, _flags); - checkbitset("no_tick_labels", ImPlotAxisFlags_NoTickLabels, _flags); - checkbitset("log_scale", ImPlotAxisFlags_LogScale, _flags); - checkbitset("invert", ImPlotAxisFlags_Invert, _flags); - checkbitset("lock_min", ImPlotAxisFlags_LockMin, _flags); - checkbitset("lock_max", ImPlotAxisFlags_LockMax, _flags); - checkbitset("time", ImPlotAxisFlags_Time, _flags); -} - -void mvPlotAxis::setLimits(float y_min, float y_max) -{ - _setLimits = true; - _limits = ImVec2(y_min, y_max); -} - -void mvPlotAxis::setLimitsAuto() -{ - _setLimits = false; -} - -void mvPlotAxis::onChildAdd(mvRef item) -{ -} - -void mvPlotAxis::onChildRemoved(mvRef item) -{ -} - -void mvPlotAxis::resetYTicks() -{ - _labels.clear(); - _clabels.clear(); - _labelLocations.clear(); -} - -void mvPlotAxis::setYTicks(const std::vector& labels, const std::vector& locations) -{ - _labels = labels; - _labelLocations = locations; - - for (const auto& item : _labels) - _clabels.push_back(item.data()); -} - -void mvPlotAxis::applySpecificTemplate(mvAppItem* item) -{ - auto titem = static_cast(item); - _flags = titem->_flags; - _axis = titem->_axis; - _setLimits = titem->_setLimits; - _limits = titem->_limits; - _limits_actual = titem->_limits_actual; - _labels = titem->_labels; - _labelLocations = titem->_labelLocations; - _clabels = titem->_clabels; -} \ No newline at end of file diff --git a/DearPyGui/src/ui/AppItems/plots/mvPlotAxis.h b/DearPyGui/src/ui/AppItems/plots/mvPlotAxis.h deleted file mode 100644 index ebb2b0edd..000000000 --- a/DearPyGui/src/ui/AppItems/plots/mvPlotAxis.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include "mvItemRegistry.h" - -class mvPlotAxis : public mvAppItem -{ - -public: - - explicit mvPlotAxis(mvUUID uuid) : mvAppItem(uuid) {} - - void draw(ImDrawList* drawlist, float x, float y) override; - void customAction(void* data = nullptr) override; - void onChildRemoved(mvRef item); - void onChildAdd(mvRef item); - void handleSpecificKeywordArgs(PyObject* dict) override; - void handleSpecificRequiredArgs(PyObject* args) override; - void getSpecificConfiguration(PyObject* dict) override; - void applySpecificTemplate(mvAppItem* item) override; - void setYTicks(const std::vector& labels, const std::vector& locations); - void resetYTicks(); - void fitAxisData(); - - void setLimits(float y_min, float y_max); - void setLimitsAuto(); - - ImPlotAxisFlags getFlags() const { return _flags; } - const ImVec2& getYLimits() const { return _limits_actual; } - -private: - - ImPlotAxisFlags _flags = 0; - int _axis = 0; - bool _setLimits = false; - ImVec2 _limits; - ImVec2 _limits_actual; - std::vector _labels; - std::vector _labelLocations; - std::vector _clabels; // to prevent conversion from string to char* every frame - bool _dirty = false; - -}; \ No newline at end of file