mixed filament re-ordering

This commit is contained in:
Rad
2026-03-11 16:53:01 +01:00
parent f1a4ff6116
commit d339f82e37
6 changed files with 447 additions and 72 deletions
+75 -13
View File
@@ -113,6 +113,30 @@ float RetinaHelper::get_scale_factor() { return float(m_window->GetContentScaleF
#undef Convex
#endif
static std::vector<unsigned int> get_ui_ordered_filament_ids(Plater *plater, size_t total_filaments)
{
std::vector<unsigned int> ordered_ids;
if (plater != nullptr)
ordered_ids = plater->sidebar().get_ui_ordered_filament_ids();
std::vector<unsigned int> sanitized_ids;
sanitized_ids.reserve(total_filaments);
std::vector<bool> used(total_filaments + 1, false);
for (const unsigned int filament_id : ordered_ids) {
if (filament_id == 0 || filament_id > total_filaments || used[filament_id])
continue;
used[filament_id] = true;
sanitized_ids.emplace_back(filament_id);
}
for (unsigned int filament_id = 1; filament_id <= total_filaments; ++filament_id) {
if (!used[filament_id])
sanitized_ids.emplace_back(filament_id);
}
return sanitized_ids;
}
GLCanvas3D::LayersEditing::~LayersEditing()
{
if (m_z_texture_id != 0) {
@@ -3304,8 +3328,16 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
if (keyCode < '7') keyCode += 10;
m_timer_set_color.Stop();
}
if (m_gizmos.get_current_type() != GLGizmosManager::MmSegmentation)
obj_list->set_extruder_for_selected_items(keyCode - '0');
if (m_gizmos.get_current_type() != GLGizmosManager::MmSegmentation) {
const int display_filament_id = keyCode - '0';
const size_t total_filaments = wxGetApp().plater()->get_extruder_colors_from_plater_config().size();
const std::vector<unsigned int> ordered_filament_ids =
get_ui_ordered_filament_ids(wxGetApp().plater(), total_filaments);
if (display_filament_id >= 1 && size_t(display_filament_id) <= ordered_filament_ids.size())
obj_list->set_extruder_for_selected_items(int(ordered_filament_ids[size_t(display_filament_id - 1)]));
else
obj_list->set_extruder_for_selected_items(display_filament_id);
}
break;
}
@@ -3847,8 +3879,11 @@ void GLCanvas3D::on_render_timer(wxTimerEvent& evt)
void GLCanvas3D::on_set_color_timer(wxTimerEvent& evt)
{
auto obj_list = wxGetApp().obj_list();
if (m_gizmos.get_current_type() != GLGizmosManager::MmSegmentation)
obj_list->set_extruder_for_selected_items(1);
if (m_gizmos.get_current_type() != GLGizmosManager::MmSegmentation) {
const std::vector<unsigned int> ordered_filament_ids =
get_ui_ordered_filament_ids(wxGetApp().plater(), wxGetApp().plater()->get_extruder_colors_from_plater_config().size());
obj_list->set_extruder_for_selected_items(ordered_filament_ids.empty() ? 1 : int(ordered_filament_ids.front()));
}
m_timer_set_color.Stop();
}
@@ -8354,28 +8389,52 @@ void GLCanvas3D::_render_paint_toolbar() const
#endif
int em_unit = wxGetApp().em_unit() / 10;
std::vector<std::string> colors = wxGetApp().plater()->get_extruder_colors_from_plater_config();
int extruder_num = colors.size();
const std::vector<std::string> actual_colors = wxGetApp().plater()->get_extruder_colors_from_plater_config();
const std::vector<unsigned int> display_filament_ids =
get_ui_ordered_filament_ids(wxGetApp().plater(), actual_colors.size());
std::vector<std::string> colors;
colors.reserve(display_filament_ids.size());
for (const unsigned int filament_id : display_filament_ids) {
if (filament_id >= 1 && filament_id <= actual_colors.size())
colors.emplace_back(actual_colors[filament_id - 1]);
}
const int extruder_num = int(colors.size());
std::vector<std::string> filament_text_first_line;
std::vector<std::string> filament_text_second_line;
{
auto preset_bundle = wxGetApp().preset_bundle;
for (auto filament_name : preset_bundle->filament_presets) {
for (auto iter = preset_bundle->filaments.lbegin(); iter != preset_bundle->filaments.end(); iter++) {
if (filament_name.compare(iter->name) == 0) {
const size_t physical_count = preset_bundle ? preset_bundle->filament_presets.size() : 0;
filament_text_first_line.reserve(colors.size());
filament_text_second_line.reserve(colors.size());
for (size_t display_idx = 0; display_idx < display_filament_ids.size(); ++display_idx) {
const unsigned int actual_filament_id = display_filament_ids[display_idx];
bool label_found = false;
if (preset_bundle != nullptr && actual_filament_id >= 1 && actual_filament_id <= physical_count) {
const std::string &filament_name = preset_bundle->filament_presets[size_t(actual_filament_id - 1)];
for (auto iter = preset_bundle->filaments.lbegin(); iter != preset_bundle->filaments.end(); ++iter) {
if (filament_name.compare(iter->name) != 0)
continue;
std::string display_filament_type;
iter->config.get_filament_type(display_filament_type);
auto pos = display_filament_type.find(' ');
if (pos != std::string::npos) {
filament_text_first_line.push_back(display_filament_type.substr(0, pos));
filament_text_second_line.push_back(display_filament_type.substr(pos + 1));
}
else {
} else {
filament_text_first_line.push_back(display_filament_type);
filament_text_second_line.push_back("");
}
label_found = true;
break;
}
}
if (!label_found) {
filament_text_first_line.push_back("Mixed");
filament_text_second_line.push_back("Filament");
}
}
}
@@ -8417,8 +8476,11 @@ void GLCanvas3D::_render_paint_toolbar() const
if (disabled)
ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
if (ImGui::Button(("##filament_button" + std::to_string(i)).c_str(), button_size)) {
if (!ImGui::IsMouseHoveringRect(left_arrow_button.Min, left_arrow_button.Max) && !ImGui::IsMouseHoveringRect(right_arrow_button.Min, right_arrow_button.Max))
wxPostEvent(m_canvas, IntEvent(EVT_GLTOOLBAR_FILLCOLOR, i + 1));
if (!ImGui::IsMouseHoveringRect(left_arrow_button.Min, left_arrow_button.Max) && !ImGui::IsMouseHoveringRect(right_arrow_button.Min, right_arrow_button.Max)) {
const int actual_filament_id =
i < int(display_filament_ids.size()) ? int(display_filament_ids[size_t(i)]) : i + 1;
wxPostEvent(m_canvas, IntEvent(EVT_GLTOOLBAR_FILLCOLOR, actual_filament_id));
}
}
if (ImGui::IsItemHovered() && i < 9) {
if (!ImGui::IsMouseHoveringRect(left_arrow_button.Min, left_arrow_button.Max) && !ImGui::IsMouseHoveringRect(right_arrow_button.Min, right_arrow_button.Max)) {
+29 -30
View File
@@ -50,7 +50,14 @@ static int filaments_count()
return static_cast<int>(mixed_mgr.total_filaments(size_t(physical)));
}
static wxString filament_menu_item_name(const int filament_id_1based)
static std::vector<unsigned int> ui_ordered_filament_ids()
{
if (wxGetApp().plater() == nullptr)
return {};
return wxGetApp().plater()->sidebar().get_ui_ordered_filament_ids();
}
static wxString filament_menu_item_name(const int filament_id_1based, const int display_filament_id_1based)
{
if (filament_id_1based <= 0)
return _L("Default");
@@ -70,7 +77,7 @@ static wxString filament_menu_item_name(const int filament_id_1based)
return wxString::Format(_L("Filament %d"), filament_id_1based);
}
return wxString::Format(_L("Mixed Filament %d"), filament_id_1based);
return wxString::Format(_L("Mixed Filament %d"), display_filament_id_1based);
}
static bool is_improper_category(const std::string& category, const int filaments_cnt, const bool is_object_settings = true)
@@ -912,8 +919,8 @@ void MenuFactory::append_menu_item_change_extruder(wxMenu* menu)
menu->Destroy(item_id);
}
const int filaments_cnt = filaments_count();
if (filaments_cnt <= 1)
const std::vector<unsigned int> ordered_filament_ids = ui_ordered_filament_ids();
if (ordered_filament_ids.size() <= 1)
return;
wxDataViewItemArray sels;
@@ -932,12 +939,13 @@ void MenuFactory::append_menu_item_change_extruder(wxMenu* menu)
initial_extruder = config.has("extruder") ? config.extruder() : 0;
}
for (int i = 0; i <= filaments_cnt; i++)
for (size_t display_idx = 0; display_idx <= ordered_filament_ids.size(); ++display_idx)
{
bool is_active_extruder = i == initial_extruder;
int icon_idx = i == 0 ? 0 : i - 1;
const int actual_filament_id = display_idx == 0 ? 0 : int(ordered_filament_ids[display_idx - 1]);
const bool is_active_extruder = actual_filament_id == initial_extruder;
const int icon_idx = actual_filament_id == 0 ? 0 : actual_filament_id - 1;
wxString item_name = filament_menu_item_name(i);
wxString item_name = filament_menu_item_name(actual_filament_id, int(display_idx));
if (is_active_extruder) {
item_name << " (" + _L("current") + ")";
@@ -945,11 +953,13 @@ void MenuFactory::append_menu_item_change_extruder(wxMenu* menu)
if (icon_idx >= 0 && icon_idx < icons.size()) {
append_menu_item(
extruder_selection_menu, wxID_ANY, item_name, "", [i](wxCommandEvent &) { obj_list()->set_extruder_for_selected_items(i); }, *icons[icon_idx], menu,
extruder_selection_menu, wxID_ANY, item_name, "",
[actual_filament_id](wxCommandEvent &) { obj_list()->set_extruder_for_selected_items(actual_filament_id); }, *icons[icon_idx], menu,
[is_active_extruder]() { return !is_active_extruder; }, m_parent);
} else {
append_menu_item(
extruder_selection_menu, wxID_ANY, item_name, "", [i](wxCommandEvent &) { obj_list()->set_extruder_for_selected_items(i); }, "", menu,
extruder_selection_menu, wxID_ANY, item_name, "",
[actual_filament_id](wxCommandEvent &) { obj_list()->set_extruder_for_selected_items(actual_filament_id); }, "", menu,
[is_active_extruder]() { return !is_active_extruder; }, m_parent);
}
}
@@ -1965,8 +1975,8 @@ void MenuFactory::append_menu_item_change_filament(wxMenu* menu)
menu->Destroy(item_id);
}
int filaments_cnt = filaments_count();
if (filaments_cnt <= 1)
const std::vector<unsigned int> ordered_filament_ids = ui_ordered_filament_ids();
if (ordered_filament_ids.size() <= 1)
return;
wxDataViewItemArray sels;
@@ -1981,12 +1991,10 @@ void MenuFactory::append_menu_item_change_filament(wxMenu* menu)
}
std::vector<wxBitmap*> icons = get_extruder_color_icons(true);
if (icons.size() < filaments_cnt) {
BOOST_LOG_TRIVIAL(warning) << boost::format("Warning: icons size %1%, filaments_cnt=%2%")%icons.size()%filaments_cnt;
if (icons.size() < ordered_filament_ids.size()) {
BOOST_LOG_TRIVIAL(warning) << boost::format("Warning: icons size %1%, filaments_cnt=%2%") % icons.size() % ordered_filament_ids.size();
if (icons.size() <= 1)
return;
else
filaments_cnt = icons.size();
}
wxMenu* extruder_selection_menu = new wxMenu();
const wxString& name = sels.Count() == 1 ? names[0] : names[1];
@@ -2002,29 +2010,20 @@ void MenuFactory::append_menu_item_change_filament(wxMenu* menu)
initial_extruder = config.has("extruder") ? config.extruder() : 0;
}
// BBS
bool has_modifier = false;
for (auto sel : sels) {
if (obj_list()->GetModel()->GetVolumeType(sel) == ModelVolumeType::PARAMETER_MODIFIER) {
has_modifier = true;
break;
}
}
for (/*int i = has_modifier ? 0 : 1*/int i = 0; i <= filaments_cnt; i++)
for (size_t display_idx = 0; display_idx <= ordered_filament_ids.size(); ++display_idx)
{
// BBS
//bool is_active_extruder = i == initial_extruder;
const int actual_filament_id = display_idx == 0 ? 0 : int(ordered_filament_ids[display_idx - 1]);
bool is_active_extruder = false;
wxString item_name = filament_menu_item_name(i);
wxString item_name = filament_menu_item_name(actual_filament_id, int(display_idx));
if (is_active_extruder) {
item_name << " (" + _L("current") + ")";
}
append_menu_item(extruder_selection_menu, wxID_ANY, item_name, "",
[i](wxCommandEvent&) { obj_list()->set_extruder_for_selected_items(i); }, i == 0 ? wxNullBitmap : *icons[i - 1], menu,
[actual_filament_id](wxCommandEvent&) { obj_list()->set_extruder_for_selected_items(actual_filament_id); },
actual_filament_id == 0 || size_t(actual_filament_id - 1) >= icons.size() ? wxNullBitmap : *icons[size_t(actual_filament_id - 1)], menu,
[is_active_extruder]() { return !is_active_extruder; }, m_parent);
}
menu->Append(wxID_ANY, name, extruder_selection_menu, _L("Change Filament"));
@@ -89,14 +89,48 @@ static std::vector<int> get_extruder_id_for_volumes(const ModelObject &model_obj
return extruders_idx;
}
static std::vector<unsigned int> get_display_filament_ids(size_t total_filaments)
{
std::vector<unsigned int> ordered_filament_ids;
if (wxGetApp().plater() != nullptr)
ordered_filament_ids = wxGetApp().plater()->sidebar().get_ui_ordered_filament_ids();
std::vector<unsigned int> sanitized_filament_ids;
sanitized_filament_ids.reserve(total_filaments);
std::vector<bool> used_filament_ids(total_filaments + 1, false);
for (const unsigned int filament_id : ordered_filament_ids) {
if (filament_id == 0 || filament_id > total_filaments || used_filament_ids[filament_id])
continue;
used_filament_ids[filament_id] = true;
sanitized_filament_ids.emplace_back(filament_id);
}
for (unsigned int filament_id = 1; filament_id <= total_filaments; ++filament_id) {
if (!used_filament_ids[filament_id])
sanitized_filament_ids.emplace_back(filament_id);
}
return sanitized_filament_ids;
}
void GLGizmoMmuSegmentation::init_extruders_data(const std::vector<ColorRGBA> &extruder_colors)
{
const size_t old_selected = m_selected_extruder_idx;
const unsigned int old_selected_filament_id =
m_selected_extruder_idx < m_display_filament_ids.size() ? m_display_filament_ids[m_selected_extruder_idx] :
(m_selected_extruder_idx < m_extruders_colors.size() ? unsigned(m_selected_extruder_idx + 1) : 0);
m_extruders_colors = extruder_colors;
m_selected_extruder_idx = m_extruders_colors.empty() ? 0 : std::min(old_selected, m_extruders_colors.size() - 1);
m_display_filament_ids = get_display_filament_ids(m_extruders_colors.size());
m_selected_extruder_idx = 0;
if (!m_display_filament_ids.empty()) {
auto selected_it = std::find(m_display_filament_ids.begin(), m_display_filament_ids.end(), old_selected_filament_id);
if (selected_it != m_display_filament_ids.end())
m_selected_extruder_idx = size_t(std::distance(m_display_filament_ids.begin(), selected_it));
}
// keep remap table consistent with current extruder count
m_extruder_remap.resize(m_extruders_colors.size());
m_extruder_remap.resize(m_display_filament_ids.size());
for (size_t i = 0; i < m_extruder_remap.size(); ++i)
m_extruder_remap[i] = i;
}
@@ -197,6 +231,7 @@ void GLGizmoMmuSegmentation::data_changed(bool is_serializing)
const std::vector<ColorRGBA> current_extruder_colors = get_extruders_colors();
const int prev_extruders_count = int(m_extruders_colors.size());
const int current_extruders_count = int(current_extruder_colors.size());
const std::vector<unsigned int> current_display_filament_ids = get_display_filament_ids(current_extruder_colors.size());
if (prev_extruders_count != current_extruders_count) {
if (current_extruder_colors.size() > GLGizmoMmuSegmentation::EXTRUDERS_LIMIT)
show_notification_extruders_limit_exceeded();
@@ -210,6 +245,9 @@ void GLGizmoMmuSegmentation::data_changed(bool is_serializing)
this->init_extruders_data(current_extruder_colors);
this->update_triangle_selectors_colors();
}
else if (current_display_filament_ids != m_display_filament_ids) {
this->init_extruders_data(current_extruder_colors);
}
else if (model_object != nullptr && get_extruder_id_for_volumes(*model_object) != m_volumes_extruder_idxs) {
this->init_model_triangle_selectors();
}
@@ -219,7 +257,7 @@ void GLGizmoMmuSegmentation::data_changed(bool is_serializing)
bool GLGizmoMmuSegmentation::on_number_key_down(int number)
{
int extruder_idx = number - 1;
if (extruder_idx < m_extruders_colors.size() && extruder_idx >= 0)
if (extruder_idx >= 0 && size_t(extruder_idx) < m_display_filament_ids.size())
m_selected_extruder_idx = extruder_idx;
return true;
@@ -421,9 +459,12 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
m_imgui->text(m_desc.at("filaments"));
float start_pos_x = ImGui::GetCursorPos().x;
size_t n_extruder_colors = std::min(GLGizmoMmuSegmentation::EXTRUDERS_LIMIT, m_extruders_colors.size());
size_t n_extruder_colors = std::min(GLGizmoMmuSegmentation::EXTRUDERS_LIMIT, m_display_filament_ids.size());
for (size_t extruder_idx = 0; extruder_idx < n_extruder_colors; ++extruder_idx) {
const ColorRGBA &extruder_color = m_extruders_colors[extruder_idx];
const unsigned int actual_filament_id = m_display_filament_ids[extruder_idx];
if (actual_filament_id == 0 || actual_filament_id > m_extruders_colors.size())
continue;
const ColorRGBA &extruder_color = m_extruders_colors[actual_filament_id - 1];
ImVec4 color_vec = ImGuiWrapper::to_ImVec4(extruder_color);
std::string color_label = std::string("##extruder color ") + std::to_string(extruder_idx);
std::string item_text = std::to_string(extruder_idx + 1);
@@ -914,10 +955,12 @@ PainterGizmoType GLGizmoMmuSegmentation::get_painter_type() const
// BBS
ColorRGBA GLGizmoMmuSegmentation::get_cursor_hover_color() const
{
if (m_selected_extruder_idx < m_extruders_colors.size())
return m_extruders_colors[m_selected_extruder_idx];
else
return m_extruders_colors[0];
if (m_selected_extruder_idx < m_display_filament_ids.size()) {
const unsigned int actual_filament_id = m_display_filament_ids[m_selected_extruder_idx];
if (actual_filament_id >= 1 && actual_filament_id <= m_extruders_colors.size())
return m_extruders_colors[actual_filament_id - 1];
}
return m_extruders_colors.empty() ? ColorRGBA() : m_extruders_colors[0];
}
void GLGizmoMmuSegmentation::on_set_state()
@@ -1021,7 +1064,7 @@ void GLMmSegmentationGizmo3DScene::finalize_triangle_indices()
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());
size_t n_extr = std::min((size_t)EnforcerBlockerType::ExtruderMax, m_display_filament_ids.size());
const std::string max_label = std::to_string(std::max<size_t>(n_extr, 1));
const ImVec2 max_label_size = ImGui::CalcTextSize(max_label.c_str(), NULL, true);
@@ -1031,7 +1074,10 @@ void GLGizmoMmuSegmentation::render_filament_remap_ui(float window_width, float
const float start_pos_x = ImGui::GetCursorPosX();
for (int src = 0; src < (int)n_extr; ++src) {
const ColorRGBA &dst_col = m_extruders_colors[m_extruder_remap[src]];
const unsigned int dst_filament_id = m_extruder_remap[src] < m_display_filament_ids.size() ? m_display_filament_ids[m_extruder_remap[src]] : 0;
if (dst_filament_id == 0 || dst_filament_id > m_extruders_colors.size())
continue;
const ColorRGBA &dst_col = m_extruders_colors[dst_filament_id - 1];
ImVec4 col_vec = ImGuiWrapper::to_ImVec4(dst_col);
if (src % max_items_per_line != 0) {
@@ -1100,7 +1146,10 @@ void GLGizmoMmuSegmentation::render_filament_remap_ui(float window_width, float
const float popup_start_pos_x = ImGui::GetCursorPosX();
for (int dst = 0; dst < (int)n_extr; ++dst) {
const ColorRGBA &dst_col_popup = m_extruders_colors[dst];
const unsigned int popup_filament_id = m_display_filament_ids[dst];
if (popup_filament_id == 0 || popup_filament_id > m_extruders_colors.size())
continue;
const ColorRGBA &dst_col_popup = m_extruders_colors[popup_filament_id - 1];
ImVec4 dst_vec = ImGuiWrapper::to_ImVec4(dst_col_popup);
if (dst % max_items_per_line != 0)
ImGui::SameLine(popup_start_pos_x + item_width * (dst % max_items_per_line));
@@ -1184,18 +1233,23 @@ void GLGizmoMmuSegmentation::remap_filament_assignments()
for (size_t i = 0; i <= MAX_EBT; ++i)
state_map[i] = static_cast<EnforcerBlockerType>(i);
size_t n_extr = std::min(m_extruder_remap.size(), MAX_EBT);
const int start_extruder = (int) EnforcerBlockerType::Extruder1;
size_t n_extr = std::min({m_extruder_remap.size(), m_display_filament_ids.size(), MAX_EBT});
bool any_change = false;
for (size_t src = 0; src < n_extr; ++src) {
size_t dst = m_extruder_remap[src];
if (dst != src) {
state_map[src+start_extruder] = static_cast<EnforcerBlockerType>(dst+start_extruder);
if (src == 0)
state_map[0] = static_cast<EnforcerBlockerType>(dst + start_extruder);
const size_t dst = m_extruder_remap[src];
if (dst >= m_display_filament_ids.size())
continue;
any_change = true;
}
const unsigned int src_state = m_display_filament_ids[src];
const unsigned int dst_state = m_display_filament_ids[dst];
if (src_state == 0 || dst_state == 0 || src_state == dst_state)
continue;
state_map[src_state] = static_cast<EnforcerBlockerType>(dst_state);
if (src_state == 1)
state_map[0] = static_cast<EnforcerBlockerType>(dst_state);
any_change = true;
}
if (!any_change)
return;
@@ -85,7 +85,12 @@ protected:
ColorRGBA get_cursor_hover_color() const override;
void on_set_state() override;
EnforcerBlockerType get_left_button_state_type() const override { return EnforcerBlockerType(m_selected_extruder_idx + 1); }
EnforcerBlockerType get_left_button_state_type() const override
{
if (m_selected_extruder_idx < m_display_filament_ids.size())
return EnforcerBlockerType(m_display_filament_ids[m_selected_extruder_idx]);
return EnforcerBlockerType::Extruder1;
}
EnforcerBlockerType get_right_button_state_type() const override { return EnforcerBlockerType(-1); }
void on_render_input_window(float x, float y, float bottom_limit) override;
@@ -103,6 +108,7 @@ protected:
// BBS
size_t m_selected_extruder_idx = 0;
std::vector<ColorRGBA> m_extruders_colors;
std::vector<unsigned int> m_display_filament_ids;
std::vector<int> m_volumes_extruder_idxs;
// BBS
+259 -6
View File
@@ -660,6 +660,14 @@ struct Sidebar::priv
bool m_mixed_filaments_collapsed = false; // Collapse state
bool m_skip_mixed_filament_sync_once = false; // Local edits already mutated manager in place.
std::unordered_set<size_t> m_expanded_mixed_filament_rows; // Expanded row editors
struct MixedFilamentRowBinding {
size_t mixed_id = size_t(-1);
wxWindow *row = nullptr;
};
std::vector<MixedFilamentRowBinding> m_mixed_filament_row_bindings;
std::vector<uint64_t> m_mixed_filament_ui_order;
bool m_mixed_filament_drag_active = false;
size_t m_mixed_filament_drag_source_mixed_id = size_t(-1);
wxStaticLine* m_staticline2;
wxPanel* m_panel_project_title;
ScalableButton* m_filament_icon = nullptr;
@@ -3870,6 +3878,82 @@ void MixedFilamentConfigPanel::update_preview()
}
}
class MixedFilamentDragHandle : public wxPanel
{
public:
MixedFilamentDragHandle(wxWindow *parent, const wxColour &dot_color, const wxColour &bg_color)
: wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE)
, m_dot_color(dot_color)
{
const wxSize handle_size = parent ? parent->FromDIP(wxSize(14, 18)) : wxSize(14, 18);
SetMinSize(handle_size);
SetMaxSize(handle_size);
SetInitialSize(handle_size);
SetBackgroundStyle(wxBG_STYLE_PAINT);
SetBackgroundColour(bg_color);
SetCursor(wxCursor(wxCURSOR_SIZING));
Bind(wxEVT_PAINT, &MixedFilamentDragHandle::on_paint, this);
}
void set_colors(const wxColour &dot_color, const wxColour &bg_color)
{
m_dot_color = dot_color;
SetBackgroundColour(bg_color);
Refresh();
}
private:
void on_paint(wxPaintEvent &)
{
wxAutoBufferedPaintDC dc(this);
dc.SetBackground(wxBrush(GetBackgroundColour()));
dc.Clear();
dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(wxBrush(m_dot_color));
const wxSize size = GetClientSize();
const int radius = std::max(1, FromDIP(1));
const int left_x = std::max(radius, size.x / 2 - FromDIP(2));
const int right_x = std::min(size.x - radius - 1, size.x / 2 + FromDIP(2));
const int top_y = std::max(radius + 1, size.y / 2 - FromDIP(5));
const int gap_y = FromDIP(4);
for (int row = 0; row < 3; ++row) {
const int y = top_y + row * gap_y;
dc.DrawCircle(wxPoint(left_x, y), radius);
dc.DrawCircle(wxPoint(right_x, y), radius);
}
}
wxColour m_dot_color;
};
static std::vector<size_t> build_mixed_filament_ui_indices(const std::vector<MixedFilament> &mixed,
const std::vector<uint64_t> &preferred_order)
{
std::vector<size_t> ordered_indices;
std::vector<bool> used(mixed.size(), false);
for (const uint64_t stable_id : preferred_order) {
for (size_t idx = 0; idx < mixed.size(); ++idx) {
const MixedFilament &entry = mixed[idx];
if (used[idx] || entry.deleted || entry.stable_id != stable_id)
continue;
used[idx] = true;
ordered_indices.emplace_back(idx);
break;
}
}
for (size_t idx = 0; idx < mixed.size(); ++idx) {
if (used[idx] || mixed[idx].deleted)
continue;
ordered_indices.emplace_back(idx);
}
return ordered_indices;
}
} // namespace
void Sidebar::update_mixed_filament_panel(bool sync_manager)
@@ -4321,6 +4405,19 @@ void Sidebar::update_mixed_filament_panel(bool sync_manager)
}
auto &mixed = mixed_mgr.mixed_filaments();
const std::vector<size_t> ordered_mixed_indices = build_mixed_filament_ui_indices(mixed, p->m_mixed_filament_ui_order);
std::vector<uint64_t> sanitized_mixed_ui_order_ids;
sanitized_mixed_ui_order_ids.reserve(ordered_mixed_indices.size());
for (const size_t mixed_id : ordered_mixed_indices) {
if (mixed_id < mixed.size() && mixed[mixed_id].stable_id != 0)
sanitized_mixed_ui_order_ids.emplace_back(mixed[mixed_id].stable_id);
}
p->m_mixed_filament_ui_order = std::move(sanitized_mixed_ui_order_ids);
p->m_mixed_filament_drag_active = false;
p->m_mixed_filament_drag_source_mixed_id = size_t(-1);
p->m_mixed_filament_row_bindings.clear();
const int compact_gap_x = FromDIP(6);
const int compact_gap_y = FromDIP(4);
const int compact_row_pad = FromDIP(6);
@@ -4493,17 +4590,43 @@ void Sidebar::update_mixed_filament_panel(bool sync_manager)
}
};
size_t visible_mixed_idx = 0;
for (size_t mixed_id = 0; mixed_id < mixed.size(); ++mixed_id) {
auto current_mixed_filament_ui_order = [this, &mixed]() {
std::vector<uint64_t> ordered_ids;
ordered_ids.reserve(p->m_mixed_filament_row_bindings.size());
for (const auto &binding : p->m_mixed_filament_row_bindings) {
if (binding.mixed_id < mixed.size() && mixed[binding.mixed_id].stable_id != 0)
ordered_ids.emplace_back(mixed[binding.mixed_id].stable_id);
}
return ordered_ids;
};
auto drop_insert_position = [this]() {
const wxPoint mouse_pos = wxGetMousePosition();
size_t visible_idx = 0;
for (const auto &binding : p->m_mixed_filament_row_bindings) {
if (binding.row == nullptr || !binding.row->IsShown())
continue;
const wxPoint top_left = binding.row->ClientToScreen(wxPoint(0, 0));
const int row_h = std::max(binding.row->GetSize().GetHeight(), binding.row->GetBestSize().GetHeight());
const int center_y = top_left.y + row_h / 2;
if (mouse_pos.y < center_y)
return visible_idx;
++visible_idx;
}
return visible_idx;
};
for (size_t display_mixed_idx = 0; display_mixed_idx < ordered_mixed_indices.size(); ++display_mixed_idx) {
const size_t mixed_id = ordered_mixed_indices[display_mixed_idx];
MixedFilament &mf = mixed[mixed_id];
if (mf.deleted)
continue;
const size_t display_mixed_idx = visible_mixed_idx++;
const bool auto_row = !mf.custom;
auto *row = new wxPanel(rows_scroller, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE);
row->SetBackgroundColour(mixed_row_bg);
auto *row_sizer = new wxBoxSizer(wxVERTICAL);
p->m_mixed_filament_row_bindings.push_back({mixed_id, row});
auto *header_panel = new wxPanel(row, wxID_ANY);
header_panel->SetBackgroundColour(mixed_row_bg);
@@ -4512,6 +4635,10 @@ void Sidebar::update_mixed_filament_panel(bool sync_manager)
const std::string synced_color = compute_entry_display_color(mf);
if (mf.display_color != synced_color)
mf.display_color = synced_color;
auto *drag_handle = new MixedFilamentDragHandle(header_panel, mixed_summary_fg, mixed_row_bg);
drag_handle->SetToolTip(_L("Drag to reorder mixed filaments in this panel."));
header_sizer->Add(drag_handle, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, compact_gap_x);
wxColour swatch_color = parse_mixed_color(mf.display_color);
auto *swatch = new wxPanel(header_panel, wxID_ANY, wxDefaultPosition, wxSize(FromDIP(12), FromDIP(12)));
swatch->SetBackgroundColour(swatch_color);
@@ -4633,11 +4760,12 @@ void Sidebar::update_mixed_filament_panel(bool sync_manager)
editor_host->Hide();
row_sizer->Add(editor_host, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, compact_row_pad);
auto set_row_hover = [row, header_panel, editor_host, mixed_row_bg, mixed_row_hover_bg](bool hovered) {
auto set_row_hover = [row, header_panel, editor_host, drag_handle, mixed_summary_fg, mixed_row_bg, mixed_row_hover_bg](bool hovered) {
const wxColour bg = hovered ? mixed_row_hover_bg : mixed_row_bg;
if (row) row->SetBackgroundColour(bg);
if (header_panel) header_panel->SetBackgroundColour(bg);
if (editor_host) editor_host->SetBackgroundColour(bg);
if (drag_handle) drag_handle->set_colors(mixed_summary_fg, bg);
if (row) row->Refresh();
if (header_panel) header_panel->Refresh();
if (editor_host) editor_host->Refresh();
@@ -4730,6 +4858,93 @@ void Sidebar::update_mixed_filament_panel(bool sync_manager)
});
};
auto release_drag_capture = [this]() {
p->m_mixed_filament_drag_active = false;
p->m_mixed_filament_drag_source_mixed_id = size_t(-1);
};
auto bind_drag_target = [this,
mixed_id,
&mixed,
drop_insert_position,
current_mixed_filament_ui_order,
release_drag_capture](wxWindow *target) {
if (!target)
return;
target->Bind(wxEVT_LEFT_DOWN, [this, mixed_id, target](wxMouseEvent &evt) {
if (!target)
return;
p->m_mixed_filament_drag_active = true;
p->m_mixed_filament_drag_source_mixed_id = mixed_id;
if (!target->HasCapture())
target->CaptureMouse();
evt.StopPropagation();
});
target->Bind(wxEVT_MOTION, [this](wxMouseEvent &evt) {
if (p->m_mixed_filament_drag_active)
evt.StopPropagation();
});
target->Bind(wxEVT_LEFT_UP, [this, &mixed, target, drop_insert_position, current_mixed_filament_ui_order](wxMouseEvent &evt) {
if (target && target->HasCapture())
target->ReleaseMouse();
if (!p->m_mixed_filament_drag_active || p->m_mixed_filament_drag_source_mixed_id >= mixed.size()) {
p->m_mixed_filament_drag_active = false;
p->m_mixed_filament_drag_source_mixed_id = size_t(-1);
evt.StopPropagation();
return;
}
const size_t source_mixed_id = p->m_mixed_filament_drag_source_mixed_id;
p->m_mixed_filament_drag_active = false;
p->m_mixed_filament_drag_source_mixed_id = size_t(-1);
std::vector<size_t> current_mixed_ids;
current_mixed_ids.reserve(p->m_mixed_filament_row_bindings.size());
for (const auto &binding : p->m_mixed_filament_row_bindings) {
if (binding.mixed_id < mixed.size() && !mixed[binding.mixed_id].deleted)
current_mixed_ids.emplace_back(binding.mixed_id);
}
const auto source_it = std::find(current_mixed_ids.begin(), current_mixed_ids.end(), source_mixed_id);
if (source_it == current_mixed_ids.end()) {
evt.StopPropagation();
return;
}
const size_t source_pos = size_t(std::distance(current_mixed_ids.begin(), source_it));
size_t insert_pos = drop_insert_position();
insert_pos = std::min(insert_pos, current_mixed_ids.size());
current_mixed_ids.erase(source_it);
if (insert_pos > source_pos)
--insert_pos;
insert_pos = std::min(insert_pos, current_mixed_ids.size());
current_mixed_ids.insert(current_mixed_ids.begin() + ptrdiff_t(insert_pos), source_mixed_id);
std::vector<uint64_t> reordered_stable_ids;
reordered_stable_ids.reserve(current_mixed_ids.size());
for (const size_t row_mixed_id : current_mixed_ids) {
if (row_mixed_id < mixed.size() && mixed[row_mixed_id].stable_id != 0)
reordered_stable_ids.emplace_back(mixed[row_mixed_id].stable_id);
}
if (reordered_stable_ids != current_mixed_filament_ui_order()) {
p->m_mixed_filament_ui_order = std::move(reordered_stable_ids);
update_mixed_filament_panel(false);
}
evt.StopPropagation();
});
target->Bind(wxEVT_MOUSE_CAPTURE_LOST, [release_drag_capture](wxMouseCaptureLostEvent &) {
release_drag_capture();
});
};
header_panel->SetToolTip(auto_row ?
_L("Click to edit automatic mixed filament settings (saved as custom).") :
_L("Click to expand/retract mixed filament settings"));
@@ -4743,6 +4958,8 @@ void Sidebar::update_mixed_filament_panel(bool sync_manager)
bind_hover_target(name_label);
bind_hover_target(summary_label);
bind_hover_target(swatch);
bind_hover_target(drag_handle);
bind_drag_target(drag_handle);
del_btn->Bind(wxEVT_LEFT_UP, [](wxMouseEvent &evt) {
evt.StopPropagation();
@@ -4774,6 +4991,42 @@ void Sidebar::update_mixed_filament_panel(bool sync_manager)
refresh_model_canvas_colors();
}
std::vector<unsigned int> Sidebar::get_ui_ordered_filament_ids() const
{
const size_t num_physical = static_cast<size_t>(std::max(wxGetApp().filaments_cnt(), 0));
std::vector<unsigned int> ordered_filament_ids;
ordered_filament_ids.reserve(num_physical);
for (size_t idx = 0; idx < num_physical; ++idx)
ordered_filament_ids.emplace_back(unsigned(idx + 1));
if (wxGetApp().preset_bundle == nullptr)
return ordered_filament_ids;
const auto &mixed = wxGetApp().preset_bundle->mixed_filaments.mixed_filaments();
if (mixed.empty())
return ordered_filament_ids;
const std::vector<size_t> ordered_mixed_indices = build_mixed_filament_ui_indices(mixed, p->m_mixed_filament_ui_order);
std::vector<unsigned int> actual_filament_id_by_mixed_idx(mixed.size(), 0);
unsigned int next_filament_id = unsigned(num_physical + 1);
for (size_t mixed_idx = 0; mixed_idx < mixed.size(); ++mixed_idx) {
if (!mixed[mixed_idx].enabled || mixed[mixed_idx].deleted)
continue;
actual_filament_id_by_mixed_idx[mixed_idx] = next_filament_id++;
}
ordered_filament_ids.reserve(size_t(next_filament_id - 1));
for (const size_t mixed_idx : ordered_mixed_indices) {
if (mixed_idx >= actual_filament_id_by_mixed_idx.size())
continue;
const unsigned int actual_filament_id = actual_filament_id_by_mixed_idx[mixed_idx];
if (actual_filament_id != 0)
ordered_filament_ids.emplace_back(actual_filament_id);
}
return ordered_filament_ids;
}
void Sidebar::add_filament() {
if (p->combos_filament.size() >= MAXIMUM_EXTRUDER_NUMBER) return;
wxColour new_col = Plater::get_next_color_for_filament();
+1
View File
@@ -157,6 +157,7 @@ public:
void on_filaments_delete(size_t filament_id);
void update_mixed_filament_panel(bool sync_manager = true);
std::vector<unsigned int> get_ui_ordered_filament_ids() const;
// BBS
void on_bed_type_change(BedType bed_type);
void load_ams_list(std::string const & device, MachineObject* obj);