GCodeViewer -> Reworked layout of imgui dialog for estimated printing times

This commit is contained in:
enricoturri1966 2020-07-09 15:57:35 +02:00
parent 6fbb3db79c
commit 431cfcc671
2 changed files with 160 additions and 101 deletions

View file

@ -40,23 +40,28 @@ static GCodeProcessor::EMoveType buffer_type(unsigned char id) {
return static_cast<GCodeProcessor::EMoveType>(static_cast<unsigned char>(GCodeProcessor::EMoveType::Retract) + id);
}
std::vector<std::array<float, 3>> decode_colors(const std::vector<std::string> & colors) {
std::array<float, 3> decode_color(const std::string& color) {
static const float INV_255 = 1.0f / 255.0f;
std::array<float, 3> ret;
const char* c = color.data() + 1;
if ((color.size() == 7) && (color.front() == '#')) {
for (size_t j = 0; j < 3; ++j) {
int digit1 = hex_digit_to_int(*c++);
int digit2 = hex_digit_to_int(*c++);
if ((digit1 == -1) || (digit2 == -1))
break;
ret[j] = float(digit1 * 16 + digit2) * INV_255;
}
}
return ret;
}
std::vector<std::array<float, 3>> decode_colors(const std::vector<std::string>& colors) {
std::vector<std::array<float, 3>> output(colors.size(), { 0.0f, 0.0f, 0.0f });
for (size_t i = 0; i < colors.size(); ++i) {
const std::string& color = colors[i];
const char* c = color.data() + 1;
if ((color.size() == 7) && (color.front() == '#')) {
for (size_t j = 0; j < 3; ++j) {
int digit1 = hex_digit_to_int(*c++);
int digit2 = hex_digit_to_int(*c++);
if ((digit1 == -1) || (digit2 == -1))
break;
output[i][j] = float(digit1 * 16 + digit2) * INV_255;
}
}
output[i] = decode_color(colors[i]);
}
return output;
}
@ -1575,6 +1580,11 @@ void GCodeViewer::render_legend() const
{
// extruders
for (unsigned int i = 0; i < (unsigned int)extruders_count; ++i) {
// shows only extruders actually used
auto it = std::find(m_extruder_ids.begin(), m_extruder_ids.end(), static_cast<unsigned char>(i));
if (it == m_extruder_ids.end())
continue;
#if USE_ICON_HEXAGON
add_item(EItemType::Hexagon, m_tool_colors[i], (boost::format(_u8L("Extruder %d")) % (i + 1)).str());
#else
@ -1671,14 +1681,9 @@ void GCodeViewer::render_legend() const
ImGui::PopStyleVar();
}
void GCodeViewer::render_time_estimate() const
{
static const std::vector<std::string> Columns_Headers = {
_u8L("Operation"),
_u8L("Remaining"),
_u8L("Duration")
};
if (!m_time_estimate_enabled)
return;
@ -1686,94 +1691,87 @@ void GCodeViewer::render_time_estimate() const
if (ps.estimated_normal_print_time == "N/A" && ps.estimated_silent_print_time == "N/A")
return;
int columns_count = 1;
if (ps.estimated_silent_print_time != "N/A")
++columns_count;
ImGuiWrapper& imgui = *wxGetApp().imgui();
Size cnv_size = wxGetApp().plater()->get_current_canvas3D()->get_canvas_size();
imgui.set_next_window_pos(static_cast<float>(cnv_size.get_width()), static_cast<float>(cnv_size.get_height()), ImGuiCond_Always, 1.0f, 1.0f);
ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, 0.0f), ImVec2(-1.0f, 0.5f * static_cast<float>(cnv_size.get_height())));
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGui::SetNextWindowBgAlpha(0.6f);
imgui.begin(std::string("Time_estimate"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove);
ImDrawList* draw_list = ImGui::GetWindowDrawList();
float icon_size = ImGui::GetTextLineHeight();
using Time = std::pair<float, float>;
using TimesList = std::vector<std::pair<CustomGCode::Type, Time>>;
using Headers = std::vector<std::string>;
using Offsets = std::array<float, 2>;
auto add_mode = [this, &imgui, icon_size, draw_list](const std::string& mode, const std::string& time, const TimesList& times, const Headers& headers) {
auto add_partial_times = [this, &imgui, icon_size, draw_list](const TimesList& times, const Headers& headers) {
auto add_color = [this, &imgui, icon_size, draw_list](int id, Offsets& offsets, const Time& time) {
ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT);
std::string text = _u8L("Color");
if (m_view_type != EViewType::ColorPrint)
text += " " + std::to_string(id);
imgui.text(text);
ImGui::PopStyleColor();
ImGui::SameLine();
// helper structure containig the data needed to render the items
struct Item
{
CustomGCode::Type type;
int extruder_id;
Color color;
Time time;
};
using Items = std::vector<Item>;
if (m_view_type == EViewType::ColorPrint) {
const Color& color = m_tool_colors[id - 1];
ImVec2 pos = ImGui::GetCursorScreenPos();
#if USE_ICON_HEXAGON
ImVec2 center(0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size));
draw_list->AddNgonFilled(center, 0.5f * icon_size, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 6);
#else
draw_list->AddRectFilled({ pos.x + 1.0f, pos.y + 1.0f }, { pos.x + icon_size - 1.0f, pos.y + icon_size - 1.0f },
ImGui::GetColorU32({ m_tool_colors[i][0], m_tool_colors[i][1], m_tool_colors[i][2], 1.0f }));
#endif // USE_ICON_HEXAGON
}
ImGui::SameLine(offsets[0]);
imgui.text(short_time(get_time_dhms(time.second)));
ImGui::SameLine(offsets[1]);
imgui.text(short_time(get_time_dhms(time.first)));
auto append_mode = [this, &imgui](const std::string& time_str, const Items& items) {
auto append_partial_times = [this, &imgui](const Items& items) {
using Headers = std::vector<std::string>;
const Headers headers = {
_u8L("Event"),
_u8L("Remaining"),
_u8L("Duration")
};
auto calc_offsets = [this, icon_size](const TimesList& times, const Headers& headers, int color_change_count) {
using Offsets = std::array<float, 2>;
auto calc_offsets = [this, &headers](const Items& items) {
Offsets ret = { ImGui::CalcTextSize(headers[0].c_str()).x, ImGui::CalcTextSize(headers[1].c_str()).x };
for (const auto& [type, time] : times) {
for (const Item& item : items) {
std::string label;
switch (type)
switch (item.type)
{
case CustomGCode::PausePrint:
{
label = _u8L("Pause");
break;
}
case CustomGCode::PausePrint: { label = _u8L("Pause"); break; }
case CustomGCode::ColorChange:
{
label = _u8L("Color");
if (m_view_type != EViewType::ColorPrint)
label += " " + std::to_string(color_change_count);
int extruders_count = wxGetApp().extruders_edited_cnt();
label = (extruders_count > 1) ? _u8L("[XX] Color") : _u8L("Color");
break;
}
default: { break; }
}
ret[0] = std::max(ret[0], ImGui::CalcTextSize(label.c_str()).x);
ret[1] = std::max(ret[1], ImGui::CalcTextSize(short_time(get_time_dhms(time.second)).c_str()).x);
ret[1] = std::max(ret[1], ImGui::CalcTextSize(short_time(get_time_dhms(item.time.second)).c_str()).x);
}
const ImGuiStyle& style = ImGui::GetStyle();
ret[0] += icon_size + style.ItemSpacing.x;
ret[0] += ImGui::GetTextLineHeight() + 2.0f * style.ItemSpacing.x;
ret[1] += ret[0] + style.ItemSpacing.x;
return ret;
};
auto append_color = [this, &imgui](int id, int extruder_id, const Color& color, Offsets& offsets, const Time& time) {
ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT);
int extruders_count = wxGetApp().extruders_edited_cnt();
std::string text;
if (extruders_count > 1)
text = "[" + std::to_string(extruder_id) + "] ";
text += _u8L("Color");
imgui.text(text);
ImGui::PopStyleColor();
ImGui::SameLine();
if (times.empty())
float icon_size = ImGui::GetTextLineHeight();
ImDrawList* draw_list = ImGui::GetWindowDrawList();
ImVec2 pos = ImGui::GetCursorScreenPos();
pos.x -= 0.5f * ImGui::GetStyle().ItemSpacing.x;
#if USE_ICON_HEXAGON
ImVec2 center(0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size));
draw_list->AddNgonFilled(center, 0.5f * icon_size, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 6);
#else
draw_list->AddRectFilled({ pos.x + 1.0f, pos.y + 1.0f }, { pos.x + icon_size - 1.0f, pos.y + icon_size - 1.0f },
ImGui::GetColorU32({ m_tool_colors[i][0], m_tool_colors[i][1], m_tool_colors[i][2], 1.0f }));
#endif // USE_ICON_HEXAGON
ImGui::SameLine(offsets[0]);
imgui.text(short_time(get_time_dhms(time.second)));
ImGui::SameLine(offsets[1]);
imgui.text(short_time(get_time_dhms(time.first)));
};
if (items.empty())
return;
int color_change_count = 0;
for (auto time : times) {
if (time.first == CustomGCode::ColorChange)
++color_change_count;
}
Offsets offsets = calc_offsets(times, headers, color_change_count);
Offsets offsets = calc_offsets(items);
ImGui::Spacing();
ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT);
@ -1783,13 +1781,11 @@ void GCodeViewer::render_time_estimate() const
ImGui::SameLine(offsets[1]);
imgui.text(headers[2]);
ImGui::PopStyleColor();
ImGui::Separator();
int last_color_id = color_change_count;
for (int i = static_cast<int>(times.size()) - 1; i >= 0; --i) {
const auto& [type, time] = times[i];
switch (type)
unsigned int last_color_id = 0;
for (const Item& item : items) {
switch (item.type)
{
case CustomGCode::PausePrint:
{
@ -1797,15 +1793,13 @@ void GCodeViewer::render_time_estimate() const
imgui.text(_u8L("Pause"));
ImGui::PopStyleColor();
ImGui::SameLine(offsets[0]);
imgui.text(short_time(get_time_dhms(time.second - time.first)));
add_color(last_color_id, offsets, time);
imgui.text(short_time(get_time_dhms(item.time.second - item.time.first)));
break;
}
case CustomGCode::ColorChange:
{
add_color(color_change_count, offsets, time);
last_color_id = color_change_count--;
append_color(last_color_id, item.extruder_id, item.color, offsets, item.time);
++last_color_id;
break;
}
default: { break; }
@ -1814,24 +1808,82 @@ void GCodeViewer::render_time_estimate() const
};
ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT);
imgui.text(mode + ":");
imgui.text(_u8L("Time") + ":");
ImGui::PopStyleColor();
ImGui::SameLine();
imgui.text(time);
add_partial_times(times, headers);
imgui.text(time_str);
append_partial_times(items);
};
auto generate_items = [this](const TimesList& times) {
std::vector<Item> items;
std::vector<CustomGCode::Item> custom_gcode_per_print_z = wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes;
int extruders_count = wxGetApp().extruders_edited_cnt();
std::vector<Color> last_color(extruders_count);
for (int i = 0; i < extruders_count; ++i) {
last_color[i] = m_tool_colors[i];
}
int last_extruder_id = 1;
for (const auto& time_rec : times) {
switch (time_rec.first)
{
case CustomGCode::PausePrint:
{
auto it = std::find_if(custom_gcode_per_print_z.begin(), custom_gcode_per_print_z.end(), [time_rec](const CustomGCode::Item& item) { return item.type == time_rec.first; });
if (it != custom_gcode_per_print_z.end()) {
items.push_back({ CustomGCode::ColorChange, it->extruder, last_color[it->extruder - 1], time_rec.second });
items.push_back({ time_rec.first, it->extruder, last_color[it->extruder - 1], time_rec.second });
custom_gcode_per_print_z.erase(it);
}
break;
}
case CustomGCode::ColorChange:
{
auto it = std::find_if(custom_gcode_per_print_z.begin(), custom_gcode_per_print_z.end(), [time_rec](const CustomGCode::Item& item) { return item.type == time_rec.first; });
if (it != custom_gcode_per_print_z.end()) {
items.push_back({ time_rec.first, it->extruder, last_color[it->extruder - 1], time_rec.second });
last_color[it->extruder - 1] = decode_color(it->color);
last_extruder_id = it->extruder;
custom_gcode_per_print_z.erase(it);
}
else
items.push_back({ time_rec.first, last_extruder_id, last_color[last_extruder_id - 1], time_rec.second });
break;
}
default: { break; }
}
}
return items;
};
Size cnv_size = wxGetApp().plater()->get_current_canvas3D()->get_canvas_size();
imgui.set_next_window_pos(static_cast<float>(cnv_size.get_width()), static_cast<float>(cnv_size.get_height()), ImGuiCond_Always, 1.0f, 1.0f);
ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, 0.0f), ImVec2(-1.0f, 0.5f * static_cast<float>(cnv_size.get_height())));
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGui::SetNextWindowBgAlpha(0.6f);
imgui.begin(std::string("Time_estimate_2"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove);
// title
imgui.title(_u8L("Estimated printing time"));
// times
if (ps.estimated_normal_print_time != "N/A")
add_mode(_u8L("Normal mode"), ps.estimated_normal_print_time, ps.estimated_normal_custom_gcode_print_times, Columns_Headers);
if (ps.estimated_silent_print_time != "N/A") {
ImGui::Separator();
add_mode(_u8L("Stealth mode"), ps.estimated_silent_print_time, ps.estimated_silent_custom_gcode_print_times, Columns_Headers);
// mode tabs
ImGui::BeginTabBar("mode_tabs");
if (ps.estimated_normal_print_time != "N/A") {
if (ImGui::BeginTabItem(_u8L("Normal").c_str())) {
append_mode(ps.estimated_normal_print_time, generate_items(ps.estimated_normal_custom_gcode_print_times));
ImGui::EndTabItem();
}
}
if (ps.estimated_silent_print_time != "N/A") {
if (ImGui::BeginTabItem(_u8L("Stealth").c_str())) {
append_mode(ps.estimated_silent_print_time, generate_items(ps.estimated_silent_custom_gcode_print_times));
ImGui::EndTabItem();
}
}
ImGui::EndTabBar();
imgui.end();
ImGui::PopStyleVar();

View file

@ -1028,6 +1028,13 @@ void ImGuiWrapper::init_style()
// Separator
set_color(ImGuiCol_Separator, COL_ORANGE_LIGHT);
// Tabs
set_color(ImGuiCol_Tab, COL_ORANGE_DARK);
set_color(ImGuiCol_TabHovered, COL_ORANGE_LIGHT);
set_color(ImGuiCol_TabActive, COL_ORANGE_LIGHT);
set_color(ImGuiCol_TabUnfocused, COL_GREY_DARK);
set_color(ImGuiCol_TabUnfocusedActive, COL_GREY_LIGHT);
}
void ImGuiWrapper::render_draw_data(ImDrawData *draw_data)