diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 94f01e25d..d2a7a23b1 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -594,7 +594,7 @@ sub new { $self->on_process_completed($event->GetInt ? undef : $event->GetString); }); -# XXX: ??? +# XXX: not done { my $timer_id = Wx::NewId(); $self->{apply_config_timer} = Wx::Timer->new($self, $timer_id); @@ -1179,7 +1179,7 @@ sub reset { $self->update; } -# XXX: not done +# XXX: VK: done sub increase { my ($self, $copies) = @_; $copies //= 1; @@ -1211,7 +1211,7 @@ sub increase { $self->schedule_background_process; } -# XXX: not done +# XXX: VK: done sub decrease { my ($self, $copies_asked) = @_; my $copies = $copies_asked // 1; @@ -1239,7 +1239,7 @@ sub decrease { $self->update; } -# XXX: not done +# XXX: VK: done sub set_number_of_copies { my ($self) = @_; # get current number of copies @@ -1258,8 +1258,8 @@ sub set_number_of_copies { } } -# XXX: not done (?) -sub _get_number_from_user { # XXX: Enrico +# XXX: VK: removed +sub _get_number_from_user { my ($self, $title, $prompt_message, $error_message, $default, $only_positive) = @_; for (;;) { my $value = Wx::GetTextFromUser($prompt_message, $title, $default, $self); @@ -1457,7 +1457,7 @@ sub changescale { $self->update; } -# XXX: not done +# XXX: VK: WIP sub arrange { my ($self) = @_; @@ -2057,7 +2057,7 @@ sub update { $self->Thaw; } -# XXX: done in sidebar? +# XXX: YS: done # When a printer technology is changed, the UI needs to be updated to show/hide needed preset combo boxes. sub show_preset_comboboxes{ my ($self, $showSLA) = @_; #if showSLA is oposite value to "ptFFF" @@ -2076,7 +2076,7 @@ sub show_preset_comboboxes{ $self->Layout; } -# XXX: not done +# XXX: YS: done # When a number of extruders changes, the UI needs to be updated to show a single filament selection combo box per extruder. # Also the wxTheApp->{preset_bundle}->filament_presets needs to be resized accordingly # and some reasonable default has to be selected for the additional extruders. @@ -2188,7 +2188,7 @@ sub on_config_change { $self->schedule_background_process; } -# XXX: not done +# XXX: YS: WIP sub item_changed_selection { my ($self, $obj_idx) = @_; @@ -2214,7 +2214,7 @@ sub collect_selections { return $selections; } -# XXX: not done +# XXX: YS: done, lambda on LEFT_DOWN # Called when clicked on the filament preset combo box. # When clicked on the icon, show the color picker. sub filament_color_box_lmouse_down @@ -2268,7 +2268,7 @@ sub filament_color_box_lmouse_down # } #} -# XXX: not done +# XXX: YS: done sub changed_object_settings { my ($self, $obj_idx, $parts_changed, $part_settings_changed) = @_; @@ -2464,7 +2464,7 @@ sub select_object { $self->selection_changed(1); } -# XXX: not done +# XXX: YS: WIP sub select_object_from_cpp { my ($self, $obj_idx, $vol_idx) = @_; diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 88e4c551a..e0cf14a57 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -609,6 +609,15 @@ ModelInstance* ModelObject::add_instance(const ModelInstance &other) return i; } +ModelInstance* ModelObject::add_instance(const Vec3d &offset, const Vec3d &scaling_factor, const Vec3d &rotation) +{ + auto *instance = add_instance(); + instance->set_offset(offset); + instance->set_scaling_factor(scaling_factor); + instance->set_rotation(rotation); + return instance; +} + void ModelObject::delete_instance(size_t idx) { ModelInstancePtrs::iterator i = this->instances.begin() + idx; diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index d9abc109a..695de6127 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -96,6 +96,7 @@ public: ModelInstance* add_instance(); ModelInstance* add_instance(const ModelInstance &instance); + ModelInstance* add_instance(const Vec3d &offset, const Vec3d &scaling_factor, const Vec3d &rotation); void delete_instance(size_t idx); void delete_last_instance(); void clear_instances(); diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index a646ab8fd..5bbeb3f6a 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -416,7 +416,8 @@ public: const PrintObjectConfig& default_object_config() const { return m_default_object_config; } const PrintRegionConfig& default_region_config() const { return m_default_region_config; } const PrintObjectPtrs& objects() const { return m_objects; } - const PrintObject* get_object(int idx) const { return m_objects[idx]; } + PrintObject* get_object(size_t idx) { return m_objects[idx]; } + const PrintObject* get_object(size_t idx) const { return m_objects[idx]; } const PrintRegionPtrs& regions() const { return m_regions; } const PlaceholderParser& placeholder_parser() const { return m_placeholder_parser; } PlaceholderParser& placeholder_parser() { return m_placeholder_parser; } diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index aa2041a36..ed2646b69 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -106,6 +106,8 @@ public: void select_tab(size_t tab) const; void select_view(const std::string& direction); + AppController* app_controller() { return m_appController; } + std::vector& get_preset_tabs(); Plater* m_plater { nullptr }; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 3af670d59..f2d42806c 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -31,6 +31,7 @@ #include "libslic3r/Format/STL.hpp" #include "libslic3r/Format/AMF.hpp" #include "libslic3r/Format/3mf.hpp" +#include "slic3r/AppController.hpp" #include "GUI.hpp" #include "GUI_App.hpp" #include "GUI_ObjectList.hpp" @@ -756,9 +757,6 @@ struct Plater::priv void remove(size_t obj_idx); void reset(); - void increase(size_t num = 1); - void decrease(size_t num = 1); - void set_number_of_copies(); void rotate(); void mirror(const Axis &axis); void scale(); @@ -781,9 +779,6 @@ struct Plater::priv void on_layer_editing_toggled(bool enable); void on_action_add(SimpleEvent&); - void on_action_arrange(SimpleEvent&); - void on_action_more(SimpleEvent&); - void on_action_fewer(SimpleEvent&); void on_action_split(SimpleEvent&); void on_action_cut(SimpleEvent&); void on_action_settings(SimpleEvent&); @@ -886,7 +881,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) : canvas3D->Bind(EVT_GLCANVAS_ARRANGE, [this](SimpleEvent&) { arrange(); }); canvas3D->Bind(EVT_GLCANVAS_ROTATE_OBJECT, [this](Event &evt) { /*TODO: call rotate */ }); canvas3D->Bind(EVT_GLCANVAS_SCALE_UNIFORMLY, [this](SimpleEvent&) { scale(); }); - canvas3D->Bind(EVT_GLCANVAS_INCREASE_OBJECTS, [this](Event &evt) { evt.data == 1 ? increase() : decrease(); }); + canvas3D->Bind(EVT_GLCANVAS_INCREASE_OBJECTS, [q](Event &evt) { evt.data == 1 ? q->increase() : q->decrease(); }); canvas3D->Bind(EVT_GLCANVAS_INSTANCE_MOVED, [this](SimpleEvent&) { update(); }); canvas3D->Bind(EVT_GLCANVAS_WIPETOWER_MOVED, &priv::on_wipetower_moved, this); canvas3D->Bind(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, &priv::on_enable_action_buttons, this); @@ -895,9 +890,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) : canvas3D->Bind(EVT_GLTOOLBAR_ADD, &priv::on_action_add, this); canvas3D->Bind(EVT_GLTOOLBAR_DELETE, [q](SimpleEvent&) { q->remove_selected(); } ); canvas3D->Bind(EVT_GLTOOLBAR_DELETE_ALL, [this](SimpleEvent&) { reset(); }); - canvas3D->Bind(EVT_GLTOOLBAR_ARRANGE, &priv::on_action_arrange, this); - canvas3D->Bind(EVT_GLTOOLBAR_MORE, &priv::on_action_more, this); - canvas3D->Bind(EVT_GLTOOLBAR_FEWER, &priv::on_action_fewer, this); + canvas3D->Bind(EVT_GLTOOLBAR_ARRANGE, [this](SimpleEvent&) { arrange(); }); + canvas3D->Bind(EVT_GLTOOLBAR_MORE, [q](SimpleEvent&) { q->increase(); }); + canvas3D->Bind(EVT_GLTOOLBAR_FEWER, [q](SimpleEvent&) { q->decrease(); }); canvas3D->Bind(EVT_GLTOOLBAR_SPLIT, &priv::on_action_split, this); canvas3D->Bind(EVT_GLTOOLBAR_CUT, &priv::on_action_cut, this); canvas3D->Bind(EVT_GLTOOLBAR_SETTINGS, &priv::on_action_settings, this); @@ -1388,21 +1383,6 @@ void Plater::priv::reset() update(); } -void Plater::priv::increase(size_t num) -{ - // TODO -} - -void Plater::priv::decrease(size_t num) -{ - // TODO -} - -void Plater::priv::set_number_of_copies() -{ - // TODO -} - void Plater::priv::rotate() { // TODO @@ -1438,7 +1418,14 @@ void Plater::priv::scale() void Plater::priv::arrange() { - // TODO + // $self->stop_background_process; + + main_frame->app_controller()->arrange_model(); + + // ignore arrange failures on purpose: user has visual feedback and we don't need to warn him + // when parts don't fit in print bed + + update(); } void Plater::priv::split_object() @@ -1574,21 +1561,6 @@ void Plater::priv::on_action_add(SimpleEvent&) load_files(input_paths); } -void Plater::priv::on_action_arrange(SimpleEvent&) -{ - // TODO -} - -void Plater::priv::on_action_more(SimpleEvent&) -{ - // TODO -} - -void Plater::priv::on_action_fewer(SimpleEvent&) -{ - // TODO -} - void Plater::priv::on_action_split(SimpleEvent&) { // TODO @@ -1717,6 +1689,8 @@ Plater::~Plater() Sidebar& Plater::sidebar() { return *p->sidebar; } Model& Plater::model() { return p->model; } +void Plater::load_files(const std::vector &input_files) { p->load_files(input_files); } + void Plater::update(bool force_autocenter) { p->update(force_autocenter); } void Plater::remove(size_t obj_idx) { p->remove(obj_idx); } @@ -1728,7 +1702,69 @@ void Plater::remove_selected() } } -void Plater::load_files(const std::vector &input_files) { p->load_files(input_files); } +void Plater::increase(size_t num) +{ + const auto obj_idx = p->selected_object(); + if (! obj_idx) { return; } + + auto *model_object = p->model.objects[*obj_idx]; + auto *model_instance = model_object->instances[model_object->instances.size() - 1]; + + // $self->stop_background_process; + + float offset = 10.0; + for (size_t i = 0; i < num; i++, offset += 10.0) { + Vec3d offset_vec = model_instance->get_offset() + Vec3d(offset, offset, 0.0); + auto *new_instance = model_object->add_instance(offset_vec, model_instance->get_scaling_factor(), model_instance->get_rotation()); + p->print.get_object(*obj_idx)->add_copy(Slic3r::to_2d(offset_vec)); + } + + sidebar().obj_list()->set_object_count(*obj_idx, model_object->instances.size()); + + if (p->get_config("autocenter") == "1") { + p->arrange(); + } else { + p->update(); + } + + p->selection_changed(); + + // $self->schedule_background_process; +} + +void Plater::decrease(size_t num) +{ + const auto obj_idx = p->selected_object(); + if (! obj_idx) { return; } + + auto *model_object = p->model.objects[*obj_idx]; + if (model_object->instances.size() > num) { + for (size_t i = 0; i < num; i++) { + model_object->delete_last_instance(); + p->print.get_object(*obj_idx)->delete_last_copy(); + } + sidebar().obj_list()->set_object_count(*obj_idx, model_object->instances.size()); + } else { + remove(*obj_idx); + } + + p->update(); +} + +void Plater::set_number_of_copies(size_t num) +{ + const auto obj_idx = p->selected_object(); + if (! obj_idx) { return; } + + auto *model_object = p->model.objects[*obj_idx]; + + auto diff = (ptrdiff_t)num - (ptrdiff_t)model_object->instances.size(); + if (diff > 0) { + increase(diff); + } else if (diff < 0) { + decrease(-diff); + } +} fs::path Plater::export_gcode(const fs::path &output_path) { diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index fd3c4e455..f8f24e2bc 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -93,11 +93,14 @@ public: Sidebar& sidebar(); Model& model(); + void load_files(const std::vector &input_files); + void update(bool force_autocenter = false); void remove(size_t obj_idx); void remove_selected(); - - void load_files(const std::vector &input_files); + void increase(size_t num = 1); + void decrease(size_t num = 1); + void set_number_of_copies(size_t num); // Note: empty path means "use the default" boost::filesystem::path export_gcode(const boost::filesystem::path &output_path = boost::filesystem::path());