Copy/paste works more intuitively in macos color dialog. Make sure crash backup updates when color data is changed
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
#include "slic3r/GUI/MainFrame.hpp"
|
||||
#include "slic3r/GUI/Tab.hpp"
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
#include "libslic3r/Format/bbs_3mf.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/TextureMapping.hpp"
|
||||
#include "libslic3r/ColorSolver.hpp"
|
||||
@@ -70,6 +71,47 @@ constexpr float SlopeAutoPaintMaxAngleDeg = 180.f;
|
||||
constexpr float ProjectionTextRasterBaseFontSize = 200.f;
|
||||
constexpr int ProjectionTextRasterMaxDimension = 2048;
|
||||
constexpr int ProjectionTextRasterMinFontSize = 18;
|
||||
|
||||
static bool queue_color_data_crash_backup(ModelObject *object)
|
||||
{
|
||||
if (object == nullptr ||
|
||||
object->get_model() == nullptr ||
|
||||
!object->get_model()->is_need_backup() ||
|
||||
object->volumes.empty() ||
|
||||
object->instances.empty())
|
||||
return false;
|
||||
|
||||
Slic3r::save_object_mesh(*object);
|
||||
return true;
|
||||
}
|
||||
|
||||
static ModelObject *find_model_object_by_id(const ObjectID &object_id)
|
||||
{
|
||||
for (ModelObject *object : wxGetApp().model().objects)
|
||||
if (object != nullptr && object->id() == object_id)
|
||||
return object;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void remember_color_data_crash_backup_object(std::vector<ObjectID> &object_ids, const ModelObject *object)
|
||||
{
|
||||
if (object == nullptr)
|
||||
return;
|
||||
|
||||
const ObjectID object_id = object->id();
|
||||
if (std::find(object_ids.begin(), object_ids.end(), object_id) == object_ids.end())
|
||||
object_ids.emplace_back(object_id);
|
||||
}
|
||||
|
||||
static void queue_color_data_crash_backups(std::vector<ObjectID> &object_ids)
|
||||
{
|
||||
bool queued = false;
|
||||
for (const ObjectID &object_id : object_ids)
|
||||
queued |= queue_color_data_crash_backup(find_model_object_by_id(object_id));
|
||||
object_ids.clear();
|
||||
if (queued)
|
||||
Slic3r::backup_soon();
|
||||
}
|
||||
}
|
||||
|
||||
struct ManagedRegionColorSource
|
||||
@@ -8226,6 +8268,8 @@ public:
|
||||
m_background_clear->Bind(wxEVT_BUTTON, [this](wxCommandEvent &) { clear_background_color(); });
|
||||
}
|
||||
|
||||
bool changed() const { return m_changed; }
|
||||
|
||||
private:
|
||||
struct Row
|
||||
{
|
||||
@@ -8578,6 +8622,7 @@ private:
|
||||
|
||||
void refresh_object_after_change()
|
||||
{
|
||||
m_changed = true;
|
||||
refresh_managed_color_data_object(m_canvas, m_object);
|
||||
notify_object_changed();
|
||||
m_canvas.set_as_dirty();
|
||||
@@ -8620,6 +8665,7 @@ private:
|
||||
std::function<void()> m_on_object_changed;
|
||||
wxPanel *m_background_picker = nullptr;
|
||||
wxButton *m_background_clear = nullptr;
|
||||
bool m_changed = false;
|
||||
std::vector<Row> m_rows;
|
||||
std::vector<wxWindow *> m_raw_image_texture_info_windows;
|
||||
wxStaticText *m_raw_image_texture_status = nullptr;
|
||||
@@ -8634,6 +8680,8 @@ void open_color_data_management_dialog(wxWindow *parent, GLCanvas3D &canvas, Mod
|
||||
|
||||
ColorDataManagementDialog dialog(parent, canvas, object, std::move(on_object_changed));
|
||||
dialog.ShowModal();
|
||||
if (dialog.changed() && queue_color_data_crash_backup(object))
|
||||
Slic3r::backup_soon();
|
||||
}
|
||||
|
||||
void GLGizmoMmuSegmentation::init_extruders_data(const std::vector<ColorRGBA> &extruder_colors)
|
||||
@@ -10807,6 +10855,8 @@ void GLGizmoMmuSegmentation::convert_selected_object_vertex_colors_to_texture_ma
|
||||
wxGetApp().plater()->get_partplate_list().notify_instance_update(object_idx, 0);
|
||||
}
|
||||
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||
if (queue_color_data_crash_backup(object))
|
||||
Slic3r::backup_soon();
|
||||
}
|
||||
|
||||
void GLGizmoMmuSegmentation::convert_selected_object_image_texture_to_texture_mapping_colors()
|
||||
@@ -10878,6 +10928,8 @@ void GLGizmoMmuSegmentation::convert_selected_object_image_texture_to_texture_ma
|
||||
wxGetApp().plater()->get_partplate_list().notify_instance_update(object_idx, 0);
|
||||
}
|
||||
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||
if (queue_color_data_crash_backup(object))
|
||||
Slic3r::backup_soon();
|
||||
}
|
||||
|
||||
void GLGizmoMmuSegmentation::convert_selected_regions_to_vertex_colors()
|
||||
@@ -10958,6 +11010,8 @@ void GLGizmoMmuSegmentation::finish_selected_regions_color_data_conversion(Model
|
||||
wxGetApp().plater()->get_partplate_list().notify_instance_update(object_idx, 0);
|
||||
}
|
||||
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||
if (queue_color_data_crash_backup(&object))
|
||||
Slic3r::backup_soon();
|
||||
m_parent.render();
|
||||
}
|
||||
|
||||
@@ -11119,6 +11173,14 @@ void GLGizmoTrueColorPainting::on_shutdown()
|
||||
m_parent.toggle_model_objects_visibility(true);
|
||||
}
|
||||
|
||||
void GLGizmoTrueColorPainting::on_set_state()
|
||||
{
|
||||
GLGizmoPainterBase::on_set_state();
|
||||
|
||||
if (get_state() == Off)
|
||||
backup_changed_rgb_data_objects();
|
||||
}
|
||||
|
||||
PainterGizmoType GLGizmoTrueColorPainting::get_painter_type() const
|
||||
{
|
||||
return PainterGizmoType::TRUE_COLOR;
|
||||
@@ -11845,6 +11907,7 @@ void GLGizmoTrueColorPainting::convert_selected_object_image_texture_to_rgb_data
|
||||
|
||||
void GLGizmoTrueColorPainting::refresh_selected_object_after_rgb_change(ModelObject *object)
|
||||
{
|
||||
remember_changed_rgb_data_object(object);
|
||||
update_selected_object_color_state();
|
||||
init_model_triangle_selectors();
|
||||
m_parent.update_volumes_colors_by_extruder();
|
||||
@@ -11859,6 +11922,16 @@ void GLGizmoTrueColorPainting::refresh_selected_object_after_rgb_change(ModelObj
|
||||
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||
}
|
||||
|
||||
void GLGizmoTrueColorPainting::remember_changed_rgb_data_object(ModelObject *object)
|
||||
{
|
||||
remember_color_data_crash_backup_object(m_changed_rgb_data_object_ids, object);
|
||||
}
|
||||
|
||||
void GLGizmoTrueColorPainting::backup_changed_rgb_data_objects()
|
||||
{
|
||||
queue_color_data_crash_backups(m_changed_rgb_data_object_ids);
|
||||
}
|
||||
|
||||
bool GLGizmoTrueColorPainting::pick_color_from_model(const Vec2d &mouse_position)
|
||||
{
|
||||
ColorRGBA color;
|
||||
@@ -12639,6 +12712,7 @@ void GLGizmoTrueColorPainting::refresh_selected_object_after_background_color_ch
|
||||
if (object == nullptr)
|
||||
return;
|
||||
|
||||
remember_changed_rgb_data_object(object);
|
||||
cancel_rgb_data_preview_conversion();
|
||||
m_preview_rgb_data_volume_ids.clear();
|
||||
m_preview_rgb_data_by_volume.clear();
|
||||
@@ -12952,6 +13026,7 @@ void GLGizmoImageProjection::on_set_state()
|
||||
} else if (get_state() == Off) {
|
||||
m_parent.enable_picking(true);
|
||||
m_parent.toggle_model_objects_visibility(true);
|
||||
backup_projected_objects();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13762,6 +13837,7 @@ bool GLGizmoImageProjection::project_image_to_selected_object()
|
||||
}
|
||||
|
||||
refresh_projected_object(object);
|
||||
remember_projected_object(object);
|
||||
m_projection_mode_initialized = true;
|
||||
m_projection_mode_object_id = object->id();
|
||||
if (converting_raw_to_rgba_image && !selected_object_has_raw_atlas_texture_data())
|
||||
@@ -14442,6 +14518,16 @@ void GLGizmoImageProjection::refresh_projected_object(ModelObject *object)
|
||||
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||
}
|
||||
|
||||
void GLGizmoImageProjection::remember_projected_object(ModelObject *object)
|
||||
{
|
||||
remember_color_data_crash_backup_object(m_projected_object_ids, object);
|
||||
}
|
||||
|
||||
void GLGizmoImageProjection::backup_projected_objects()
|
||||
{
|
||||
queue_color_data_crash_backups(m_projected_object_ids);
|
||||
}
|
||||
|
||||
void GLMmSegmentationGizmo3DScene::release_geometry() {
|
||||
if (this->vertices_VBO_id) {
|
||||
glsafe(::glDeleteBuffers(1, &this->vertices_VBO_id));
|
||||
|
||||
@@ -309,6 +309,7 @@ private:
|
||||
void update_from_model_object(bool first_update = false) override;
|
||||
void on_opening() override;
|
||||
void on_shutdown() override;
|
||||
void on_set_state() override;
|
||||
PainterGizmoType get_painter_type() const override;
|
||||
|
||||
void init_model_triangle_selectors();
|
||||
@@ -322,6 +323,8 @@ private:
|
||||
void convert_selected_object_vertex_colors_to_rgb_data();
|
||||
void convert_selected_object_image_texture_to_rgb_data();
|
||||
void refresh_selected_object_after_rgb_change(ModelObject *object);
|
||||
void remember_changed_rgb_data_object(ModelObject *object);
|
||||
void backup_changed_rgb_data_objects();
|
||||
void update_triangle_selectors_color();
|
||||
void update_rgb_data_preview_conversion();
|
||||
void start_rgb_data_preview_conversion(ModelObject &object);
|
||||
@@ -391,6 +394,7 @@ private:
|
||||
bool m_color_picker_active = false;
|
||||
bool m_brush_stroke_active = false;
|
||||
ObjectID m_selected_color_state_object_id;
|
||||
std::vector<ObjectID> m_changed_rgb_data_object_ids;
|
||||
std::vector<std::vector<Vec3f>> m_brush_stroke_points_by_volume;
|
||||
std::vector<ObjectID> m_preview_rgb_data_volume_ids;
|
||||
std::vector<std::unique_ptr<ColorFacetsAnnotation>> m_preview_rgb_data_by_volume;
|
||||
@@ -477,6 +481,8 @@ private:
|
||||
bool project_to_image_texture(ModelObject *object);
|
||||
bool project_to_rgb_data(ModelObject *object);
|
||||
void refresh_projected_object(ModelObject *object);
|
||||
void remember_projected_object(ModelObject *object);
|
||||
void backup_projected_objects();
|
||||
|
||||
ProjectionMode m_projection_mode = ProjectionMode::RGBData;
|
||||
bool m_projection_mode_initialized = false;
|
||||
@@ -512,6 +518,7 @@ private:
|
||||
bool m_apply_transparency_as_background = false;
|
||||
bool m_pass_through_model = false;
|
||||
bool m_convert_existing_colors_to_raw_offsets = true;
|
||||
std::vector<ObjectID> m_projected_object_ids;
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
@@ -2888,6 +2888,9 @@ void MainFrame::init_menubar_as_editor()
|
||||
// BBS Copy
|
||||
append_menu_item(editMenu, wxID_ANY, _L("Copy") + sep + ctrl_t + "C",
|
||||
_L("Copy selection to clipboard"), [this, handle_key_event](wxCommandEvent&) {
|
||||
if (mac_copy_to_text_control()) {
|
||||
return;
|
||||
}
|
||||
wxKeyEvent e;
|
||||
e.SetEventType(wxEVT_KEY_DOWN);
|
||||
e.SetControlDown(true);
|
||||
@@ -2896,7 +2899,7 @@ void MainFrame::init_menubar_as_editor()
|
||||
return;
|
||||
}
|
||||
m_plater->copy_selection_to_clipboard(); },
|
||||
"", nullptr, [this](){return m_plater->can_copy_to_clipboard(); }, this);
|
||||
"", nullptr, [this](){return mac_can_copy_to_text_control() || m_plater->can_copy_to_clipboard(); }, this);
|
||||
// BBS Paste
|
||||
append_menu_item(editMenu, wxID_ANY, _L("Paste") + sep + ctrl_t + "V",
|
||||
_L("Paste clipboard"), [this, handle_key_event](wxCommandEvent&) {
|
||||
|
||||
@@ -9,7 +9,9 @@ namespace GUI {
|
||||
#if __APPLE__
|
||||
extern bool mac_dark_mode();
|
||||
extern double mac_max_scaling_factor();
|
||||
extern bool mac_can_copy_to_text_control();
|
||||
extern bool mac_can_paste_to_text_control();
|
||||
extern bool mac_copy_to_text_control();
|
||||
extern bool mac_paste_to_text_control();
|
||||
extern void mac_install_text_paste_shortcut();
|
||||
extern void set_miniaturizable(void * window);
|
||||
|
||||
@@ -42,36 +42,95 @@ double mac_max_scaling_factor()
|
||||
return scaling;
|
||||
}
|
||||
|
||||
static id mac_text_paste_target()
|
||||
static id mac_text_target_for_action(SEL action)
|
||||
{
|
||||
id target = [NSApp targetForAction:@selector(paste:) to:nil from:nil];
|
||||
id target = [NSApp targetForAction:action to:nil from:nil];
|
||||
if (target != nil && [target isKindOfClass:[NSText class]])
|
||||
return target;
|
||||
return nil;
|
||||
|
||||
id responder = [[NSApp keyWindow] firstResponder];
|
||||
return [responder isKindOfClass:[NSText class]] ? responder : nil;
|
||||
}
|
||||
|
||||
static id mac_text_paste_target()
|
||||
{
|
||||
return mac_text_target_for_action(@selector(paste:));
|
||||
}
|
||||
|
||||
static id mac_text_copy_target()
|
||||
{
|
||||
return mac_text_target_for_action(@selector(copy:));
|
||||
}
|
||||
|
||||
static bool mac_text_target_has_selection(id target)
|
||||
{
|
||||
return [target respondsToSelector:@selector(selectedRange)] && [target selectedRange].length > 0;
|
||||
}
|
||||
|
||||
static bool mac_string_is_six_hex(NSString *string)
|
||||
{
|
||||
if ([string length] != 6)
|
||||
return false;
|
||||
|
||||
NSCharacterSet *non_hex = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789abcdefABCDEF"] invertedSet];
|
||||
return [string rangeOfCharacterFromSet:non_hex].location == NSNotFound;
|
||||
}
|
||||
|
||||
static bool mac_string_is_hex_field_value(NSString *string)
|
||||
{
|
||||
NSUInteger length = [string length];
|
||||
if (length < 6)
|
||||
return false;
|
||||
|
||||
NSCharacterSet *non_hex = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789abcdefABCDEF"] invertedSet];
|
||||
return [string rangeOfCharacterFromSet:non_hex].location == NSNotFound;
|
||||
}
|
||||
|
||||
static bool mac_key_window_is_color_panel()
|
||||
{
|
||||
return [[NSApp keyWindow] isKindOfClass:[NSColorPanel class]];
|
||||
}
|
||||
|
||||
static NSString *mac_color_panel_hex_string()
|
||||
{
|
||||
NSWindow *window = [NSApp keyWindow];
|
||||
if (![window isKindOfClass:[NSColorPanel class]])
|
||||
if (!mac_key_window_is_color_panel())
|
||||
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)
|
||||
NSString *value = [string hasPrefix:@"#"] ? [string substringFromIndex:1] : string;
|
||||
if (!mac_string_is_six_hex(value))
|
||||
return nil;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static NSString *mac_color_panel_hex_target_value(id target)
|
||||
{
|
||||
if (!mac_key_window_is_color_panel() || ![target respondsToSelector:@selector(string)])
|
||||
return nil;
|
||||
|
||||
NSString *string = [target string];
|
||||
return mac_string_is_hex_field_value(string) ? string : nil;
|
||||
}
|
||||
|
||||
static void mac_select_hex_text_target(id target)
|
||||
{
|
||||
if (![target respondsToSelector:@selector(string)] || ![target respondsToSelector:@selector(setSelectedRange:)])
|
||||
return;
|
||||
|
||||
NSString *string = mac_color_panel_hex_target_value(target);
|
||||
if (string != nil)
|
||||
[target setSelectedRange:NSMakeRange(0, [string length])];
|
||||
}
|
||||
|
||||
bool mac_can_copy_to_text_control()
|
||||
{
|
||||
id target = mac_text_copy_target();
|
||||
return target != nil && (mac_text_target_has_selection(target) || mac_color_panel_hex_target_value(target) != nil);
|
||||
}
|
||||
|
||||
bool mac_can_paste_to_text_control()
|
||||
{
|
||||
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
|
||||
@@ -80,6 +139,25 @@ bool mac_can_paste_to_text_control()
|
||||
return mac_text_paste_target() != nil;
|
||||
}
|
||||
|
||||
bool mac_copy_to_text_control()
|
||||
{
|
||||
id target = mac_text_copy_target();
|
||||
if (target == nil)
|
||||
return false;
|
||||
|
||||
if (!mac_text_target_has_selection(target)) {
|
||||
NSString *color_panel_hex = mac_color_panel_hex_target_value(target);
|
||||
if (color_panel_hex == nil)
|
||||
return false;
|
||||
|
||||
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
|
||||
[pasteboard clearContents];
|
||||
return [pasteboard setString:color_panel_hex forType:NSPasteboardTypeString] == YES;
|
||||
}
|
||||
|
||||
return [NSApp sendAction:@selector(copy:) to:nil from:nil] == YES;
|
||||
}
|
||||
|
||||
bool mac_paste_to_text_control()
|
||||
{
|
||||
id target = mac_text_paste_target();
|
||||
@@ -88,6 +166,7 @@ bool mac_paste_to_text_control()
|
||||
|
||||
NSString *color_panel_hex = mac_color_panel_hex_string();
|
||||
if (color_panel_hex != nil && [target respondsToSelector:@selector(insertText:)]) {
|
||||
mac_select_hex_text_target(target);
|
||||
[target insertText:color_panel_hex];
|
||||
return true;
|
||||
}
|
||||
@@ -106,8 +185,13 @@ void mac_install_text_paste_shortcut()
|
||||
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;
|
||||
if ([characters length] == 1) {
|
||||
NSString *key = [characters lowercaseString];
|
||||
if ([key isEqualToString:@"c"] && mac_copy_to_text_control())
|
||||
return nil;
|
||||
if ([key isEqualToString:@"v"] && mac_paste_to_text_control())
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
return event;
|
||||
}];
|
||||
|
||||
Reference in New Issue
Block a user