- Allow pasting hex codes in color picker on macos
- Prevent texture mapping zone panel resetting to top
- Fix solid rectangle showing in projection panel while text is being rendered
- Allow textures to be restored from crash backups
This commit is contained in:
sentientstardust
2026-05-19 20:24:18 +01:00
parent 49424433df
commit ade01c68d3
7 changed files with 179 additions and 20 deletions

View File

@@ -1950,6 +1950,7 @@ static void append_triangle_material_data(std::vector<uint8_t> &uv_valid,
void _generate_current_object_list(std::vector<Component> &sub_objects, Id object_id, IdToCurrentObjectMap& current_objects);
bool _generate_volumes_new(ModelObject& object, const std::vector<Component> &sub_objects, const ObjectMetadata::VolumeMetadataList& volumes, ConfigSubstitutionContext& config_substitutions);
bool _try_extract_imported_obj_texture_from_archive(mz_zip_archive &archive, const std::string &image_file, std::vector<uint8_t> &image_payload);
void _restore_imported_obj_textures_from_archive(mz_zip_archive &archive);
void _restore_prime_tower_texture_from_archive(mz_zip_archive &archive, const DynamicPrintConfig &config, Model &model);
//bool _generate_volumes(ModelObject& object, const Geometry& geometry, const ObjectMetadata::VolumeMetadataList& volumes, ConfigSubstitutionContext& config_substitutions);
@@ -5931,6 +5932,53 @@ static void append_triangle_material_data(std::vector<uint8_t> &uv_valid,
return true;
}
bool _BBS_3MF_Importer::_try_extract_imported_obj_texture_from_archive(mz_zip_archive &archive, const std::string &image_file, std::vector<uint8_t> &image_payload)
{
image_payload.clear();
if (try_extract_file_from_archive(archive, image_file, image_payload))
return true;
if (!m_load_restore)
return false;
for (const std::string &sub_model_path : m_sub_model_paths) {
std::string path = sub_model_path;
std::replace(path.begin(), path.end(), '\\', '/');
while (!path.empty() && path.front() == '/')
path.erase(path.begin());
if (path.empty())
continue;
const boost::filesystem::path object_archive_path = boost::filesystem::path(m_backup_path) / path;
if (!boost::filesystem::exists(object_archive_path))
continue;
mz_zip_archive object_archive;
mz_zip_zero_struct(&object_archive);
if (!open_zip_reader(&object_archive, object_archive_path.string()))
continue;
const bool found = try_extract_file_from_archive(object_archive, image_file, image_payload);
close_zip_reader(&object_archive);
if (found)
return true;
}
if (!m_origin_file.empty() && boost::filesystem::exists(m_origin_file)) {
mz_zip_archive origin_archive;
mz_zip_zero_struct(&origin_archive);
if (open_zip_reader(&origin_archive, m_origin_file)) {
const bool found = try_extract_file_from_archive(origin_archive, image_file, image_payload);
close_zip_reader(&origin_archive);
if (found)
return true;
}
}
image_payload.clear();
return false;
}
void _BBS_3MF_Importer::_restore_imported_obj_textures_from_archive(mz_zip_archive &archive)
{
if (m_model == nullptr)
@@ -5946,7 +5994,7 @@ static void append_triangle_material_data(std::vector<uint8_t> &uv_valid,
continue;
std::vector<uint8_t> image_payload;
if (!try_extract_file_from_archive(archive, source.image_file, image_payload)) {
if (!_try_extract_imported_obj_texture_from_archive(archive, source.image_file, image_payload)) {
BOOST_LOG_TRIVIAL(warning) << "3MF texture2d payload missing for image='" << source.image_file << "'";
continue;
}

View File

@@ -114,7 +114,7 @@ struct TextureMappingZone
static constexpr bool DefaultSeamHiding = false;
static constexpr bool DefaultNonlinearOffsetAdjustment = false;
static constexpr int DefaultModulationMode = int(ModulationLineWidth);
static constexpr bool DefaultRecolorSmallPerimeterLoops = true;
static constexpr bool DefaultRecolorSmallPerimeterLoops = false;
static constexpr bool DefaultRecolorTopVisiblePerimeterSections = false;
static constexpr int DefaultTopVisiblePerimeterRecolorAggressiveness = int(TopVisibleRecolorAggressive);
static constexpr bool DefaultCompactOffsetMode = true;

View File

@@ -13498,19 +13498,6 @@ void GLGizmoImageProjection::on_render_input_window(float x, float y, float bott
ensure_text_projection_image();
update_default_projection_mode();
if (m_show_overlay && ensure_overlay_texture()) {
const OverlayRect rect = overlay_rect();
if (rect.width > 0.f && rect.height > 0.f) {
ImGui::GetBackgroundDrawList()->AddImage((void *)(intptr_t)m_overlay_texture.get_id(),
ImVec2(rect.left, rect.top),
ImVec2(rect.left + rect.width, rect.top + rect.height),
ImVec2(0.f, 0.f),
ImVec2(1.f, 1.f),
ImGui::GetColorU32(
ImVec4(1.f, 1.f, 1.f, 0.72f * std::clamp(m_projection_opacity, 0.f, 1.f))));
}
}
const float approx_height = m_imgui->scaled(12.0f);
y = std::min(y, bottom_limit - approx_height);
GizmoImguiSetNextWIndowPos(x, y, ImGuiCond_Always);
@@ -13649,6 +13636,19 @@ void GLGizmoImageProjection::on_render_input_window(float x, float y, float bott
GizmoImguiEnd();
ImGuiWrapper::pop_toolbar_style();
if (m_show_overlay && ensure_overlay_texture()) {
const OverlayRect rect = overlay_rect();
if (rect.width > 0.f && rect.height > 0.f) {
ImGui::GetBackgroundDrawList()->AddImage((void *)(intptr_t)m_overlay_texture.get_id(),
ImVec2(rect.left, rect.top),
ImVec2(rect.left + rect.width, rect.top + rect.height),
ImVec2(0.f, 0.f),
ImVec2(1.f, 1.f),
ImGui::GetColorU32(
ImVec4(1.f, 1.f, 1.f, 0.72f * std::clamp(m_projection_opacity, 0.f, 1.f))));
}
}
}
bool GLGizmoImageProjection::project_image_to_selected_object()

View File

@@ -300,6 +300,7 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_
{
#ifdef __WXOSX__
set_miniaturizable(GetHandle());
mac_install_text_paste_shortcut();
#endif
#ifdef __WXGTK__
@@ -2899,6 +2900,9 @@ void MainFrame::init_menubar_as_editor()
// BBS Paste
append_menu_item(editMenu, wxID_ANY, _L("Paste") + sep + ctrl_t + "V",
_L("Paste clipboard"), [this, handle_key_event](wxCommandEvent&) {
if (mac_paste_to_text_control()) {
return;
}
wxKeyEvent e;
e.SetEventType(wxEVT_KEY_DOWN);
e.SetControlDown(true);
@@ -2907,7 +2911,7 @@ void MainFrame::init_menubar_as_editor()
return;
}
m_plater->paste_from_clipboard(); },
"", nullptr, [this](){return m_plater->can_paste_from_clipboard(); }, this);
"", nullptr, [this](){return mac_can_paste_to_text_control() || m_plater->can_paste_from_clipboard(); }, this);
#if 0
// BBS Delete selected
append_menu_item(editMenu, wxID_ANY, _L("Delete selected") + "\t" + _L("Backspace"),
@@ -4346,4 +4350,3 @@ void SettingsDialog::on_dpi_changed(const wxRect& suggested_rect)
} // GUI
} // Slic3r

View File

@@ -719,6 +719,21 @@ static wxSize from_dip_for_parent(wxWindow *parent, const wxSize &size)
return wxWindow::FromDIP(size, parent);
}
class TextureMappingScrolledWindow : public wxScrolledWindow
{
public:
TextureMappingScrolledWindow(wxWindow *parent,
wxWindowID id = wxID_ANY,
const wxPoint &pos = wxDefaultPosition,
const wxSize &size = wxDefaultSize,
long style = wxVSCROLL)
: wxScrolledWindow(parent, id, pos, size, style)
{
}
bool ShouldScrollToChildOnFocus(wxWindow *child) override { return false; }
};
class TextureMappingPatternPreview : public wxPanel
{
public:
@@ -1353,7 +1368,7 @@ public:
m_recolor_top_visible_perimeter_sections_checkbox->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &) { update_modulation_mode_options_visibility(false); });
auto *top_visible_recolor_row = new wxBoxSizer(wxHORIZONTAL);
m_top_visible_perimeter_recolor_aggressiveness_label =
new wxStaticText(print_settings_page, wxID_ANY, _L("Top-visible recolor sensitivity:"));
new wxStaticText(print_settings_page, wxID_ANY, _L("Top layer line recolor sensitivity:"));
top_visible_recolor_row->Add(m_top_visible_perimeter_recolor_aggressiveness_label, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap);
wxArrayString top_visible_recolor_choices;
top_visible_recolor_choices.Add(_L("Conservative"));
@@ -4090,7 +4105,7 @@ Sidebar::Sidebar(Plater *parent)
spliter_texture_2->SetLineColour("#CECECE");
scrolled_sizer->Add(spliter_texture_2, 0, wxEXPAND);
p->m_panel_texture_mapping_content = new wxScrolledWindow(p->scrolled, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
p->m_panel_texture_mapping_content = new TextureMappingScrolledWindow(p->scrolled, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
p->m_panel_texture_mapping_content->SetScrollRate(0, 5);
p->m_panel_texture_mapping_content->ShowScrollbars(wxSHOW_SB_NEVER, wxSHOW_SB_DEFAULT);
p->m_panel_texture_mapping_content->SetBackgroundColour(wxGetApp().dark_mode() ? wxColour(45, 45, 49) : wxColour(255, 255, 255));
@@ -5659,6 +5674,19 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
wxWindowUpdateLocker no_updates_sidebar(this);
wxWindowUpdateLocker no_updates_panel(p->m_panel_texture_mapping_content);
int texture_mapping_scroll_x = 0;
int texture_mapping_scroll_y = 0;
p->m_panel_texture_mapping_content->GetViewStart(&texture_mapping_scroll_x, &texture_mapping_scroll_y);
auto scroll_texture_mapping_content_to = [this](int scroll_x, int scroll_y) {
if (p->m_panel_texture_mapping_content != nullptr)
p->m_panel_texture_mapping_content->Scroll(scroll_x, scroll_y);
};
auto restore_texture_mapping_scroll = [scroll_texture_mapping_content_to, texture_mapping_scroll_x, texture_mapping_scroll_y]() {
scroll_texture_mapping_content_to(texture_mapping_scroll_x, texture_mapping_scroll_y);
};
PresetBundle *bundle = wxGetApp().preset_bundle;
if (bundle == nullptr)
return;
@@ -5735,9 +5763,12 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
return;
content_sizer->Clear(true);
content_sizer->AddSpacer(FromDIP(SidebarProps::ContentMargin()));
auto update_texture_mapping_area_height = [this]() {
auto update_texture_mapping_area_height = [this, scroll_texture_mapping_content_to]() {
if (p->m_panel_texture_mapping_content == nullptr || p->m_panel_texture_mapping_content->GetSizer() == nullptr)
return;
int scroll_x = 0;
int scroll_y = 0;
p->m_panel_texture_mapping_content->GetViewStart(&scroll_x, &scroll_y);
const int max_height = FromDIP(260);
p->m_panel_texture_mapping_content->SetMaxSize(wxSize(-1, max_height));
p->m_panel_texture_mapping_content->Layout();
@@ -5746,6 +5777,7 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
if (min_size.y > max_height)
min_size.y = max_height;
p->m_panel_texture_mapping_content->SetMinSize(wxSize(-1, std::max(FromDIP(1), min_size.y)));
scroll_texture_mapping_content_to(scroll_x, scroll_y);
};
if (p->m_btn_add_texture_map != nullptr)
@@ -5839,6 +5871,7 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
update_texture_mapping_area_height();
m_scrolled_sizer->Layout();
Layout();
restore_texture_mapping_scroll();
return;
}
@@ -6395,6 +6428,7 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
update_texture_mapping_area_height();
m_scrolled_sizer->Layout();
Layout();
restore_texture_mapping_scroll();
}
std::vector<unsigned int> Sidebar::get_ui_ordered_filament_ids() const

View File

@@ -9,6 +9,9 @@ namespace GUI {
#if __APPLE__
extern bool mac_dark_mode();
extern double mac_max_scaling_factor();
extern bool mac_can_paste_to_text_control();
extern bool mac_paste_to_text_control();
extern void mac_install_text_paste_shortcut();
extern void set_miniaturizable(void * window);
void WKWebView_evaluateJavaScript(void * web, wxString const & script, void (*callback)(wxString const &));
void WKWebView_setTransparentBackground(void * web);

View File

@@ -41,6 +41,77 @@ double mac_max_scaling_factor()
}
return scaling;
}
static id mac_text_paste_target()
{
id target = [NSApp targetForAction:@selector(paste:) to:nil from:nil];
if (target != nil && [target isKindOfClass:[NSText class]])
return target;
return nil;
}
static NSString *mac_color_panel_hex_string()
{
NSWindow *window = [NSApp keyWindow];
if (![window isKindOfClass:[NSColorPanel class]])
return nil;
NSString *string = [[NSPasteboard generalPasteboard] stringForType:NSPasteboardTypeString];
string = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if (![string hasPrefix:@"#"])
return nil;
NSString *value = [string substringFromIndex:1];
if ([value length] != 6)
return nil;
NSCharacterSet *non_hex = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789abcdefABCDEF"] invertedSet];
if ([value rangeOfCharacterFromSet:non_hex].location != NSNotFound)
return nil;
return value;
}
bool mac_can_paste_to_text_control()
{
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
if ([pasteboard stringForType:NSPasteboardTypeString] == nil)
return false;
return mac_text_paste_target() != nil;
}
bool mac_paste_to_text_control()
{
id target = mac_text_paste_target();
if (target == nil)
return false;
NSString *color_panel_hex = mac_color_panel_hex_string();
if (color_panel_hex != nil && [target respondsToSelector:@selector(insertText:)]) {
[target insertText:color_panel_hex];
return true;
}
return [NSApp sendAction:@selector(paste:) to:nil from:nil] == YES;
}
void mac_install_text_paste_shortcut()
{
static id monitor = nil;
if (monitor != nil)
return;
monitor = [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyDown handler:^NSEvent *(NSEvent *event) {
NSEventModifierFlags flags = [event modifierFlags];
if ((flags & NSEventModifierFlagCommand) != 0 &&
(flags & (NSEventModifierFlagShift | NSEventModifierFlagControl | NSEventModifierFlagOption)) == 0) {
NSString *characters = [event charactersIgnoringModifiers];
if ([characters length] == 1 && [[characters lowercaseString] isEqualToString:@"v"] && mac_paste_to_text_control())
return nil;
}
return event;
}];
}
void set_miniaturizable(void * window)
{