mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-05-16 18:12:10 +00:00
Fix stale keyboard refresh and auto-resize flicker of speed profile window in Preview tab (#12707)
* Fix speed popup refresh and sizing in Preview Fix two UX issues in the Preview actual speed profile popup. Keyboard-driven horizontal slider changes could leave the popup visually stale until a later input event, which made keyboard navigation feel delayed. Also, the speed-profile popup could briefly render at an incorrect height before resizing on the next frame. This change makes keyboard slider updates explicitly request a follow-up frame, so refresh no longer depends on incidental mouse activity. It also removes auto-resize from ToolPositionTableWnd and sizes the popup before begin() each frame. The popup height is computed from plot height, table rows, and window paddings, then clamped to at least the height of the adjacent ToolPosition window. The popup width is now computed from translated header text and padding terms, with a 16:9-derived minimum for a more stable appearance. The width is cached for the session and recalculated when UI scale changes. Result: - keyboard navigation updates reliably - popup no longer shows the transient wrong-height first draw - sizing is more stable across scale and localization * Fix ToolPosition window also + other fixes * Fix compile error when ENABLE_ACTUAL_SPEED_DEBUG disabled IMGUI_DEFINE_MATH_OPERATORS is needed even if ENABLE_ACTUAL_SPEED_DEBUG is not enabled * Guard seam fallback vertex index in GCodeViewer
This commit is contained in:
@@ -28,9 +28,8 @@
|
||||
#include "Widgets/ProgressDialog.hpp"
|
||||
#include "MsgDialog.hpp"
|
||||
|
||||
#if ENABLE_ACTUAL_SPEED_DEBUG
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
#endif // ENABLE_ACTUAL_SPEED_DEBUG
|
||||
|
||||
#include <imgui/imgui_internal.h>
|
||||
|
||||
#include <glad/gl.h>
|
||||
@@ -301,8 +300,6 @@ static std::string to_string(libvgcode::EGCodeExtrusionRole role)
|
||||
|
||||
void GCodeViewer::SequentialView::Marker::render_position_window(const libvgcode::Viewer* viewer, int canvas_width, int canvas_height, const libvgcode::EViewType& view_type)
|
||||
{
|
||||
static float last_window_width = 0.0f;
|
||||
static size_t last_text_length = 0;
|
||||
static bool properties_shown = false;
|
||||
|
||||
const std::string NA_TXT = _u8L("N/A");
|
||||
@@ -320,199 +317,281 @@ void GCodeViewer::SequentialView::Marker::render_position_window(const libvgcode
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 8.0f * m_scale);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding , ImVec2(10.f, 10.f) * m_scale);
|
||||
ImGui::SetNextWindowBgAlpha(0.8f);
|
||||
imgui.begin(std::string("ToolPosition"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove);
|
||||
ImGui::AlignTextToFramePadding();
|
||||
// ImGuiWrapper::text_colored(ImGuiWrapper::COL_ORCA, _u8L("Position") + ":");
|
||||
// ImGui::SameLine();
|
||||
|
||||
libvgcode::PathVertex vertex = viewer->get_current_vertex();
|
||||
size_t vertex_id = viewer->get_current_vertex_id();
|
||||
if (view_type != libvgcode::EViewType::FeatureType && vertex.type == libvgcode::EMoveType::Seam) { // exclude FeatureType for proper type readings
|
||||
vertex_id = static_cast<size_t>(viewer->get_view_visible_range()[1]) - 1;
|
||||
vertex = viewer->get_vertex_at(vertex_id);
|
||||
// Seam moves may contain non-deterministic vertex data, so use the
|
||||
// last visible non-seam vertex instead (except in FeatureType view)
|
||||
if (view_type != libvgcode::EViewType::FeatureType && vertex.type == libvgcode::EMoveType::Seam) {
|
||||
const libvgcode::Interval& visible_range = viewer->get_view_visible_range();
|
||||
if (visible_range[1] > 0) {
|
||||
vertex_id = static_cast<size_t>(visible_range[1]) - 1;
|
||||
vertex = viewer->get_vertex_at(vertex_id);
|
||||
}
|
||||
}
|
||||
const bool is_extrusion = vertex.is_extrusion();
|
||||
|
||||
const ImGuiStyle& style = ImGui::GetStyle();
|
||||
|
||||
char detail_buf[1024];
|
||||
switch (view_type) {
|
||||
case libvgcode::EViewType::FeatureType:
|
||||
if (is_extrusion)
|
||||
strcpy(detail_buf, to_string(vertex.role).c_str());
|
||||
else if (vertex.type != libvgcode::EMoveType::Noop)
|
||||
strcpy(detail_buf, to_string(vertex.type).c_str());
|
||||
else
|
||||
strcpy(detail_buf, NA_CSTR); // Noop moves are not shown in the "Line type" view, so show N/A for them.
|
||||
break;
|
||||
case libvgcode::EViewType::Height:
|
||||
if (is_extrusion)
|
||||
sprintf(detail_buf, "%s%.2f", _u8L("Height: ").c_str(), vertex.height);
|
||||
else
|
||||
sprintf(detail_buf, "%s%s", _u8L("Height: ").c_str(), NA_CSTR);
|
||||
break;
|
||||
case libvgcode::EViewType::Width:
|
||||
if (is_extrusion)
|
||||
sprintf(detail_buf, "%s%.2f", _u8L("Width: ").c_str(), vertex.width);
|
||||
else
|
||||
sprintf(detail_buf, "%s%s", _u8L("Width: ").c_str(), NA_CSTR);
|
||||
break;
|
||||
case libvgcode::EViewType::VolumetricFlowRate:
|
||||
if (is_extrusion)
|
||||
sprintf(detail_buf, "%s%.2f", _u8L("Flow: ").c_str(), vertex.volumetric_rate());
|
||||
else
|
||||
sprintf(detail_buf, "%s%s", _u8L("Flow: ").c_str(), NA_CSTR);
|
||||
break;
|
||||
case libvgcode::EViewType::FanSpeed:
|
||||
sprintf(detail_buf, "%s%.0f", _u8L("Fan: ").c_str(), vertex.fan_speed);
|
||||
break;
|
||||
case libvgcode::EViewType::Temperature:
|
||||
sprintf(detail_buf, "%s%.0f", _u8L("Temperature: ").c_str(), vertex.temperature);
|
||||
break;
|
||||
case libvgcode::EViewType::LayerTimeLinear:
|
||||
case libvgcode::EViewType::LayerTimeLogarithmic:
|
||||
sprintf(detail_buf, "%s%.1f", _u8L("Layer Time: ").c_str(), vertex.layer_duration);
|
||||
break;
|
||||
case libvgcode::EViewType::Tool:
|
||||
sprintf(detail_buf, "%s%d", _u8L("Tool: ").c_str(), vertex.extruder_id + 1);
|
||||
break;
|
||||
case libvgcode::EViewType::ColorPrint:
|
||||
sprintf(detail_buf, "%s%d", _u8L("Color: ").c_str(), vertex.color_id + 1);
|
||||
break;
|
||||
case libvgcode::EViewType::Acceleration:
|
||||
sprintf(detail_buf, "%s%.0f", _u8L("Acceleration: ").c_str(), vertex.acceleration);
|
||||
break;
|
||||
case libvgcode::EViewType::Jerk:
|
||||
sprintf(detail_buf, "%s%.1f", _u8L("Jerk: ").c_str(), vertex.jerk);
|
||||
break;
|
||||
case libvgcode::EViewType::PressureAdvance:
|
||||
sprintf(detail_buf, "%s%.4f", _u8L("PA: ").c_str(), vertex.pressure_advance);
|
||||
break;
|
||||
default:
|
||||
detail_buf[0] = '\0';
|
||||
break;
|
||||
}
|
||||
|
||||
// ORCA Moved position and information to bottom
|
||||
std::vector<std::pair<std::string, std::string>> properties_rows;
|
||||
float table_content_w = 0.0f;
|
||||
if (properties_shown) {
|
||||
float label_w = 0.0f;
|
||||
float value_w = 0.0f;
|
||||
properties_rows.reserve(13);
|
||||
auto add_row = [&properties_rows, &label_w, &value_w](std::string label, std::string value) {
|
||||
label_w = std::max(label_w, ImGui::CalcTextSize(label.c_str()).x);
|
||||
value_w = std::max(value_w, ImGui::CalcTextSize(value.c_str()).x);
|
||||
properties_rows.emplace_back(std::move(label), std::move(value));
|
||||
};
|
||||
char buff[1024];
|
||||
add_row(_u8L("Type"), _u8L(to_string(vertex.type)));
|
||||
add_row(_u8L("Line Type"), is_extrusion ? _u8L(to_string(vertex.role)) : NA_TXT);
|
||||
if (is_extrusion) sprintf(buff, ("%.3f " + _u8L("mm")).c_str(), vertex.width); else strcpy(buff, NA_CSTR);
|
||||
add_row(_u8L("Width"), buff);
|
||||
if (is_extrusion) sprintf(buff, ("%.3f " + _u8L("mm")).c_str(), vertex.height); else strcpy(buff, NA_CSTR);
|
||||
add_row(_u8L("Height"), buff);
|
||||
sprintf(buff, "%d", vertex.layer_id + 1);
|
||||
add_row(_u8L("Layer"), buff);
|
||||
sprintf(buff, ("%.1f " + _u8L("mm/s")).c_str(), vertex.feedrate);
|
||||
add_row(_u8L("Speed"), buff);
|
||||
sprintf(buff, ("%.0f " + _u8L("mm/s²")).c_str(), vertex.acceleration);
|
||||
add_row(_u8L("Acceleration"), buff);
|
||||
sprintf(buff, ("%.1f " + _u8L("mm/s")).c_str(), vertex.jerk);
|
||||
add_row(_u8L("Jerk"), buff);
|
||||
if (is_extrusion) sprintf(buff, ("%.3f " + _u8L("mm³/s")).c_str(), vertex.volumetric_rate()); else strcpy(buff, NA_CSTR);
|
||||
add_row(_u8L("Flow rate"), buff);
|
||||
sprintf(buff, "%.0f %%", vertex.fan_speed);
|
||||
add_row(_u8L("Fan speed"), buff);
|
||||
sprintf(buff, ("%.0f " + _u8L("°C")).c_str(), vertex.temperature);
|
||||
add_row(_u8L("Temperature"), buff);
|
||||
sprintf(buff, "%.4f", vertex.pressure_advance);
|
||||
add_row(_u8L("Pressure Advance"), buff);
|
||||
const float estimated_time = viewer->get_estimated_time_at(vertex_id);
|
||||
sprintf(buff, "%s (%.3fs)", get_time_dhms(estimated_time).c_str(), vertex.times[static_cast<size_t>(viewer->get_time_mode())]);
|
||||
add_row(_u8L("Time"), buff);
|
||||
|
||||
table_content_w = 2 * std::max(label_w, value_w) + style.ItemInnerSpacing.x;
|
||||
}
|
||||
|
||||
// "ToolPosition" layout width calculation
|
||||
const float axes_spacing_x = ImGui::CalcTextSize("sp").x; // Spacing between axes labels
|
||||
const float axes_width = ImGui::CalcTextSize("X 999.999").x; // Width of the longest possible axis label
|
||||
const float axes_content_w = 3.0f * axes_width + 2.0f * axes_spacing_x; // Three axes
|
||||
const float speed_width = ImGui::CalcTextSize((_u8L("Speed: ") + "9999 ").c_str()).x; // Width of the longest possible speed label
|
||||
const float detail_width = ImGui::CalcTextSize(detail_buf).x; // Width of the detail text
|
||||
const float info_content_w = speed_width + detail_width; // Speed + detail
|
||||
const float info_group_w = std::max(axes_content_w, info_content_w); // The width of the group containing position and detail info, whichever is wider
|
||||
const float fold_button_w = 24.0f * m_scale; // Width of the fold/unfold button
|
||||
const float bottom_row_w = fold_button_w + style.ItemSpacing.x + info_group_w; // The width of the bottom row containing the fold button and the info group
|
||||
float speed_profile_row_w = 0.0f;
|
||||
#if ENABLE_ACTUAL_SPEED_DEBUG
|
||||
const float table_btn_width = std::max(ImGui::CalcTextSize(_u8L("Hide").c_str()).x, ImGui::CalcTextSize(_u8L("Show").c_str()).x);
|
||||
const float btn_padding_x = 8.0f * m_scale;
|
||||
|
||||
if (properties_shown) {
|
||||
auto append_table_row = [](const std::string& label, std::function<void(void)> value_callback) {
|
||||
// The width of the row containing the button to show/hide the actual speed profile table and its label
|
||||
speed_profile_row_w = table_btn_width + btn_padding_x * 2.0f + style.ItemSpacing.x + ImGui::CalcTextSize(_u8L("Actual speed profile").c_str()).x;
|
||||
}
|
||||
#endif // ENABLE_ACTUAL_SPEED_DEBUG
|
||||
const float properties_w = std::max(table_content_w, speed_profile_row_w); // The width of the properties section, whichever is wider between the properties table and the speed profile row
|
||||
const float content_w = std::max(bottom_row_w, properties_w); // The width of the window content, whichever is wider between the bottom row and the properties table
|
||||
const float window_w = std::ceil(content_w + 2.0f * style.WindowPadding.x); // Final window width with padding, rounded up for better look
|
||||
|
||||
// "ToolPosition" layout height calculation
|
||||
const float text_h = ImGui::GetTextLineHeight();
|
||||
const float item_spacing_y = style.ItemSpacing.y;
|
||||
const float cell_pad_y = style.CellPadding.y;
|
||||
const float window_pad_h = 2.0f * style.WindowPadding.y;
|
||||
const float show_button_h = text_h + 2.0f * 3.0f * m_scale; // ImGuiStyleVar_FramePadding.y is set to 3.f * m_scale
|
||||
const float main_row_h = 2.0f * text_h + item_spacing_y; // Two lines of text (position and detail) + spacing between them
|
||||
const float properties_h = static_cast<float>(properties_rows.size()) * (text_h + 2.0f * cell_pad_y) + 2.0f * cell_pad_y + 1.0f + item_spacing_y // table rows
|
||||
+ item_spacing_y + show_button_h // Spacing() + Show/Hide button row
|
||||
+ item_spacing_y + 1.0f + style.FramePadding.y; // Spacing() + Separator() + Dummy()
|
||||
const float folded_window_h = std::ceil(window_pad_h + main_row_h); // Height of the window when properties are hidden, with padding, rounded up for better look
|
||||
const float unfolded_window_h = std::ceil(folded_window_h + properties_h); // Height of the window when properties are shown, with padding, rounded up for better look
|
||||
const float window_h = properties_shown ? unfolded_window_h : folded_window_h; // Final window height depending on whether properties are shown or not
|
||||
|
||||
ImGui::SetNextWindowSize(ImVec2(window_w, window_h), ImGuiCond_Always);
|
||||
|
||||
imgui.begin(std::string("ToolPosition"), ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize);
|
||||
ImGui::AlignTextToFramePadding();
|
||||
|
||||
if (properties_shown) {
|
||||
auto append_table_row = [](const std::string& label, const std::string& value) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableSetColumnIndex(0);
|
||||
ImGuiWrapper::text_colored(ImGuiWrapper::COL_ORCA, label);
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
value_callback();
|
||||
ImGuiWrapper::text(value);
|
||||
};
|
||||
|
||||
//ImGui::Separator();
|
||||
if (ImGui::BeginTable("Properties", 2)) {
|
||||
char buff[1024];
|
||||
|
||||
append_table_row(_u8L("Type"), [&vertex]() {
|
||||
ImGuiWrapper::text(_u8L(to_string(vertex.type)));
|
||||
});
|
||||
append_table_row(_u8L("Line Type"), [&vertex, NA_TXT]() {
|
||||
std::string text;
|
||||
if (vertex.is_extrusion())
|
||||
text = _u8L(to_string(vertex.role));
|
||||
else
|
||||
text = NA_TXT;
|
||||
ImGuiWrapper::text(text);
|
||||
});
|
||||
append_table_row(_u8L("Width"), [&vertex, &buff, NA_TXT]() {
|
||||
std::string text;
|
||||
if (vertex.is_extrusion()) {
|
||||
sprintf(buff, ("%.3f " + _u8L("mm")).c_str(), vertex.width);
|
||||
text = std::string(buff);
|
||||
}
|
||||
else
|
||||
text = NA_TXT;
|
||||
ImGuiWrapper::text(text);
|
||||
});
|
||||
append_table_row(_u8L("Height"), [&vertex, &buff, NA_TXT]() {
|
||||
std::string text;
|
||||
if (vertex.is_extrusion()) {
|
||||
sprintf(buff, ("%.3f " + _u8L("mm")).c_str(), vertex.height);
|
||||
text = std::string(buff);
|
||||
}
|
||||
else
|
||||
text = NA_TXT;
|
||||
ImGuiWrapper::text(text);
|
||||
});
|
||||
append_table_row(_u8L("Layer"), [&vertex, &buff]() {
|
||||
sprintf(buff, "%d", vertex.layer_id + 1);
|
||||
const std::string text = std::string(buff);
|
||||
ImGuiWrapper::text(text);
|
||||
});
|
||||
append_table_row(_u8L("Speed"), [&vertex, &buff]() {
|
||||
sprintf(buff, ("%.1f " + _u8L("mm/s")).c_str(), vertex.feedrate);
|
||||
const std::string text = std::string(buff);
|
||||
ImGuiWrapper::text(text);
|
||||
});
|
||||
append_table_row(_u8L("Acceleration"), [&vertex, &buff]() {
|
||||
sprintf(buff, ("%.0f " + _u8L("mm/s²")).c_str(), vertex.acceleration);
|
||||
const std::string text = std::string(buff);
|
||||
ImGuiWrapper::text(text);
|
||||
});
|
||||
append_table_row(_u8L("Jerk"), [&vertex, &buff]() {
|
||||
sprintf(buff, ("%.1f " + _u8L("mm/s")).c_str(), vertex.jerk);
|
||||
const std::string text = std::string(buff);
|
||||
ImGuiWrapper::text(text);
|
||||
});
|
||||
append_table_row(_u8L("Flow rate"), [&vertex, &buff, NA_TXT]() { // ORCA use "Flow rate" instead "Volumetric flow Rate" to make window more compact
|
||||
std::string text;
|
||||
if (vertex.is_extrusion()) {
|
||||
sprintf(buff, ("%.3f " + _u8L("mm³/s")).c_str(), vertex.volumetric_rate());
|
||||
text = std::string(buff);
|
||||
}
|
||||
else
|
||||
text = NA_TXT;
|
||||
ImGuiWrapper::text(text);
|
||||
});
|
||||
append_table_row(_u8L("Fan speed"), [&vertex, &buff]() {
|
||||
sprintf(buff, "%.0f %%", vertex.fan_speed);
|
||||
const std::string text = std::string(buff);
|
||||
ImGuiWrapper::text(text);
|
||||
});
|
||||
append_table_row(_u8L("Temperature"), [&vertex, &buff]() {
|
||||
sprintf(buff, ("%.0f " + _u8L("°C")).c_str(), vertex.temperature);
|
||||
ImGuiWrapper::text(std::string(buff));
|
||||
});
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
append_table_row(_u8L("Pressure Advance"), [&vertex, &buff]() {
|
||||
sprintf(buff, "%.4f", vertex.pressure_advance);
|
||||
ImGuiWrapper::text(std::string(buff));
|
||||
});
|
||||
append_table_row(_u8L("Time"), [viewer, &vertex, &buff, vertex_id]() {
|
||||
const float estimated_time = viewer->get_estimated_time_at(vertex_id);
|
||||
sprintf(buff, "%s (%.3fs)", get_time_dhms(estimated_time).c_str(), vertex.times[static_cast<size_t>(viewer->get_time_mode())]);
|
||||
const std::string text = std::string(buff);
|
||||
ImGuiWrapper::text(text);
|
||||
});
|
||||
for (const auto& row : properties_rows)
|
||||
append_table_row(row.first, row.second);
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
#if ENABLE_ACTUAL_SPEED_DEBUG
|
||||
bool actual_speed_exist = vertex.is_extrusion() || vertex.is_travel() || vertex.is_wipe();
|
||||
//if (vertex.is_extrusion() || vertex.is_travel() || vertex.is_wipe()) { // ORCA always show button to keep properties on same place
|
||||
ImGui::Spacing();
|
||||
//ImGuiWrapper::text(_u8L("Actual speed profile"));
|
||||
//ImGui::SameLine();
|
||||
static float cached_table_wnd_width = 0.0f; // ORCA: Cache the calculated window width to avoid recalculation on every frame
|
||||
static float cached_table_wnd_scale = 0.0f; // ORCA: Cache the calculated window scale to avoid recalculation on every frame
|
||||
ImGui::Spacing();
|
||||
|
||||
static bool table_shown = false;
|
||||
imgui.push_confirm_button_style();
|
||||
const float table_btn_width = std::max(ImGui::CalcTextSize(_u8L("Hide").c_str()).x, ImGui::CalcTextSize(_u8L("Show").c_str()).x);
|
||||
float btn_padding_x = 8.0f * m_scale;
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding , 3.f * m_scale);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding , ImVec2(btn_padding_x, 3.f * m_scale));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(.5f, .5f));
|
||||
if (imgui.button((table_shown ? _L("Hide") : _L("Show")).c_str(), ImVec2(table_btn_width + btn_padding_x * 2.f, 0.f), actual_speed_exist))
|
||||
table_shown = !table_shown;
|
||||
ImGui::PopStyleVar(3);
|
||||
imgui.pop_confirm_button_style();
|
||||
ImGui::SameLine();
|
||||
ImGuiWrapper::text(_u8L("Actual speed profile").c_str()); // ORCA show label and plot on external window to make main window more compact
|
||||
static bool table_shown = false;
|
||||
imgui.push_confirm_button_style();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding , 3.f * m_scale);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding , ImVec2(btn_padding_x, 3.f * m_scale));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(.5f, .5f));
|
||||
if (imgui.button((table_shown ? _L("Hide") : _L("Show")).c_str(), ImVec2(table_btn_width + btn_padding_x * 2.f, 0.f), actual_speed_exist))
|
||||
table_shown = !table_shown;
|
||||
ImGui::PopStyleVar(3);
|
||||
imgui.pop_confirm_button_style();
|
||||
ImGui::SameLine();
|
||||
ImGuiWrapper::text(_u8L("Actual speed profile").c_str()); // ORCA show label and plot on external window to make main window more compact
|
||||
|
||||
//ImGui::Separator();
|
||||
//const int hover_id = m_actual_speed_imgui_widget.plot("##ActualSpeedProfile", { -1.0f, 150.0f });
|
||||
if (actual_speed_exist && table_shown) {
|
||||
static float table_wnd_height = 0.0f;
|
||||
//const ImVec2 wnd_size = ImGui::GetWindowSize();
|
||||
imgui.set_next_window_pos(ImGui::GetWindowPos().x - 5.f * m_scale /*+ wnd_size.x*/, static_cast<float>(canvas_height), ImGuiCond_Always, 1.0f, 1.0f);
|
||||
//ImGui::SetNextWindowSizeConstraints({ 0.0f, 0.0f }, { -1.0f, wnd_size.y });
|
||||
imgui.begin(std::string("ToolPositionTableWnd"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar |
|
||||
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(9.f, 1.f) * m_scale);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.f, 0.f));
|
||||
ImGui::PushStyleColor(ImGuiCol_HeaderHovered , ImGui::GetStyle().Colors[ImGuiCol_TableHeaderBg]);
|
||||
const int hover_id = m_actual_speed_imgui_widget.plot("##ActualSpeedProfile", { -1.f, 135.f * m_scale});
|
||||
if (ImGui::BeginTable("ToolPositionTable", 2, ImGuiTableFlags_Borders /*| ImGuiTableFlags_ScrollY*/)) { // ORCA showing scrollbar causes expanding window
|
||||
char buff[1024];
|
||||
//ImGui::TableSetupScrollFreeze(0, 1); // Make top row always visible
|
||||
ImGui::TableSetupColumn((_u8L("Position") + " (" + _u8L("mm") + ")").c_str());
|
||||
ImGui::TableSetupColumn((_u8L("Speed") + " (" + _u8L("mm/s") + ")").c_str());
|
||||
ImGui::TableHeadersRow();
|
||||
int counter = 0;
|
||||
for (const ActualSpeedImguiWidget::Item& item : m_actual_speed_imgui_widget.data) {
|
||||
const bool highlight = hover_id >= 0 && (counter == hover_id || counter == hover_id + 1);
|
||||
//if (highlight && counter == hover_id)
|
||||
// ImGui::SetScrollHereY();
|
||||
ImGui::TableNextRow();
|
||||
const ImU32 row_bg_color = ImGui::GetColorU32(item.internal ? ImVec4(0.0f, 150.f / 255.0f, 136.0f / 255.f, 0.15f) : ImVec4(0.2f, 0.2f, 0.2f, 0.25f)); // ORCA
|
||||
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, row_bg_color);
|
||||
ImGui::TableSetColumnIndex(0);
|
||||
sprintf(buff, "%.3f", item.pos);
|
||||
imgui.text_colored(highlight ? ImGuiWrapper::COL_ORCA : ImGuiWrapper::to_ImVec4(ColorRGBA::WHITE()), buff);
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
sprintf(buff, "%.1f", item.speed);
|
||||
imgui.text_colored(highlight ? ImGuiWrapper::COL_ORCA : ImGuiWrapper::to_ImVec4(ColorRGBA::WHITE()), buff);
|
||||
++counter;
|
||||
}
|
||||
if (actual_speed_exist && table_shown) {
|
||||
const float plot_height = 135.f * m_scale; // 135 is the height of the plot without labels
|
||||
|
||||
// ORCA add blank rows to keep plot in same place. row count can be 9 but mostly it shows between 3 to 5
|
||||
for (int id = 7 - counter; id > 0; --id) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableSetColumnIndex(0);
|
||||
imgui.text_colored(ImVec4(0.f, 0.f, 0.f, 0.f), "f");
|
||||
}
|
||||
if (cached_table_wnd_scale != m_scale) { // ORCA
|
||||
// Catch the window width to avoid recalculation on every frame,
|
||||
// but recalculate it when/if scale changes.
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
ImGui::PopStyleVar(2);
|
||||
ImGui::PopStyleColor(1);
|
||||
const float curr_table_wnd_height = ImGui::GetWindowHeight();
|
||||
if (table_wnd_height != curr_table_wnd_height) {
|
||||
table_wnd_height = curr_table_wnd_height;
|
||||
// require extra frame to hide the table scroll bar (bug in imgui)
|
||||
imgui.set_requires_extra_frame();
|
||||
}
|
||||
imgui.end();
|
||||
const float cell_pad_x = 9.f * m_scale; // matches ImGuiStyleVar_CellPadding.x below
|
||||
const float wnd_pad_x = 2.0f * style.WindowPadding.x;
|
||||
const float table_border_x = 6.0f * m_scale;
|
||||
|
||||
// Calculate the width needed to fully show each table column header
|
||||
// but not clamping to a minimum because later the window width is clamped anyway.
|
||||
const float col0_w = ImGui::CalcTextSize((_u8L("Position") + " (" + _u8L("mm") + ")").c_str()).x;
|
||||
const float col1_w = ImGui::CalcTextSize((_u8L("Speed") + " (" + _u8L("mm/s") + ")").c_str()).x;
|
||||
|
||||
const float content_w = std::ceil(col0_w + col1_w + 4.0f * cell_pad_x + table_border_x + wnd_pad_x);
|
||||
const float aspect_w = std::ceil(plot_height * (16.0f / 9.0f)); // 16:9 ratio for better look
|
||||
// Try to obtain 16:9 ratio if possible, but keep enough width for content to make
|
||||
// window looking good on different languages, especially with long words in table header
|
||||
cached_table_wnd_width = std::max(content_w, aspect_w);
|
||||
cached_table_wnd_scale = m_scale;
|
||||
}
|
||||
|
||||
// ORCA: Pre-calculate the height of the table based on number of rows
|
||||
// and clamp the final window height to keep at least the same height as ToolPosition window.
|
||||
const float cell_pad_y = 1.f * m_scale; // ImGuiStyleVar_CellPadding.y below
|
||||
const float row_height = ImGui::GetTextLineHeight() + 2.f * cell_pad_y;
|
||||
const float rows = static_cast<float>(m_actual_speed_imgui_widget.data.size());
|
||||
const float table_h = row_height * (1.0f + rows) + 2.f * m_scale; // border allowance
|
||||
const float target_h = std::ceil(plot_height + table_h + 2.f * style.WindowPadding.y);
|
||||
const float min_h = ImGui::GetWindowHeight(); // keep at least the same height as ToolPosition window
|
||||
const float max_h = static_cast<float>(canvas_height) - 8.f * m_scale; // keep inside canvas with a small margin
|
||||
const float final_h = std::clamp(target_h, min_h, max_h);
|
||||
const bool needs_scroll = target_h > max_h;
|
||||
const float table_view_h = std::max(1.0f, final_h - plot_height - 2.f * style.WindowPadding.y);
|
||||
|
||||
//const ImVec2 wnd_size = ImGui::GetWindowSize();
|
||||
imgui.set_next_window_pos(ImGui::GetWindowPos().x - 5.f * m_scale /*+ wnd_size.x*/, static_cast<float>(canvas_height), ImGuiCond_Always, 1.0f, 1.0f);
|
||||
ImGui::SetNextWindowSize(ImVec2(cached_table_wnd_width, final_h), ImGuiCond_Always);
|
||||
//ImGui::SetNextWindowSizeConstraints({ 0.0f, 0.0f }, { -1.0f, wnd_size.y });
|
||||
imgui.begin(std::string("ToolPositionTableWnd"), ImGuiWindowFlags_NoTitleBar |
|
||||
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove |
|
||||
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(9.f, 1.f) * m_scale);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.f, 0.f));
|
||||
ImGui::PushStyleColor(ImGuiCol_HeaderHovered , style.Colors[ImGuiCol_TableHeaderBg]);
|
||||
const int hover_id = m_actual_speed_imgui_widget.plot("##ActualSpeedProfile", { -1.f, plot_height});
|
||||
const ImGuiTableFlags table_flags = ImGuiTableFlags_Borders | (needs_scroll ? ImGuiTableFlags_ScrollY : 0);
|
||||
if (ImGui::BeginTable("ToolPositionTable", 2, table_flags, ImVec2(0.0f, needs_scroll ? table_view_h : 0.0f))) {
|
||||
char buff[1024];
|
||||
if (needs_scroll)
|
||||
ImGui::TableSetupScrollFreeze(0, 1); // Make top row always visible
|
||||
ImGui::TableSetupColumn((_u8L("Position") + " (" + _u8L("mm") + ")").c_str());
|
||||
ImGui::TableSetupColumn((_u8L("Speed") + " (" + _u8L("mm/s") + ")").c_str());
|
||||
ImGui::TableHeadersRow();
|
||||
int counter = 0;
|
||||
for (const ActualSpeedImguiWidget::Item& item : m_actual_speed_imgui_widget.data) {
|
||||
const bool highlight = hover_id >= 0 && (counter == hover_id || counter == hover_id + 1);
|
||||
ImGui::TableNextRow();
|
||||
const ImU32 row_bg_color = ImGui::GetColorU32(item.internal ? ImVec4(0.0f, 150.f / 255.0f, 136.0f / 255.f, 0.15f) : ImVec4(0.2f, 0.2f, 0.2f, 0.25f)); // ORCA
|
||||
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, row_bg_color);
|
||||
ImGui::TableSetColumnIndex(0);
|
||||
sprintf(buff, "%.3f", item.pos);
|
||||
imgui.text_colored(highlight ? ImGuiWrapper::COL_ORCA : ImGuiWrapper::to_ImVec4(ColorRGBA::WHITE()), buff);
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
sprintf(buff, "%.1f", item.speed);
|
||||
imgui.text_colored(highlight ? ImGuiWrapper::COL_ORCA : ImGuiWrapper::to_ImVec4(ColorRGBA::WHITE()), buff);
|
||||
++counter;
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
ImGui::PopStyleVar(2);
|
||||
ImGui::PopStyleColor(1);
|
||||
imgui.end();
|
||||
}
|
||||
|
||||
#endif // ENABLE_ACTUAL_SPEED_DEBUG
|
||||
|
||||
ImGui::Spacing();
|
||||
ImGui::Separator();
|
||||
ImGui::Dummy({0, ImGui::GetStyle().FramePadding.y});
|
||||
ImGui::Dummy({0, style.FramePadding.y});
|
||||
}
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding , 3.f * m_scale);
|
||||
@@ -540,7 +619,7 @@ void GCodeViewer::SequentialView::Marker::render_position_window(const libvgcode
|
||||
ImGui::SameLine();
|
||||
|
||||
if(!properties_shown)
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() - ImGui::GetStyle().FramePadding.y); // aligns button with next group
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() - style.FramePadding.y); // aligns button with next group
|
||||
|
||||
ImGui::BeginGroup(); // group contents to make information area more compact
|
||||
|
||||
@@ -548,7 +627,6 @@ void GCodeViewer::SequentialView::Marker::render_position_window(const libvgcode
|
||||
auto pos =vertex.position;
|
||||
int max_value = std::round(std::max(std::max(pos[0], pos[1]),pos[2]));
|
||||
auto precision = max_value > 9999 ? "%.1f" : max_value > 999 ? "%.2f" : "%.3f";
|
||||
const float axes_width = ImGui::CalcTextSize("X 999.999sp").x;
|
||||
|
||||
char xBuf[32];
|
||||
ImGui::TextColored(ImGuiWrapper::to_ImVec4(ColorRGBA::X()),"X ");
|
||||
@@ -557,119 +635,30 @@ void GCodeViewer::SequentialView::Marker::render_position_window(const libvgcode
|
||||
ImGui::Text("%s", xBuf);
|
||||
|
||||
char yBuf[32];
|
||||
ImGui::SameLine(axes_width);
|
||||
ImGui::SameLine(axes_width + axes_spacing_x);
|
||||
ImGui::TextColored(ImGuiWrapper::to_ImVec4(ColorRGBA::Y()),"Y ");
|
||||
ImGui::SameLine(0,0); // ignore item spacing
|
||||
sprintf(yBuf, precision, pos[1]);
|
||||
ImGui::Text("%s", yBuf);
|
||||
|
||||
char zBuf[32];
|
||||
ImGui::SameLine(axes_width * 2);
|
||||
ImGui::SameLine(2.0f * (axes_width + axes_spacing_x));
|
||||
ImGui::TextColored(ImGuiWrapper::to_ImVec4(ColorRGBA::Z()),"Z ");
|
||||
ImGui::SameLine(0,0); // ignore item spacing
|
||||
sprintf(zBuf, precision, pos[2]);
|
||||
ImGui::Text("%s", zBuf);
|
||||
|
||||
ImGui::SameLine(axes_width * 3);
|
||||
ImGui::SameLine(3.0f * axes_width + 2.0f * axes_spacing_x);
|
||||
ImGui::Dummy({0,0});
|
||||
|
||||
const bool is_extrusion = vertex.is_extrusion();
|
||||
char buf[1024] = ""; char valBuf[32]; char spdBuf[128];
|
||||
char spdBuf[128];
|
||||
sprintf(spdBuf, "%s%.0f ", _u8L("Speed: ").c_str(), vertex.feedrate);
|
||||
const float speed_width = ImGui::CalcTextSize((_u8L("Speed: ") + "9999 ").c_str()).x;
|
||||
ImGuiWrapper::text(std::string(spdBuf)); // render Speed as differrent item to keep next item in same place
|
||||
switch (view_type) {
|
||||
case libvgcode::EViewType::FeatureType: {
|
||||
if (is_extrusion && !vertex.is_option()) // ORCA show more types on FeatureType
|
||||
sprintf(buf, "%s", to_string(vertex.role).c_str());
|
||||
else if(vertex.is_travel() || vertex.is_option() || vertex.is_wipe())
|
||||
sprintf(buf, "%s", to_string(vertex.type).c_str());
|
||||
else
|
||||
sprintf(buf, "%s", NA_CSTR);
|
||||
break;
|
||||
}
|
||||
case libvgcode::EViewType::Height: {
|
||||
if (is_extrusion)
|
||||
sprintf(valBuf, "%.2f", vertex.height);
|
||||
else
|
||||
sprintf(valBuf, "%s", NA_CSTR);
|
||||
sprintf(buf, "%s%s", _u8L("Height: ").c_str(), valBuf);
|
||||
break;
|
||||
}
|
||||
case libvgcode::EViewType::Width: {
|
||||
if (is_extrusion)
|
||||
sprintf(valBuf, "%.2f", vertex.width);
|
||||
else
|
||||
sprintf(valBuf, "%s", NA_CSTR);
|
||||
sprintf(buf, "%s%s", _u8L("Width: ").c_str(), valBuf);
|
||||
break;
|
||||
}
|
||||
case libvgcode::EViewType::VolumetricFlowRate: {
|
||||
if (is_extrusion)
|
||||
sprintf(valBuf, "%.2f", vertex.volumetric_rate());
|
||||
else
|
||||
sprintf(valBuf, "%s", NA_CSTR);
|
||||
sprintf(buf, "%s%s", _u8L("Flow: ").c_str(), valBuf);
|
||||
break;
|
||||
}
|
||||
case libvgcode::EViewType::FanSpeed: {
|
||||
sprintf(buf, "%s%.0f", _u8L("Fan: ").c_str(), vertex.fan_speed);
|
||||
break;
|
||||
}
|
||||
case libvgcode::EViewType::Temperature: {
|
||||
sprintf(buf, "%s%.0f", _u8L("Temperature: ").c_str(), vertex.temperature);
|
||||
break;
|
||||
}
|
||||
case libvgcode::EViewType::LayerTimeLinear:
|
||||
case libvgcode::EViewType::LayerTimeLogarithmic: {
|
||||
sprintf(buf, "%s%.1f", _u8L("Layer Time: ").c_str(), vertex.layer_duration);
|
||||
break;
|
||||
}
|
||||
case libvgcode::EViewType::Tool: {
|
||||
sprintf(buf, "%s%d", _u8L("Tool: ").c_str(), vertex.extruder_id + 1);
|
||||
break;
|
||||
}
|
||||
case libvgcode::EViewType::ColorPrint: {
|
||||
sprintf(buf, "%s%d", _u8L("Color: ").c_str(), vertex.color_id + 1);
|
||||
break;
|
||||
}
|
||||
case libvgcode::EViewType::ActualVolumetricFlowRate: {
|
||||
// Don't display the actual flow, since it only gives data for the end of a segment
|
||||
//if (is_extrusion)
|
||||
// sprintf(valBuf, "%.2f", vertex.actual_volumetric_rate());
|
||||
//else
|
||||
// sprintf(valBuf, "%s", NA_CSTR);
|
||||
//sprintf(buf, "%s%s", _u8L("Actual Flow: ").c_str(), valBuf);
|
||||
break;
|
||||
}
|
||||
case libvgcode::EViewType::ActualSpeed: {
|
||||
// Don't display the actual flow, since it only gives data for the end of a segment
|
||||
//sprintf(buf, "%s%.1f", _u8L("Actual Speed: ").c_str(), vertex.actual_feedrate);
|
||||
break;
|
||||
}
|
||||
case libvgcode::EViewType::Acceleration: {
|
||||
sprintf(buf, "%s %s%.0f", buf, _u8L("Acceleration: ").c_str(), vertex.acceleration);
|
||||
break;
|
||||
}
|
||||
case libvgcode::EViewType::Jerk: {
|
||||
sprintf(buf, "%s %s%.1f", buf, _u8L("Jerk: ").c_str(), vertex.jerk);
|
||||
break;
|
||||
}
|
||||
// ORCA: Add Pressure Advance visualization support
|
||||
case libvgcode::EViewType::PressureAdvance: {
|
||||
sprintf(buf, "%s%.4f", _u8L("PA: ").c_str(), vertex.pressure_advance);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ImGuiWrapper::text(spdBuf); // render Speed as differrent item to keep next item in same place
|
||||
|
||||
if (buf[0] != '\0') { // dont render if buffer empty
|
||||
if (detail_buf[0] != '\0') { // dont render if buffer empty
|
||||
ImGui::SameLine(speed_width);
|
||||
ImGuiWrapper::text(std::string(buf));
|
||||
ImGuiWrapper::text(detail_buf);
|
||||
}
|
||||
|
||||
ImGui::EndGroup();
|
||||
|
||||
imgui.end();
|
||||
|
||||
Reference in New Issue
Block a user