From ceb295944aa8d77c7b2b20b9ae0d178a1f588b7d Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Mon, 8 Oct 2018 19:14:55 +0200 Subject: [PATCH] WIP: Plater, tracking in Plater.pm --- lib/Slic3r/GUI/Plater.pm | 60 +++++++++++++++++++++- src/slic3r/GUI/Plater.cpp | 103 +++++++++++++++++++++++++++----------- src/slic3r/GUI/Plater.hpp | 4 ++ 3 files changed, 136 insertions(+), 31 deletions(-) diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index b834bc202..de6b0d726 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -41,6 +41,7 @@ our $PROCESS_COMPLETED_EVENT = Wx::NewEventType; my $PreventListEvents = 0; our $appController; +# XXX: VK: done, except callback handling and timer sub new { my ($class, $parent, %params) = @_; my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); @@ -813,12 +814,14 @@ sub new { return $self; } +# XXX: VK: WIP # sets the callback sub on_select_preset { my ($self, $cb) = @_; $self->{on_select_preset} = $cb; } +# XXX: merged with on_select_preset # Called from the platter combo boxes selecting the active print, filament or printer. sub _on_select_preset { my ($self, $group, $choice, $idx) = @_; @@ -855,6 +858,7 @@ sub _on_select_preset { $self->on_config_change(wxTheApp->{preset_bundle}->full_config); } +# XXX: VK: done sub on_layer_editing_toggled { my ($self, $new_state) = @_; Slic3r::GUI::_3DScene::enable_layers_editing($self->{canvas3D}, $new_state); @@ -873,11 +877,13 @@ sub on_layer_editing_toggled { $self->{canvas3D}->Update; } -sub GetFrame { # XXX: main_frame in C++ Plater +# XXX: VK: done (Plater::priv::main_frame) +sub GetFrame { my ($self) = @_; return &Wx::GetTopLevelParent($self); } +# XXX: not done # Called after the Preferences dialog is closed and the program settings are saved. # Update the UI based on the current preferences. sub update_ui_from_settings @@ -889,6 +895,7 @@ sub update_ui_from_settings } } +# XXX: VK: done # Update preset combo boxes (Print settings, Filament, Material, Printer) from their respective tabs. # Called by # Slic3r::GUI::Tab::Print::_on_presets_changed @@ -934,12 +941,14 @@ sub update_presets { wxTheApp->{preset_bundle}->export_selections(wxTheApp->{app_config}); } +# XXX: VK: done, in on_action_add() sub add { my ($self) = @_; my @input_files = wxTheApp->open_model($self); $self->load_files(\@input_files); } +# XXX: VK: done sub load_files { my ($self, $input_files) = @_; @@ -1030,6 +1039,7 @@ sub load_files { return @obj_idx; } +# XXX: VK: done, except a few todos sub load_model_objects { my ($self, @model_objects) = @_; @@ -1112,6 +1122,7 @@ sub load_model_objects { return @obj_idx; } +# XXX: Removed sub bed_centerf { my ($self) = @_; @@ -1120,6 +1131,7 @@ sub bed_centerf { return Slic3r::Pointf->new(unscale($bed_center->x), unscale($bed_center->y)); #) } +# XXX: VK: done sub remove { my ($self, $obj_idx) = @_; @@ -1146,6 +1158,7 @@ sub remove { $self->update; } +# XXX: VK: done sub reset { my ($self) = @_; @@ -1166,6 +1179,7 @@ sub reset { $self->update; } +# XXX: not done sub increase { my ($self, $copies) = @_; $copies //= 1; @@ -1197,6 +1211,7 @@ sub increase { $self->schedule_background_process; } +# XXX: not done sub decrease { my ($self, $copies_asked) = @_; my $copies = $copies_asked // 1; @@ -1224,6 +1239,7 @@ sub decrease { $self->update; } +# XXX: not done sub set_number_of_copies { my ($self) = @_; # get current number of copies @@ -1242,6 +1258,7 @@ sub set_number_of_copies { } } +# XXX: not done (?) sub _get_number_from_user { # XXX: Enrico my ($self, $title, $prompt_message, $error_message, $default, $only_positive) = @_; for (;;) { @@ -1264,6 +1281,7 @@ sub _get_number_from_user { # XXX: Enrico } } +# XXX: not done sub rotate { my ($self, $angle, $axis, $relative_key, $axis_x, $axis_y, $axis_z) = @_; $relative_key //= 'absolute'; # relative or absolute coordinates @@ -1334,6 +1352,7 @@ sub rotate { $self->update; } +# XXX: not done sub mirror { my ($self, $axis) = @_; @@ -1363,6 +1382,7 @@ sub mirror { $self->update; } +# XXX: not done sub changescale { my ($self, $axis, $tosize) = @_; @@ -1437,6 +1457,7 @@ sub changescale { $self->update; } +# XXX: not done sub arrange { my ($self) = @_; @@ -1454,6 +1475,7 @@ sub arrange { $self->update(0); } +# XXX: not done sub split_object { my $self = shift; @@ -1485,6 +1507,7 @@ sub split_object { } } +# XXX: not done # Trigger $self->async_apply_config() after 500ms. # The call is delayed to avoid restarting the background processing during typing into an edit field. sub schedule_background_process { @@ -1492,6 +1515,7 @@ sub schedule_background_process { $self->{apply_config_timer}->Start(0.5 * 1000, 1); # 1 = one shot, every half a second. } +# XXX: not done # Executed asynchronously by a timer every PROCESS_DELAY (0.5 second). # The timer is started by schedule_background_process(), sub async_apply_config { @@ -1526,6 +1550,7 @@ sub async_apply_config { } } +# XXX: not done # Background processing is started either by the "Slice now" button, by the "Export G-code button" or by async_apply_config(). sub start_background_process { my ($self) = @_; @@ -1546,6 +1571,7 @@ sub start_background_process { $self->{background_slicing_process}->start; } +# XXX: not done # Stop the background processing sub stop_background_process { my ($self) = @_; @@ -1554,6 +1580,7 @@ sub stop_background_process { # $self->{preview3D}->reload_print if $self->{preview3D}; } +# XXX: not done # Called by the "Slice now" button, which is visible only if the background processing is disabled. sub reslice { # explicitly cancel a previous thread and start a new one. @@ -1574,6 +1601,7 @@ sub reslice { } } +# XXX: VK: done sub export_gcode { my ($self, $output_file) = @_; @@ -1654,6 +1682,7 @@ sub export_gcode { return $self->{export_gcode_output_file}; } +# XXX: not done # This message should be called by the background process synchronously. sub on_update_print_preview { my ($self) = @_; @@ -1666,6 +1695,7 @@ sub on_update_print_preview { Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 1); } +# XXX: not done # This gets called also if we have no threads. sub on_progress_event { my ($self, $percent, $message) = @_; @@ -1676,6 +1706,7 @@ sub on_progress_event { $self->statusbar->SetStatusText("$message..."); } +# XXX: not done # Called when the G-code export finishes, either successfully or with an error. # This gets called also if we don't have threads. sub on_process_completed { @@ -1743,6 +1774,7 @@ sub on_process_completed { # $self->{preview3D}->reload_print if $self->{preview3D}; } +# XXX: partially done in the Sidebar # Fill in the "Sliced info" box with the result of the G-code generator. sub print_info_box_show { my ($self, $show) = @_; @@ -1819,6 +1851,7 @@ sub print_info_box_show { $panel->Refresh; } +# XXX: not done - to be removed sub do_print { my ($self) = @_; @@ -1832,6 +1865,7 @@ sub do_print { $printer_panel->load_print_job($self->{print_file}, $filament_stats); } +# XXX: VK: done sub export_stl { my ($self) = @_; return if !@{$self->{objects}}; @@ -1842,6 +1876,7 @@ sub export_stl { $self->statusbar->SetStatusText(L("STL file exported to ").$output_file); } +# XXX: not done sub reload_from_disk { my ($self) = @_; @@ -1873,6 +1908,7 @@ sub reload_from_disk { $self->remove($obj_idx); } +# XXX: VK: done sub export_object_stl { my ($self) = @_; my ($obj_idx, $object) = $self->selected_object; @@ -1884,6 +1920,7 @@ sub export_object_stl { $self->statusbar->SetStatusText(L("STL file exported to ").$output_file); } +# XXX: not done sub fix_through_netfabb { my ($self) = @_; my ($obj_idx, $object) = $self->selected_object; @@ -1912,6 +1949,7 @@ sub fix_through_netfabb { $self->remove($obj_idx); } +# XXX: VK: WIP sub export_amf { my ($self) = @_; return if !@{$self->{objects}}; @@ -1928,6 +1966,7 @@ sub export_amf { } } +# XXX: VK: WIP sub export_3mf { my ($self) = @_; return if !@{$self->{objects}}; @@ -1944,6 +1983,7 @@ sub export_3mf { } } +# XXX: VK: done # Ask user to select an output file for a given file format (STl, AMF, 3MF). # Propose a default file name based on the 'output_filename_format' configuration value. sub _get_export_file { @@ -1993,6 +2033,7 @@ sub _get_export_file { # $self->{objects}[$obj_idx]->thumbnail(undef); #} +# XXX: VK: done # this method gets called whenever print center is changed or the objects' bounding box changes # (i.e. when an object is added/removed/moved/rotated/scaled) sub update { @@ -2016,6 +2057,7 @@ sub update { $self->Thaw; } +# XXX: done in sidebar? # 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" @@ -2034,6 +2076,7 @@ sub show_preset_comboboxes{ $self->Layout; } +# XXX: not 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. @@ -2078,6 +2121,7 @@ sub on_extruders_change { $self->Layout; } +# XXX: not done sub on_config_change { my ($self, $config) = @_; @@ -2144,6 +2188,7 @@ sub on_config_change { $self->schedule_background_process; } +# XXX: not done sub item_changed_selection { my ($self, $obj_idx) = @_; @@ -2159,6 +2204,7 @@ sub item_changed_selection { } } +# XXX: VK: done sub collect_selections { my ($self) = @_; my $selections = []; @@ -2168,6 +2214,7 @@ sub collect_selections { return $selections; } +# XXX: not done # Called when clicked on the filament preset combo box. # When clicked on the icon, show the color picker. sub filament_color_box_lmouse_down @@ -2221,6 +2268,7 @@ sub filament_color_box_lmouse_down # } #} +# XXX: not done sub changed_object_settings { my ($self, $obj_idx, $parts_changed, $part_settings_changed) = @_; @@ -2246,6 +2294,7 @@ sub changed_object_settings { } } +# XXX: VK: done # Called to update various buttons depending on whether there are any objects or # whether background processing (export of a G-code, sending to Octoprint, forced background re-slicing) is active. sub object_list_changed { @@ -2276,6 +2325,7 @@ sub object_list_changed { for grep $self->{"btn_$_"}, qw(reslice export_gcode print send_gcode); } +# XXX: VK: WIP # Selection of an active 3D object changed. sub selection_changed { my ($self) = @_; @@ -2393,6 +2443,7 @@ sub selection_changed { $self->{right_panel}->Thaw; } +# XXX: VK: done sub select_object { my ($self, $obj_idx, $child) = @_; @@ -2413,6 +2464,7 @@ sub select_object { $self->selection_changed(1); } +# XXX: not done sub select_object_from_cpp { my ($self, $obj_idx, $vol_idx) = @_; @@ -2457,16 +2509,19 @@ sub select_object_from_cpp { $self->selection_changed(1); } +# XXX: VK: done sub selected_object { my ($self) = @_; my $obj_idx = first { $self->{objects}[$_]->selected } 0..$#{ $self->{objects} }; return defined $obj_idx ? ($obj_idx, $self->{objects}[$obj_idx]) : undef; } +# XXX: VK: done sub statusbar { return $_[0]->GetFrame->{statusbar}; } +# XXX: not done, to be removed (?) sub object_menu { my ($self) = @_; @@ -2577,6 +2632,7 @@ sub object_menu { return $menu; } +# XXX: not done # Set a camera direction, zoom to all objects. sub select_view { my ($self, $direction) = @_; @@ -2594,6 +2650,8 @@ sub select_view { } } + +# XXX: VK: done, in PlaterDropTarget package Slic3r::GUI::Plater::DropTarget; use Wx::DND; use base 'Wx::FileDropTarget'; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index b4b0cb726..1b6f9ad0d 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -566,6 +566,13 @@ void Sidebar::show_buttons(const bool show) } } +void Sidebar::enable_buttons(bool enable) +{ + p->btn_reslice->Enable(enable); + p->btn_export_gcode->Enable(enable); + p->btn_send_gcode->Enable(enable); +} + // Plater::Object struct PlaterObject @@ -587,13 +594,28 @@ public: private: Plater *plater; + + static const std::regex pattern_drop; }; +const std::regex PlaterDropTarget::pattern_drop("[.](stl|obj|amf|3mf|prusa)$", std::regex::icase); + bool PlaterDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString &filenames) { - // TODO - // return false; - throw 0; + std::vector paths; + + for (const auto &filename : filenames) { + fs::path path(filename); + + if (std::regex_match(path.string(), pattern_drop)) { + paths.push_back(std::move(path)); + } else { + return false; + } + } + + plater->load_files(paths); + return true; } // Plater / private @@ -643,7 +665,9 @@ struct Plater::priv void select_object(optional obj_idx); optional selected_object() const; void selection_changed(); + void object_list_changed(); + void remove(size_t obj_idx); void reset(); void on_notebook_changed(wxBookCtrlEvent &); @@ -1081,8 +1105,16 @@ void Plater::priv::select_object(optional obj_idx) objects[*obj_idx].selected = true; } - // TODO: - // $self->selection_changed(1); + selection_changed(); +} + +optional Plater::priv::selected_object() const +{ + for (size_t i = 0; i < objects.size(); i++) { + if (objects[i].selected) { return i; } + } + + return boost::none; } void Plater::priv::selection_changed() @@ -1107,12 +1139,9 @@ void Plater::priv::selection_changed() bool can_select_by_parts = false; if (have_sel) { - // my $model_object = $self->{model}->objects->[$obj_idx]; const auto *model_object = model.objects[*obj_idx]; - // $can_select_by_parts = ($obj_idx >= 0) && ($obj_idx < 1000) && ($model_object->volumes_count > 1); // XXX: ? can_select_by_parts = *obj_idx < 1000 && model_object->volumes.size() > 1; - // Slic3r::GUI::_3DScene::enable_toolbar_item($self->{canvas3D}, "fewer", $model_object->instances_count > 1); _3DScene::enable_toolbar_item(canvas3D, "fewer", model_object->instances.size() > 1); } @@ -1170,20 +1199,43 @@ void Plater::priv::selection_changed() q->Layout(); } -optional Plater::priv::selected_object() const +void Plater::priv::object_list_changed() { - for (size_t i = 0; i < objects.size(); i++) { - if (objects[i].selected) { return i; } - } + // Enable/disable buttons depending on whether there are any objects on the platter. + const bool have_objects = !objects.empty(); - return boost::none; + _3DScene::enable_toolbar_item(canvas3D, "deleteall", have_objects); + _3DScene::enable_toolbar_item(canvas3D, "arrange", have_objects); + + const bool export_in_progress = !(export_gcode_output_file.empty() && send_gcode_file.empty()); + // XXX: is this right? + const bool model_fits = _3DScene::check_volumes_outside_state(canvas3D, config) == ModelInstance::PVS_Inside; + + sidebar->enable_buttons(have_objects && !export_in_progress && model_fits); +} + +void Plater::priv::remove(size_t obj_idx) +{ + // $self->stop_background_process; // TODO + + // Prevent toolpaths preview from rendering while we modify the Print object + preview->set_enabled(false); + + objects.erase(objects.begin() + obj_idx); + model.delete_object(obj_idx); + print.delete_object(obj_idx); + // Delete object from Sidebar list + sidebar->obj_list()->delete_object_from_list(); + + object_list_changed(); + + select_object(boost::none); + update(); } void Plater::priv::reset() { - // TODO - - // $self->stop_background_process; + // $self->stop_background_process; // TODO // Prevent toolpaths preview from rendering while we modify the Print object preview->set_enabled(false); @@ -1193,13 +1245,10 @@ void Plater::priv::reset() print.clear_objects(); // Delete all objects from list on c++ side - // TODO - // Slic3r::GUI::delete_all_objects_from_list(); sidebar->obj_list()->delete_all_objects_from_list(); - // $self->object_list_changed; + object_list_changed(); - // TODO - // $self->select_object(undef); + select_object(boost::none); update(); } @@ -1350,15 +1399,8 @@ Plater::~Plater() Sidebar& Plater::sidebar() { return *p->sidebar; } Model& Plater::model() { return p->model; } -void Plater::update(bool force_autocenter) -{ - p->update(force_autocenter); -} - -void Plater::remove(size_t obj_idx) -{ - // TODO -} +void Plater::update(bool force_autocenter) { p->update(force_autocenter); } +void Plater::remove(size_t obj_idx) { p->remove(obj_idx); } void Plater::remove_selected() { @@ -1368,6 +1410,7 @@ void Plater::remove_selected() } } +void Plater::load_files(const std::vector &input_files) { p->load_files(input_files); } 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 f449cc75f..17b911c04 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -2,6 +2,7 @@ #define slic3r_Plater_hpp_ #include +#include #include #include @@ -47,6 +48,7 @@ public: int get_ol_selection(); void show_info_sizers(const bool show); void show_buttons(const bool show); + void enable_buttons(bool enable); private: struct priv; @@ -71,6 +73,8 @@ public: void remove(size_t obj_idx); void remove_selected(); + void load_files(const std::vector &input_files); + // Note: empty path means "use the default" boost::filesystem::path export_gcode(const boost::filesystem::path &output_path = boost::filesystem::path()); void export_stl();