mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	Merge branch 'master' of https://github.com/prusa3d/Slic3r into et_canvas_gui_refactoring
This commit is contained in:
		
						commit
						aca78cfba2
					
				
					 11 changed files with 187 additions and 80 deletions
				
			
		|  | @ -80,9 +80,8 @@ public: | ||||||
| // Provokes static_assert in the right way.
 | // Provokes static_assert in the right way.
 | ||||||
| template<class T = void> struct VeryFalse { static const bool value = false; }; | template<class T = void> struct VeryFalse { static const bool value = false; }; | ||||||
| 
 | 
 | ||||||
| // This has to be explicitly implemented in the gui layer or a default zlib
 | // This can be explicitly implemented in the gui layer or the default Zipper
 | ||||||
| // based implementation is needed. I don't have time for that and I'm delegating
 | // API in libslic3r with minz.
 | ||||||
| // the implementation to the gui layer where the gui toolkit can cover this.
 |  | ||||||
| template<class Fmt> class LayerWriter { | template<class Fmt> class LayerWriter { | ||||||
| public: | public: | ||||||
| 
 | 
 | ||||||
|  | @ -91,21 +90,28 @@ public: | ||||||
|                       "No layer writer implementation provided!"); |                       "No layer writer implementation provided!"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     // Should create a new file within the zip with the given filename. It
 | ||||||
|  |     // should also finish any previous entry.
 | ||||||
|     void next_entry(const std::string& /*fname*/) {} |     void next_entry(const std::string& /*fname*/) {} | ||||||
| 
 | 
 | ||||||
|     // binary entry
 |     // Should create a new file within the archive and write the provided data.
 | ||||||
|     void binary_entry(const std::string& /*fname*/, |     void binary_entry(const std::string& /*fname*/, | ||||||
|                       const std::uint8_t* buf, size_t len); |                       const std::uint8_t* buf, size_t len); | ||||||
| 
 | 
 | ||||||
|  |     // Get the name of the archive but only the name part without the path or
 | ||||||
|  |     // the extension.
 | ||||||
|     std::string get_name() { return ""; } |     std::string get_name() { return ""; } | ||||||
| 
 | 
 | ||||||
|  |     // Test whether the object can still be used for writing.
 | ||||||
|     bool is_ok() { return false; } |     bool is_ok() { return false; } | ||||||
| 
 | 
 | ||||||
|  |     // Write some data (text) into the current file (entry) within the archive.
 | ||||||
|     template<class T> LayerWriter& operator<<(T&& /*arg*/) { |     template<class T> LayerWriter& operator<<(T&& /*arg*/) { | ||||||
|         return *this; |         return *this; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void close() {} |     // Flush the current entry into the archive.
 | ||||||
|  |     void finalize() {} | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| // Implementation for PNG raster output
 | // Implementation for PNG raster output
 | ||||||
|  | @ -267,7 +273,7 @@ public: | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             writer.close(); |             writer.finalize(); | ||||||
|         } catch(std::exception& e) { |         } catch(std::exception& e) { | ||||||
|             BOOST_LOG_TRIVIAL(error) << e.what(); |             BOOST_LOG_TRIVIAL(error) << e.what(); | ||||||
|             // Rethrow the exception
 |             // Rethrow the exception
 | ||||||
|  |  | ||||||
|  | @ -322,18 +322,18 @@ template<> class LayerWriter<SLAminzZipper> { | ||||||
|     Zipper m_zip; |     Zipper m_zip; | ||||||
| public: | public: | ||||||
| 
 | 
 | ||||||
|     inline LayerWriter(const std::string& zipfile_path): m_zip(zipfile_path) {} |     LayerWriter(const std::string& zipfile_path): m_zip(zipfile_path) {} | ||||||
| 
 | 
 | ||||||
|     inline void next_entry(const std::string& fname) { m_zip.add_entry(fname); } |     void next_entry(const std::string& fname) { m_zip.add_entry(fname); } | ||||||
| 
 | 
 | ||||||
|     inline void binary_entry(const std::string& fname, |     void binary_entry(const std::string& fname, | ||||||
|                              const std::uint8_t* buf, |                              const std::uint8_t* buf, | ||||||
|                              size_t l) |                              size_t l) | ||||||
|     { |     { | ||||||
|         m_zip.add_entry(fname, buf, l); |         m_zip.add_entry(fname, buf, l); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     inline std::string get_name() const { |     std::string get_name() const { | ||||||
|         return m_zip.get_name(); |         return m_zip.get_name(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -345,7 +345,11 @@ public: | ||||||
|         return true; // m_zip blows up if something goes wrong...
 |         return true; // m_zip blows up if something goes wrong...
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     inline void close() { m_zip.close(); } |     // After finalize, no writing to the archive will have an effect. The only
 | ||||||
|  |     // valid operation is to dispose the object calling the destructor which
 | ||||||
|  |     // should close the file. This method can throw and signal potential errors
 | ||||||
|  |     // when flushing the archive. This is why its present.
 | ||||||
|  |     void finalize() { m_zip.finalize(); } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  |  | ||||||
|  | @ -111,6 +111,11 @@ public: | ||||||
|     { |     { | ||||||
|         throw std::runtime_error(formatted_errorstr()); |         throw std::runtime_error(formatted_errorstr()); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     bool is_alive() | ||||||
|  |     { | ||||||
|  |         return arch.m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; | ||||||
|  |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| Zipper::Zipper(const std::string &zipfname, e_compression compression) | Zipper::Zipper(const std::string &zipfname, e_compression compression) | ||||||
|  | @ -129,11 +134,19 @@ Zipper::Zipper(const std::string &zipfname, e_compression compression) | ||||||
| 
 | 
 | ||||||
| Zipper::~Zipper() | Zipper::~Zipper() | ||||||
| { | { | ||||||
|     try { |     if(m_impl->is_alive()) { | ||||||
|         close(); |         // Flush the current entry if not finished yet.
 | ||||||
|     } catch(...) { |         try { finish_entry(); } catch(...) { | ||||||
|             BOOST_LOG_TRIVIAL(error) << m_impl->formatted_errorstr(); |             BOOST_LOG_TRIVIAL(error) << m_impl->formatted_errorstr(); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         if(!mz_zip_writer_finalize_archive(&m_impl->arch)) | ||||||
|  |             BOOST_LOG_TRIVIAL(error) << m_impl->formatted_errorstr(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // The file should be closed no matter what...
 | ||||||
|  |     if(!mz_zip_writer_end(&m_impl->arch)) | ||||||
|  |         BOOST_LOG_TRIVIAL(error) << m_impl->formatted_errorstr(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Zipper::Zipper(Zipper &&m): | Zipper::Zipper(Zipper &&m): | ||||||
|  | @ -152,12 +165,16 @@ Zipper &Zipper::operator=(Zipper &&m) { | ||||||
| 
 | 
 | ||||||
| void Zipper::add_entry(const std::string &name) | void Zipper::add_entry(const std::string &name) | ||||||
| { | { | ||||||
|  |     if(!m_impl->is_alive()) return; | ||||||
|  | 
 | ||||||
|     finish_entry(); // finish previous business
 |     finish_entry(); // finish previous business
 | ||||||
|     m_entry = name; |     m_entry = name; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Zipper::add_entry(const std::string &name, const uint8_t *data, size_t l) | void Zipper::add_entry(const std::string &name, const uint8_t *data, size_t l) | ||||||
| { | { | ||||||
|  |     if(!m_impl->is_alive()) return; | ||||||
|  | 
 | ||||||
|     finish_entry(); |     finish_entry(); | ||||||
|     mz_uint cmpr = MZ_NO_COMPRESSION; |     mz_uint cmpr = MZ_NO_COMPRESSION; | ||||||
|     switch (m_compression) { |     switch (m_compression) { | ||||||
|  | @ -175,7 +192,9 @@ void Zipper::add_entry(const std::string &name, const uint8_t *data, size_t l) | ||||||
| 
 | 
 | ||||||
| void Zipper::finish_entry() | void Zipper::finish_entry() | ||||||
| { | { | ||||||
|     if(!m_data.empty() > 0 && !m_entry.empty()) { |     if(!m_impl->is_alive()) return; | ||||||
|  | 
 | ||||||
|  |     if(!m_data.empty() && !m_entry.empty()) { | ||||||
|         mz_uint compression = MZ_NO_COMPRESSION; |         mz_uint compression = MZ_NO_COMPRESSION; | ||||||
| 
 | 
 | ||||||
|         switch (m_compression) { |         switch (m_compression) { | ||||||
|  | @ -198,12 +217,12 @@ std::string Zipper::get_name() const { | ||||||
|     return boost::filesystem::path(m_impl->m_zipname).stem().string(); |     return boost::filesystem::path(m_impl->m_zipname).stem().string(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Zipper::close() | void Zipper::finalize() | ||||||
| { | { | ||||||
|     finish_entry(); |     finish_entry(); | ||||||
| 
 | 
 | ||||||
|     if(!mz_zip_writer_finalize_archive(&m_impl->arch)) m_impl->blow_up(); |     if(m_impl->is_alive()) if(!mz_zip_writer_finalize_archive(&m_impl->arch)) | ||||||
|     if(!mz_zip_writer_end(&m_impl->arch)) m_impl->blow_up(); |         m_impl->blow_up(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -47,6 +47,7 @@ public: | ||||||
|     void add_entry(const std::string& name); |     void add_entry(const std::string& name); | ||||||
| 
 | 
 | ||||||
|     /// Add a new binary file entry with an instantly given byte buffer.
 |     /// Add a new binary file entry with an instantly given byte buffer.
 | ||||||
|  |     /// This method throws exactly like finish_entry() does.
 | ||||||
|     void add_entry(const std::string& name, const std::uint8_t* data, size_t l); |     void add_entry(const std::string& name, const std::uint8_t* data, size_t l); | ||||||
| 
 | 
 | ||||||
|     // Writing data to the archive works like with standard streams. The target
 |     // Writing data to the archive works like with standard streams. The target
 | ||||||
|  | @ -74,12 +75,16 @@ public: | ||||||
|     /// buffer and ones an entry is added, the buffer will bind to the new entry
 |     /// buffer and ones an entry is added, the buffer will bind to the new entry
 | ||||||
|     /// If the buffer was written, but no entry was added, the buffer will be
 |     /// If the buffer was written, but no entry was added, the buffer will be
 | ||||||
|     /// cleared after this call.
 |     /// cleared after this call.
 | ||||||
|  |     ///
 | ||||||
|  |     /// This method will throw a runtime exception if an error occures. The
 | ||||||
|  |     /// entry will still be open (with the data intact) but the state of the
 | ||||||
|  |     /// file is up to minz after the erroneous write.
 | ||||||
|     void finish_entry(); |     void finish_entry(); | ||||||
| 
 | 
 | ||||||
|     /// Gets the name of the archive without the path or extension.
 |     /// Gets the name of the archive without the path or extension.
 | ||||||
|     std::string get_name() const; |     std::string get_name() const; | ||||||
| 
 | 
 | ||||||
|     void close(); |     void finalize(); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -649,20 +649,16 @@ void GUI_App::add_config_menu(wxMenuBar *menu) | ||||||
|         } |         } | ||||||
|         case ConfigMenuLanguage: |         case ConfigMenuLanguage: | ||||||
|         { |         { | ||||||
|             /* Before change application language, let's check unsaved changes
 |             /* Before change application language, let's check unsaved changes on 3D-Scene
 | ||||||
|              * and draw user's attention to the application restarting after a language change |              * and draw user's attention to the application restarting after a language change | ||||||
|              */ |              */ | ||||||
|             wxMessageDialog dialog(nullptr, |             wxMessageDialog dialog(nullptr, | ||||||
|                 _(L("Application will be restarted after language change, " |                 _(L("Application will be restarted after language change.")) + "\n" + | ||||||
|                     "and 3D-Scene will be cleaned.")) + "\n" + |                 _(L("3D-Scene will be cleaned.")) + "\n\n" + | ||||||
|                 _(L("Please, check your changes before.")) + "\n\n" + |                 _(L("Please, check your changes before.")), | ||||||
|                 _(L("Continue anyway?")), |  | ||||||
|                 _(L("Attention!")), |                 _(L("Attention!")), | ||||||
|                 wxICON_QUESTION | wxYES_NO | wxNO_DEFAULT); |                 wxICON_QUESTION | wxOK | wxCANCEL); | ||||||
|             if ( dialog.ShowModal() != wxID_YES) |             if ( dialog.ShowModal() == wxID_CANCEL) | ||||||
|                 return; |  | ||||||
| 
 |  | ||||||
|             if (!wxGetApp().check_unsaved_changes()) |  | ||||||
|                 return; |                 return; | ||||||
| 
 | 
 | ||||||
|             wxArrayString names; |             wxArrayString names; | ||||||
|  |  | ||||||
|  | @ -228,6 +228,21 @@ int ObjectList::get_selected_obj_idx() const | ||||||
|     return -1; |     return -1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | DynamicPrintConfig& ObjectList::get_item_config(const wxDataViewItem& item) const  | ||||||
|  | { | ||||||
|  |     assert(item); | ||||||
|  |     const ItemType type = m_objects_model->GetItemType(item); | ||||||
|  | 
 | ||||||
|  |     const int obj_idx = type & itObject ? m_objects_model->GetIdByItem(item) : | ||||||
|  |         m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item)); | ||||||
|  | 
 | ||||||
|  |     const int vol_idx = type & itVolume ? m_objects_model->GetVolumeIdByItem(item) : -1; | ||||||
|  | 
 | ||||||
|  |     assert(obj_idx >= 0 || ((type & itVolume) && vol_idx >=0)); | ||||||
|  |     return type & itObject|itInstance ? (*m_objects)[obj_idx]->config : | ||||||
|  |         (*m_objects)[obj_idx]->volumes[vol_idx]->config; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| wxDataViewColumn* ObjectList::create_objects_list_extruder_column(int extruders_count) | wxDataViewColumn* ObjectList::create_objects_list_extruder_column(int extruders_count) | ||||||
| { | { | ||||||
|     wxArrayString choices; |     wxArrayString choices; | ||||||
|  | @ -910,8 +925,10 @@ wxMenuItem* ObjectList::append_menu_item_split(wxMenu* menu) | ||||||
| wxMenuItem* ObjectList::append_menu_item_settings(wxMenu* menu_)  | wxMenuItem* ObjectList::append_menu_item_settings(wxMenu* menu_)  | ||||||
| { | { | ||||||
|     PrusaMenu* menu = dynamic_cast<PrusaMenu*>(menu_); |     PrusaMenu* menu = dynamic_cast<PrusaMenu*>(menu_); | ||||||
|  | 
 | ||||||
|  |     const wxString menu_name = _(L("Add settings")); | ||||||
|     // Delete old items from settings popupmenu
 |     // Delete old items from settings popupmenu
 | ||||||
|     auto settings_id = menu->FindItem(_("Add settings")); |     auto settings_id = menu->FindItem(menu_name); | ||||||
|     if (settings_id != wxNOT_FOUND) |     if (settings_id != wxNOT_FOUND) | ||||||
|         menu->Destroy(settings_id); |         menu->Destroy(settings_id); | ||||||
| 
 | 
 | ||||||
|  | @ -966,13 +983,9 @@ wxMenuItem* ObjectList::append_menu_item_settings(wxMenu* menu_) | ||||||
|     menu->m_separator_scnd = menu->AppendSeparator(); |     menu->m_separator_scnd = menu->AppendSeparator(); | ||||||
| 
 | 
 | ||||||
|     // Add full settings list
 |     // Add full settings list
 | ||||||
|     auto  menu_item = new wxMenuItem(menu, wxID_ANY, _(L("Add settings"))); |     auto  menu_item = new wxMenuItem(menu, wxID_ANY, menu_name); | ||||||
|     menu_item->SetBitmap(m_bmp_cog); |     menu_item->SetBitmap(m_bmp_cog); | ||||||
| 
 | 
 | ||||||
| //     const auto sel_vol = get_selected_model_volume();
 |  | ||||||
| //     if (sel_vol && sel_vol->type() >= ModelVolumeType::SUPPORT_ENFORCER)
 |  | ||||||
| //         menu_item->Enable(false);
 |  | ||||||
| //     else
 |  | ||||||
|     menu_item->SetSubMenu(create_settings_popupmenu(menu)); |     menu_item->SetSubMenu(create_settings_popupmenu(menu)); | ||||||
| 
 | 
 | ||||||
|     return menu->Append(menu_item); |     return menu->Append(menu_item); | ||||||
|  | @ -1018,6 +1031,37 @@ void ObjectList::append_menu_item_export_stl(wxMenu* menu) const | ||||||
|     menu->AppendSeparator(); |     menu->AppendSeparator(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void ObjectList::append_menu_item_change_extruder(wxMenu* menu) const | ||||||
|  | { | ||||||
|  |     const wxString name = _(L("Change extruder")); | ||||||
|  |     // Delete old menu item
 | ||||||
|  |     const int item_id = menu->FindItem(name); | ||||||
|  |     if (item_id != wxNOT_FOUND) | ||||||
|  |         menu->Destroy(item_id); | ||||||
|  | 
 | ||||||
|  |     const int extruders_cnt = extruders_count(); | ||||||
|  |     const wxDataViewItem item = GetSelection(); | ||||||
|  |     if (item && extruders_cnt > 1) | ||||||
|  |     { | ||||||
|  |         DynamicPrintConfig& config = get_item_config(item); | ||||||
|  | 
 | ||||||
|  |         const int initial_extruder = !config.has("extruder") ? 0 : | ||||||
|  |                                       config.option<ConfigOptionInt>("extruder")->value; | ||||||
|  | 
 | ||||||
|  |         wxMenu* extruder_selection_menu = new wxMenu(); | ||||||
|  | 
 | ||||||
|  |         for (int i = 0; i <= extruders_cnt; i++) | ||||||
|  |         { | ||||||
|  |             const wxString& item_name = i == 0 ? _(L("Default")) : wxString::Format("%d", i); | ||||||
|  | 
 | ||||||
|  |             append_menu_radio_item(extruder_selection_menu, wxID_ANY, item_name, "", | ||||||
|  |                 [this, i](wxCommandEvent&) { set_extruder_for_selected_items(i); }, menu)->Check(i == initial_extruder); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         menu->AppendSubMenu(extruder_selection_menu, name, _(L("Select new extruder for the object/part"))); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void ObjectList::create_object_popupmenu(wxMenu *menu) | void ObjectList::create_object_popupmenu(wxMenu *menu) | ||||||
| { | { | ||||||
| #ifdef __WXOSX__   | #ifdef __WXOSX__   | ||||||
|  | @ -1989,7 +2033,7 @@ void ObjectList::update_selections_on_canvas() | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     auto add_to_selection = [this](const wxDataViewItem& item, Selection& selection, bool as_single_selection) |     auto add_to_selection = [this](const wxDataViewItem& item, Selection& selection, int instance_idx, bool as_single_selection) | ||||||
|     { |     { | ||||||
|         if (m_objects_model->GetParent(item) == wxDataViewItem(0)) { |         if (m_objects_model->GetParent(item) == wxDataViewItem(0)) { | ||||||
|             selection.add_object(m_objects_model->GetIdByItem(item), as_single_selection); |             selection.add_object(m_objects_model->GetIdByItem(item), as_single_selection); | ||||||
|  | @ -1999,7 +2043,7 @@ void ObjectList::update_selections_on_canvas() | ||||||
|         if (m_objects_model->GetItemType(item) == itVolume) { |         if (m_objects_model->GetItemType(item) == itVolume) { | ||||||
|             const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetParent(item)); |             const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetParent(item)); | ||||||
|             const int vol_idx = m_objects_model->GetVolumeIdByItem(item); |             const int vol_idx = m_objects_model->GetVolumeIdByItem(item); | ||||||
|             selection.add_volume(obj_idx, vol_idx, 0, as_single_selection); |             selection.add_volume(obj_idx, vol_idx, std::max(instance_idx, 0), as_single_selection); | ||||||
|         } |         } | ||||||
|         else if (m_objects_model->GetItemType(item) == itInstance) { |         else if (m_objects_model->GetItemType(item) == itInstance) { | ||||||
|             const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item)); |             const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item)); | ||||||
|  | @ -2011,9 +2055,9 @@ void ObjectList::update_selections_on_canvas() | ||||||
|     if (sel_cnt == 1) { |     if (sel_cnt == 1) { | ||||||
|         wxDataViewItem item = GetSelection(); |         wxDataViewItem item = GetSelection(); | ||||||
|         if (m_objects_model->GetItemType(item) & (itSettings|itInstanceRoot)) |         if (m_objects_model->GetItemType(item) & (itSettings|itInstanceRoot)) | ||||||
|             add_to_selection(m_objects_model->GetParent(item), selection, true); |             add_to_selection(m_objects_model->GetParent(item), selection, -1, true); | ||||||
|         else |         else | ||||||
|             add_to_selection(item, selection, true); |             add_to_selection(item, selection, -1, true); | ||||||
| 
 | 
 | ||||||
|         wxGetApp().plater()->canvas3D()->update_gizmos_on_off_state(); |         wxGetApp().plater()->canvas3D()->update_gizmos_on_off_state(); | ||||||
|         return; |         return; | ||||||
|  | @ -2022,9 +2066,11 @@ void ObjectList::update_selections_on_canvas() | ||||||
|     wxDataViewItemArray sels; |     wxDataViewItemArray sels; | ||||||
|     GetSelections(sels); |     GetSelections(sels); | ||||||
| 
 | 
 | ||||||
|  |     // stores current instance idx before to clear the selection
 | ||||||
|  |     int instance_idx = selection.get_instance_idx(); | ||||||
|     selection.clear(); |     selection.clear(); | ||||||
|     for (auto item: sels) |     for (auto item: sels) | ||||||
|         add_to_selection(item, selection, false); |         add_to_selection(item, selection, instance_idx, false); | ||||||
| 
 | 
 | ||||||
|     wxGetApp().plater()->canvas3D()->update_gizmos_on_off_state(); |     wxGetApp().plater()->canvas3D()->update_gizmos_on_off_state(); | ||||||
| } | } | ||||||
|  | @ -2425,15 +2471,7 @@ void ObjectList::set_extruder_for_selected_items(const int extruder) const | ||||||
| 
 | 
 | ||||||
|     for (const wxDataViewItem& item : sels) |     for (const wxDataViewItem& item : sels) | ||||||
|     { |     { | ||||||
|         const ItemType type = m_objects_model->GetItemType(item); |         DynamicPrintConfig& config = get_item_config(item); | ||||||
| 
 |  | ||||||
|         const int obj_idx = type & itObject ? m_objects_model->GetIdByItem(item) : |  | ||||||
|                             m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item)); |  | ||||||
| 
 |  | ||||||
|         const int vol_idx = type & itVolume ? m_objects_model->GetVolumeIdByItem(item) : -1; |  | ||||||
| 
 |  | ||||||
|         DynamicPrintConfig& config = type & itObject ? (*m_objects)[obj_idx]->config :  |  | ||||||
|                                      (*m_objects)[obj_idx]->volumes[vol_idx]->config; |  | ||||||
|          |          | ||||||
|         if (config.has("extruder")) { |         if (config.has("extruder")) { | ||||||
|             if (extruder == 0) |             if (extruder == 0) | ||||||
|  | @ -2446,7 +2484,16 @@ void ObjectList::set_extruder_for_selected_items(const int extruder) const | ||||||
| 
 | 
 | ||||||
|         const wxString extruder_str = extruder == 0 ? wxString ("default") :  |         const wxString extruder_str = extruder == 0 ? wxString ("default") :  | ||||||
|                                       wxString::Format("%d", config.option<ConfigOptionInt>("extruder")->value); |                                       wxString::Format("%d", config.option<ConfigOptionInt>("extruder")->value); | ||||||
|         m_objects_model->SetValue(extruder_str, item, 1); | 
 | ||||||
|  |         auto const type = m_objects_model->GetItemType(item); | ||||||
|  | 
 | ||||||
|  |         /* We can change extruder for Object/Volume only.
 | ||||||
|  |          * So, if Instance is selected, get its Object item and change it | ||||||
|  |          */ | ||||||
|  |         m_objects_model->SetValue(extruder_str, type & itInstance ? m_objects_model->GetTopParent(item) : item, 1); | ||||||
|  | 
 | ||||||
|  |         const int obj_idx = type & itObject ? m_objects_model->GetIdByItem(item) : | ||||||
|  |                             m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item)); | ||||||
| 
 | 
 | ||||||
|         wxGetApp().plater()->canvas3D()->ensure_on_bed(obj_idx); |         wxGetApp().plater()->canvas3D()->ensure_on_bed(obj_idx); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -187,6 +187,7 @@ public: | ||||||
|     void                append_menu_items_osx(wxMenu* menu); |     void                append_menu_items_osx(wxMenu* menu); | ||||||
|     void                append_menu_item_fix_through_netfabb(wxMenu* menu); |     void                append_menu_item_fix_through_netfabb(wxMenu* menu); | ||||||
|     void                append_menu_item_export_stl(wxMenu* menu) const ; |     void                append_menu_item_export_stl(wxMenu* menu) const ; | ||||||
|  |     void                append_menu_item_change_extruder(wxMenu* menu) const; | ||||||
|     void                create_object_popupmenu(wxMenu *menu); |     void                create_object_popupmenu(wxMenu *menu); | ||||||
|     void                create_sla_object_popupmenu(wxMenu*menu); |     void                create_sla_object_popupmenu(wxMenu*menu); | ||||||
|     void                create_part_popupmenu(wxMenu*menu); |     void                create_part_popupmenu(wxMenu*menu); | ||||||
|  | @ -213,6 +214,7 @@ public: | ||||||
|     wxPoint             get_mouse_position_in_control(); |     wxPoint             get_mouse_position_in_control(); | ||||||
|     wxBoxSizer*         get_sizer() {return  m_sizer;} |     wxBoxSizer*         get_sizer() {return  m_sizer;} | ||||||
|     int                 get_selected_obj_idx() const; |     int                 get_selected_obj_idx() const; | ||||||
|  |     DynamicPrintConfig& get_item_config(const wxDataViewItem& item) const; | ||||||
|     bool                is_parts_changed() const { return m_parts_changed; } |     bool                is_parts_changed() const { return m_parts_changed; } | ||||||
|     bool                is_part_settings_changed() const { return m_part_settings_changed; } |     bool                is_part_settings_changed() const { return m_part_settings_changed; } | ||||||
|     void                part_settings_changed(); |     void                part_settings_changed(); | ||||||
|  |  | ||||||
|  | @ -28,7 +28,7 @@ MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &he | ||||||
| {} | {} | ||||||
| 
 | 
 | ||||||
| MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &headline, wxBitmap bitmap, wxWindowID button_id) : | MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &headline, wxBitmap bitmap, wxWindowID button_id) : | ||||||
| 	wxDialog(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxRESIZE_BORDER), | wxDialog(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER), | ||||||
| 	boldfont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)), | 	boldfont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)), | ||||||
| 	content_sizer(new wxBoxSizer(wxVERTICAL)), | 	content_sizer(new wxBoxSizer(wxVERTICAL)), | ||||||
| 	btn_sizer(new wxBoxSizer(wxHORIZONTAL)) | 	btn_sizer(new wxBoxSizer(wxHORIZONTAL)) | ||||||
|  |  | ||||||
|  | @ -427,7 +427,7 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent, const int label_width) : | ||||||
| 
 | 
 | ||||||
|     option = m_og->get_option("fill_density"); |     option = m_og->get_option("fill_density"); | ||||||
|     option.opt.label = L("Infill"); |     option.opt.label = L("Infill"); | ||||||
|     option.opt.width = 5 * wxGetApp().em_unit(); |     option.opt.width = 6 * wxGetApp().em_unit(); | ||||||
|     option.opt.sidetext = "     "; |     option.opt.sidetext = "     "; | ||||||
|     line.append_option(option); |     line.append_option(option); | ||||||
| 
 | 
 | ||||||
|  | @ -2624,6 +2624,11 @@ void Plater::priv::on_right_click(Vec2dEvent& evt) | ||||||
| 
 | 
 | ||||||
|     sidebar->obj_list()->append_menu_item_settings(menu); |     sidebar->obj_list()->append_menu_item_settings(menu); | ||||||
| 
 | 
 | ||||||
|  |     if (printer_technology != ptSLA) | ||||||
|  |         sidebar->obj_list()->append_menu_item_change_extruder(menu); | ||||||
|  | 
 | ||||||
|  |     if (menu != &part_menu) | ||||||
|  |     { | ||||||
|         /* Remove/Prepend "increase/decrease instances" menu items according to the view mode.
 |         /* Remove/Prepend "increase/decrease instances" menu items according to the view mode.
 | ||||||
|          * Suppress to show those items for a Simple mode |          * Suppress to show those items for a Simple mode | ||||||
|          */ |          */ | ||||||
|  | @ -2649,6 +2654,7 @@ void Plater::priv::on_right_click(Vec2dEvent& evt) | ||||||
|                 menu->Prepend(items_increase[id]); |                 menu->Prepend(items_increase[id]); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     if (q != nullptr) { |     if (q != nullptr) { | ||||||
| #ifdef __linux__ | #ifdef __linux__ | ||||||
|  |  | ||||||
|  | @ -61,6 +61,24 @@ wxMenuItem* append_submenu(wxMenu* menu, wxMenu* sub_menu, int id, const wxStrin | ||||||
|     return item; |     return item; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | wxMenuItem* append_menu_radio_item(wxMenu* menu, int id, const wxString& string, const wxString& description, | ||||||
|  |     std::function<void(wxCommandEvent& event)> cb, wxEvtHandler* event_handler) | ||||||
|  | { | ||||||
|  |     if (id == wxID_ANY) | ||||||
|  |         id = wxNewId(); | ||||||
|  | 
 | ||||||
|  |     wxMenuItem* item = menu->AppendRadioItem(id, string, description); | ||||||
|  | 
 | ||||||
|  | #ifdef __WXMSW__ | ||||||
|  |     if (event_handler != nullptr && event_handler != menu) | ||||||
|  |         event_handler->Bind(wxEVT_MENU, cb, id); | ||||||
|  |     else | ||||||
|  | #endif // __WXMSW__
 | ||||||
|  |         menu->Bind(wxEVT_MENU, cb, id); | ||||||
|  | 
 | ||||||
|  |     return item; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| const unsigned int wxCheckListBoxComboPopup::DefaultWidth = 200; | const unsigned int wxCheckListBoxComboPopup::DefaultWidth = 200; | ||||||
| const unsigned int wxCheckListBoxComboPopup::DefaultHeight = 200; | const unsigned int wxCheckListBoxComboPopup::DefaultHeight = 200; | ||||||
| const unsigned int wxCheckListBoxComboPopup::DefaultItemHeight = 18; | const unsigned int wxCheckListBoxComboPopup::DefaultItemHeight = 18; | ||||||
|  |  | ||||||
|  | @ -25,7 +25,11 @@ wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const | ||||||
| wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const wxString& description, | wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const wxString& description, | ||||||
|     std::function<void(wxCommandEvent& event)> cb, const std::string& icon = "", wxEvtHandler* event_handler = nullptr); |     std::function<void(wxCommandEvent& event)> cb, const std::string& icon = "", wxEvtHandler* event_handler = nullptr); | ||||||
| 
 | 
 | ||||||
| wxMenuItem* append_submenu(wxMenu* menu, wxMenu* sub_menu, int id, const wxString& string, const wxString& description, const std::string& icon = ""); | wxMenuItem* append_submenu(wxMenu* menu, wxMenu* sub_menu, int id, const wxString& string, const wxString& description,  | ||||||
|  |     const std::string& icon = ""); | ||||||
|  | 
 | ||||||
|  | wxMenuItem* append_menu_radio_item(wxMenu* menu, int id, const wxString& string, const wxString& description,  | ||||||
|  |     std::function<void(wxCommandEvent& event)> cb, wxEvtHandler* event_handler); | ||||||
| 
 | 
 | ||||||
| wxBitmap create_scaled_bitmap(const std::string& bmp_name); | wxBitmap create_scaled_bitmap(const std::string& bmp_name); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Enrico Turri
						Enrico Turri