diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 06fb79a50..4974d66fc 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -45,6 +45,10 @@ add_library(libslic3r_gui STATIC ${LIBDIR}/slic3r/GUI/MainFrame.hpp ${LIBDIR}/slic3r/GUI/Plater.cpp ${LIBDIR}/slic3r/GUI/Plater.hpp + ${LIBDIR}/slic3r/GUI/GUI_ObjectList.cpp + ${LIBDIR}/slic3r/GUI/GUI_ObjectList.hpp + ${LIBDIR}/slic3r/GUI/GUI_ObjectManipulation.cpp + ${LIBDIR}/slic3r/GUI/GUI_ObjectManipulation.hpp ${LIBDIR}/slic3r/GUI/LambdaObjectDialog.cpp ${LIBDIR}/slic3r/GUI/LambdaObjectDialog.hpp ${LIBDIR}/slic3r/GUI/Tab.cpp diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 328d5af39..f65e380e5 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -11,6 +11,7 @@ #include "../../libslic3r/PrintConfig.hpp" #include "../../libslic3r/GCode/PreviewData.hpp" #include "GUI_App.hpp" +#include "GUI_ObjectManipulation.hpp" #include @@ -2982,7 +2983,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) #else m_on_gizmo_scale_uniformly_callback.call((double)m_gizmos.get_scale()); #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM - update_scale_values(); + wxGetApp().obj_manipul()->update_scale_values(); m_dirty = true; break; } @@ -2993,7 +2994,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) #else m_on_gizmo_rotate_callback.call((double)m_gizmos.get_angle_z()); #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM - update_rotation_values(); + wxGetApp().obj_manipul()->update_rotation_values(); m_dirty = true; break; } @@ -3181,7 +3182,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) v->set_offset(v->get_offset() + Vec3d(vector(0), vector(1), 0.0)); } - update_position_values(volume->get_offset()); + wxGetApp().obj_manipul()->update_position_values(volume->get_offset()); m_mouse.drag.start_position_3D = cur_pos; m_dirty = true; @@ -3222,7 +3223,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) { v->set_offset(v->get_offset() + offset); } - update_position_values(volume->get_offset()); + wxGetApp().obj_manipul()->update_position_values(volume->get_offset()); break; } case Gizmos::Scale: @@ -3234,7 +3235,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) { v->set_scaling_factor(scale); } - update_scale_values(scale); + wxGetApp().obj_manipul()->update_scale_values(scale); #else // Apply new temporary scale factor float scale_factor = m_gizmos.get_scale(); @@ -3255,7 +3256,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) { v->set_rotation(rotation); } - update_rotation_value(rotation); + wxGetApp().obj_manipul()->update_rotation_value(rotation); #else // Apply new temporary angle_z float angle_z = m_gizmos.get_angle_z(); @@ -3430,7 +3431,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) break; } m_gizmos.stop_dragging(); - update_settings_value(); + wxGetApp().obj_manipul()->update_values(); } m_mouse.drag.move_volume_idx = -1; @@ -5351,7 +5352,7 @@ void GLCanvas3D::_on_move(const std::vector& volume_idxs) model_object->instances[instance_idx]->offset = Vec2d(offset(0), offset(1)); #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM model_object->invalidate_bounding_box(); - update_position_values(); + wxGetApp().obj_manipul()->update_position_values(); object_moved = true; } } diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp index 2ec5028f5..34889b809 100644 --- a/src/slic3r/GUI/GUI.cpp +++ b/src/slic3r/GUI/GUI.cpp @@ -519,135 +519,6 @@ void set_model_events_from_perl(Model &model, // add_collapsible_panes(parent, sizer); } -void Sidebar::add_frequently_changed_parameters(wxWindow* parent, wxBoxSizer* sizer/*, wxFlexGridSizer* preset_sizer*/) -{ - DynamicPrintConfig* config = &wxGetApp().preset_bundle->prints.get_edited_preset().config; - std::shared_ptr optgroup = std::make_shared(parent, "", config); -// const wxArrayInt& ar = preset_sizer->GetColWidths(); -// m_label_width = ar.IsEmpty() ? 100 : ar.front()-4; - optgroup->label_width = 100;// m_label_width; - - auto m_optgroups = get_optgroups(); - - //Frequently changed parameters - optgroup->m_on_change = [config, m_optgroups](t_config_option_key opt_key, boost::any value){ - TabPrint* tab_print = nullptr; - for (size_t i = 0; i < wxGetApp().tab_panel()->GetPageCount(); ++i) { - Tab *tab = dynamic_cast(wxGetApp().tab_panel()->GetPage(i)); - if (!tab) - continue; - if (tab->name() == "print"){ - tab_print = static_cast(tab); - break; - } - } - if (tab_print == nullptr) - return; - - if (opt_key == "fill_density"){ - value = m_optgroups[ogFrequentlyChangingParameters]->get_config_value(*config, opt_key); - tab_print->set_value(opt_key, value); - tab_print->update(); - } - else{ - DynamicPrintConfig new_conf = *config; - if (opt_key == "brim"){ - double new_val; - double brim_width = config->opt_float("brim_width"); - if (boost::any_cast(value) == true) - { - new_val = 10;// m_brim_width == 0.0 ? 10 : -// m_brim_width < 0.0 ? m_brim_width * (-1) : -// m_brim_width; - } - else{ -// m_brim_width = brim_width * (-1); - new_val = 0; - } - new_conf.set_key_value("brim_width", new ConfigOptionFloat(new_val)); - } - else{ //(opt_key == "support") - const wxString& selection = boost::any_cast(value); - - auto support_material = selection == _("None") ? false : true; - new_conf.set_key_value("support_material", new ConfigOptionBool(support_material)); - - if (selection == _("Everywhere")) - new_conf.set_key_value("support_material_buildplate_only", new ConfigOptionBool(false)); - else if (selection == _("Support on build plate only")) - new_conf.set_key_value("support_material_buildplate_only", new ConfigOptionBool(true)); - } - tab_print->load_config(new_conf); - } - - tab_print->update_dirty(); - }; - - Option option = optgroup->get_option("fill_density"); - option.opt.sidetext = ""; - option.opt.full_width = true; - optgroup->append_single_option_line(option); - - ConfigOptionDef def; - - def.label = L("Support"); - def.type = coStrings; - def.gui_type = "select_open"; - def.tooltip = L("Select what kind of support do you need"); - def.enum_labels.push_back(L("None")); - def.enum_labels.push_back(L("Support on build plate only")); - def.enum_labels.push_back(L("Everywhere")); - std::string selection = !config->opt_bool("support_material") ? - "None" : - config->opt_bool("support_material_buildplate_only") ? - "Support on build plate only" : - "Everywhere"; - def.default_value = new ConfigOptionStrings { selection }; - option = Option(def, "support"); - option.opt.full_width = true; - optgroup->append_single_option_line(option); - - auto m_brim_width = config->opt_float("brim_width"); - def.label = L("Brim"); - def.type = coBool; - def.tooltip = L("This flag enables the brim that will be printed around each object on the first layer."); - def.gui_type = ""; - def.default_value = new ConfigOptionBool{ m_brim_width > 0.0 ? true : false }; - option = Option(def, "brim"); - optgroup->append_single_option_line(option); - - - Line line = { "", "" }; - line.widget = [config, this](wxWindow* parent){ - auto g_wiping_dialog_button = get_wiping_dialog_button(); - g_wiping_dialog_button = new wxButton(parent, wxID_ANY, _(L("Purging volumes")) + dots, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); - auto sizer = new wxBoxSizer(wxHORIZONTAL); - sizer->Add(g_wiping_dialog_button); - g_wiping_dialog_button->Bind(wxEVT_BUTTON, ([parent](wxCommandEvent& e) - { - auto &config = wxGetApp().preset_bundle->project_config; - const std::vector &init_matrix = (config.option("wiping_volumes_matrix"))->values; - const std::vector &init_extruders = (config.option("wiping_volumes_extruders"))->values; - - WipingDialog dlg(parent,cast(init_matrix),cast(init_extruders)); - - if (dlg.ShowModal() == wxID_OK) { - std::vector matrix = dlg.get_matrix(); - std::vector extruders = dlg.get_extruders(); - (config.option("wiping_volumes_matrix"))->values = std::vector(matrix.begin(),matrix.end()); - (config.option("wiping_volumes_extruders"))->values = std::vector(extruders.begin(),extruders.end()); - g_on_request_update_callback.call(); - } - })); - return sizer; - }; - optgroup->append_line(line); - - sizer->Add(optgroup->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT, 2); - - m_optgroups.push_back(optgroup);// ogFrequentlyChangingParameters -} - void show_buttons(bool show) { g_buttons[abReslice]->Show(show); diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 00071f01d..8fdef00cd 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1,4 +1,5 @@ #include "GUI_App.hpp" +#include "GUI_ObjectManipulation.hpp" #include #include @@ -647,7 +648,17 @@ void GUI_App::load_current_presets() } } -wxNotebook* GUI_App::tab_panel() const +Sidebar& GUI_App::sidebar() +{ + return mainframe->m_plater->sidebar(); +} + +ObjectManipulation* GUI_App::obj_manipul() +{ + return sidebar().obj_manipul(); +} + +wxNotebook* GUI_App::tab_panel() const { return mainframe->m_tabpanel; } diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index e084481dd..022fd0d37 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -123,6 +123,15 @@ public: // Tab* get_tab(const std::string& name); void load_current_presets(); + + Sidebar& sidebar(); + ObjectManipulation* obj_manipul(); +// ObjectList& get_obj_list(); + + // Functions for updating of the object manipulation values + void update_position_values(); + void update_position_values(const Vec3d& position); + AppConfig* app_config{ nullptr }; PresetBundle* preset_bundle{ nullptr }; PresetUpdater* preset_updater{ nullptr }; diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp new file mode 100644 index 000000000..f44c5be8e --- /dev/null +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -0,0 +1,188 @@ +#include "GUI_ObjectList.hpp" +#include "GUI_App.hpp" + +#include "OptionsGroup.hpp" +#include "PresetBundle.hpp" +#include "Tab.hpp" +#include "wxExtensions.hpp" + +// #include "Model.hpp" +// #include "LambdaObjectDialog.hpp" +// #include "../../libslic3r/Utils.hpp" +// +// #include +// #include +#include +// #include "Geometry.hpp" +#include "slic3r/Utils/FixModelByWin10.hpp" + +// +// #include +// #include "3DScene.hpp" + +namespace Slic3r +{ +namespace GUI +{ + +ObjectList::ObjectList(wxWindow* parent) : + m_parent(parent) +{ +// wxBoxSizer* sizer; + // create control + create_objects_ctrl(); + + // describe control behavior + m_objects_ctrl->Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [](wxEvent& event) { + object_ctrl_selection_changed(); +#ifndef __WXMSW__ + set_tooltip_for_item(get_mouse_position_in_control()); +#endif //__WXMSW__ + }); + + m_objects_ctrl->Bind(wxEVT_DATAVIEW_ITEM_CONTEXT_MENU, [](wxDataViewEvent& event) { + object_ctrl_context_menu(); + // event.Skip(); + }); + + m_objects_ctrl->Bind(wxEVT_CHAR, [](wxKeyEvent& event) { object_ctrl_key_event(event); }); // doesn't work on OSX + +#ifdef __WXMSW__ + // Extruder value changed + m_objects_ctrl->Bind(wxEVT_CHOICE, [](wxCommandEvent& event) { update_extruder_in_config(event.GetString()); }); + + m_objects_ctrl->GetMainWindow()->Bind(wxEVT_MOTION, [this](wxMouseEvent& event) { + set_tooltip_for_item(event.GetPosition()); + event.Skip(); + }); +#else + // equivalent to wxEVT_CHOICE on __WXMSW__ + m_objects_ctrl->Bind(wxEVT_DATAVIEW_ITEM_VALUE_CHANGED, [](wxDataViewEvent& event) { object_ctrl_item_value_change(event); }); +#endif //__WXMSW__ + + m_objects_ctrl->Bind(wxEVT_DATAVIEW_ITEM_BEGIN_DRAG, [](wxDataViewEvent& e) {on_begin_drag(e); }); + m_objects_ctrl->Bind(wxEVT_DATAVIEW_ITEM_DROP_POSSIBLE, [](wxDataViewEvent& e) {on_drop_possible(e); }); + m_objects_ctrl->Bind(wxEVT_DATAVIEW_ITEM_DROP, [](wxDataViewEvent& e) {on_drop(e); }); +} + +void ObjectList::create_objects_ctrl() +{ + m_objects_ctrl = new wxDataViewCtrl(m_parent, wxID_ANY, wxDefaultPosition, wxDefaultSize); + m_objects_ctrl->SetMinSize(wxSize(-1, 150)); // TODO - Set correct height according to the opened/closed objects + + m_sizer = new wxBoxSizer(wxVERTICAL); + m_sizer->Add(m_objects_ctrl, 1, wxGROW | wxLEFT, 20); + + m_objects_model = new PrusaObjectDataViewModel; + m_objects_ctrl->AssociateModel(m_objects_model); +#if wxUSE_DRAG_AND_DROP && wxUSE_UNICODE + m_objects_ctrl->EnableDragSource(wxDF_UNICODETEXT); + m_objects_ctrl->EnableDropTarget(wxDF_UNICODETEXT); +#endif // wxUSE_DRAG_AND_DROP && wxUSE_UNICODE + + // column 0(Icon+Text) of the view control: + // And Icon can be consisting of several bitmaps + m_objects_ctrl->AppendColumn(new wxDataViewColumn(_(L("Name")), new PrusaBitmapTextRenderer(), + 0, 200, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE)); + + // column 1 of the view control: + m_objects_ctrl->AppendTextColumn(_(L("Copy")), 1, wxDATAVIEW_CELL_INERT, 45, + wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE); + + // column 2 of the view control: + m_objects_ctrl->AppendColumn(create_objects_list_extruder_column(4)); + + // column 3 of the view control: + m_objects_ctrl->AppendBitmapColumn(" ", 3, wxDATAVIEW_CELL_INERT, 25, + wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE); +} + +// ModelObjectPtrs& ObjectList::get_objects() +// { +// return wxGetApp().mainframe->m_plater->model().objects; +// } + + +void ObjectList::set_tooltip_for_item(const wxPoint& pt) +{ + wxDataViewItem item; + wxDataViewColumn* col; + m_objects_ctrl->HitTest(pt, item, col); + if (!item) return; + + if (col->GetTitle() == " ") + m_objects_ctrl->GetMainWindow()->SetToolTip(_(L("Right button click the icon to change the object settings"))); +// else if (col->GetTitle() == _("Name") && +// m_objects_model->GetIcon(item).GetRefData() == m_icon_manifold_warning.GetRefData()) { +// int obj_idx = m_objects_model->GetIdByItem(item); +// auto& stats = (*m_objects)[obj_idx]->volumes[0]->mesh.stl.stats; +// int errors = stats.degenerate_facets + stats.edges_fixed + stats.facets_removed + +// stats.facets_added + stats.facets_reversed + stats.backwards_edges; +// +// wxString tooltip = wxString::Format(_(L("Auto-repaired (%d errors):\n")), errors); +// +// std::map error_msg; +// error_msg[L("degenerate facets")] = stats.degenerate_facets; +// error_msg[L("edges fixed")] = stats.edges_fixed; +// error_msg[L("facets removed")] = stats.facets_removed; +// error_msg[L("facets added")] = stats.facets_added; +// error_msg[L("facets reversed")] = stats.facets_reversed; +// error_msg[L("backwards edges")] = stats.backwards_edges; +// +// for (auto error : error_msg) +// { +// if (error.second > 0) +// tooltip += wxString::Format(_("\t%d %s\n"), error.second, error.first); +// } +// // OR +// // tooltip += wxString::Format(_(L("%d degenerate facets, %d edges fixed, %d facets removed, " +// // "%d facets added, %d facets reversed, %d backwards edges")), +// // stats.degenerate_facets, stats.edges_fixed, stats.facets_removed, +// // stats.facets_added, stats.facets_reversed, stats.backwards_edges); +// +// if (is_windows10()) +// tooltip += _(L("Right button click the icon to fix STL through Netfabb")); +// +// m_objects_ctrl->GetMainWindow()->SetToolTip(tooltip); +// } + else + m_objects_ctrl->GetMainWindow()->SetToolTip(""); // hide tooltip +} + +wxPoint ObjectList::get_mouse_position_in_control() { + const wxPoint& pt = wxGetMousePosition(); + wxWindow* win = m_objects_ctrl->GetMainWindow(); + return wxPoint(pt.x - win->GetScreenPosition().x, + pt.y - win->GetScreenPosition().y); +} + +wxDataViewColumn* ObjectList::create_objects_list_extruder_column(int extruders_count) +{ + wxArrayString choices; + choices.Add("default"); + for (int i = 1; i <= extruders_count; ++i) + choices.Add(wxString::Format("%d", i)); + wxDataViewChoiceRenderer *c = + new wxDataViewChoiceRenderer(choices, wxDATAVIEW_CELL_EDITABLE, wxALIGN_CENTER_HORIZONTAL); + wxDataViewColumn* column = new wxDataViewColumn(_(L("Extruder")), c, 2, 60, wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE); + return column; +} + +void ObjectList::update_objects_list_extruder_column(int extruders_count) +{ + if (!m_objects_ctrl) return; // #ys_FIXME + if (wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA) + extruders_count = 1; + + // delete old 3rd column + m_objects_ctrl->DeleteColumn(m_objects_ctrl->GetColumn(2)); + // insert new created 3rd column + m_objects_ctrl->InsertColumn(2, create_objects_list_extruder_column(extruders_count)); + // set show/hide for this column + set_extruder_column_hidden(extruders_count <= 1); +} + + + +} //namespace GUI +} //namespace Slic3r \ No newline at end of file diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp new file mode 100644 index 000000000..77530a590 --- /dev/null +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -0,0 +1,50 @@ +#ifndef slic3r_GUI_ObjectList_hpp_ +#define slic3r_GUI_ObjectList_hpp_ + +#include +#include + +class wxBoxSizer; +class wxDataViewCtrl; +class wxDataViewColumn; +class PrusaObjectDataViewModel; + +namespace Slic3r { +namespace GUI { + +class ConfigOptionsGroup; + +class ObjectList +{ + wxBoxSizer *m_sizer {nullptr}; + wxDataViewCtrl *m_objects_ctrl{ nullptr }; + PrusaObjectDataViewModel *m_objects_model{ nullptr }; + wxWindow *m_parent{ nullptr }; + + wxBitmap m_icon_modifiermesh; + wxBitmap m_icon_solidmesh; + wxBitmap m_icon_manifold_warning; + wxBitmap m_bmp_cog; + wxBitmap m_bmp_split; + + int m_selected_object_id = -1; + +public: + ObjectList(wxWindow* parent); + ~ObjectList() {} + + void create_objects_ctrl(); + wxDataViewColumn* create_objects_list_extruder_column(int extruders_count); + void update_objects_list_extruder_column(int extruders_count); + + void set_tooltip_for_item(const wxPoint& pt); + + wxPoint get_mouse_position_in_control(); + wxBoxSizer* get_sizer(){return m_sizer;} + int get_sel_obj_id() { return m_selected_object_id; } +}; + + +}} + +#endif //slic3r_GUI_ObjectList_hpp_ diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp new file mode 100644 index 000000000..86e657d8e --- /dev/null +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -0,0 +1,304 @@ +#include "GUI_ObjectManipulation.hpp" + +#include "OptionsGroup.hpp" +#include "wxExtensions.hpp" +#include "Model.hpp" +#include "Geometry.hpp" + +#include + +namespace Slic3r +{ +namespace GUI +{ + +OG_Settings::OG_Settings(wxWindow* parent, const bool staticbox) +{ + wxString title = staticbox ? " " : ""; // temporary workaround - #ys_FIXME + m_og = std::make_shared(parent, title); +} + +wxSizer* OG_Settings::get_sizer() +{ + return m_og->sizer; +} + +ObjectManipulation::ObjectManipulation(wxWindow* parent): + OG_Settings(parent, true) +{ + m_og->set_name(_(L("Object Manipulation"))); + m_og->label_width = 100; + m_og->set_grid_vgap(5); + + m_og->m_on_change = [this](t_config_option_key opt_key, boost::any value){ + if (opt_key == "scale_unit"){ + const wxString& selection = boost::any_cast(value); + std::vector axes{ "x", "y", "z" }; + for (auto axis : axes) { + std::string key = "scale_" + axis; + get_optgroup(ogFrequentlyObjectSettings)->set_side_text(key, selection); + } + + m_is_percent_scale = selection == _("%"); + update_scale_values(); + } + }; + + ConfigOptionDef def; + + // Objects(sub-objects) name + def.label = L("Name"); + // def.type = coString; + def.gui_type = "legend"; + def.tooltip = L("Object name"); + def.full_width = true; + def.default_value = new ConfigOptionString{ " " }; + m_og->append_single_option_line(Option(def, "object_name")); + + // Legend for object modification + auto line = Line{ "", "" }; + def.label = ""; + def.type = coString; + def.width = 55; + + std::vector axes{ "x", "y", "z" }; + for (const auto axis : axes) { + const auto label = boost::algorithm::to_upper_copy(axis); + def.default_value = new ConfigOptionString{ " " + label }; + Option option = Option(def, axis + "_axis_legend"); + line.append_option(option); + } + m_og->append_line(line); + + + auto add_og_to_object_settings = [](const std::string& option_name, const std::string& sidetext) + { + int def_value = 0; + Line line = { _(option_name), "" }; + if (option_name == "Scale") { + line.near_label_widget = [](wxWindow* parent) { + auto btn = new PrusaLockButton(parent, wxID_ANY); + btn->Bind(wxEVT_BUTTON, [btn](wxCommandEvent &event){ + event.Skip(); + wxTheApp->CallAfter([btn]() { set_uniform_scaling(btn->IsLocked()); }); + }); + return btn; + }; + } + + ConfigOptionDef def; + def.type = coInt; + def.default_value = new ConfigOptionInt(def_value); + def.width = 55; + + if (option_name == "Rotation") + def.min = -360; + + const std::string lower_name = boost::algorithm::to_lower_copy(option_name); + + std::vector axes{ "x", "y", "z" }; + for (auto axis : axes) { + if (axis == "z" && option_name != "Scale") + def.sidetext = sidetext; + Option option = Option(def, lower_name + "_" + axis); + option.opt.full_width = true; + line.append_option(option); + } + + if (option_name == "Scale") + { + def.width = 45; + def.type = coStrings; + def.gui_type = "select_open"; + def.enum_labels.push_back(L("%")); + def.enum_labels.push_back(L("mm")); + def.default_value = new ConfigOptionStrings{ "mm" }; + + const Option option = Option(def, lower_name + "_unit"); + line.append_option(option); + } + + return line; + }; + + + // Settings table + m_og->append_line(add_og_to_object_settings(L("Position"), L("mm"))); + m_og->append_line(add_og_to_object_settings(L("Rotation"), "°")); + m_og->append_line(add_og_to_object_settings(L("Scale"), "mm")); + + + def.label = L("Place on bed"); + def.type = coBool; + def.tooltip = L("Automatic placing of models on printing bed in Y axis"); + def.gui_type = ""; + def.sidetext = ""; + def.default_value = new ConfigOptionBool{ false }; + m_og->append_single_option_line(Option(def, "place_on_bed")); + + m_extra_settings_sizer = new wxBoxSizer(wxVERTICAL); + m_og->sizer->Add(m_extra_settings_sizer, 1, wxEXPAND | wxLEFT, 5); + + m_og->disable(); +} + +int ObjectManipulation::ol_selection() +{ + return wxGetApp().sidebar().get_ol_selection(); +} + +void ObjectManipulation::update_values() +{ + int selection = ol_selection(); + if (selection < 0 || wxGetApp().mainframe->m_plater->model().objects.size() <= selection) { + m_og->set_value("position_x", 0); + m_og->set_value("position_y", 0); + m_og->set_value("position_z", 0); + m_og->set_value("scale_x", 0); + m_og->set_value("scale_y", 0); + m_og->set_value("scale_z", 0); + m_og->set_value("rotation_x", 0); + m_og->set_value("rotation_y", 0); + m_og->set_value("rotation_z", 0); + m_og->disable(); + return; + } + m_is_percent_scale = boost::any_cast(m_og->get_value("scale_unit")) == _("%"); + + update_position_values(); + update_scale_values(); + update_rotation_values(); + m_og->enable(); +} + +void ObjectManipulation::update_scale_values() +{ + int selection = ol_selection(); + ModelObjectPtrs& objects = wxGetApp().mainframe->m_plater->model().objects; + + auto instance = objects[selection]->instances.front(); + auto size = objects[selection]->instance_bounding_box(0).size(); + +#if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM + if (m_is_percent_scale) { + m_og->set_value("scale_x", int(instance->get_scaling_factor(X) * 100)); + m_og->set_value("scale_y", int(instance->get_scaling_factor(Y) * 100)); + m_og->set_value("scale_z", int(instance->get_scaling_factor(Z) * 100)); + } + else { + m_og->set_value("scale_x", int(instance->get_scaling_factor(X) * size(0) + 0.5)); + m_og->set_value("scale_y", int(instance->get_scaling_factor(Y) * size(1) + 0.5)); + m_og->set_value("scale_z", int(instance->get_scaling_factor(Z) * size(2) + 0.5)); + } +#else + if (m_is_percent_scale) { + auto scale = instance->scaling_factor * 100.0; + m_og->set_value("scale_x", int(scale)); + m_og->set_value("scale_y", int(scale)); + m_og->set_value("scale_z", int(scale)); + } + else { + m_og->set_value("scale_x", int(instance->scaling_factor * size(0) + 0.5)); + m_og->set_value("scale_y", int(instance->scaling_factor * size(1) + 0.5)); + m_og->set_value("scale_z", int(instance->scaling_factor * size(2) + 0.5)); + } +#endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM +} + +void ObjectManipulation::update_position_values() +{ + auto instance = wxGetApp().mainframe->m_plater->model().objects[ol_selection()]->instances.front(); + +#if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM + m_og->set_value("position_x", int(instance->get_offset(X))); + m_og->set_value("position_y", int(instance->get_offset(Y))); + m_og->set_value("position_z", int(instance->get_offset(Z))); +#else + m_og->set_value("position_x", int(instance->offset(0))); + m_og->set_value("position_y", int(instance->offset(1))); + m_og->set_value("position_z", 0); +#endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM +} + +void ObjectManipulation::update_position_values(const Vec3d& position) +{ + m_og->set_value("position_x", int(position(0))); + m_og->set_value("position_y", int(position(1))); + m_og->set_value("position_z", int(position(2))); +} + +#if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM +void ObjectManipulation::update_scale_values(const Vec3d& scaling_factor) +{ + // this is temporary + // to be able to update the values as size + // we need to store somewhere the original size + // or have it passed as parameter + if (!m_is_percent_scale) + m_og->set_value("scale_unit", _("%")); + + auto scale = scaling_factor * 100.0; + m_og->set_value("scale_x", int(scale(0))); + m_og->set_value("scale_y", int(scale(1))); + m_og->set_value("scale_z", int(scale(2))); +} +#else +void ObjectManipulation::update_scale_values(double scaling_factor) +{ + // this is temporary + // to be able to update the values as size + // we need to store somewhere the original size + // or have it passed as parameter + if (!m_is_percent_scale) + m_og->set_value("scale_unit", _("%")); + + auto scale = scaling_factor * 100.0; + m_og->set_value("scale_x", int(scale)); + m_og->set_value("scale_y", int(scale)); + m_og->set_value("scale_z", int(scale)); +} +#endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM + +void ObjectManipulation::update_rotation_values() +{ +#if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM + update_rotation_value(wxGetApp().mainframe->m_plater->model().objects[ol_selection()]->instances.front()->get_rotation()); +#else + auto instance = wxGetApp().mainframe->m_plater->model().objects[ol_selection()]->instances.front(); + m_og->set_value("rotation_x", 0); + m_og->set_value("rotation_y", 0); + m_og->set_value("rotation_z", int(Geometry::rad2deg(instance->rotation))); +#endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM +} + +void ObjectManipulation::update_rotation_value(double angle, Axis axis) +{ + std::string axis_str; + switch (axis) { + case X: { + axis_str = "rotation_x"; + break; } + case Y: { + axis_str = "rotation_y"; + break; } + case Z: { + axis_str = "rotation_z"; + break; } + } + + m_og->set_value(axis_str, round_nearest(int(Geometry::rad2deg(angle)), 0)); +} + +#if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM +void ObjectManipulation::update_rotation_value(const Vec3d& rotation) +{ + m_og->set_value("rotation_x", int(round_nearest(Geometry::rad2deg(rotation(0)), 0))); + m_og->set_value("rotation_y", int(round_nearest(Geometry::rad2deg(rotation(1)), 0))); + m_og->set_value("rotation_z", int(round_nearest(Geometry::rad2deg(rotation(2)), 0))); +} +#endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM + + + +} //namespace GUI +} //namespace Slic3r \ No newline at end of file diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.hpp b/src/slic3r/GUI/GUI_ObjectManipulation.hpp new file mode 100644 index 000000000..feeaeb3ab --- /dev/null +++ b/src/slic3r/GUI/GUI_ObjectManipulation.hpp @@ -0,0 +1,64 @@ +#ifndef slic3r_GUI_ObjectManipulation_hpp_ +#define slic3r_GUI_ObjectManipulation_hpp_ + +#include + +#include + +#include "Preset.hpp" + +class wxBoxSizer; + +namespace Slic3r { +namespace GUI { +class ConfigOptionsGroup; + + +class OG_Settings +{ +protected: + std::shared_ptr m_og; +public: + OG_Settings(wxWindow* parent, const bool staticbox); + ~OG_Settings() {} + + wxSizer* get_sizer(); +}; + + +class ObjectManipulation : public OG_Settings +{ + bool m_is_percent_scale = false; // true -> percentage scale unit + // false -> uniform scale unit + wxBoxSizer* m_extra_settings_sizer{ nullptr }; // sizer for extra Object/Part's settings + +public: + ObjectManipulation(wxWindow* parent); + ~ObjectManipulation() {} + + int ol_selection(); + + void update_values(); + // update position values displacements or "gizmos" + void update_position_values(); + void update_position_values(const Vec3d& position); + // update scale values after scale unit changing or "gizmos" + void update_scale_values(); +#if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM + void update_scale_values(const Vec3d& scaling_factor); +#else + void update_scale_values(double scaling_factor); +#endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM + // update rotation values object selection changing + void update_rotation_values(); + // update rotation value after "gizmos" + void update_rotation_value(double angle, Axis axis); +#if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM + void update_rotation_value(const Vec3d& rotation); +#endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM + +}; + +}} + +#endif // slic3r_GUI_ObjectManipulation_hpp_ diff --git a/src/slic3r/GUI/GUI_ObjectParts.cpp b/src/slic3r/GUI/GUI_ObjectParts.cpp index ae1f5a276..f578f6466 100644 --- a/src/slic3r/GUI/GUI_ObjectParts.cpp +++ b/src/slic3r/GUI/GUI_ObjectParts.cpp @@ -21,12 +21,8 @@ namespace Slic3r { namespace GUI { -wxSizer *m_sizer_object_buttons = nullptr; -wxSizer *m_sizer_part_buttons = nullptr; -wxSizer *m_sizer_object_movers = nullptr; wxDataViewCtrl *m_objects_ctrl = nullptr; PrusaObjectDataViewModel *m_objects_model = nullptr; -wxCollapsiblePane *m_collpane_settings = nullptr; PrusaDoubleSlider *m_slider = nullptr; wxGLCanvas *m_preview_canvas = nullptr; @@ -36,19 +32,12 @@ wxBitmap m_icon_manifold_warning; wxBitmap m_bmp_cog; wxBitmap m_bmp_split; -wxSlider* m_mover_x = nullptr; -wxSlider* m_mover_y = nullptr; -wxSlider* m_mover_z = nullptr; -wxButton* m_btn_move_up = nullptr; -wxButton* m_btn_move_down = nullptr; -Vec3d m_move_options; -Vec3d m_last_coords; int m_selected_object_id = -1; bool g_prevent_list_events = false; // We use this flag to avoid circular event handling Select() // happens to fire a wxEVT_LIST_ITEM_SELECTED on OSX, whose event handler // calls this method again and again and again -bool g_is_percent_scale = false; // It indicates if scale unit is percentage +// bool g_is_percent_scale = false; // It indicates if scale unit is percentage bool g_is_uniform_scale = false; // It indicates if scale is uniform ModelObjectPtrs* m_objects; std::shared_ptr m_config; @@ -158,457 +147,6 @@ void init_mesh_icons(){ bool is_parts_changed(){return m_parts_changed;} bool is_part_settings_changed(){ return m_part_settings_changed; } -void set_tooltip_for_item(const wxPoint& pt) -{ - wxDataViewItem item; - wxDataViewColumn* col; - m_objects_ctrl->HitTest(pt, item, col); - if (!item) return; - - if (col->GetTitle() == " ") - m_objects_ctrl->GetMainWindow()->SetToolTip(_(L("Right button click the icon to change the object settings"))); - else if (col->GetTitle() == _("Name") && - m_objects_model->GetIcon(item).GetRefData() == m_icon_manifold_warning.GetRefData()) { - int obj_idx = m_objects_model->GetIdByItem(item); - auto& stats = (*m_objects)[obj_idx]->volumes[0]->mesh.stl.stats; - int errors = stats.degenerate_facets + stats.edges_fixed + stats.facets_removed + - stats.facets_added + stats.facets_reversed + stats.backwards_edges; - - wxString tooltip = wxString::Format(_(L("Auto-repaired (%d errors):\n")), errors); - - std::map error_msg; - error_msg[L("degenerate facets")] = stats.degenerate_facets; - error_msg[L("edges fixed")] = stats.edges_fixed; - error_msg[L("facets removed")] = stats.facets_removed; - error_msg[L("facets added")] = stats.facets_added; - error_msg[L("facets reversed")] = stats.facets_reversed; - error_msg[L("backwards edges")] = stats.backwards_edges; - - for (auto error : error_msg) - { - if (error.second > 0) - tooltip += wxString::Format(_("\t%d %s\n"), error.second, error.first); - } -// OR -// tooltip += wxString::Format(_(L("%d degenerate facets, %d edges fixed, %d facets removed, " -// "%d facets added, %d facets reversed, %d backwards edges")), -// stats.degenerate_facets, stats.edges_fixed, stats.facets_removed, -// stats.facets_added, stats.facets_reversed, stats.backwards_edges); - - if (is_windows10()) - tooltip += _(L("Right button click the icon to fix STL through Netfabb")); - - m_objects_ctrl->GetMainWindow()->SetToolTip(tooltip); - } - else - m_objects_ctrl->GetMainWindow()->SetToolTip(""); // hide tooltip -} - -wxPoint get_mouse_position_in_control() { - const wxPoint& pt = wxGetMousePosition(); - wxWindow* win = m_objects_ctrl->GetMainWindow(); - return wxPoint(pt.x - win->GetScreenPosition().x, - pt.y - win->GetScreenPosition().y); -} - -bool is_mouse_position_in_control(wxPoint& pt) { - pt = get_mouse_position_in_control(); - const wxSize& cz = m_objects_ctrl->GetSize(); - if (pt.x > 0 && pt.x < cz.x && - pt.y > 0 && pt.y < cz.y) - return true; - return false; -} - -wxDataViewColumn* object_ctrl_create_extruder_column(int extruders_count) -{ - wxArrayString choices; - choices.Add("default"); - for (int i = 1; i <= extruders_count; ++i) - choices.Add(wxString::Format("%d", i)); - wxDataViewChoiceRenderer *c = - new wxDataViewChoiceRenderer(choices, wxDATAVIEW_CELL_EDITABLE, wxALIGN_CENTER_HORIZONTAL); - wxDataViewColumn* column = new wxDataViewColumn(_(L("Extruder")), c, 2, 60, wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE); - return column; -} - -void create_objects_ctrl(wxWindow* win, wxBoxSizer*& objects_sz) -{ - m_objects_ctrl = new wxDataViewCtrl(win, wxID_ANY, wxDefaultPosition, wxDefaultSize); - m_objects_ctrl->SetMinSize(wxSize(-1, 150)); // TODO - Set correct height according to the opened/closed objects - - objects_sz = new wxBoxSizer(wxVERTICAL); - objects_sz->Add(m_objects_ctrl, 1, wxGROW | wxLEFT, 20); - - m_objects_model = new PrusaObjectDataViewModel; - m_objects_ctrl->AssociateModel(m_objects_model); -#if wxUSE_DRAG_AND_DROP && wxUSE_UNICODE - m_objects_ctrl->EnableDragSource(wxDF_UNICODETEXT); - m_objects_ctrl->EnableDropTarget(wxDF_UNICODETEXT); -#endif // wxUSE_DRAG_AND_DROP && wxUSE_UNICODE - - // column 0(Icon+Text) of the view control: - // And Icon can be consisting of several bitmaps - m_objects_ctrl->AppendColumn(new wxDataViewColumn(_(L("Name")), new PrusaBitmapTextRenderer(), - 0, 200, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE)); - - // column 1 of the view control: - m_objects_ctrl->AppendTextColumn(_(L("Copy")), 1, wxDATAVIEW_CELL_INERT, 45, - wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE); - - // column 2 of the view control: - m_objects_ctrl->AppendColumn(object_ctrl_create_extruder_column(4)); - - // column 3 of the view control: - m_objects_ctrl->AppendBitmapColumn(" ", 3, wxDATAVIEW_CELL_INERT, 25, - wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE); -} - -// ****** from GUI.cpp -wxBoxSizer* create_objects_list(wxWindow *win) -{ - wxBoxSizer* objects_sz; - // create control - create_objects_ctrl(win, objects_sz); - - // describe control behavior - m_objects_ctrl->Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [](wxEvent& event) { - object_ctrl_selection_changed(); -#ifndef __WXMSW__ - set_tooltip_for_item(get_mouse_position_in_control()); -#endif //__WXMSW__ - }); - - m_objects_ctrl->Bind(wxEVT_DATAVIEW_ITEM_CONTEXT_MENU, [](wxDataViewEvent& event) { - object_ctrl_context_menu(); -// event.Skip(); - }); - - m_objects_ctrl->Bind(wxEVT_CHAR, [](wxKeyEvent& event) { object_ctrl_key_event(event); }); // doesn't work on OSX - -#ifdef __WXMSW__ - // Extruder value changed - m_objects_ctrl->Bind(wxEVT_CHOICE, [](wxCommandEvent& event) { update_extruder_in_config(event.GetString()); }); - - m_objects_ctrl->GetMainWindow()->Bind(wxEVT_MOTION, [](wxMouseEvent& event) { - set_tooltip_for_item(event.GetPosition()); - event.Skip(); - }); -#else - // equivalent to wxEVT_CHOICE on __WXMSW__ - m_objects_ctrl->Bind(wxEVT_DATAVIEW_ITEM_VALUE_CHANGED, [](wxDataViewEvent& event) { object_ctrl_item_value_change(event); }); -#endif //__WXMSW__ - - m_objects_ctrl->Bind(wxEVT_DATAVIEW_ITEM_BEGIN_DRAG, [](wxDataViewEvent& e) {on_begin_drag(e);}); - m_objects_ctrl->Bind(wxEVT_DATAVIEW_ITEM_DROP_POSSIBLE, [](wxDataViewEvent& e) {on_drop_possible(e); }); - m_objects_ctrl->Bind(wxEVT_DATAVIEW_ITEM_DROP, [](wxDataViewEvent& e) {on_drop(e);}); - return objects_sz; -} - -wxBoxSizer* create_edit_object_buttons(wxWindow* win) -{ - auto sizer = new wxBoxSizer(wxVERTICAL); - - auto btn_load_part = new wxButton(win, wxID_ANY, /*Load */"part" + dots, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT | wxNO_BORDER/*wxBU_LEFT*/); - auto btn_load_modifier = new wxButton(win, wxID_ANY, /*Load */"modifier" + dots, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT | wxNO_BORDER/*wxBU_LEFT*/); - auto btn_load_lambda_modifier = new wxButton(win, wxID_ANY, /*Load */"generic" + dots, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT | wxNO_BORDER/*wxBU_LEFT*/); - auto btn_delete = new wxButton(win, wxID_ANY, "Delete"/*" part"*/, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT | wxNO_BORDER/*wxBU_LEFT*/); - auto btn_split = new wxButton(win, wxID_ANY, "Split"/*" part"*/, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT | wxNO_BORDER/*wxBU_LEFT*/); - m_btn_move_up = new wxButton(win, wxID_ANY, "", wxDefaultPosition, wxDefaultSize/*wxSize(30, -1)*/, wxBU_LEFT); - m_btn_move_down = new wxButton(win, wxID_ANY, "", wxDefaultPosition, wxDefaultSize/*wxSize(30, -1)*/, wxBU_LEFT); - - //*** button's functions - btn_load_part->Bind(wxEVT_BUTTON, [win](wxEvent&) { -// on_btn_load(win); - }); - - btn_load_modifier->Bind(wxEVT_BUTTON, [win](wxEvent&) { -// on_btn_load(win, true); - }); - - btn_load_lambda_modifier->Bind(wxEVT_BUTTON, [win](wxEvent&) { -// on_btn_load(win, true, true); - }); - - btn_delete ->Bind(wxEVT_BUTTON, [](wxEvent&) { on_btn_del(); }); - btn_split ->Bind(wxEVT_BUTTON, [](wxEvent&) { on_btn_split(true); }); - m_btn_move_up ->Bind(wxEVT_BUTTON, [](wxEvent&) { on_btn_move_up(); }); - m_btn_move_down ->Bind(wxEVT_BUTTON, [](wxEvent&) { on_btn_move_down(); }); - //*** - - m_btn_move_up->SetMinSize(wxSize(20, -1)); - m_btn_move_down->SetMinSize(wxSize(20, -1)); - btn_load_part->SetBitmap(wxBitmap(from_u8(Slic3r::var("brick_add.png")), wxBITMAP_TYPE_PNG)); - btn_load_modifier->SetBitmap(wxBitmap(from_u8(Slic3r::var("brick_add.png")), wxBITMAP_TYPE_PNG)); - btn_load_lambda_modifier->SetBitmap(wxBitmap(from_u8(Slic3r::var("brick_add.png")), wxBITMAP_TYPE_PNG)); - btn_delete->SetBitmap(wxBitmap(from_u8(Slic3r::var("brick_delete.png")), wxBITMAP_TYPE_PNG)); - btn_split->SetBitmap(wxBitmap(from_u8(Slic3r::var("shape_ungroup.png")), wxBITMAP_TYPE_PNG)); - m_btn_move_up->SetBitmap(wxBitmap(from_u8(Slic3r::var("bullet_arrow_up.png")), wxBITMAP_TYPE_PNG)); - m_btn_move_down->SetBitmap(wxBitmap(from_u8(Slic3r::var("bullet_arrow_down.png")), wxBITMAP_TYPE_PNG)); - - m_sizer_object_buttons = new wxGridSizer(1, 3, 0, 0); - m_sizer_object_buttons->Add(btn_load_part, 0, wxEXPAND); - m_sizer_object_buttons->Add(btn_load_modifier, 0, wxEXPAND); - m_sizer_object_buttons->Add(btn_load_lambda_modifier, 0, wxEXPAND); - m_sizer_object_buttons->Show(false); - - m_sizer_part_buttons = new wxGridSizer(1, 3, 0, 0); - m_sizer_part_buttons->Add(btn_delete, 0, wxEXPAND); - m_sizer_part_buttons->Add(btn_split, 0, wxEXPAND); - { - auto up_down_sizer = new wxGridSizer(1, 2, 0, 0); - up_down_sizer->Add(m_btn_move_up, 1, wxEXPAND); - up_down_sizer->Add(m_btn_move_down, 1, wxEXPAND); - m_sizer_part_buttons->Add(up_down_sizer, 0, wxEXPAND); - } - m_sizer_part_buttons->Show(false); - - btn_load_part->SetFont(wxGetApp().small_font()); - btn_load_modifier->SetFont(wxGetApp().small_font()); - btn_load_lambda_modifier->SetFont(wxGetApp().small_font()); - btn_delete->SetFont(wxGetApp().small_font()); - btn_split->SetFont(wxGetApp().small_font()); - m_btn_move_up->SetFont(wxGetApp().small_font()); - m_btn_move_down->SetFont(wxGetApp().small_font()); - - sizer->Add(m_sizer_object_buttons, 0, wxEXPAND | wxLEFT, 20); - sizer->Add(m_sizer_part_buttons, 0, wxEXPAND | wxLEFT, 20); - return sizer; -} - -void update_after_moving() -{ - auto item = m_objects_ctrl->GetSelection(); - if (!item || m_selected_object_id<0) - return; - - auto volume_id = m_objects_model->GetVolumeIdByItem(item); - if (volume_id < 0) - return; - - auto d = m_move_options - m_last_coords; - auto volume = (*m_objects)[m_selected_object_id]->volumes[volume_id]; - volume->mesh.translate(d(0), d(1), d(2)); - m_last_coords = m_move_options; - - m_parts_changed = true; - parts_changed(m_selected_object_id); -} - -wxSizer* object_movers(wxWindow *win) -{ -// DynamicPrintConfig* config = &wxGetApp().preset_bundle->/*full_config();//*/printers.get_edited_preset().config; // TODO get config from Model_volume - std::shared_ptr optgroup = std::make_shared(win, "Move"/*, config*/); - optgroup->label_width = 20; - optgroup->m_on_change = [](t_config_option_key opt_key, boost::any value){ - int val = boost::any_cast(value); - bool update = false; - if (opt_key == "x" && m_move_options(0) != val){ - update = true; - m_move_options(0) = val; - } - else if (opt_key == "y" && m_move_options(1) != val){ - update = true; - m_move_options(1) = val; - } - else if (opt_key == "z" && m_move_options(2) != val){ - update = true; - m_move_options(2) = val; - } - if (update) update_after_moving(); - }; - - ConfigOptionDef def; - def.label = L("X"); - def.type = coInt; - def.gui_type = "slider"; - def.default_value = new ConfigOptionInt(0); - - Option option = Option(def, "x"); - option.opt.full_width = true; - optgroup->append_single_option_line(option); - m_mover_x = dynamic_cast(optgroup->get_field("x")->getWindow()); - - def.label = L("Y"); - option = Option(def, "y"); - optgroup->append_single_option_line(option); - m_mover_y = dynamic_cast(optgroup->get_field("y")->getWindow()); - - def.label = L("Z"); - option = Option(def, "z"); - optgroup->append_single_option_line(option); - m_mover_z = dynamic_cast(optgroup->get_field("z")->getWindow()); - - get_optgroups().push_back(optgroup); // ogObjectMovers - - m_sizer_object_movers = optgroup->sizer; - m_sizer_object_movers->Show(false); - - m_move_options = Vec3d(0, 0, 0); - m_last_coords = Vec3d(0, 0, 0); - - return optgroup->sizer; -} - -void Sidebar::add_objects_list(wxWindow* parent, wxBoxSizer* sizer) -{ - const auto ol_sizer = create_objects_list(parent); - sizer->Add(ol_sizer, 1, wxEXPAND | wxTOP, 20); - set_objects_list_sizer(ol_sizer); -} - -Line add_og_to_object_settings(const std::string& option_name, const std::string& sidetext, int def_value = 0) -{ - Line line = { _(option_name), "" }; - if (option_name == "Scale") { - line.near_label_widget = [](wxWindow* parent) { - auto btn = new PrusaLockButton(parent, wxID_ANY); - btn->Bind(wxEVT_BUTTON, [btn](wxCommandEvent &event){ - event.Skip(); - wxTheApp->CallAfter([btn]() { set_uniform_scaling(btn->IsLocked()); }); - }); - return btn; - }; - } - - ConfigOptionDef def; - def.type = coInt; - def.default_value = new ConfigOptionInt(def_value); - def.width = 55; - - if (option_name == "Rotation") - def.min = -360; - - const std::string lower_name = boost::algorithm::to_lower_copy(option_name); - - std::vector axes{ "x", "y", "z" }; - for (auto axis : axes) { - if (axis == "z" && option_name != "Scale") - def.sidetext = sidetext; - Option option = Option(def, lower_name + "_" + axis); - option.opt.full_width = true; - line.append_option(option); - } - - if (option_name == "Scale") - { - def.width = 45; - def.type = coStrings; - def.gui_type = "select_open"; - def.enum_labels.push_back(L("%")); - def.enum_labels.push_back(L("mm")); - def.default_value = new ConfigOptionStrings{ "mm" }; - - const Option option = Option(def, lower_name + "_unit"); - line.append_option(option); - } - - return line; -} - -void Sidebar::add_object_settings(wxWindow* parent, wxBoxSizer* sizer, t_optgroups& optgroups) -{ - auto optgroup = std::make_shared(parent, _(L("Object Settings"))); - optgroup->label_width = 100; - optgroup->set_grid_vgap(5); - - optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value){ - if (opt_key == "scale_unit"){ - const wxString& selection = boost::any_cast(value); - std::vector axes{ "x", "y", "z" }; - for (auto axis : axes) { - std::string key = "scale_" + axis; - get_optgroup(ogFrequentlyObjectSettings)->set_side_text(key, selection); - } - - g_is_percent_scale = selection == _("%"); - update_scale_values(); - } - }; - - ConfigOptionDef def; - - // Objects(sub-objects) name - def.label = L("Name"); -// def.type = coString; - def.gui_type = "legend"; - def.tooltip = L("Object name"); - def.full_width = true; - def.default_value = new ConfigOptionString{ " " }; - optgroup->append_single_option_line(Option(def, "object_name")); - - // Legend for object modification - auto line = Line{ "", "" }; - def.label = ""; - def.type = coString; - def.width = 55; - - std::vector axes{ "x", "y", "z" }; - for (const auto axis : axes) { - const auto label = boost::algorithm::to_upper_copy(axis); - def.default_value = new ConfigOptionString{ " "+label }; - Option option = Option(def, axis + "_axis_legend"); - line.append_option(option); - } - optgroup->append_line(line); - - - // Settings table - optgroup->append_line(add_og_to_object_settings(L("Position"), L("mm"))); - optgroup->append_line(add_og_to_object_settings(L("Rotation"), "°")); - optgroup->append_line(add_og_to_object_settings(L("Scale"), "mm")); - - - def.label = L("Place on bed"); - def.type = coBool; - def.tooltip = L("Automatic placing of models on printing bed in Y axis"); - def.gui_type = ""; - def.sidetext = ""; - def.default_value = new ConfigOptionBool{ false }; - optgroup->append_single_option_line(Option(def, "place_on_bed")); - - m_option_sizer = new wxBoxSizer(wxVERTICAL); - optgroup->sizer->Add(m_option_sizer, 1, wxEXPAND | wxLEFT, 5); - - sizer->Add(optgroup->sizer, 0, wxEXPAND | wxLEFT | wxTOP, 20); - - optgroup->disable(); - - optgroups.push_back(optgroup); // ogFrequentlyObjectSettings -} - -void add_object_to_list(const std::string &name, ModelObject* model_object) -{ - wxString item_name = name; - auto item = m_objects_model->Add(item_name, model_object->instances.size()); - m_objects_ctrl->Select(item); - - // Add error icon if detected auto-repaire - auto stats = model_object->volumes[0]->mesh.stl.stats; - int errors = stats.degenerate_facets + stats.edges_fixed + stats.facets_removed + - stats.facets_added + stats.facets_reversed + stats.backwards_edges; - if (errors > 0) { - const PrusaDataViewBitmapText data(item_name, m_icon_manifold_warning); - wxVariant variant; - variant << data; - m_objects_model->SetValue(variant, item, 0); - } - - if (model_object->volumes.size() > 1) { - for (auto id = 0; id < model_object->volumes.size(); id++) - m_objects_model->AddChild(item, - model_object->volumes[id]->name, - m_icon_solidmesh, - model_object->volumes[id]->config.option("extruder")->value, - false); - m_objects_ctrl->Expand(item); - } - -#ifndef __WXOSX__ - object_ctrl_selection_changed(); -#endif //__WXMSW__ -} - void delete_object_from_list() { auto item = m_objects_ctrl->GetSelection(); @@ -714,9 +252,7 @@ void object_ctrl_context_menu() { wxDataViewItem item; wxDataViewColumn* col; -// printf("object_ctrl_context_menu\n"); - const wxPoint pt = get_mouse_position_in_control(); -// printf("mouse_position_in_control: x = %d, y = %d\n", pt.x, pt.y); + const wxPoint pt;//!!! = get_mouse_position_in_control(); m_objects_ctrl->HitTest(pt, item, col); if (!item) #ifdef __WXOSX__ // #ys_FIXME temporary workaround for OSX @@ -730,9 +266,7 @@ void object_ctrl_context_menu() #else return; #endif // __WXOSX__ -// printf("item exists\n"); const wxString title = col->GetTitle(); -// printf("title = *%s*\n", title.data().AsChar()); if (title == " ") show_context_menu(); @@ -1472,29 +1006,6 @@ void parts_changed(int obj_idx) e.SetString(event_str); // get_main_frame()->ProcessWindowEvent(e); // #ys_FIXME } - -void update_settings_value() -{ - auto og = get_optgroup(ogFrequentlyObjectSettings); - if (m_selected_object_id < 0 || m_objects->size() <= m_selected_object_id) { - og->set_value("position_x", 0); - og->set_value("position_y", 0); - og->set_value("position_z", 0); - og->set_value("scale_x", 0); - og->set_value("scale_y", 0); - og->set_value("scale_z", 0); - og->set_value("rotation_x", 0); - og->set_value("rotation_y", 0); - og->set_value("rotation_z", 0); - og->disable(); - return; - } - g_is_percent_scale = boost::any_cast(og->get_value("scale_unit")) == _("%"); - update_position_values(); - update_scale_values(); - update_rotation_values(); - og->enable(); -} void part_selection_changed() { @@ -1549,7 +1060,7 @@ void part_selection_changed() m_selected_object_id = obj_idx; - update_settings_value(); +// update_values(); } void set_extruder_column_hidden(bool hide) @@ -1571,149 +1082,6 @@ void update_extruder_in_config(const wxString& selection) } } -void update_scale_values() -{ - auto og = get_optgroup(ogFrequentlyObjectSettings); - auto instance = (*m_objects)[m_selected_object_id]->instances.front(); - auto size = (*m_objects)[m_selected_object_id]->instance_bounding_box(0).size(); - -#if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM - if (g_is_percent_scale) { - og->set_value("scale_x", int(instance->get_scaling_factor(X) * 100)); - og->set_value("scale_y", int(instance->get_scaling_factor(Y) * 100)); - og->set_value("scale_z", int(instance->get_scaling_factor(Z) * 100)); - } - else { - og->set_value("scale_x", int(instance->get_scaling_factor(X) * size(0) + 0.5)); - og->set_value("scale_y", int(instance->get_scaling_factor(Y) * size(1) + 0.5)); - og->set_value("scale_z", int(instance->get_scaling_factor(Z) * size(2) + 0.5)); - } -#else - if (g_is_percent_scale) { - auto scale = instance->scaling_factor * 100.0; - og->set_value("scale_x", int(scale)); - og->set_value("scale_y", int(scale)); - og->set_value("scale_z", int(scale)); - } - else { - og->set_value("scale_x", int(instance->scaling_factor * size(0) + 0.5)); - og->set_value("scale_y", int(instance->scaling_factor * size(1) + 0.5)); - og->set_value("scale_z", int(instance->scaling_factor * size(2) + 0.5)); - } -#endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM -} - -void update_position_values() -{ - auto og = get_optgroup(ogFrequentlyObjectSettings); - auto instance = (*m_objects)[m_selected_object_id]->instances.front(); - -#if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM - og->set_value("position_x", int(instance->get_offset(X))); - og->set_value("position_y", int(instance->get_offset(Y))); - og->set_value("position_z", int(instance->get_offset(Z))); -#else - og->set_value("position_x", int(instance->offset(0))); - og->set_value("position_y", int(instance->offset(1))); - og->set_value("position_z", 0); -#endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM -} - -void update_position_values(const Vec3d& position) -{ - auto og = get_optgroup(ogFrequentlyObjectSettings); - - og->set_value("position_x", int(position(0))); - og->set_value("position_y", int(position(1))); - og->set_value("position_z", int(position(2))); -} - -#if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM -void update_scale_values(const Vec3d& scaling_factor) -{ - auto og = get_optgroup(ogFrequentlyObjectSettings); - - // this is temporary - // to be able to update the values as size - // we need to store somewhere the original size - // or have it passed as parameter - if (!g_is_percent_scale) - og->set_value("scale_unit", _("%")); - - auto scale = scaling_factor * 100.0; - og->set_value("scale_x", int(scale(0))); - og->set_value("scale_y", int(scale(1))); - og->set_value("scale_z", int(scale(2))); -} -#else -void update_scale_values(double scaling_factor) -{ - auto og = get_optgroup(ogFrequentlyObjectSettings); - - // this is temporary - // to be able to update the values as size - // we need to store somewhere the original size - // or have it passed as parameter - if (!g_is_percent_scale) - og->set_value("scale_unit", _("%")); - - auto scale = scaling_factor * 100.0; - og->set_value("scale_x", int(scale)); - og->set_value("scale_y", int(scale)); - og->set_value("scale_z", int(scale)); -} -#endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM - -void update_rotation_values() -{ -#if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM - update_rotation_value((*m_objects)[m_selected_object_id]->instances.front()->get_rotation()); -#else - auto og = get_optgroup(ogFrequentlyObjectSettings); - auto instance = (*m_objects)[m_selected_object_id]->instances.front(); - og->set_value("rotation_x", 0); - og->set_value("rotation_y", 0); - og->set_value("rotation_z", int(Geometry::rad2deg(instance->rotation))); -#endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM -} - -void update_rotation_value(double angle, Axis axis) -{ - auto og = get_optgroup(ogFrequentlyObjectSettings); - - std::string axis_str; - switch (axis) - { - case X: - { - axis_str = "rotation_x"; - break; - } - case Y: - { - axis_str = "rotation_y"; - break; - } - case Z: - { - axis_str = "rotation_z"; - break; - } - } - - og->set_value(axis_str, round_nearest(int(Geometry::rad2deg(angle)), 0)); -} - -#if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM -void update_rotation_value(const Vec3d& rotation) -{ - auto og = get_optgroup(ogFrequentlyObjectSettings); - og->set_value("rotation_x", int(round_nearest(Geometry::rad2deg(rotation(0)), 0))); - og->set_value("rotation_y", int(round_nearest(Geometry::rad2deg(rotation(1)), 0))); - og->set_value("rotation_z", int(round_nearest(Geometry::rad2deg(rotation(2)), 0))); -} -#endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM - void set_uniform_scaling(const bool uniform_scale) { g_is_uniform_scale = uniform_scale; @@ -1792,20 +1160,6 @@ void on_drop(wxDataViewEvent &event) g_prevent_list_events = false; } -void update_objects_list_extruder_column(int extruders_count) -{ - if (!m_objects_ctrl) return; // #ys_FIXME - if (wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA) - extruders_count = 1; - - // delete old 3rd column - m_objects_ctrl->DeleteColumn(m_objects_ctrl->GetColumn(2)); - // insert new created 3rd column - m_objects_ctrl->InsertColumn(2, object_ctrl_create_extruder_column(extruders_count)); - // set show/hide for this column - set_extruder_column_hidden(extruders_count <= 1); -} - void create_double_slider(wxWindow* parent, wxBoxSizer* sizer, wxGLCanvas* canvas) { m_slider = new PrusaDoubleSlider(parent, wxID_ANY, 0, 0, 0, 100); diff --git a/src/slic3r/GUI/GUI_ObjectParts.hpp b/src/slic3r/GUI/GUI_ObjectParts.hpp index 01011d2c4..18614c4ee 100644 --- a/src/slic3r/GUI/GUI_ObjectParts.hpp +++ b/src/slic3r/GUI/GUI_ObjectParts.hpp @@ -106,28 +106,11 @@ void on_btn_move_down(); void parts_changed(int obj_idx); void part_selection_changed(); -void update_settings_value(); // show/hide "Extruder" column for Objects List void set_extruder_column_hidden(bool hide); // update extruder in current config void update_extruder_in_config(const wxString& selection); -// update position values displacements or "gizmos" -void update_position_values(); -void update_position_values(const Vec3d& position); -// update scale values after scale unit changing or "gizmos" -void update_scale_values(); -#if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM -void update_scale_values(const Vec3d& scaling_factor); -#else -void update_scale_values(double scaling_factor); -#endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM -// update rotation values object selection changing -void update_rotation_values(); -// update rotation value after "gizmos" -void update_rotation_value(double angle, Axis axis); -#if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM -void update_rotation_value(const Vec3d& rotation); -#endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM + void set_uniform_scaling(const bool uniform_scale); void on_begin_drag(wxDataViewEvent &event); diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 502394aca..07f4c5e8e 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -274,7 +274,7 @@ void MainFrame::create_preset_tabs() void MainFrame::add_created_tab(Tab* panel) { - panel->create_preset_tab(wxGetApp().preset_bundle); + panel->create_preset_tab(); // Load the currently selected preset into the GUI, update the preset selection box. panel->load_current_preset(); diff --git a/src/slic3r/GUI/OptionsGroup.hpp b/src/slic3r/GUI/OptionsGroup.hpp index 3e196f70c..8ee2ee167 100644 --- a/src/slic3r/GUI/OptionsGroup.hpp +++ b/src/slic3r/GUI/OptionsGroup.hpp @@ -231,6 +231,7 @@ public: bool m_full_labels {0}; t_opt_map m_opt_map; + void set_config(DynamicPrintConfig* config){ m_config = config; } Option get_option(const std::string& opt_key, int opt_index = -1); Line create_single_option_line(const std::string& title, int idx = -1) /*const*/{ Option option = get_option(title, idx); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 2133533eb..29e79b79d 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -27,10 +27,11 @@ #include "libslic3r/Polygon.hpp" #include "GUI.hpp" #include "GUI_App.hpp" +#include "GUI_ObjectList.hpp" +#include "GUI_ObjectManipulation.hpp" #include "MainFrame.hpp" #include "3DScene.hpp" #include "GLCanvas3D.hpp" -#include "GUI_ObjectParts.hpp" #include "GLToolbar.hpp" #include "GUI_Preview.hpp" #include "Tab.hpp" @@ -200,6 +201,141 @@ PresetComboBox::PresetComboBox(wxWindow *parent, Preset::Type preset_type) : PresetComboBox::~PresetComboBox() {} +// Frequently changed parameters + +class FreqChangedParams : public OG_Settings +{ + double m_brim_width = 0.0; + wxButton* m_wiping_dialog_button{ nullptr }; +public: + FreqChangedParams(wxWindow* parent, const int label_width); + ~FreqChangedParams() {} + + wxButton* get_wiping_dialog_button() { return m_wiping_dialog_button; } +}; + +FreqChangedParams::FreqChangedParams(wxWindow* parent, const int label_width) : + OG_Settings(parent, false) +{ + DynamicPrintConfig* config = &wxGetApp().preset_bundle->prints.get_edited_preset().config; + + m_og->set_config(config); + m_og->label_width = label_width; + + m_og->m_on_change = [config, this](t_config_option_key opt_key, boost::any value){ + TabPrint* tab_print = nullptr; + for (size_t i = 0; i < wxGetApp().tab_panel()->GetPageCount(); ++i) { + Tab *tab = dynamic_cast(wxGetApp().tab_panel()->GetPage(i)); + if (!tab) + continue; + if (tab->name() == "print"){ + tab_print = static_cast(tab); + break; + } + } + if (tab_print == nullptr) + return; + + if (opt_key == "fill_density"){ + value = m_og->get_config_value(*config, opt_key); + tab_print->set_value(opt_key, value); + tab_print->update(); + } + else{ + DynamicPrintConfig new_conf = *config; + if (opt_key == "brim"){ + double new_val; + double brim_width = config->opt_float("brim_width"); + if (boost::any_cast(value) == true) + { + new_val = m_brim_width == 0.0 ? 10 : + m_brim_width < 0.0 ? m_brim_width * (-1) : + m_brim_width; + } + else{ + m_brim_width = brim_width * (-1); + new_val = 0; + } + new_conf.set_key_value("brim_width", new ConfigOptionFloat(new_val)); + } + else{ //(opt_key == "support") + const wxString& selection = boost::any_cast(value); + + auto support_material = selection == _("None") ? false : true; + new_conf.set_key_value("support_material", new ConfigOptionBool(support_material)); + + if (selection == _("Everywhere")) + new_conf.set_key_value("support_material_buildplate_only", new ConfigOptionBool(false)); + else if (selection == _("Support on build plate only")) + new_conf.set_key_value("support_material_buildplate_only", new ConfigOptionBool(true)); + } + tab_print->load_config(new_conf); + } + + tab_print->update_dirty(); + }; + + Option option = m_og->get_option("fill_density"); + option.opt.sidetext = ""; + option.opt.full_width = true; + m_og->append_single_option_line(option); + + ConfigOptionDef def; + + def.label = L("Support"); + def.type = coStrings; + def.gui_type = "select_open"; + def.tooltip = L("Select what kind of support do you need"); + def.enum_labels.push_back(L("None")); + def.enum_labels.push_back(L("Support on build plate only")); + def.enum_labels.push_back(L("Everywhere")); + std::string selection = !config->opt_bool("support_material") ? + "None" : + config->opt_bool("support_material_buildplate_only") ? + "Support on build plate only" : + "Everywhere"; + def.default_value = new ConfigOptionStrings{ selection }; + option = Option(def, "support"); + option.opt.full_width = true; + m_og->append_single_option_line(option); + + m_brim_width = config->opt_float("brim_width"); + def.label = L("Brim"); + def.type = coBool; + def.tooltip = L("This flag enables the brim that will be printed around each object on the first layer."); + def.gui_type = ""; + def.default_value = new ConfigOptionBool{ m_brim_width > 0.0 ? true : false }; + option = Option(def, "brim"); + m_og->append_single_option_line(option); + + + Line line = { "", "" }; + line.widget = [config, this](wxWindow* parent){ + m_wiping_dialog_button = new wxButton(parent, wxID_ANY, _(L("Purging volumes")) + dots, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); + auto sizer = new wxBoxSizer(wxHORIZONTAL); + sizer->Add(m_wiping_dialog_button); + m_wiping_dialog_button->Bind(wxEVT_BUTTON, ([parent](wxCommandEvent& e) + { + auto &config = wxGetApp().preset_bundle->project_config; + const std::vector &init_matrix = (config.option("wiping_volumes_matrix"))->values; + const std::vector &init_extruders = (config.option("wiping_volumes_extruders"))->values; + + WipingDialog dlg(parent, cast(init_matrix), cast(init_extruders)); + + if (dlg.ShowModal() == wxID_OK) { + std::vector matrix = dlg.get_matrix(); + std::vector extruders = dlg.get_extruders(); + (config.option("wiping_volumes_matrix"))->values = std::vector(matrix.begin(), matrix.end()); + (config.option("wiping_volumes_extruders"))->values = std::vector(extruders.begin(), extruders.end()); + g_on_request_update_callback.call(); + } + })); + return sizer; + }; + m_og->append_line(line); +} + + // Sidebar / private struct Sidebar::priv @@ -216,6 +352,9 @@ struct Sidebar::priv PresetComboBox *combo_printer; wxBoxSizer *sizer_params; + FreqChangedParams *frequently_changed_parameters; + ObjectList *object_list; + ObjectManipulation *object_manipulation; ObjectInfo *object_info; SlicedInfo *sliced_info; @@ -225,10 +364,6 @@ struct Sidebar::priv wxButton *btn_send_gcode; std::vector > optgroups {}; - double brim_width = 0.0; - size_t label_width = 100; - wxButton* btn_wiping_dialog {nullptr}; - }; @@ -268,16 +403,24 @@ Sidebar::Sidebar(wxWindow *parent) init_combo(&p->combo_sla_material, _(L("SLA material")), Preset::TYPE_SLA_MATERIAL, false); init_combo(&p->combo_printer, _(L("Printer")), Preset::TYPE_PRINTER, false); + // calculate width of the preset labels p->sizer_presets->Layout(); + const wxArrayInt& ar = p->sizer_presets->GetColWidths(); + int label_width = ar.IsEmpty() ? 100 : ar.front()-4; + + p->sizer_params = new wxBoxSizer(wxVERTICAL); // Frequently changed parameters - p->sizer_params = new wxBoxSizer(wxVERTICAL); - add_frequently_changed_parameters(p->scrolled, p->sizer_params/*, p->sizer_presets*/); + p->frequently_changed_parameters = new FreqChangedParams(p->scrolled, label_width); + p->sizer_params->Add(p->frequently_changed_parameters->get_sizer(), 0, wxEXPAND | wxBOTTOM | wxLEFT, 2); // Object List - add_objects_list(p->scrolled, p->sizer_params); + p->object_list = new ObjectList(p->scrolled); + p->sizer_params->Add(p->object_list->get_sizer(), 1, wxEXPAND | wxTOP, 20); + // Frequently Object Settings - add_object_settings(p->scrolled, p->sizer_params, p->optgroups); + p->object_manipulation = new ObjectManipulation(p->scrolled); + p->sizer_params->Add(p->object_manipulation->get_sizer(), 0, wxEXPAND | wxLEFT | wxTOP, 20); // Buttons in the scrolled area wxBitmap arrow_up(GUI::from_u8(Slic3r::var("brick_go.png")), wxBITMAP_TYPE_PNG); @@ -364,6 +507,11 @@ void Sidebar::update_presets(Preset::Type preset_type) // wxTheApp->{preset_bundle}->export_selections(wxTheApp->{app_config}); } +ObjectManipulation* Sidebar::obj_manipul() +{ + return p->object_manipulation; +} + ConfigOptionsGroup* Sidebar::get_optgroup(size_t i) { return p->optgroups.empty() ? nullptr : p->optgroups[i].get(); @@ -375,7 +523,17 @@ t_optgroups& Sidebar::get_optgroups() { wxButton* Sidebar::get_wiping_dialog_button() { - return p->btn_wiping_dialog; + return p->frequently_changed_parameters->get_wiping_dialog_button(); +} + +void Sidebar::update_objects_list_extruder_column(int extruders_count) +{ + p->object_list->update_objects_list_extruder_column(extruders_count); +} + +int Sidebar::get_ol_selection() +{ + return p->object_list->get_sel_obj_id(); } @@ -431,7 +589,7 @@ struct Plater::priv wxNotebook *notebook; Sidebar *sidebar; wxGLCanvas *canvas3D; // TODO: Use GLCanvas3D when we can - GUI::Preview *preview; + Preview *preview; BackgroundSlicingProcess background_process; static const int gl_attrs[]; @@ -933,6 +1091,7 @@ Plater::~Plater() } Sidebar& Plater::sidebar() { return *p->sidebar; } +Model& Plater::model() { return p->model; } std::string Plater::export_gcode(const std::string &output_path) { diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 14de62674..1d9022350 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -4,17 +4,18 @@ #include #include -#include #include "Preset.hpp" -class wxBoxSizer; - namespace Slic3r { + +class Model; + namespace GUI { class MainFrame; class ConfigOptionsGroup; +class ObjectManipulation; using t_optgroups = std::vector >; @@ -30,14 +31,14 @@ public: void update_presets(Slic3r::Preset::Type preset_type); - void add_frequently_changed_parameters(wxWindow* parent, wxBoxSizer* sizer); - void add_objects_list(wxWindow* parent, wxBoxSizer* sizer); - void add_object_settings(wxWindow* parent, wxBoxSizer* sizer, t_optgroups& optgroups); + ObjectManipulation* obj_manipul(); - - ConfigOptionsGroup* get_optgroup(size_t i); - t_optgroups& get_optgroups(); + ConfigOptionsGroup* get_optgroup(size_t i); // #ys_FIXME_for_delete + t_optgroups& get_optgroups();// #ys_FIXME_for_delete wxButton* get_wiping_dialog_button(); + void update_objects_list_extruder_column(int extruders_count); + int get_ol_selection(); + private: struct priv; std::unique_ptr p; @@ -57,6 +58,7 @@ public: ~Plater(); Sidebar& sidebar(); + Model& model(); // TODO: use fs::path // Note: empty string means request default path diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 07063a6bb..7a13f6df7 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -33,9 +33,9 @@ namespace Slic3r { namespace GUI { -void Tab::create_preset_tab(PresetBundle *preset_bundle) +void Tab::create_preset_tab() { - m_preset_bundle = preset_bundle; + m_preset_bundle = wxGetApp().preset_bundle; // Vertical sizer to hold the choice menu and the rest of the page. #ifdef __WXOSX__ @@ -711,7 +711,7 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) // Show/hide the 'purging volumes' button void Tab::update_wiping_button_visibility() { - if (wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA) + if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA) return; // ys_FIXME bool wipe_tower_enabled = dynamic_cast( (m_preset_bundle->prints.get_edited_preset().config ).option("wipe_tower"))->value; bool multiple_extruders = dynamic_cast((m_preset_bundle->printers.get_edited_preset().config).option("nozzle_diameter"))->values.size() > 1; @@ -1044,7 +1044,7 @@ void TabPrint::reload_config(){ void TabPrint::update() { - if (wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA) + if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA) return; // ys_FIXME Freeze(); @@ -1410,7 +1410,7 @@ void TabFilament::reload_config(){ void TabFilament::update() { - if (wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA) + if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA) return; // ys_FIXME Freeze(); @@ -1842,7 +1842,8 @@ void TabPrinter::extruders_count_changed(size_t extruders_count){ build_extruder_pages(); reload_config(); on_value_change("extruders_count", extruders_count); - update_objects_list_extruder_column(extruders_count); + if (wxGetApp().mainframe) + wxGetApp().mainframe->m_plater->sidebar().update_objects_list_extruder_column(extruders_count); } void TabPrinter::append_option_line(ConfigOptionsGroupShp optgroup, const std::string opt_key) @@ -3030,7 +3031,7 @@ void TabSLAMaterial::build() void TabSLAMaterial::update() { - if (wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology() == ptFFF) + if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptFFF) return; // ys_FIXME } diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index afdf2008b..c9fb1764c 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -215,7 +215,7 @@ public: void set_event_value_change(wxEventType evt) { m_event_value_change = evt; } void set_event_presets_changed(wxEventType evt) { m_event_presets_changed = evt; } - void create_preset_tab(PresetBundle *preset_bundle); + void create_preset_tab(); void load_current_preset(); void rebuild_page_tree(bool tree_sel_change_event = false); void select_preset(std::string preset_name = "");