mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-06-21 19:33:26 +00:00
Merge branch 'main' into draco
This commit is contained in:
@@ -2,6 +2,19 @@
|
||||
@echo off
|
||||
set WP=%CD%
|
||||
|
||||
@REM Check for Ninja Multi-Config option (-x)
|
||||
set USE_NINJA=0
|
||||
for %%a in (%*) do (
|
||||
if "%%a"=="-x" set USE_NINJA=1
|
||||
)
|
||||
|
||||
if "%USE_NINJA%"=="1" (
|
||||
echo Using Ninja Multi-Config generator
|
||||
set CMAKE_GENERATOR="Ninja Multi-Config"
|
||||
set VS_VERSION=Ninja
|
||||
goto :generator_ready
|
||||
)
|
||||
|
||||
@REM Detect Visual Studio version using msbuild
|
||||
echo Detecting Visual Studio version using msbuild...
|
||||
|
||||
@@ -50,6 +63,8 @@ if "%VS_MAJOR%"=="16" (
|
||||
echo Detected Visual Studio %VS_VERSION% (version %VS_MAJOR%)
|
||||
echo Using CMake generator: %CMAKE_GENERATOR%
|
||||
|
||||
:generator_ready
|
||||
|
||||
@REM Pack deps
|
||||
if "%1"=="pack" (
|
||||
setlocal ENABLEDELAYEDEXPANSION
|
||||
@@ -96,8 +111,13 @@ echo "building deps.."
|
||||
echo on
|
||||
REM Set minimum CMake policy to avoid <3.5 errors
|
||||
set CMAKE_POLICY_VERSION_MINIMUM=3.5
|
||||
cmake ../ -G %CMAKE_GENERATOR% -A x64 -DCMAKE_BUILD_TYPE=%build_type%
|
||||
cmake --build . --config %build_type% --target deps -- -m
|
||||
if "%USE_NINJA%"=="1" (
|
||||
cmake ../ -G %CMAKE_GENERATOR% -DCMAKE_BUILD_TYPE=%build_type%
|
||||
cmake --build . --config %build_type% --target deps
|
||||
) else (
|
||||
cmake ../ -G %CMAKE_GENERATOR% -A x64 -DCMAKE_BUILD_TYPE=%build_type%
|
||||
cmake --build . --config %build_type% --target deps -- -m
|
||||
)
|
||||
@echo off
|
||||
|
||||
if "%1"=="deps" exit /b 0
|
||||
@@ -110,8 +130,13 @@ cd %build_dir%
|
||||
|
||||
echo on
|
||||
set CMAKE_POLICY_VERSION_MINIMUM=3.5
|
||||
cmake .. -G %CMAKE_GENERATOR% -A x64 -DORCA_TOOLS=ON %SIG_FLAG% -DCMAKE_BUILD_TYPE=%build_type%
|
||||
cmake --build . --config %build_type% --target ALL_BUILD -- -m
|
||||
if "%USE_NINJA%"=="1" (
|
||||
cmake .. -G %CMAKE_GENERATOR% -DORCA_TOOLS=ON %SIG_FLAG% -DCMAKE_BUILD_TYPE=%build_type%
|
||||
cmake --build . --config %build_type% --target ALL_BUILD
|
||||
) else (
|
||||
cmake .. -G %CMAKE_GENERATOR% -A x64 -DORCA_TOOLS=ON %SIG_FLAG% -DCMAKE_BUILD_TYPE=%build_type%
|
||||
cmake --build . --config %build_type% --target ALL_BUILD -- -m
|
||||
)
|
||||
@echo off
|
||||
cd ..
|
||||
call scripts/run_gettext.bat
|
||||
|
||||
@@ -64,26 +64,26 @@
|
||||
|
||||
[hint:Precise wall]
|
||||
text = Precise wall\nDid you know that turning on precise wall can improve precision and layer consistency?
|
||||
documentation_link = https://github.com/OrcaSlicer/OrcaSlicer/wiki/quality_settings_precision
|
||||
documentation_link = https://www.orcaslicer.com/wiki/quality_settings_precision#precise-wall
|
||||
|
||||
[hint:Sandwich mode]
|
||||
text = Sandwich mode\nDid you know that you can use sandwich mode (inner-outer-inner) to improve precision and layer consistency if your model doesn't have very steep overhangs?
|
||||
|
||||
[hint:Chamber temperature]
|
||||
text = Chamber temperature\nDid you know that OrcaSlicer supports chamber temperature?
|
||||
documentation_link = https://github.com/OrcaSlicer/OrcaSlicer/wiki/Chamber-temperature
|
||||
documentation_link = https://www.orcaslicer.com/wiki/material_temperatures#print-chamber-temperature
|
||||
|
||||
[hint:Calibration]
|
||||
text = Calibration\nDid you know that calibrating your printer can do wonders? Check out our beloved calibration solution in OrcaSlicer.
|
||||
documentation_link = https://github.com/OrcaSlicer/OrcaSlicer/wiki/Calibration
|
||||
documentation_link = https://www.orcaslicer.com/wiki/calibration
|
||||
|
||||
[hint:Auxiliary fan]
|
||||
text = Auxiliary fan\nDid you know that OrcaSlicer supports Auxiliary part cooling fan?
|
||||
documentation_link = https://github.com/OrcaSlicer/OrcaSlicer/wiki/Auxiliary-fan
|
||||
documentation_link = https://www.orcaslicer.com/wiki/material_cooling#auxiliary-part-cooling-fan
|
||||
|
||||
[hint:Air filtration]
|
||||
text = Air filtration/Exhaust Fan\nDid you know that OrcaSlicer can support Air filtration/Exhaust Fan?
|
||||
documentation_link = https://github.com/OrcaSlicer/OrcaSlicer/wiki/air-filtration
|
||||
documentation_link = https://www.orcaslicer.com/wiki/material_cooling#activate-air-filtration
|
||||
|
||||
[hint:G-code window]
|
||||
text = G-code window\nYou can turn on/off the G-code window by pressing the <b>C</b> key.
|
||||
|
||||
@@ -224,7 +224,9 @@ void Fill3DHoneycomb::_fill_surface_single(
|
||||
// This means that the resultant infill won't be an ideal truncated octahedron,
|
||||
// but it should look better than the equivalent quantised version
|
||||
|
||||
coordf_t layerHeight = scale_(thickness_layers);
|
||||
//Orca: uses a fixed layer height to avoid inconsistent bridges and variable layer height artifacts.
|
||||
//coordf_t layerHeight = scale_(thickness_layers);
|
||||
coordf_t layerHeight = scale_(1.0);
|
||||
// ceiling to an integer value of layers per Z
|
||||
// (with a little nudge in case it's close to perfect)
|
||||
coordf_t layersPerModule = floor((gridSize * 2) / (zScale * layerHeight) + 0.05);
|
||||
@@ -300,4 +302,4 @@ void Fill3DHoneycomb::_fill_surface_single(
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
} // namespace Slic3r
|
||||
|
||||
@@ -1194,7 +1194,7 @@ StringObjectException Print::validate(StringObjectException *warning, Polygons*
|
||||
}
|
||||
}
|
||||
|
||||
if (m_config.print_sequence == PrintSequence::ByObject && m_objects.size() > 1) {
|
||||
if (m_config.print_sequence == PrintSequence::ByObject && (m_objects.size() > 1 || m_objects[0]->instances().size() > 1)) {
|
||||
if (m_config.timelapse_type == TimelapseType::tlSmooth)
|
||||
return {L("Smooth mode of timelapse is not supported when \"by object\" sequence is enabled.")};
|
||||
|
||||
|
||||
@@ -2615,13 +2615,16 @@ void PrintObject::bridge_over_infill()
|
||||
auto determine_bridging_angle = [](const Polygons &bridged_area, const Lines &anchors, InfillPattern dominant_pattern, double infill_direction) {
|
||||
AABBTreeLines::LinesDistancer<Line> lines_tree(anchors);
|
||||
|
||||
// Orca: since 3D Honeycomb was "fixed" by forcing coordf_t layerHeight = scale_(1.0), this is no longer needed.
|
||||
// CorssHatch also does not need fixed angle.
|
||||
//
|
||||
// Check it the infill that require a fixed infill angle.
|
||||
switch (dominant_pattern) {
|
||||
case ip3DHoneycomb:
|
||||
case ipCrossHatch:
|
||||
return (infill_direction + 45.0) * 2.0 * M_PI / 360.;
|
||||
default: break;
|
||||
}
|
||||
//switch (dominant_pattern) {
|
||||
//case ip3DHoneycomb:
|
||||
//case ipCrossHatch:
|
||||
// return (infill_direction + 45.0) * 2.0 * M_PI / 360.;
|
||||
//default: break;
|
||||
//}
|
||||
|
||||
std::map<double, int> counted_directions;
|
||||
for (const Polygon &p : bridged_area) {
|
||||
|
||||
@@ -260,7 +260,7 @@ std::vector<double> layer_height_profile_adaptive(const SlicingParameters& slici
|
||||
// last facet visited by the as.next_layer_height() function, where the facets are sorted by their increasing Z span.
|
||||
size_t current_facet = 0;
|
||||
// loop until we have at least one layer and the max slice_z reaches the object height
|
||||
while (print_z + EPSILON < slicing_params.object_print_z_height()) {
|
||||
while (print_z + EPSILON < slicing_params.object_print_z_uncompensated_height()) {
|
||||
float height = slicing_params.max_layer_height;
|
||||
// Slic3r::debugf "\n Slice layer: %d\n", $id;
|
||||
// determine next layer height
|
||||
@@ -331,10 +331,10 @@ std::vector<double> layer_height_profile_adaptive(const SlicingParameters& slici
|
||||
print_z += height;
|
||||
}
|
||||
|
||||
double z_gap = slicing_params.object_print_z_height() - *(layer_height_profile.end() - 2);
|
||||
double z_gap = slicing_params.object_print_z_uncompensated_height() - *(layer_height_profile.end() - 2);
|
||||
if (z_gap > 0.0)
|
||||
{
|
||||
layer_height_profile.push_back(slicing_params.object_print_z_height());
|
||||
layer_height_profile.push_back(slicing_params.object_print_z_uncompensated_height());
|
||||
layer_height_profile.push_back(std::clamp(z_gap, slicing_params.min_layer_height, slicing_params.max_layer_height));
|
||||
}
|
||||
|
||||
|
||||
@@ -2197,4 +2197,15 @@ bool TriangleSelector::Capsule2D::is_edge_inside_cursor(const Triangle &tr, cons
|
||||
return false;
|
||||
}
|
||||
|
||||
// ORCA: Helper to extract used states from serialized data
|
||||
std::vector<EnforcerBlockerType> TriangleSelector::extract_used_facet_states(const TriangleSplittingData &data)
|
||||
{
|
||||
std::vector<EnforcerBlockerType> out;
|
||||
for (size_t i = 0; i < data.used_states.size(); ++i) {
|
||||
if (data.used_states[i])
|
||||
out.push_back(static_cast<EnforcerBlockerType>(i));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
@@ -679,23 +679,60 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::Dummy(ImVec2(0.0f, ImGui::GetFontSize() * 0.5f));
|
||||
|
||||
|
||||
// ORCA: Remap filaments section (Border only, Title in border).
|
||||
// Styled as a panel for visual grouping.
|
||||
if (m_imgui->button(m_desc.at("perform_remap"))) {
|
||||
m_show_filament_remap_ui = !m_show_filament_remap_ui;
|
||||
if (m_show_filament_remap_ui) {
|
||||
// reset remap to identity on opening
|
||||
m_extruder_remap.resize(m_extruders_colors.size());
|
||||
for (size_t i = 0; i < m_extruder_remap.size(); ++i)
|
||||
m_extruder_remap[i] = i;
|
||||
m_show_remap_panel = !m_show_remap_panel;
|
||||
}
|
||||
|
||||
if (m_show_remap_panel)
|
||||
{
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
std::string title = into_u8(m_desc.at("perform_remap"));
|
||||
float available_width = ImGui::GetContentRegionAvail().x;
|
||||
|
||||
// ORCA: Draw Background filled (consistent with Filaments section)
|
||||
// Use static to remember height from previous frame so we can draw it behind.
|
||||
static float remap_panel_high = 40.0f;
|
||||
ImVec2 p_bg_min = ImGui::GetCursorScreenPos();
|
||||
// Adjust background position: slight negative offset to align with padding, width fills available
|
||||
// height from static variable.
|
||||
draw_list->AddRectFilled({p_bg_min.x - 10.0f, p_bg_min.y - 7.0f}, {p_bg_min.x + available_width + ImGui::GetFrameHeight(), p_bg_min.y + remap_panel_high}, ImGui::GetColorU32(ImGuiCol_FrameBgActive, 1.0f), 5.0f);
|
||||
|
||||
float start_y = ImGui::GetCursorPos().y;
|
||||
|
||||
// ORCA: Title as simple text - Removed as per request (redundant with button)
|
||||
// m_imgui->text(title);
|
||||
|
||||
ImGui::BeginGroup();
|
||||
// ORCA: Reduce vertical spacing within this group
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(m_imgui->scaled(0.4f), m_imgui->scaled(0.2f)));
|
||||
|
||||
render_filament_remap_ui(window_width, max_tooltip_width);
|
||||
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::EndGroup();
|
||||
|
||||
// ORCA: Update height for next frame fill
|
||||
remap_panel_high = ImGui::GetCursorPos().y - start_y;
|
||||
|
||||
// ORCA: Add Remap and Cancel buttons (outside the panel)
|
||||
ImGui::Dummy(ImVec2(0.0f, ImGui::GetFontSize() * 0.2f));
|
||||
if (m_imgui->button(m_desc.at("remap"))) {
|
||||
this->remap_filament_assignments();
|
||||
// Reset mapping to identity after apply
|
||||
for (size_t i = 0; i < m_extruder_remap.size(); ++i) m_extruder_remap[i] = i;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (m_imgui->button(m_desc.at("cancel_remap"))) {
|
||||
// Reset mapping to identity
|
||||
for (size_t i = 0; i < m_extruder_remap.size(); ++i) m_extruder_remap[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Render filament swap UI if enabled
|
||||
if (m_show_filament_remap_ui) {
|
||||
ImGui::Separator();
|
||||
render_filament_remap_ui(window_width, max_tooltip_width);
|
||||
}
|
||||
|
||||
ImGui::Dummy(ImVec2(0.0f, ImGui::GetFontSize() * 0.5f));
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f));
|
||||
@@ -763,6 +800,9 @@ void GLGizmoMmuSegmentation::update_model_object()
|
||||
wxGetApp().obj_list()->update_info_items(obj_idx);
|
||||
wxGetApp().plater()->get_partplate_list().notify_instance_update(obj_idx, 0);
|
||||
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||
|
||||
// ORCA: Refresh cache
|
||||
this->update_used_filaments();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -825,6 +865,9 @@ void GLGizmoMmuSegmentation::update_from_model_object(bool first_update)
|
||||
this->init_extruders_data();
|
||||
|
||||
this->init_model_triangle_selectors();
|
||||
|
||||
// ORCA: Refresh cache when model changes
|
||||
this->update_used_filaments();
|
||||
}
|
||||
|
||||
void GLGizmoMmuSegmentation::tool_changed(wchar_t old_tool, wchar_t new_tool)
|
||||
@@ -1010,6 +1053,35 @@ void GLMmSegmentationGizmo3DScene::finalize_triangle_indices()
|
||||
}
|
||||
}
|
||||
|
||||
// ORCA: Update the cache of used filaments (both base volume extruders and painted triangles)
|
||||
void GLGizmoMmuSegmentation::update_used_filaments()
|
||||
{
|
||||
m_used_filaments.clear();
|
||||
|
||||
// Add base extruder IDs from volumes (unpainted areas)
|
||||
for (int ext_id : m_volumes_extruder_idxs) {
|
||||
// ext_id is 1-based (1 = Extruder 1), 0 = Default (usually maps to first available or object default)
|
||||
// Here we assume 0 maps to index 0 (Extruder 1) for simplicity in display,
|
||||
// or we should check logic in init_model_triangle_selectors where it does:
|
||||
// int extruder_idx = (mv->extruder_id() > 0) ? mv->extruder_id() - 1 : 0;
|
||||
int idx = (ext_id > 0) ? ext_id - 1 : 0;
|
||||
if (idx >= 0 && idx < m_extruders_colors.size())
|
||||
m_used_filaments.insert((size_t)idx);
|
||||
}
|
||||
|
||||
// Add painted states
|
||||
for (const auto& selector : m_triangle_selectors) {
|
||||
if (!selector) continue;
|
||||
TriangleSelector::TriangleSplittingData data = selector->serialize();
|
||||
std::vector<EnforcerBlockerType> states = TriangleSelector::extract_used_facet_states(data);
|
||||
for (EnforcerBlockerType s : states) {
|
||||
int idx = (int)s - (int)EnforcerBlockerType::Extruder1;
|
||||
if (idx >= 0 && idx < m_extruders_colors.size())
|
||||
m_used_filaments.insert((size_t)idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoMmuSegmentation::render_filament_remap_ui(float window_width, float max_tooltip_width)
|
||||
{
|
||||
size_t n_extr = std::min((size_t)EnforcerBlockerType::ExtruderMax, m_extruders_colors.size());
|
||||
@@ -1017,18 +1089,34 @@ void GLGizmoMmuSegmentation::render_filament_remap_ui(float window_width, float
|
||||
const ImVec2 max_label_size = ImGui::CalcTextSize("99", NULL, true);
|
||||
const ImVec2 button_size(max_label_size.x + m_imgui->scaled(0.5f), 0.f);
|
||||
|
||||
for (int src = 0; src < (int)n_extr; ++src) {
|
||||
int displayed_count = 0;
|
||||
const int max_per_line = 8;
|
||||
|
||||
// ORCA: Use m_used_filaments to show only relevant source filaments
|
||||
for (size_t src : m_used_filaments) {
|
||||
if (src >= n_extr) continue;
|
||||
|
||||
const ColorRGBA &src_col = m_extruders_colors[src]; // keep for text contrast
|
||||
const ColorRGBA &dst_col = m_extruders_colors[m_extruder_remap[src]];
|
||||
ImVec4 col_vec = ImGuiWrapper::to_ImVec4(dst_col);
|
||||
|
||||
// ORCA: Button now shows the SOURCE color (per maintainer request)
|
||||
// This keeps the UI stable until "Remap" is clicked.
|
||||
ImVec4 col_vec = ImGuiWrapper::to_ImVec4(src_col);
|
||||
|
||||
if (src) ImGui::SameLine();
|
||||
if (displayed_count > 0 && (displayed_count % max_per_line != 0))
|
||||
ImGui::SameLine();
|
||||
|
||||
std::string btn_id = "##remap_src_" + std::to_string(src);
|
||||
std::string pop_id = "popup_" + std::to_string(src);
|
||||
|
||||
ImGuiColorEditFlags flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoInputs |
|
||||
ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoPicker |
|
||||
ImGuiColorEditFlags_NoTooltip;
|
||||
if (m_selected_extruder_idx != src) flags |= ImGuiColorEditFlags_NoBorder;
|
||||
|
||||
// ORCA: Show border ONLY if the popup is open (visual feedback for active selection)
|
||||
// Decoupled from m_selected_extruder_idx to prevent unwanted selection highlights.
|
||||
if (!ImGui::IsPopupOpen(pop_id.c_str()))
|
||||
flags |= ImGuiColorEditFlags_NoBorder;
|
||||
|
||||
#ifdef __APPLE__
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGuiWrapper::COL_ORCA);
|
||||
@@ -1047,8 +1135,9 @@ void GLGizmoMmuSegmentation::render_filament_remap_ui(float window_width, float
|
||||
#endif
|
||||
|
||||
// overlay destination number with proper contrast calculation
|
||||
// ORCA: Text still shows DESTINATION index, but contrast is against SOURCE color now.
|
||||
std::string dst_txt = std::to_string(m_extruder_remap[src] + 1);
|
||||
float gray = 0.299f * dst_col.r() + 0.587f * dst_col.g() + 0.114f * dst_col.b();
|
||||
float gray = 0.299f * src_col.r() + 0.587f * src_col.g() + 0.114f * src_col.b();
|
||||
ImVec2 txt_sz = ImGui::CalcTextSize(dst_txt.c_str());
|
||||
ImVec2 pos = ImGui::GetItemRectMin();
|
||||
ImVec2 size = ImGui::GetItemRectSize();
|
||||
@@ -1062,8 +1151,35 @@ void GLGizmoMmuSegmentation::render_filament_remap_ui(float window_width, float
|
||||
ImVec2(pos.x + (size.x - txt_sz.x) * 0.5f, pos.y + (size.y - txt_sz.y) * 0.5f),
|
||||
IM_COL32(0,0,0,255), dst_txt.c_str());
|
||||
|
||||
// ORCA: Show NEW color as a small triangle in the corner if remapped
|
||||
if (src != m_extruder_remap[src]) {
|
||||
float s = m_imgui->scaled(0.55f);
|
||||
float offset = m_imgui->scaled(0.15f); // Inset to avoid rounded corner clipping
|
||||
ImVec2 p = ImVec2(pos.x + offset, pos.y + offset);
|
||||
|
||||
// Contrast outline: White for dark backgrounds, Black for light backgrounds
|
||||
// Use dst_col (new color) for outline contrast check? Or src_col?
|
||||
// Usually outline is around the triangle (dst_col).
|
||||
float dst_gray = 0.299f * dst_col.r() + 0.587f * dst_col.g() + 0.114f * dst_col.b();
|
||||
ImU32 outline_col = (dst_gray * 255.f < 80.f) ? IM_COL32(255, 255, 255, 180) : IM_COL32(0, 0, 0, 180);
|
||||
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
draw_list->AddTriangleFilled(
|
||||
p,
|
||||
ImVec2(p.x + s, p.y),
|
||||
ImVec2(p.x, p.y + s),
|
||||
ImGuiWrapper::to_ImU32(dst_col));
|
||||
|
||||
// ORCA: Add a thin outline for better contrast when colors are similar
|
||||
draw_list->AddTriangle(
|
||||
p,
|
||||
ImVec2(p.x + s, p.y),
|
||||
ImVec2(p.x, p.y + s),
|
||||
outline_col,
|
||||
0.5f);
|
||||
}
|
||||
|
||||
// popup with possible destinations
|
||||
std::string pop_id = "popup_" + std::to_string(src);
|
||||
if (clicked) {
|
||||
// Calculate popup position centered below the current button
|
||||
ImVec2 button_pos = ImGui::GetItemRectMin();
|
||||
@@ -1079,15 +1195,19 @@ void GLGizmoMmuSegmentation::render_filament_remap_ui(float window_width, float
|
||||
// Apply popup styling before BeginPopup using standard Orca colors
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_PopupRounding, 4.0f);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_PopupBorderSize, 1.0f);
|
||||
ImGui::PushStyleColor(ImGuiCol_PopupBg, m_is_dark_mode ? ImGuiWrapper::COL_WINDOW_BG_DARK : ImGuiWrapper::COL_WINDOW_BG);
|
||||
// ORCA: Use FrameBgActive for consistency and to ensure visibility of white filaments
|
||||
ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGui::GetStyleColorVec4(ImGuiCol_FrameBgActive));
|
||||
ImGui::PushStyleColor(ImGuiCol_Border, m_is_dark_mode ? ImVec4(0.5f, 0.5f, 0.5f, 1.0f) : ImVec4(0.6f, 0.6f, 0.6f, 1.0f));
|
||||
|
||||
if (ImGui::BeginPopup(pop_id.c_str())) {
|
||||
|
||||
m_imgui->text(_L("To:"));
|
||||
|
||||
for (int dst = 0; dst < (int)n_extr; ++dst) {
|
||||
const ColorRGBA &dst_col_popup = m_extruders_colors[dst];
|
||||
ImVec4 dst_vec = ImGuiWrapper::to_ImVec4(dst_col_popup);
|
||||
if (dst) ImGui::SameLine();
|
||||
if (dst > 0 && (dst % max_per_line != 0))
|
||||
ImGui::SameLine();
|
||||
std::string dst_btn = "##dst_" + std::to_string(src) + "_" + std::to_string(dst);
|
||||
|
||||
// Apply same styling to destination buttons
|
||||
@@ -1142,18 +1262,9 @@ void GLGizmoMmuSegmentation::render_filament_remap_ui(float window_width, float
|
||||
// Clean up popup styling (always pop, whether popup was open or not)
|
||||
ImGui::PopStyleColor(2); // PopupBg and Border
|
||||
ImGui::PopStyleVar(2); // PopupRounding and PopupBorderSize
|
||||
|
||||
displayed_count++;
|
||||
}
|
||||
|
||||
ImGui::Dummy(ImVec2(0.0f, ImGui::GetFontSize() * 0.3f));
|
||||
|
||||
if (m_imgui->button(m_desc.at("remap"))) {
|
||||
remap_filament_assignments();
|
||||
m_show_filament_remap_ui = false;
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
if (m_imgui->button(m_desc.at("cancel_remap")))
|
||||
m_show_filament_remap_ui = false;
|
||||
}
|
||||
|
||||
void GLGizmoMmuSegmentation::remap_filament_assignments()
|
||||
@@ -1193,21 +1304,46 @@ void GLGizmoMmuSegmentation::remap_filament_assignments()
|
||||
ModelObject* mo = m_c->selection_info()->model_object();
|
||||
if (!mo) return;
|
||||
|
||||
bool volume_extruder_changed = false;
|
||||
|
||||
for (ModelVolume* mv : mo->volumes) {
|
||||
if (!mv->is_model_part()) continue;
|
||||
++idx;
|
||||
TriangleSelectorGUI* ts = m_triangle_selectors[idx].get();
|
||||
if (!ts) continue;
|
||||
|
||||
// Remap painted triangles
|
||||
ts->remap_triangle_state(state_map);
|
||||
ts->request_update_render_data(true);
|
||||
|
||||
// ORCA: Remap base volume extruder as well if selected
|
||||
int current_ext_id = mv->extruder_id();
|
||||
int current_idx = (current_ext_id > 0) ? current_ext_id - 1 : 0;
|
||||
|
||||
if (current_idx >= 0 && current_idx < m_extruder_remap.size()) {
|
||||
size_t dest_idx = m_extruder_remap[current_idx];
|
||||
if (dest_idx != current_idx) {
|
||||
mv->config.set("extruder", (int)dest_idx + 1);
|
||||
if (idx < m_volumes_extruder_idxs.size())
|
||||
m_volumes_extruder_idxs[idx] = (int)dest_idx + 1;
|
||||
volume_extruder_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if (updated) {
|
||||
wxGetApp().plater()->get_notification_manager()->push_notification(
|
||||
_L("Filament remapping finished.").ToStdString());
|
||||
// ORCA: Update renderer colors if base volume extruder changed
|
||||
if (volume_extruder_changed)
|
||||
this->update_triangle_selectors_colors();
|
||||
|
||||
// ORCA: Removed "Filament remapping finished" notification to reduce UI noise.
|
||||
update_model_object();
|
||||
m_parent.set_as_dirty();
|
||||
|
||||
// ORCA: Refresh used filaments cache
|
||||
this->update_used_filaments();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -114,8 +114,10 @@ protected:
|
||||
bool m_detect_geometry_edge = true;
|
||||
|
||||
// Filament remap feature
|
||||
bool m_show_remap_panel = false;
|
||||
std::vector<size_t> m_extruder_remap; // index → target extruder index
|
||||
bool m_show_filament_remap_ui = false;
|
||||
// ORCA: Cache used filaments to filter UI
|
||||
std::set<size_t> m_used_filaments; // Set of used filament indices (cached)
|
||||
|
||||
static const constexpr float CursorRadiusMin = 0.1f; // cannot be zero
|
||||
|
||||
@@ -141,6 +143,8 @@ private:
|
||||
// Filament remapping methods
|
||||
void remap_filament_assignments();
|
||||
void render_filament_remap_ui(float window_width, float max_tooltip_width);
|
||||
// ORCA: Helper to update the cache of used filaments
|
||||
void update_used_filaments();
|
||||
|
||||
// This map holds all translated description texts, so they can be easily referenced during layout calculations
|
||||
// etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect.
|
||||
|
||||
22
task.md
22
task.md
@@ -1,12 +1,12 @@
|
||||
Analyze the bug that it failed to load project(3mf) from old version.
|
||||
It failed pass below check in PresetBundle::load_config_file_config function, hence throw error.
|
||||
if (config.option("extruder_variant_list")) {
|
||||
//3mf support multiple extruder logic
|
||||
size_t extruder_count = config.option<ConfigOptionFloats>("nozzle_diameter")->values.size();
|
||||
extruder_variant_count = config.option<ConfigOptionStrings>("filament_extruder_variant", true)->size();
|
||||
if ((extruder_variant_count != filament_self_indice.size())
|
||||
|| (extruder_variant_count < num_filaments)) {
|
||||
assert(false);
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": invalid config file %1%, can not find suitable filament_extruder_variant or filament_self_index") % name_or_path;
|
||||
throw Slic3r::RuntimeError(std::string("Invalid configuration file: ") + name_or_path);
|
||||
Analyze the bug that it failed to load project(3mf) from old version.
|
||||
It failed pass below check in PresetBundle::load_config_file_config function, hence throw error.
|
||||
if (config.option("extruder_variant_list")) {
|
||||
//3mf support multiple extruder logic
|
||||
size_t extruder_count = config.option<ConfigOptionFloats>("nozzle_diameter")->values.size();
|
||||
extruder_variant_count = config.option<ConfigOptionStrings>("filament_extruder_variant", true)->size();
|
||||
if ((extruder_variant_count != filament_self_indice.size())
|
||||
|| (extruder_variant_count < num_filaments)) {
|
||||
assert(false);
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": invalid config file %1%, can not find suitable filament_extruder_variant or filament_self_index") % name_or_path;
|
||||
throw Slic3r::RuntimeError(std::string("Invalid configuration file: ") + name_or_path);
|
||||
}
|
||||
Reference in New Issue
Block a user