4066{
4068 return;
4069
4070 const Size cnv_size = wxGetApp().plater()->get_current_canvas3D()->get_canvas_size();
4071
4072 ImGuiWrapper& imgui = *wxGetApp().imgui();
4073
4074
4075 imgui.set_next_window_pos(
float(canvas_width - right_margin *
m_scale), 4.0f *
m_scale, ImGuiCond_Always, 1.0f, 0.0f);
4076 ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 8.0f *
m_scale);
4077 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0,0.0));
4078 ImGui::PushStyleColor(ImGuiCol_Separator, ImVec4(1.0f,1.0f,1.0f,0.6f));
4079 ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.00f, 0.59f, 0.53f, 1.0f));
4080 ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.00f, 0.59f, 0.53f, 1.0f));
4081 ImGui::PushStyleColor(ImGuiCol_ScrollbarGrab, ImVec4(0.42f, 0.42f, 0.42f, 1.00f));
4082 ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabHovered, ImVec4(0.93f, 0.93f, 0.93f, 1.00f));
4083 ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabActive, ImVec4(0.93f, 0.93f, 0.93f, 1.00f));
4084
4085 ImGui::PushStyleColor(ImGuiCol_Border, {1, 0, 0, 0});
4086 ImGui::SetNextWindowBgAlpha(0.8f);
4087 const float max_height = 0.75f * static_cast<float>(cnv_size.get_height());
4088 const float child_height = 0.3333f * max_height;
4089 ImGui::SetNextWindowSizeConstraints({ 0.0f, 0.0f }, { -1.0f, max_height });
4090 imgui.begin(std::string("Legend"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove);
4091
4092 enum class EItemType : unsigned char
4093 {
4094 Rect,
4097 Line,
4099 };
4100
4103 const int curr_view_type_i = static_cast<int>(curr_view_type);
4104 const size_t current_time_mode =
static_cast<size_t>(
m_viewer.get_time_mode());
4105 const float total_estimated_time = time_mode.time > 0.0f ? time_mode.time :
m_viewer.get_estimated_time();
4109
4110 const float icon_size = ImGui::GetTextLineHeight() * 0.7;
4111
4112
4113 const float percent_bar_size = 0;
4114
4115 bool imperial_units = wxGetApp().app_config->get("use_inches") == "1";
4116 ImDrawList* draw_list = ImGui::GetWindowDrawList();
4117 ImVec2 pos_rect = ImGui::GetCursorScreenPos();
4118 float window_padding = 4.0f *
m_scale;
4119
4120 auto format_compact_count = [](unsigned long long value) {
4121 static constexpr const char* suffixes[] = { "", "K", "M", "B", "T", "P", "E" };
4122 constexpr size_t suffix_count = sizeof(suffixes) / sizeof(suffixes[0]);
4123
4124 if (value < 1000)
4125 return std::to_string(value);
4126
4127 size_t suffix_index = 0;
4128 unsigned long long divisor = 1;
4129 while (suffix_index + 1 < suffix_count && value / divisor >= 1000) {
4130 divisor *= 1000;
4131 ++suffix_index;
4132 }
4133
4134 const unsigned long long whole = value / divisor;
4135 const unsigned long long tenths = (value % divisor) * 10 / divisor;
4136
4137 std::string ret = std::to_string(whole);
4138 if (tenths != 0)
4139 ret += "." + std::to_string(tenths);
4140 ret += suffixes[suffix_index];
4141 return ret;
4142 };
4143
4144 auto format_percent = [](float percent) {
4145 if (percent == 0.0f)
4146 return std::string("0");
4147
4148 char buffer[64];
4149 percent > 0.001f ? ::sprintf(buffer, "%.1f", percent * 100.0f) : ::sprintf(buffer, "<0.1");
4150 return std::string(buffer);
4151 };
4152
4153
4154
4155
4156
4157
4158 auto append_item = [icon_size, &imgui, &window_padding, &draw_list, this](
4159 EItemType type,
4160 const ColorRGBA& color,
4161 const std::vector<std::pair<std::string, float>>& columns_offsets,
4162 bool checkbox = true,
4163 float checkbox_pos = 0.f,
4164 bool visible = true,
4165 std::function<void()> callback = nullptr)
4166 {
4167
4168 ImVec2
pos = ImVec2(ImGui::GetCursorScreenPos().x + window_padding * 3, ImGui::GetCursorScreenPos().y);
4169 switch (type) {
4170 default:
4171 case EItemType::Rect: {
4173 break;
4174 }
4175 case EItemType::Circle: {
4176 ImVec2
center(0.5f * (
pos.x +
pos.x + icon_size), 0.5f * (
pos.y +
pos.y + icon_size + 5.0f));
4178 break;
4179 }
4180 case EItemType::Hexagon: {
4181 ImVec2
center(0.5f * (
pos.x +
pos.x + icon_size), 0.5f * (
pos.y +
pos.y + icon_size + 5.0f));
4183 break;
4184 }
4185 case EItemType::Line: {
4187 break;
4188 }
4189 case EItemType::None:
4190 break;
4191 }
4192
4193 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(20.0 *
m_scale, 6.0 *
m_scale));
4194
4195
4196 ImGui::Dummy({ 0.0, 0.0 });
4197 ImGui::SameLine();
4198 if (callback) {
4199 ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f *
m_scale);
4200 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(20.0 *
m_scale, 0.0));
4201 ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(1.00f, 0.68f, 0.26f, 0.0f));
4202 ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(1.00f, 0.68f, 0.26f, 0.0f));
4203 ImGui::PushStyleColor(ImGuiCol_BorderActive, ImVec4(0.00f, 0.59f, 0.53f, 1.00f));
4204 float max_height = 0.f;
4205 for (auto column_offset : columns_offsets) {
4206 if (ImGui::CalcTextSize(column_offset.first.c_str()).y > max_height)
4207 max_height = ImGui::CalcTextSize(column_offset.first.c_str()).y;
4208 }
4209 bool b_menu_item = ImGui::BBLMenuItem(("##" + columns_offsets[0].first).c_str(), nullptr, false, true, max_height);
4210 ImGui::PopStyleVar(2);
4211 ImGui::PopStyleColor(3);
4212 if (b_menu_item)
4213 callback();
4214 if (checkbox) {
4215
4216
4217
4218 ImGui::SameLine(checkbox_pos);
4219 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0, 0.0));
4220 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0, 0.0));
4221 ImGui::Text(
"%s",
into_u8(visible ? ImGui::VisibleIcon : ImGui::HiddenIcon).c_str());
4222 ImGui::PopStyleVar(2);
4223 }
4224 }
4225
4226
4227 {
4228 if(callback && !checkbox && !visible)
4229 ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(172 / 255.0f, 172 / 255.0f, 172 / 255.0f, 1.00f));
4230 float dummy_size = type == EItemType::None ? window_padding * 3 : ImGui::GetStyle().ItemSpacing.x + icon_size;
4231 ImGui::SameLine(dummy_size);
4232 imgui.text(columns_offsets[0].first);
4233
4234 for (auto i = 1; i < columns_offsets.size(); i++) {
4235 ImGui::SameLine(columns_offsets[i].second);
4236 imgui.text(columns_offsets[i].first);
4237 }
4238 if (callback && !checkbox && !visible)
4239 ImGui::PopStyleColor(1);
4240 }
4241
4242 ImGui::PopStyleVar(1);
4243
4244 };
4245
4246 auto append_range = [append_item](
const libvgcode::ColorRange&
range,
unsigned int decimals) {
4247 auto append_range_item = [append_item, &
range](
int i,
float value,
unsigned int decimals) {
4248 char buf[1024];
4249 ::sprintf(buf, "%.*f", decimals, value);
4251 };
4252
4253 std::vector<float> values =
range.get_values();
4254 if (values.size() == 1)
4255
4256 append_range_item(0, values.front(), decimals);
4257 else if (values.size() == 2) {
4258 append_range_item(
static_cast<int>(
range.get_palette().size()) - 1, values.back(), decimals);
4259 append_range_item(0, values.front(), decimals);
4260 }
4261 else {
4262 for (
int i =
static_cast<int>(
range.get_palette().size()) - 1; i >= 0; --i) {
4263 append_range_item(i, values[i], decimals);
4264 }
4265 }
4266 };
4267
4268 auto append_headers = [&imgui, window_padding, this](const std::vector<std::pair<std::string, float>>& title_offsets) {
4269 for (size_t i = 0; i < title_offsets.size(); i++) {
4270 if (title_offsets[i].first ==
_u8L(
"Display")) {
4271 ImGui::SameLine(title_offsets[i].second);
4272 ImGui::Dummy({16.f *
m_scale, 1});
4273 continue;
4274 }
4275 ImGui::SameLine(title_offsets[i].second);
4276 imgui.bold_text(title_offsets[i].first);
4277 }
4278
4279 ImGui::SameLine();
4280 ImGui::Dummy({window_padding, 1});
4281 ImGui::Separator();
4282 };
4283
4284 auto max_width = [](const std::vector<std::string>& items, const std::string& title, float extra_size = 0.0f) {
4285 float ret = ImGui::CalcTextSize(title.c_str()).x;
4286 for (const std::string& item : items) {
4287 ret = std::max(ret, extra_size + ImGui::CalcTextSize(item.c_str()).x);
4288 }
4289 return ret;
4290 };
4291
4292 auto calculate_offsets = [max_width, this](const std::vector<std::pair<std::string, std::vector<std::string>>>& title_columns, float extra_size = 0.0f) {
4293 const ImGuiStyle&
style = ImGui::GetStyle();
4294 std::vector<float> offsets;
4295
4296 offsets.push_back(max_width(title_columns[0].second, title_columns[0].first, extra_size) + 12.f *
m_scale + ImGui::GetTextLineHeight());
4297 for (size_t i = 1; i < title_columns.size() - 1; i++)
4298 offsets.push_back(offsets.back() + max_width(title_columns[i].second, title_columns[i].first) + ((title_columns[i].first ==
_u8L(
"Display") ? 0 : 12.f) *
m_scale));
4299 if (title_columns.back().first ==
_u8L(
"Display") && title_columns.size() > 2)
4300 offsets[title_columns.size() - 2] -= 3.f;
4301
4302 float average_col_width = ImGui::GetWindowWidth() / static_cast<float>(title_columns.size());
4303 std::vector<float> ret;
4304 ret.push_back(0);
4305 for (size_t i = 1; i < title_columns.size(); i++) {
4306 ret.push_back(std::max(offsets[i - 1], i * average_col_width));
4307 }
4308 return ret;
4309 };
4310
4311 auto color_print_ranges = [
this](
unsigned char extruder_id,
const std::vector<CustomGCode::Item>&
custom_gcode_per_print_z) {
4312 std::vector<std::pair<ColorRGBA, std::pair<double, double>>> ret;
4314
4315
4316
4317
4318 std::vector<float> zs;
4319 bool zs_built = false;
4320
4322 if (extruder_id + 1 != static_cast<unsigned char>(item.extruder))
4323 continue;
4324
4326 continue;
4327
4328 if (!zs_built) {
4330 zs_built = true;
4331 }
4332 auto lower_b = std::lower_bound(zs.begin(), zs.end(),
4333 static_cast<float>(item.print_z -
epsilon()));
4334 if (lower_b == zs.end())
4335 continue;
4336
4337 const double current_z = *lower_b;
4338 const double previous_z = (lower_b == zs.begin()) ? 0.0 : *(--lower_b);
4339
4340
4341 if (ret.empty() || !(ret.back().second.first == previous_z && ret.back().second.second == current_z))
4342 {
4343 ColorRGBA color;
4345 ret.push_back({ color, { previous_z, current_z } });
4346 }
4347 }
4348
4349 return ret;
4350 };
4351
4352
4353
4354 auto upto_label = [](double z) {
4355 char buf[64];
4356 ::sprintf(buf, "%.2f", z);
4358 };
4359
4360 auto above_label = [](double z) {
4361 char buf[64];
4362 ::sprintf(buf, "%.2f", z);
4364 };
4365
4366 auto fromto_label = [](double z1, double z2) {
4367 char buf1[64];
4368 ::sprintf(buf1, "%.2f", z1);
4369 char buf2[64];
4370 ::sprintf(buf2, "%.2f", z2);
4371 return format(
_u8L(
"from %1% to %2% mm"), buf1, buf2);
4372 };
4373
4375 const float time =
m_viewer.get_extrusion_role_estimated_time(role);
4376 return std::make_pair(time, total_estimated_time > 0.0f ? time / total_estimated_time : 0.0f);
4377 };
4378
4379 auto travel_time_and_percent = [this, total_estimated_time]() {
4380 const float time =
m_viewer.get_travels_estimated_time();
4381 return std::make_pair(time, total_estimated_time > 0.0f ? time / total_estimated_time : 0.0f);
4382 };
4383
4384 auto format_distance = [imperial_units](float distance_mm) {
4385 char buffer[64];
4386 if (imperial_units) {
4388 } else if (std::fabs(distance_mm) < 1000.0f) {
4389 ::sprintf(buffer, "%.0fmm", distance_mm);
4390 } else {
4391 ::sprintf(buffer, "%.2fm", distance_mm / 1000.0f);
4392 }
4393 return std::string(buffer);
4394 };
4395
4396 auto used_filament_per_role = [
this, imperial_units](
ExtrusionRole role) {
4399 return std::make_pair(0.0, 0.0);
4400
4403 return std::make_pair(it->second.first / koef, it->second.second / unit_conver);
4404 };
4405
4406
4407 auto get_used_filament_from_volume = [this, imperial_units](double volume, int extruder_id) {
4411 return ret;
4412 };
4413
4414
4415 ImGui::Dummy({ window_padding, window_padding });
4416 ImGui::Dummy({ window_padding, window_padding });
4417 ImGui::SameLine(window_padding * 2);
4418
4419 ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
4420 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(84 / 255.f, 84 / 255.f, 90 / 255.f, 1.f));
4421 ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(84 / 255.f, 84 / 255.f, 90 / 255.f, 1.f));
4422 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding , ImVec2(2.f, 2.f) *
m_scale);
4423 ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f *
m_scale);
4424
4425
4426 const wchar_t foldIcon =
m_fold ? ImGui::UnfoldButtonIcon : ImGui::FoldButtonIcon;
4427 if (imgui.glyph_button(foldIcon, ImVec2(16.f, 16.f) *
m_scale)) {
4429 }
4430
4431 ImGui::SameLine();
4432 const wchar_t gCodeToggle = ImGui::gCodeButtonIcon;
4433 if (imgui.glyph_button(gCodeToggle, ImVec2(16.f, 16.f) *
m_scale)) {
4434 wxGetApp().toggle_show_gcode_window();
4435 wxGetApp().plater()->get_current_canvas3D()->post_event(SimpleEvent(wxEVT_PAINT));
4436 }
4437
4438 ImGui::PopStyleColor(3);
4439 ImGui::PopStyleVar(2);
4440
4441
4443
4444 ImGui::SameLine();
4446 ImGuiComboFlags flags = ImGuiComboFlags_HeightLargest;
4447 if (ImGui::BBLBeginCombo("", view_type_value, flags)) {
4448 ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 0.0f);
4456
4458 if (!view_type_name.empty())
4459 wxGetApp().app_config->set("preview_last_view_type", view_type_name);
4461 #if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
4462 imgui.set_requires_extra_frame();
4463 #else
4464 wxGetApp().plater()->get_current_canvas3D()->set_as_dirty();
4465 wxGetApp().plater()->get_current_canvas3D()->request_extra_frame();
4466 #endif
4467 }
4468 if (is_selected) {
4469 ImGui::SetItemDefaultFocus();
4470 }
4471 }
4472 ImGui::PopStyleVar(1);
4473 ImGui::EndCombo();
4474 }
4476 ImGui::SameLine(0, window_padding);
4477
4478 float predictable_icon_pos = ImGui::GetCursorPosX() - icon_size - window_padding - ImGui::GetStyle().ItemSpacing.x - 1.f *
m_scale;
4479 ImGui::Dummy({ window_padding, window_padding });
4480 ImGui::Dummy({ window_padding, window_padding });
4481 float window_width = ImGui::GetWindowWidth();
4482
4484 legend_height = ImGui::GetFrameHeight() + window_padding * 4;
4485 ImGui::SameLine(window_width);
4486 ImGui::Dummy({ 0, 0 });
4487 imgui.end();
4488 ImGui::PopStyleColor(7);
4489 ImGui::PopStyleVar(2);
4490 return;
4491 }
4492
4493
4494 std::vector<float> offsets;
4495 std::vector<std::string> labels;
4496 std::vector<std::string> times;
4497 std::string travel_time;
4498 std::vector<std::string> percents;
4499 std::vector<std::string> used_filaments_length;
4500 std::vector<std::string> used_filaments_weight;
4501 std::string travel_percent;
4502 std::string travel_distance;
4503 std::string travel_moves;
4504 std::vector<double> model_used_filaments_m;
4505 std::vector<double> model_used_filaments_g;
4506 double total_model_used_filament_m = 0, total_model_used_filament_g = 0;
4507 std::vector<double> flushed_filaments_m;
4508 std::vector<double> flushed_filaments_g;
4509 double total_flushed_filament_m = 0, total_flushed_filament_g = 0;
4510 std::vector<double> wipe_tower_used_filaments_m;
4511 std::vector<double> wipe_tower_used_filaments_g;
4512 double total_wipe_tower_used_filament_m = 0, total_wipe_tower_used_filament_g = 0;
4513 std::vector<double> support_used_filaments_m;
4514 std::vector<double> support_used_filaments_g;
4515 double total_support_used_filament_m = 0, total_support_used_filament_g = 0;
4516 struct ColumnData {
4517 enum {
4518 Model = 1,
4519 Flushed = 2,
4522 };
4523 };
4524 int displayed_columns = 0;
4525 std::map<std::string, float> color_print_offsets;
4526 const PrintStatistics& ps = wxGetApp().plater()->get_partplate_list().get_current_fff_print().print_statistics();
4529 std::vector<double> used_filaments_m;
4530 std::vector<double> used_filaments_g;
4531
4532
4533 for (
size_t extruder_id :
m_viewer.get_used_extruders_ids()) {
4535 model_used_filaments_m.push_back(0.0);
4536 model_used_filaments_g.push_back(0.0);
4537 }
4538 else {
4540 auto [model_used_filament_m, model_used_filament_g] = get_used_filament_from_volume(volume, extruder_id);
4541 model_used_filaments_m.push_back(model_used_filament_m);
4542 model_used_filaments_g.push_back(model_used_filament_g);
4543 total_model_used_filament_m += model_used_filament_m;
4544 total_model_used_filament_g += model_used_filament_g;
4545 displayed_columns |= ColumnData::Model;
4546 }
4547 }
4548
4549 for (
size_t extruder_id :
m_viewer.get_used_extruders_ids()) {
4551 wipe_tower_used_filaments_m.push_back(0.0);
4552 wipe_tower_used_filaments_g.push_back(0.0);
4553 }
4554 else {
4556 auto [wipe_tower_used_filament_m, wipe_tower_used_filament_g] = get_used_filament_from_volume(volume, extruder_id);
4557 wipe_tower_used_filaments_m.push_back(wipe_tower_used_filament_m);
4558 wipe_tower_used_filaments_g.push_back(wipe_tower_used_filament_g);
4559 total_wipe_tower_used_filament_m += wipe_tower_used_filament_m;
4560 total_wipe_tower_used_filament_g += wipe_tower_used_filament_g;
4561 displayed_columns |= ColumnData::WipeTower;
4562 }
4563 }
4564
4565 for (
size_t extruder_id :
m_viewer.get_used_extruders_ids()) {
4567 flushed_filaments_m.push_back(0.0);
4568 flushed_filaments_g.push_back(0.0);
4569 }
4570 else {
4572 auto [flushed_filament_m, flushed_filament_g] = get_used_filament_from_volume(volume, extruder_id);
4573 flushed_filaments_m.push_back(flushed_filament_m);
4574 flushed_filaments_g.push_back(flushed_filament_g);
4575 total_flushed_filament_m += flushed_filament_m;
4576 total_flushed_filament_g += flushed_filament_g;
4577 displayed_columns |= ColumnData::Flushed;
4578 }
4579 }
4580
4581 for (
size_t extruder_id :
m_viewer.get_used_extruders_ids()) {
4583 support_used_filaments_m.push_back(0.0);
4584 support_used_filaments_g.push_back(0.0);
4585 }
4586 else {
4588 auto [used_filament_m, used_filament_g] = get_used_filament_from_volume(volume, extruder_id);
4589 support_used_filaments_m.push_back(used_filament_m);
4590 support_used_filaments_g.push_back(used_filament_g);
4591 total_support_used_filament_m += used_filament_m;
4592 total_support_used_filament_g += used_filament_g;
4593 displayed_columns |= ColumnData::Support;
4594 }
4595 }
4596
4597
4598
4599 ImGui::Dummy({ window_padding, window_padding });
4600 ImGui::SameLine();
4601 switch (curr_view_type)
4602 {
4604 {
4605
4606 char buffer[64];
4607 const std::vector<libvgcode::EGCodeExtrusionRole>& roles =
m_viewer.get_extrusion_roles();
4612 auto [time, percent] = role_time_and_percent(role);
4614 if (percent == 0)
4615 ::sprintf(buffer, "0");
4616 else
4617 percent > 0.001 ? ::sprintf(buffer, "%.1f", percent * 100) : ::sprintf(buffer, "<0.1");
4618 percents.push_back(buffer);
4619
4620 auto [model_used_filament_m, model_used_filament_g] = used_filament_per_role(
convert(role));
4621 ::sprintf(buffer, imperial_units ? "%.2fin" : "%.2fm", model_used_filament_m);
4622 used_filaments_length.push_back(buffer);
4624 }
4625 }
4626
4627
4628 {
4629 auto [time, percent] = travel_time_and_percent();
4631 if (percent == 0)
4632 ::sprintf(buffer, "0");
4633 else
4634 percent > 0.001 ? ::sprintf(buffer, "%.1f", percent * 100) : ::sprintf(buffer, "<0.1");
4635 travel_percent = buffer;
4636 percents.push_back(travel_percent);
4637
4638
4640 used_filaments_length.push_back(travel_distance);
4641
4643 used_filaments_weight.push_back(travel_moves);
4644 }
4645
4646
4647 offsets = calculate_offsets({ {
_u8L(
"Line Type"), labels}, {
_u8L(
"Time"), times}, {
"%", percents}, {
"", used_filaments_length}, {
"", used_filaments_weight}, {
_u8L(
"Display"), {
""}}}, icon_size);
4648 percents.pop_back();
4649 append_headers({{
_u8L(
"Line Type"), offsets[0]}, {
_u8L(
"Time"), offsets[1]}, {
"%", offsets[2]}, {
_u8L(
"Usage"), offsets[3]}, {
_u8L(
"Display"), offsets[5]}});
4650 break;
4651 }
4655 {
4656 imgui.title(
_u8L(
"Speed (mm/s)"));
4657 break;
4658 }
4660 {
4661 imgui.title(
_u8L(
"Actual Speed (mm/s)"));
4662 break;
4663 }
4665 {
4666 imgui.title(
_u8L(
"Acceleration (mm/s²)"));
4667 break;
4668 }
4670 {
4671 imgui.title(
_u8L(
"Jerk (mm/s)"));
4672 break;
4673 }
4676
4679 { imgui.title(
_u8L(
"Volumetric flow rate (mm³/s)"));
break; }
4681 { imgui.title(
_u8L(
"Actual volumetric flow rate (mm³/s)"));
break; }
4683 { imgui.title(
_u8L(
"Layer Time"));
break; }
4685 { imgui.title(
_u8L(
"Layer Time (log)"));
break; }
4686
4688 {
4689
4691 used_filaments_m = std::vector<double>(extruders_count, 0.0);
4692 used_filaments_g = std::vector<double>(extruders_count, 0.0);
4693 const std::vector<uint8_t>& used_extruders_ids =
m_viewer.get_used_extruders_ids();
4694 for (uint8_t extruder_id : used_extruders_ids) {
4696 continue;
4698
4699 auto [model_used_filament_m, model_used_filament_g] = get_used_filament_from_volume(volume, extruder_id);
4700 model_used_filaments_m.push_back(model_used_filament_m);
4701 model_used_filaments_g.push_back(model_used_filament_g);
4702 }
4703
4704 offsets = calculate_offsets({ { "Extruder NNN", {""}}}, icon_size);
4705 append_headers({ {
_u8L(
"Filament"), offsets[0]}, {
_u8L(
"Usage"), offsets[1]} });
4706 break;
4707 }
4709 {
4710 std::vector<std::string> total_filaments;
4711 char buffer[64];
4713 ::sprintf(buffer, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", ps.total_used_filament / koef, total_weight_text.c_str());
4714 total_filaments.push_back(buffer);
4715
4716
4717 std::vector<std::pair<std::string, std::vector<std::string>>> title_columns;
4718 if (displayed_columns & ColumnData::Model) {
4719 title_columns.push_back({
_u8L(
"Filament"), {
""} });
4720 title_columns.push_back({
_u8L(
"Model"), total_filaments });
4721 }
4722 if (displayed_columns & ColumnData::Support) {
4723 title_columns.push_back({
_u8L(
"Support"), total_filaments });
4724 }
4725 if (displayed_columns & ColumnData::Flushed) {
4726 title_columns.push_back({
_u8L(
"Flushed"), total_filaments });
4727 }
4728 if (displayed_columns & ColumnData::WipeTower) {
4729 title_columns.push_back({
_u8L(
"Tower"), total_filaments });
4730 }
4731 if ((displayed_columns & ~ColumnData::Model) > 0) {
4732 title_columns.push_back({
_u8L(
"Total"), total_filaments });
4733 }
4734 title_columns.push_back({
_u8L(
"Display"), {
""}});
4735 auto offsets_ = calculate_offsets(title_columns, icon_size);
4736 std::vector<std::pair<std::string, float>> title_offsets;
4737 for (int i = 0; i < offsets_.size(); i++) {
4738 title_offsets.push_back({ title_columns[i].first, offsets_[i] });
4739 color_print_offsets[title_columns[i].first] = offsets_[i];
4740 }
4741 append_headers(title_offsets);
4742
4743 break;
4744 }
4745 default: { break; }
4746 }
4747
4748 auto append_option_item = [
this, append_item, current_time_mode, total_estimated_time, &format_compact_count, &format_percent, &format_distance](
libvgcode::EOptionType type, std::vector<float> offsets) {
4749 const bool full_layout = offsets.size() > 4;
4750 auto option_stats = [
this, current_time_mode, total_estimated_time, &format_compact_count, &format_percent, &format_distance, full_layout](
libvgcode::EOptionType option_type) -> std::array<std::string, 4> {
4752 bool has_move_type = true;
4753 switch (option_type) {
4759 default: { has_move_type = false; break; }
4760 }
4761
4762 if (!has_move_type)
4763 return { "", "", "", "" };
4764
4765 const size_t move_type_idx = static_cast<size_t>(move_type);
4768
4770 }
4772 const std::string percent_text = full_layout && total_estimated_time > 0.0f ? format_percent(time / total_estimated_time) : "";
4776 ? format_distance(distance)
4777 : "";
4778 const std::string count_text = full_layout ? format_compact_count(
m_move_type_counts[move_type_idx]) :
"";
4779
4780 return { time_text, percent_text, distance_text, count_text };
4781 };
4782
4783 auto append_option_item_with_type = [
this, offsets, append_item, full_layout](
libvgcode::EOptionType type,
const ColorRGBA& color,
const std::string& label,
bool visible,
4784 const std::string& time_text, const std::string& percent_text, const std::string& distance_text, const std::string& count_text) {
4785 std::vector<std::pair<std::string, float>> columns_offsets;
4786 columns_offsets.push_back({ label , offsets[0] });
4787 if (full_layout && !time_text.empty())
4788 columns_offsets.push_back({ time_text, offsets[1] });
4789 if (full_layout && !percent_text.empty())
4790 columns_offsets.push_back({ percent_text, offsets[2] });
4791 if (full_layout && !distance_text.empty())
4792 columns_offsets.push_back({ distance_text, offsets[3] });
4793 if (full_layout && !count_text.empty())
4794 columns_offsets.push_back({ count_text, distance_text.empty() ? offsets[3] : offsets[4] });
4795 append_item(EItemType::Rect, color, columns_offsets, true, offsets.back(), visible, [this, type]() {
4796 m_viewer.toggle_option_visibility(type);
4797 update_moves_slider();
4798 });
4799 };
4800 const bool visible =
m_viewer.is_option_visible(type);
4802
4804 }
4806 const auto option_values = option_stats(type);
4808 option_values[0], option_values[1], option_values[2], option_values[3]);
4809 }
4811 const auto option_values = option_stats(type);
4813 option_values[0], option_values[1], option_values[2], option_values[3]);
4814 }
4816 const auto option_values = option_stats(type);
4818 option_values[0], option_values[1], option_values[2], option_values[3]);
4819 }
4821 const auto option_values = option_stats(type);
4823 option_values[0], option_values[1], option_values[2], option_values[3]);
4824 }
4826 const auto option_values = option_stats(type);
4828 option_values[0], option_values[1], option_values[2], option_values[3]);
4829 }
4830 };
4831
4833
4834
4835 switch (new_view_type)
4836 {
4838 {
4839 auto roles =
m_viewer.get_extrusion_roles();
4840 for (size_t i = 0; i < roles.size(); ++i) {
4843 continue;
4844 const bool visible =
m_viewer.is_extrusion_role_visible(role);
4845 std::vector<std::pair<std::string, float>> columns_offsets;
4846 columns_offsets.push_back({ labels[i], offsets[0] });
4847 columns_offsets.push_back({ times[i], offsets[1] });
4848 columns_offsets.push_back({percents[i], offsets[2]});
4849 columns_offsets.push_back({used_filaments_length[i], offsets[3]});
4850 columns_offsets.push_back({used_filaments_weight[i], offsets[4]});
4852 true, offsets.back(), visible, [this, role]() {
4853 m_viewer.toggle_extrusion_role_visibility(role);
4854 update_moves_slider();
4855 });
4856 }
4857
4858 auto options =
m_viewer.get_options();
4859 for(auto item : options) {
4861 append_option_item(item, offsets);
4862 } else {
4863
4864 const bool visible =
m_viewer.is_option_visible(item);
4865 std::vector<std::pair<std::string, float>> columns_offsets;
4866 columns_offsets.push_back({
_u8L(
"Travel"), offsets[0] });
4867 columns_offsets.push_back({ travel_time, offsets[1] });
4868 columns_offsets.push_back({ travel_percent, offsets[2] });
4869 columns_offsets.push_back({ travel_distance, offsets[3] });
4870 columns_offsets.push_back({ travel_moves, offsets[4] });
4872 m_viewer.toggle_option_visibility(item);
4873 update_moves_slider();
4874 });
4875 }
4876 }
4877 break;
4878 }
4883 ImGui::Spacing();
4884 ImGui::Dummy({ window_padding, window_padding });
4885 ImGui::SameLine();
4886 offsets = calculate_offsets({ {
_u8L(
"Options"), {
_u8L(
"Travel")}}, {
_u8L(
"Display"), {
""}} }, icon_size);
4887 append_headers({ {
_u8L(
"Options"), offsets[0] }, {
_u8L(
"Display"), offsets[1]} });
4889 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 3.0f));
4892
4894 });
4895 ImGui::PopStyleVar(1);
4896 break;
4897 }
4900 ImGui::Spacing();
4901 ImGui::Dummy({ window_padding, window_padding });
4902 ImGui::SameLine();
4903 offsets = calculate_offsets({ {
_u8L(
"Options"), {
_u8L(
"Travel")}}, {
_u8L(
"Display"), {
""}} }, icon_size);
4904 append_headers({ {
_u8L(
"Options"), offsets[0] }, {
_u8L(
"Display"), offsets[1]} });
4906 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 3.0f));
4909
4911 });
4912 ImGui::PopStyleVar(1);
4913 break;
4914 }
4917 ImGui::Spacing();
4918 ImGui::Dummy({ window_padding, window_padding });
4919 ImGui::SameLine();
4920 offsets = calculate_offsets({ {
_u8L(
"Options"), {
_u8L(
"Travel")}}, {
_u8L(
"Display"), {
""}} }, icon_size);
4921 append_headers({ {
_u8L(
"Options"), offsets[0] }, {
_u8L(
"Display"), offsets[1]} });
4923 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 3.0f));
4927 });
4928 ImGui::PopStyleVar(1);
4929 break;
4930 }
4933 ImGui::Spacing();
4934 ImGui::Dummy({ window_padding, window_padding });
4935 ImGui::SameLine();
4936 offsets = calculate_offsets({ {
_u8L(
"Options"), {
_u8L(
"Travel")}}, {
_u8L(
"Display"), {
""}} }, icon_size);
4937 append_headers({ {
_u8L(
"Options"), offsets[0] }, {
_u8L(
"Display"), offsets[1]} });
4939 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 3.0f));
4943 });
4944 ImGui::PopStyleVar(1);
4945 break;
4946 }
4949
4956 {
4957
4958 char buf[64];
4959 size_t i = 0;
4960 const std::vector<uint8_t>& used_extruders_ids =
m_viewer.get_used_extruders_ids();
4961 for (uint8_t extruder_id : used_extruders_ids) {
4963 ::sprintf(buf, imperial_units ? "%.2f in %s" : "%.2f m %s", model_used_filaments_m[i], weight_text.c_str());
4965
4966
4967 i++;
4968 }
4969 break;
4970 }
4972 {
4973 char buf[64];
4974 imgui.text(
_u8L(
"Total") +
":");
4975 ImGui::SameLine();
4977 ::sprintf(buf, imperial_units ? "%.2f in / %s" : "%.2f m / %s", ps.total_used_filament / koef, total_weight_text.c_str());
4978 imgui.text(buf);
4979
4980 ImGui::Dummy({window_padding, window_padding});
4981 ImGui::SameLine();
4982 imgui.text(
_u8L(
"Cost") +
":");
4983 ImGui::SameLine();
4984 ::sprintf(buf, "%.2f", ps.total_cost);
4985 imgui.text(buf);
4986
4987 ImGui::Dummy({window_padding, window_padding});
4988 ImGui::SameLine();
4989 imgui.text(
_u8L(
"Total time") +
":");
4990 ImGui::SameLine();
4992 break;
4993 }
4995
4997 size_t total_items = 1;
4998
4999
5000
5001
5002
5003
5004 const bool need_scrollable = static_cast<float>(total_items) * (icon_size + ImGui::GetStyle().ItemSpacing.y) > child_height;
5005
5006
5007 if (need_scrollable)
5008 ImGui::BeginChild("color_prints", { -1.0f, child_height }, false);
5009
5010
5011 size_t i = 0;
5012 const std::vector<uint8_t>& used_extruders_ids =
m_viewer.get_used_extruders_ids();
5013 auto tool_colors =
m_viewer.get_tool_colors();
5014 for (auto extruder_idx : used_extruders_ids) {
5015 if (i < model_used_filaments_m.size() && i < model_used_filaments_g.size()) {
5016 std::vector<std::pair<std::string, float>> columns_offsets;
5017 columns_offsets.push_back({ std::to_string(extruder_idx + 1), color_print_offsets[
_u8L(
"Filament")]});
5018
5019 char buf[64];
5020 float column_sum_m = 0.0f;
5021 float column_sum_g = 0.0f;
5022 if (displayed_columns & ColumnData::Model) {
5024 if ((displayed_columns & ~ColumnData::Model) > 0)
5025 ::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", model_used_filaments_m[i], weight_text.c_str());
5026 else
5027 ::sprintf(buf, imperial_units ? "%.2f in %s" : "%.2f m %s", model_used_filaments_m[i], weight_text.c_str());
5028 columns_offsets.push_back({ buf, color_print_offsets[
_u8L(
"Model")] });
5029 column_sum_m += model_used_filaments_m[i];
5030 column_sum_g += model_used_filaments_g[i];
5031 }
5032 if (displayed_columns & ColumnData::Support) {
5034 ::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", support_used_filaments_m[i], weight_text.c_str());
5035 columns_offsets.push_back({ buf, color_print_offsets[
_u8L(
"Support")] });
5036 column_sum_m += support_used_filaments_m[i];
5037 column_sum_g += support_used_filaments_g[i];
5038 }
5039 if (displayed_columns & ColumnData::Flushed) {
5041 ::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", flushed_filaments_m[i], weight_text.c_str());
5042 columns_offsets.push_back({ buf, color_print_offsets[
_u8L(
"Flushed")]});
5043 column_sum_m += flushed_filaments_m[i];
5044 column_sum_g += flushed_filaments_g[i];
5045 }
5046 if (displayed_columns & ColumnData::WipeTower) {
5047 const std::string weight_text =
format_compact_weight(wipe_tower_used_filaments_g[i], imperial_units);
5048 ::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", wipe_tower_used_filaments_m[i], weight_text.c_str());
5049 columns_offsets.push_back({ buf, color_print_offsets[
_u8L(
"Tower")] });
5050 column_sum_m += wipe_tower_used_filaments_m[i];
5051 column_sum_g += wipe_tower_used_filaments_g[i];
5052 }
5053 if ((displayed_columns & ~ColumnData::Model) > 0) {
5055 ::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", column_sum_m, weight_text.c_str());
5056 columns_offsets.push_back({ buf, color_print_offsets[
_u8L(
"Total")] });
5057 }
5058
5059 float checkbox_pos = std::max(predictable_icon_pos, color_print_offsets[
_u8L(
"Display")]);
5061 }
5062 i++;
5063 }
5064
5065 if (need_scrollable)
5066 ImGui::EndChild();
5067
5068
5069 char buf[64];
5070 if (used_extruders_ids.size() > 1) {
5071
5072 ImGuiWindow* window = ImGui::GetCurrentWindow();
5073 const ImRect separator(ImVec2(window->Pos.x + window_padding * 3, window->DC.CursorPos.y), ImVec2(window->Pos.x + window->Size.x - window_padding * 3, window->DC.CursorPos.y + 1.0f));
5074 ImGui::ItemSize(ImVec2(0.0f, 0.0f));
5075 const bool item_visible = ImGui::ItemAdd(separator, 0);
5076 window->DrawList->AddLine(separator.Min, ImVec2(separator.Max.x, separator.Min.y), ImGui::GetColorU32(ImGuiCol_Separator));
5077
5078 std::vector<std::pair<std::string, float>> columns_offsets;
5079 columns_offsets.push_back({
_u8L(
"Total"), color_print_offsets[
_u8L(
"Filament")]});
5080 if (displayed_columns & ColumnData::Model) {
5082 if ((displayed_columns & ~ColumnData::Model) > 0)
5083 ::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", total_model_used_filament_m, weight_text.c_str());
5084 else
5085 ::sprintf(buf, imperial_units ? "%.2f in %s" : "%.2f m %s", total_model_used_filament_m, weight_text.c_str());
5086 columns_offsets.push_back({ buf, color_print_offsets[
_u8L(
"Model")] });
5087 }
5088 if (displayed_columns & ColumnData::Support) {
5089 const std::string weight_text =
format_compact_weight(total_support_used_filament_g, imperial_units);
5090 ::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", total_support_used_filament_m, weight_text.c_str());
5091 columns_offsets.push_back({ buf, color_print_offsets[
_u8L(
"Support")] });
5092 }
5093 if (displayed_columns & ColumnData::Flushed) {
5095 ::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", total_flushed_filament_m, weight_text.c_str());
5096 columns_offsets.push_back({ buf, color_print_offsets[
_u8L(
"Flushed")] });
5097 }
5098 if (displayed_columns & ColumnData::WipeTower) {
5099 const std::string weight_text =
format_compact_weight(total_wipe_tower_used_filament_g, imperial_units);
5100 ::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", total_wipe_tower_used_filament_m, weight_text.c_str());
5101 columns_offsets.push_back({ buf, color_print_offsets[
_u8L(
"Tower")] });
5102 }
5103 if ((displayed_columns & ~ColumnData::Model) > 0) {
5104 const std::string weight_text =
format_compact_weight(total_model_used_filament_g + total_support_used_filament_g + total_flushed_filament_g + total_wipe_tower_used_filament_g, imperial_units);
5105 ::sprintf(buf, imperial_units ? "%.2f in\n%s" : "%.2f m\n%s", total_model_used_filament_m + total_support_used_filament_m + total_flushed_filament_m + total_wipe_tower_used_filament_m,
5106 weight_text.c_str());
5107 columns_offsets.push_back({ buf, color_print_offsets[
_u8L(
"Total")] });
5108 }
5110 }
5111
5112
5113 ImGui::Dummy({window_padding, window_padding});
5114 ImGui::SameLine();
5115 imgui.text(
_u8L(
"Filament change times") +
":");
5116 ImGui::SameLine();
5118
5119
5120 ImGui::Dummy({window_padding, window_padding});
5121 ImGui::SameLine();
5122 imgui.text(
_u8L(
"Tool changes") +
":");
5123 ImGui::SameLine();
5125
5126
5127 ImGui::Dummy({ window_padding, window_padding });
5128 ImGui::SameLine();
5129 imgui.text(
_u8L(
"Cost")+
":");
5130 ImGui::SameLine();
5131 ::sprintf(buf, "%.2f", ps.total_cost);
5132 imgui.text(buf);
5133
5134 break;
5135 }
5136 default: { break; }
5137 }
5138
5139
5141 using Times = std::pair<float, float>;
5142 using TimesList = std::vector<std::pair<CustomGCode::Type, Times>>;
5143
5144
5145 struct PartialTime
5146 {
5147 enum class EType : unsigned char
5148 {
5149 Print,
5151 Pause
5152 };
5153 EType type;
5154 int extruder_id;
5155 ColorRGBA color1;
5156 ColorRGBA color2;
5157 Times times;
5158 std::pair<double, double> used_filament {0.0f, 0.0f};
5159 };
5160 using PartialTimes = std::vector<PartialTime>;
5161
5162 auto generate_partial_times = [this, get_used_filament_from_volume](const TimesList& times, const std::vector<double>& used_filaments) {
5163 PartialTimes items;
5164
5165
5168 std::vector<ColorRGBA> last_color(extruders_count);
5169 for (size_t i = 0; i < extruders_count; ++i) {
5171 }
5172 int last_extruder_id = 1;
5173 int color_change_idx = 0;
5174 for (const auto& time_rec : times) {
5175 switch (time_rec.first)
5176 {
5180 items.push_back({ PartialTime::EType::Print, it->extruder, last_color[it->extruder - 1],
ColorRGBA::BLACK(), time_rec.second });
5183 }
5184 break;
5185 }
5189 items.push_back({ PartialTime::EType::Print, it->extruder, last_color[it->extruder - 1],
ColorRGBA::BLACK(), time_rec.second, get_used_filament_from_volume(used_filaments[color_change_idx++], it->extruder - 1) });
5190 ColorRGBA color;
5193 items.push_back({ PartialTime::EType::ColorChange, it->extruder, last_color[it->extruder - 1], color, time_rec.second });
5194 last_color[it->extruder - 1] = color;
5195 last_extruder_id = it->extruder;
5197 }
5198 else
5199 items.push_back({ PartialTime::EType::Print, last_extruder_id, last_color[last_extruder_id - 1],
ColorRGBA::BLACK(), time_rec.second, get_used_filament_from_volume(used_filaments[color_change_idx++], last_extruder_id - 1) });
5200
5201 break;
5202 }
5203 default: { break; }
5204 }
5205 }
5206
5207 return items;
5208 };
5209
5210 auto append_color_change = [&imgui](const ColorRGBA& color1, const ColorRGBA& color2, const std::array<float, 4>& offsets, const Times& times) {
5211 imgui.text(
_u8L(
"Color change"));
5212 ImGui::SameLine();
5213
5214 float icon_size = ImGui::GetTextLineHeight();
5215 ImDrawList* draw_list = ImGui::GetWindowDrawList();
5216 ImVec2
pos = ImGui::GetCursorScreenPos();
5217 pos.x -= 0.5f * ImGui::GetStyle().ItemSpacing.x;
5218
5219 add_swatch(draw_list, {
pos.x + 1.0f,
pos.y + 1.0f }, {
pos.x + icon_size - 1.0f,
pos.y + icon_size - 1.0f }, color1);
5221 add_swatch(draw_list, {
pos.x + 1.0f,
pos.y + 1.0f }, {
pos.x + icon_size - 1.0f,
pos.y + icon_size - 1.0f }, color2);
5222
5223 ImGui::SameLine(offsets[0]);
5225 };
5226
5227 auto append_print = [&imgui, imperial_units](const ColorRGBA& color, const std::array<float, 4>& offsets, const Times& times, std::pair<double, double> used_filament) {
5229 ImGui::SameLine();
5230
5231 float icon_size = ImGui::GetTextLineHeight();
5232 ImDrawList* draw_list = ImGui::GetWindowDrawList();
5233 ImVec2
pos = ImGui::GetCursorScreenPos();
5234 pos.x -= 0.5f * ImGui::GetStyle().ItemSpacing.x;
5235
5236 add_swatch(draw_list, {
pos.x + 1.0f,
pos.y + 1.0f }, {
pos.x + icon_size - 1.0f,
pos.y + icon_size - 1.0f }, color);
5237
5238 ImGui::SameLine(offsets[0]);
5240 ImGui::SameLine(offsets[1]);
5242 if (used_filament.first > 0.0f) {
5243 char buffer[64];
5244 ImGui::SameLine(offsets[2]);
5245 ::sprintf(buffer, imperial_units ? "%.2f in" : "%.2f m", used_filament.first);
5246 imgui.text(buffer);
5247
5248 ImGui::SameLine(offsets[3]);
5250 }
5251 };
5252
5253 PartialTimes partial_times = generate_partial_times(time_mode.custom_gcode_times,
m_print_statistics.volumes_per_color_change);
5254 if (!partial_times.empty()) {
5255 labels.clear();
5256 times.clear();
5257
5258 for (const PartialTime& item : partial_times) {
5259 switch (item.type)
5260 {
5261 case PartialTime::EType::Print: { labels.push_back(
_u8L_CONTEXT(
"Print",
"Noun"));
break; }
5262 case PartialTime::EType::Pause: { labels.push_back(
_u8L(
"Pause"));
break; }
5263 case PartialTime::EType::ColorChange: { labels.push_back(
_u8L(
"Color change"));
break; }
5264 }
5266 }
5267
5268 std::string longest_used_filament_string;
5269 for (const PartialTime& item : partial_times) {
5270 if (item.used_filament.first > 0.0f) {
5271 char buffer[64];
5272 ::sprintf(buffer, imperial_units ? "%.2f in" : "%.2f m", item.used_filament.first);
5273 if (::strlen(buffer) > longest_used_filament_string.length())
5274 longest_used_filament_string = buffer;
5275 }
5276 }
5277
5278
5279
5280
5281
5282
5283
5284
5285
5286
5287
5288
5289
5290
5291
5292
5293
5294
5295
5296
5297
5298
5299
5300
5301
5302
5303
5304
5305
5306
5307
5308
5309 }
5310 }
5311
5312
5315 {
5322 break;
5323 }
5324 default: {
5325
5326
5327
5328
5330
5331
5332
5333
5334 break;
5335 }
5336 }
5337 }
5338
5339
5340
5341
5342
5343
5344
5345
5346
5347
5348
5349
5350
5351
5352
5353
5354
5355
5356
5357
5358
5359
5360
5361
5362
5363
5364
5365
5366
5367
5368
5369
5370
5371
5372
5373
5374
5375
5376
5377
5378
5379
5380
5381
5382
5383
5384
5385
5386 bool has_settings = false;
5389 bool has_filament_settings = true;
5392 has_filament_settings &= !fs.empty();
5393 }
5394 has_settings |= has_filament_settings;
5395
5398 show_settings &= has_settings;
5399 if (show_settings) {
5400 auto calc_offset = [this]() {
5401 float ret = 0.0f;
5403 ret = std::max(ret, ImGui::CalcTextSize((
_u8L(
"Printer") + std::string(
":")).c_str()).x);
5405 ret = std::max(ret, ImGui::CalcTextSize((
_u8L(
"Print settings") + std::string(
":")).c_str()).x);
5407 for (
unsigned char i :
m_viewer.get_used_extruders_ids()) {
5408 ret = std::max(ret, ImGui::CalcTextSize((
_u8L(
"Filament") +
" " + std::to_string(i + 1) +
":").c_str()).x);
5409 }
5410 }
5411 if (ret > 0.0f)
5412 ret += 2.0f * ImGui::GetStyle().ItemSpacing.x;
5413 return ret;
5414 };
5415
5416 ImGui::Spacing();
5417 imgui.title(
_u8L(
"Settings"));
5418
5419 float offset = calc_offset();
5420
5422 imgui.text(
_u8L(
"Printer") +
":");
5425 }
5427 imgui.text(
_u8L(
"Print settings") +
":");
5430 }
5432 for (
unsigned char i :
m_viewer.get_used_extruders_ids()) {
5434 std::string txt =
_u8L(
"Filament");
5435 txt += (
m_viewer.get_used_extruders_count() == 1) ?
":" :
" " + std::to_string(i + 1);
5436 imgui.text(txt);
5439 }
5440 }
5441 }
5442 }
5443
5445 wxGetApp().plater()->model().get_curr_plate_custom_gcodes().
gcodes :
5448 float max_len = window_padding + 2 * ImGui::GetStyle().ItemSpacing.x;
5449 ImGui::Spacing();
5450
5451 std::string cgcode_title_str =
_u8L(
"Custom G-code");
5452 std::string cgcode_layer_str =
_u8L(
"Layer");
5453 std::string cgcode_time_str =
_u8L(
"Time");
5454
5455 std::string cgcode_pause_str =
_u8L(
"Pause");
5456 std::string cgcode_template_str=
_u8L(
"Template");
5457 std::string cgcode_toolchange_str =
_u8L(
"Tool Change");
5458 std::string cgcode_custom_str =
_u8L(
"Custom");
5459 std::string cgcode_unknown_str =
_u8L(
"Unknown");
5460
5461
5462 max_len += std::max(ImGui::CalcTextSize(cgcode_title_str.c_str()).x,
5463 std::max(ImGui::CalcTextSize(cgcode_pause_str.c_str()).x,
5464 std::max(ImGui::CalcTextSize(cgcode_template_str.c_str()).x,
5465 std::max(ImGui::CalcTextSize(cgcode_toolchange_str.c_str()).x,
5466 std::max(ImGui::CalcTextSize(cgcode_custom_str.c_str()).x,
5467 ImGui::CalcTextSize(cgcode_unknown_str.c_str()).x))))
5468
5469 );
5470
5471 ImGui::Dummy(ImVec2(0.0f, ImGui::GetFontSize() * 0.1));
5472 ImGui::Dummy({window_padding, window_padding});
5473 ImGui::SameLine();
5474 imgui.title(cgcode_title_str,true);
5475 ImGui::SameLine(max_len);
5476 imgui.title(cgcode_layer_str, true);
5477 ImGui::SameLine(max_len*1.5);
5478 imgui.title(cgcode_time_str, false);
5479
5480
5482
5483 const std::vector<float> layer_times =
m_viewer.get_layers_estimated_times();
5484
5486 ImGui::Dummy({window_padding, window_padding});
5487 ImGui::SameLine();
5488
5489 switch (custom_gcode.type) {
5494 default: imgui.text(cgcode_unknown_str); break;
5495 }
5496 ImGui::SameLine(max_len);
5497 char buf[64];
5499 ::sprintf(buf, "%d", layer + 1);
5500 imgui.text(buf);
5501 ImGui::SameLine(max_len * 1.5);
5502
5503 float custom_gcode_time = 0;
5504 if (layer > 0)
5505 {
5506 for (int i = 0; i < layer; i++) {
5507 custom_gcode_time += layer_times[i];
5508 }
5509 }
5511
5512 }
5513 }
5514
5515
5516
5517 ImGui::Spacing();
5520 std::vector<std::string> time_strs;
5524 const auto it = std::find(time_strs.begin(), time_strs.end(), time_str);
5525 if (it == time_strs.end())
5526 time_strs.emplace_back(time_str);
5527 }
5528 }
5529 return time_strs.size() > 1;
5530 };
5531
5533 if (can_show_mode_button(time_mode_id)) {
5534 switch (time_mode_id)
5535 {
5537 default: { assert(false); break; }
5538 }
5539 }
5540 ImGui::Dummy(ImVec2(0.0f, ImGui::GetFontSize() * 0.1));
5541 ImGui::Dummy({ window_padding, window_padding });
5542 ImGui::SameLine();
5543 imgui.title(time_title);
5544 std::string total_filament_str =
_u8L(
"Total Filament");
5545 std::string model_filament_str =
_u8L(
"Model Filament");
5546 std::string cost_str =
_u8L(
"Cost");
5547 std::string prepare_str =
_u8L(
"Prepare time");
5548 std::string print_str =
_u8L(
"Model printing time");
5549 std::string total_str =
_u8L(
"Total time");
5550 float max_len = window_padding + 2 * ImGui::GetStyle().ItemSpacing.x;
5551 if (
m_viewer.get_layers_count() == 0)
5552 max_len += ImGui::CalcTextSize(total_str.c_str()).x;
5553 else {
5555 max_len += std::max(ImGui::CalcTextSize(cost_str.c_str()).x,
5556 std::max(ImGui::CalcTextSize(print_str.c_str()).x,
5557 std::max(std::max(ImGui::CalcTextSize(prepare_str.c_str()).x, ImGui::CalcTextSize(total_str.c_str()).x),
5558 std::max(ImGui::CalcTextSize(total_filament_str.c_str()).x, ImGui::CalcTextSize(model_filament_str.c_str()).x))));
5559 else
5560 max_len += std::max(ImGui::CalcTextSize(print_str.c_str()).x,
5561 (std::max(ImGui::CalcTextSize(prepare_str.c_str()).x, ImGui::CalcTextSize(total_str.c_str()).x)));
5562 }
5564
5565 ImGui::Dummy({ window_padding, window_padding });
5566 ImGui::SameLine();
5567 imgui.text(total_filament_str + ":");
5568 ImGui::SameLine(max_len);
5569
5570 bool imperial_units = wxGetApp().app_config->get("use_inches") == "1";
5571 char buf[64];
5572 ::sprintf(buf, imperial_units ? "%.2f in" : "%.2f m", ps.total_used_filament / koef);
5573 imgui.text(buf);
5574 ImGui::SameLine();
5576 ImGui::Dummy({ window_padding, window_padding });
5577 ImGui::SameLine();
5578 imgui.text(model_filament_str + ":");
5579 ImGui::SameLine(max_len);
5580 auto exlude_m = total_support_used_filament_m + total_flushed_filament_m + total_wipe_tower_used_filament_m;
5581 auto exlude_g = total_support_used_filament_g + total_flushed_filament_g + total_wipe_tower_used_filament_g;
5582 ::sprintf(buf, imperial_units ? "%.2f in" : "%.2f m", ps.total_used_filament / koef - exlude_m);
5583 imgui.text(buf);
5584 ImGui::SameLine();
5586
5587 ImGui::Dummy({ window_padding, window_padding });
5588 ImGui::SameLine();
5589 imgui.text(cost_str + ":");
5590 ImGui::SameLine(max_len);
5591 ::sprintf(buf, "%.2f", ps.total_cost);
5592 imgui.text(buf);
5593 }
5594
5595 if (time_mode.prepare_time != 0.0f) {
5596 ImGui::Dummy({ window_padding, window_padding });
5597 ImGui::SameLine();
5598 imgui.text(prepare_str + ":");
5599 ImGui::SameLine(max_len);
5601 }
5602 ImGui::Dummy({ window_padding, window_padding });
5603 ImGui::SameLine();
5604 imgui.text(print_str + ":");
5605 ImGui::SameLine(max_len);
5607 ImGui::Dummy({ window_padding, window_padding });
5608 ImGui::SameLine();
5609 imgui.text(total_str + ":");
5610 ImGui::SameLine(max_len);
5612
5613 auto show_mode_button = [
this, &imgui, can_show_mode_button](
const std::string& label,
libvgcode::ETimeMode mode) {
5614 if (can_show_mode_button(mode)) {
5615 if (imgui.button(label)) {
5617#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
5618 imgui.set_requires_extra_frame();
5619#else
5620 wxGetApp().plater()->get_current_canvas3D()->set_as_dirty();
5621 wxGetApp().plater()->get_current_canvas3D()->request_extra_frame();
5622#endif
5623 }
5624 }
5625 };
5626
5627 switch (time_mode_id) {
5630 break;
5631 }
5634 break;
5635 }
5636 default : { assert(false); break; }
5637 }
5638
5640 ImGui::Spacing();
5641 ImGui::Dummy({ window_padding, window_padding });
5642 ImGui::SameLine();
5643 offsets = calculate_offsets({ {
_u8L(
"Options"), {
""}}, {
_u8L(
"Display"), {
""}} }, icon_size);
5644 offsets[1] = std::max(predictable_icon_pos, color_print_offsets[
_u8L(
"Display")]);
5645 append_headers({ {
_u8L(
"Options"), offsets[0] }, {
_u8L(
"Display"), offsets[1]} });
5646 for (
auto item :
m_viewer.get_options())
5647 append_option_item(item, offsets);
5648 }
5649 ImGui::Dummy({ window_padding, window_padding });
5652
5653
5654 legend_height = ImGui::GetCurrentWindow()->Size.y;
5655 imgui.end();
5656 ImGui::PopStyleColor(7);
5657 ImGui::PopStyleVar(2);
5658}
struct IMGUI_API ImRect
Definition IMSlider.hpp:19
static const ColorRGBA BLACK()
Definition Color.hpp:127
static std::string role_to_string(ExtrusionRole role)
Definition ExtrusionEntity.cpp:673
static std::string view_type_to_config_name(libvgcode::EViewType type)
Definition GCodeViewer.cpp:1236
bool m_fold
Definition GCodeViewer.hpp:238
size_t get_extruders_count()
Definition GCodeViewer.hpp:529
bool is_legend_shown() const
Definition GCodeViewer.hpp:517
std::vector< std::string > view_type_items_str
Definition GCodeViewer.hpp:345
std::vector< libvgcode::EViewType > view_type_items
Definition GCodeViewer.hpp:344
void set_view_type(libvgcode::EViewType type)
Definition GCodeViewer.hpp:479
void update_moves_slider(bool set_to_max=false)
Definition GCodeViewer.cpp:2715
int m_view_type_sel
Definition GCodeViewer.hpp:346
void push_combo_style()
Definition GCodeViewer.cpp:5660
void pop_combo_style()
Definition GCodeViewer.cpp:5674
ColorRGBA shown_filament_color(ColorRGBA color) const
Definition GCodeViewer.cpp:3251
void render_legend_color_arr_recommen(float window_padding)
Definition GCodeViewer.cpp:3796
void reset_visible(libvgcode::EViewType type)
Definition GCodeViewer.hpp:492
std::vector< double > get_layers_zs() const
Definition GCodeViewer.hpp:438
static const double oz_to_g
Definition GizmoObjectManipulation.hpp:33
static ImU32 to_ImU32(const ColorRGBA &color)
Definition ImGuiWrapper.cpp:2239
@ PausePrint
Definition CustomGCode.hpp:20
@ ToolChange
Definition CustomGCode.hpp:21
@ Template
Definition CustomGCode.hpp:22
@ Custom
Definition CustomGCode.hpp:23
@ ColorChange
Definition CustomGCode.hpp:19
static int find_close_layer_idx(const std::vector< double > &zs, double &z, double eps)
Definition GCodeViewer.cpp:208
std::string format(const char *fmt, TArgs &&... args)
Definition format.hpp:36
std::string into_u8(const wxString &str)
Definition GUI.cpp:549
@ None
Definition DesignOffer.hpp:25
constexpr double epsilon()
Definition IMSlider.hpp:31
static wxColour decode_color(const std::string &color)
Definition SliceInfoPanel.cpp:51
float distance(SpiralVase::SpiralPoint a, SpiralVase::SpiralPoint b)
Definition SpiralVase.cpp:19
static CustomGCode::Info custom_gcode_per_print_z
Definition ToolOrdering.cpp:3253
void center(ExPolygonsWithIds &e)
Definition Emboss.cpp:1382
auto range(Cont &&cont)
Definition libslic3r.h:405
@ Hexagon
Definition Model.hpp:279
@ Circle
Definition BuildVolume.hpp:25
EMoveType
Definition Types.hpp:121
@ ToolChange
Definition Types.hpp:126
@ Wipe
Definition Types.hpp:131
@ Seam
Definition Types.hpp:125
EGCodeExtrusionRole
Definition Types.hpp:142
@ COUNT
Definition Types.hpp:166
EOptionType
Definition Types.hpp:175
@ ToolChanges
Definition Types.hpp:183
@ Wipes
Definition Types.hpp:179
@ Seams
Definition Types.hpp:182
@ Unretractions
Definition Types.hpp:181
@ Travels
Definition Types.hpp:178
@ Retractions
Definition Types.hpp:180
static constexpr std::size_t GCODE_EXTRUSION_ROLES_COUNT
Definition Types.hpp:169
ETimeMode
Definition Types.hpp:200
@ Stealth
Definition Types.hpp:202
@ Summary
Definition Types.hpp:92
@ Width
Definition Types.hpp:98
@ Acceleration
Definition Types.hpp:108
@ Speed
Definition Types.hpp:95
@ ActualVolumetricFlowRate
Definition Types.hpp:100
@ LayerTimeLogarithmic
Definition Types.hpp:102
@ PressureAdvance
Definition Types.hpp:106
@ ActualSpeed
Definition Types.hpp:96
@ Jerk
Definition Types.hpp:110
@ LayerTimeLinear
Definition Types.hpp:101
@ Tool
Definition Types.hpp:111
@ FanSpeed
Definition Types.hpp:103
@ VolumetricFlowRate
Definition Types.hpp:99
@ Temperature
Definition Types.hpp:104
@ Height
Definition Types.hpp:97
#define _u8L_CONTEXT(s, ctx)
Definition I18N.hpp:16
std::vector< Item > gcodes
Definition CustomGCode.hpp:71