This commit is contained in:
Vojtech Bubnik 2021-03-15 10:36:22 +01:00
commit fb9d537b58
14 changed files with 1376 additions and 1415 deletions

View file

@ -28,6 +28,7 @@ src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp
src/slic3r/GUI/GUI.cpp
src/slic3r/GUI/GUI_App.cpp
src/slic3r/GUI/GUI_Init.cpp
src/slic3r/GUI/GUI_Factories.cpp
src/slic3r/GUI/GUI_ObjectLayers.cpp
src/slic3r/GUI/GUI_ObjectList.cpp
src/slic3r/GUI/GUI_ObjectManipulation.cpp

View file

@ -1302,52 +1302,54 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b
void ModelObject::split(ModelObjectPtrs* new_objects)
{
if (this->volumes.size() > 1) {
// We can't split meshes if there's more than one volume, because
// we can't group the resulting meshes by object afterwards
new_objects->emplace_back(this);
return;
}
ModelVolume* volume = this->volumes.front();
TriangleMeshPtrs meshptrs = volume->mesh().split();
size_t counter = 1;
for (TriangleMesh *mesh : meshptrs) {
for (ModelVolume* volume : this->volumes) {
if (volume->type() != ModelVolumeType::MODEL_PART)
continue;
// FIXME: crashes if not satisfied
if (mesh->facets_count() < 3) continue;
TriangleMeshPtrs meshptrs = volume->mesh().split();
size_t counter = 1;
for (TriangleMesh* mesh : meshptrs) {
mesh->repair();
// XXX: this seems to be the only real usage of m_model, maybe refactor this so that it's not needed?
ModelObject* new_object = m_model->add_object();
new_object->name = this->name + (meshptrs.size() > 1 ? "_" + std::to_string(counter++) : "");
// FIXME: crashes if not satisfied
if (mesh->facets_count() < 3) continue;
// Don't copy the config's ID.
new_object->config.assign_config(this->config);
assert(new_object->config.id().valid());
assert(new_object->config.id() != this->config.id());
new_object->instances.reserve(this->instances.size());
for (const ModelInstance *model_instance : this->instances)
new_object->add_instance(*model_instance);
ModelVolume* new_vol = new_object->add_volume(*volume, std::move(*mesh));
mesh->repair();
for (ModelInstance* model_instance : new_object->instances)
{
Vec3d shift = model_instance->get_transformation().get_matrix(true) * new_vol->get_offset();
model_instance->set_offset(model_instance->get_offset() + shift);
// XXX: this seems to be the only real usage of m_model, maybe refactor this so that it's not needed?
ModelObject* new_object = m_model->add_object();
if (meshptrs.size() == 1) {
new_object->name = volume->name;
// Don't copy the config's ID.
new_object->config.assign_config(this->config.size() > 0 ? this->config : volume->config);
}
else {
new_object->name = this->name + (meshptrs.size() > 1 ? "_" + std::to_string(counter++) : "");
// Don't copy the config's ID.
new_object->config.assign_config(this->config);
}
assert(new_object->config.id().valid());
assert(new_object->config.id() != this->config.id());
new_object->instances.reserve(this->instances.size());
for (const ModelInstance* model_instance : this->instances)
new_object->add_instance(*model_instance);
ModelVolume* new_vol = new_object->add_volume(*volume, std::move(*mesh));
for (ModelInstance* model_instance : new_object->instances)
{
Vec3d shift = model_instance->get_transformation().get_matrix(true) * new_vol->get_offset();
model_instance->set_offset(model_instance->get_offset() + shift);
}
new_vol->set_offset(Vec3d::Zero());
// reset the source to disable reload from disk
new_vol->source = ModelVolume::Source();
new_objects->emplace_back(new_object);
delete mesh;
}
new_vol->set_offset(Vec3d::Zero());
// reset the source to disable reload from disk
new_vol->source = ModelVolume::Source();
new_objects->emplace_back(new_object);
delete mesh;
}
return;
}
void ModelObject::merge()
{
if (this->volumes.size() == 1) {
@ -1738,6 +1740,7 @@ size_t ModelVolume::split(unsigned int max_extruders)
this->object->volumes[ivolume]->translate(offset);
this->object->volumes[ivolume]->name = name + "_" + std::to_string(idx + 1);
this->object->volumes[ivolume]->config.set_deserialize("extruder", auto_extruder_id(max_extruders, extruder_counter));
this->object->volumes[ivolume]->m_is_splittable = 0;
delete mesh;
++ idx;
}

View file

@ -93,6 +93,8 @@ set(SLIC3R_GUI_SOURCES
GUI/SavePresetDialog.cpp
GUI/PhysicalPrinterDialog.hpp
GUI/PhysicalPrinterDialog.cpp
GUI/GUI_Factories.cpp
GUI/GUI_Factories.hpp
GUI/GUI_ObjectList.cpp
GUI/GUI_ObjectList.hpp
GUI/GUI_ObjectManipulation.cpp

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,104 @@
#ifndef slic3r_GUI_Factories_hpp_
#define slic3r_GUI_Factories_hpp_
#include <map>
#include <vector>
#include <array>
#include <wx/bitmap.h>
#include "libslic3r/PrintConfig.hpp"
#include "wxExtensions.hpp"
class wxMenu;
class wxMenuItem;
namespace Slic3r {
enum class ModelVolumeType : int;
namespace GUI {
struct SettingsFactory
{
// category -> vector ( option )
typedef std::map<std::string, std::vector<std::string>> Bundle;
static std::map<std::string, std::string> CATEGORY_ICON;
static wxBitmap get_category_bitmap(const std::string& category_name);
static Bundle get_bundle(const DynamicPrintConfig* config, bool is_object_settings);
static std::vector<std::string> get_options(bool is_part);
};
class MenuFactory
{
public:
static std::vector<std::pair<std::string, std::string>> ADD_VOLUME_MENU_ITEMS;
static std::vector<wxBitmap> get_volume_bitmaps();
MenuFactory();
~MenuFactory() = default;
void init(wxWindow* parent);
void update_object_menu();
void msw_rescale();
wxMenu* default_menu();
wxMenu* object_menu();
wxMenu* sla_object_menu();
wxMenu* part_menu();
wxMenu* instance_menu();
wxMenu* layer_menu();
wxMenu* multi_selection_menu();
private:
enum MenuType {
mtObjectFFF = 0,
mtObjectSLA,
mtCount
};
wxWindow* m_parent {nullptr};
MenuWithSeparators m_object_menu;
MenuWithSeparators m_part_menu;
MenuWithSeparators m_sla_object_menu;
MenuWithSeparators m_default_menu;
MenuWithSeparators m_instance_menu;
// Removed/Prepended Items according to the view mode
std::array<wxMenuItem*, mtCount> items_increase;
std::array<wxMenuItem*, mtCount> items_decrease;
std::array<wxMenuItem*, mtCount> items_set_number_of_copies;
void create_default_menu();
void create_common_object_menu(wxMenu *menu);
void create_object_menu();
void create_sla_object_menu();
void create_part_menu();
wxMenu* append_submenu_add_generic(wxMenu* menu, ModelVolumeType type);
void append_menu_items_add_volume(wxMenu* menu);
wxMenuItem* append_menu_item_layers_editing(wxMenu* menu);
wxMenuItem* append_menu_item_settings(wxMenu* menu);
wxMenuItem* append_menu_item_change_type(wxMenu* menu);
wxMenuItem* append_menu_item_instance_to_object(wxMenu* menu);
wxMenuItem* append_menu_item_printable(wxMenu* menu);
void append_menu_items_osx(wxMenu* menu);
wxMenuItem* append_menu_item_fix_through_netfabb(wxMenu* menu);
void append_menu_item_export_stl(wxMenu* menu);
void append_menu_item_reload_from_disk(wxMenu* menu);
void append_menu_item_change_extruder(wxMenu* menu);
void append_menu_item_delete(wxMenu* menu);
void append_menu_item_scale_selection_to_fit_print_volume(wxMenu* menu);
void append_menu_items_convert_unit(wxMenu* menu, int insert_pos = 1); // Add "Conver/Revert..." menu items (from/to inches/meters) after "Reload From Disk"
void append_menu_item_merge_to_multipart_object(wxMenu *menu);
// void append_menu_item_merge_to_single_object(wxMenu *menu);
void append_menu_items_mirror(wxMenu *menu);
void append_menu_items_instance_manipulation(wxMenu *menu);
void update_menu_items_instance_manipulation(MenuType type);
};
}}
#endif //slic3r_GUI_Factories_hpp_

View file

@ -260,16 +260,15 @@ void ObjectLayers::msw_rescale()
editor->msw_rescale();
}
const std::vector<size_t> btns = {2, 3}; // del_btn, add_btn
for (auto btn : btns)
{
wxSizerItem* b_item = item->GetSizer()->GetItem(btn);
if (b_item->IsWindow()) {
auto button = dynamic_cast<PlusMinusButton*>(b_item->GetWindow());
if (button != nullptr)
button->msw_rescale();
}
}
if (item->GetSizer()->GetItemCount() > 2) // if there are Add/Del buttons
for (size_t btn : {2, 3}) { // del_btn, add_btn
wxSizerItem* b_item = item->GetSizer()->GetItem(btn);
if (b_item->IsWindow()) {
auto button = dynamic_cast<PlusMinusButton*>(b_item->GetWindow());
if (button != nullptr)
button->msw_rescale();
}
}
}
}
m_grid_sizer->Layout();

File diff suppressed because it is too large Load diff

View file

@ -31,18 +31,11 @@ class TriangleMesh;
enum class ModelVolumeType : int;
// FIXME: broken build on mac os because of this is missing:
typedef std::vector<std::string> t_config_option_keys;
typedef std::map<std::string, std::vector<std::string>> SettingsBundle;
// category -> vector ( option ; label )
typedef std::map< std::string, std::vector< std::pair<std::string, std::string> > > settings_menu_hierarchy;
typedef std::vector<ModelVolume*> ModelVolumePtrs;
typedef double coordf_t;
typedef std::pair<coordf_t, coordf_t> t_layer_height_range;
typedef std::map<t_layer_height_range, ModelConfig> t_layer_config_ranges;
typedef std::vector<std::string> t_config_option_keys;
typedef std::vector<ModelVolume*> ModelVolumePtrs;
typedef double coordf_t;
typedef std::pair<coordf_t, coordf_t> t_layer_height_range;
typedef std::map<t_layer_height_range, ModelConfig> t_layer_config_ranges;
namespace GUI {
@ -106,7 +99,7 @@ public:
private:
SELECTION_MODE m_selection_mode {smUndef};
int m_selected_layers_range_idx;
int m_selected_layers_range_idx {-1};
Clipboard m_clipboard;
@ -147,23 +140,6 @@ private:
} m_dragged_data;
wxBoxSizer *m_sizer {nullptr};
wxWindow *m_parent {nullptr};
ScalableBitmap m_bmp_modifiermesh;
ScalableBitmap m_bmp_solidmesh;
ScalableBitmap m_bmp_support_enforcer;
ScalableBitmap m_bmp_support_blocker;
ScalableBitmap m_bmp_manifold_warning;
ScalableBitmap m_bmp_cog;
MenuWithSeparators m_menu_object;
MenuWithSeparators m_menu_part;
MenuWithSeparators m_menu_sla_object;
MenuWithSeparators m_menu_instance;
MenuWithSeparators m_menu_layer;
MenuWithSeparators m_menu_default;
wxMenuItem* m_menu_item_settings { nullptr };
wxMenuItem* m_menu_item_split_instances { nullptr };
ObjectDataViewModel *m_objects_model{ nullptr };
ModelConfig *m_config {nullptr};
@ -185,7 +161,6 @@ private:
// update_settings_items - updating canvas selection is undesirable,
// because it would turn off the gizmos (mainly a problem for the SLA gizmo)
int m_selected_row = 0;
wxDataViewItem m_last_selected_item {nullptr};
#ifdef __WXMSW__
// Workaround for entering the column editing mode on Windows. Simulate keyboard enter when another column of the active line is selected.
@ -193,8 +168,8 @@ private:
#endif /* __MSW__ */
#if 0
SettingsBundle m_freq_settings_fff;
SettingsBundle m_freq_settings_sla;
SettingsFactory::Bundle m_freq_settings_fff;
SettingsFactory::Bundle m_freq_settings_sla;
#endif
size_t m_items_count { size_t(-1) };
@ -212,8 +187,6 @@ public:
void set_min_height();
void update_min_height();
std::map<std::string, wxBitmap> CATEGORY_ICON;
ObjectDataViewModel* GetModel() const { return m_objects_model; }
ModelConfig* config() const { return m_config; }
std::vector<ModelObject*>* objects() const { return m_objects; }
@ -221,7 +194,6 @@ public:
ModelObject* object(const int obj_idx) const ;
void create_objects_ctrl();
void create_popup_menus();
void update_objects_list_extruder_column(size_t extruders_count);
void update_extruder_colors();
// show/hide "Extruder" column for Objects List
@ -232,9 +204,6 @@ public:
void update_name_in_model(const wxDataViewItem& item) const;
void update_extruder_values_for_items(const size_t max_extruder);
void init_icons();
void msw_rescale_icons();
// Get obj_idx and vol_idx values for the selected (by default) or an adjusted item
void get_selected_item_indexes(int& obj_idx, int& vol_idx, const wxDataViewItem& item = wxDataViewItem(0));
void get_selection_indexes(std::vector<int>& obj_idxs, std::vector<int>& vol_idxs);
@ -264,39 +233,11 @@ public:
void increase_instances();
void decrease_instances();
void get_settings_choice(const wxString& category_name);
void get_freq_settings_choice(const wxString& bundle_name);
void add_category_to_settings_from_selection(const std::vector< std::pair<std::string, bool> >& category_options, wxDataViewItem item);
void add_category_to_settings_from_frequent(const std::vector<std::string>& category_options, wxDataViewItem item);
void show_settings(const wxDataViewItem settings_item);
bool is_instance_or_object_selected();
wxMenu* append_submenu_add_generic(wxMenu* menu, const ModelVolumeType type);
void append_menu_items_add_volume(wxMenu* menu);
wxMenuItem* append_menu_item_split(wxMenu* menu);
wxMenuItem* append_menu_item_layers_editing(wxMenu* menu, wxWindow* parent);
wxMenuItem* append_menu_item_settings(wxMenu* menu);
wxMenuItem* append_menu_item_change_type(wxMenu* menu, wxWindow* parent = nullptr);
wxMenuItem* append_menu_item_instance_to_object(wxMenu* menu, wxWindow* parent);
wxMenuItem* append_menu_item_printable(wxMenu* menu, wxWindow* parent);
void append_menu_items_osx(wxMenu* menu);
wxMenuItem* append_menu_item_fix_through_netfabb(wxMenu* menu);
void append_menu_item_export_stl(wxMenu* menu) const;
void append_menu_item_reload_from_disk(wxMenu* menu) const;
void append_menu_item_change_extruder(wxMenu* menu);
void append_menu_item_delete(wxMenu* menu);
void append_menu_item_scale_selection_to_fit_print_volume(wxMenu* menu);
void append_menu_items_convert_unit(wxMenu* menu, int insert_pos = 1); // Add "Conver/Revert..." menu items (from/to inches/meters) after "Reload From Disk"
void append_menu_item_merge_to_multipart_object(wxMenu *menu);
void append_menu_item_merge_to_single_object(wxMenu *menu);
void create_object_popupmenu(wxMenu *menu);
void create_sla_object_popupmenu(wxMenu*menu);
void create_part_popupmenu(wxMenu*menu);
void create_instance_popupmenu(wxMenu*menu);
void create_default_popupmenu(wxMenu *menu);
wxMenu* create_settings_popupmenu(wxMenu *parent_menu);
void create_freq_settings_popupmenu(wxMenu *parent_menu, const bool is_object_settings = true);
void update_opt_keys(t_config_option_keys& t_optopt_keys, const bool is_object);
void load_subobject(ModelVolumeType type);
void load_part(ModelObject* model_object, std::vector<std::pair<wxString, bool>> &volumes_info, ModelVolumeType type);
void load_generic_subobject(const std::string& type_name, const ModelVolumeType type);
@ -318,7 +259,7 @@ public:
DynamicPrintConfig get_default_layer_config(const int obj_idx);
bool get_volume_by_item(const wxDataViewItem& item, ModelVolume*& volume);
bool is_splittable();
bool is_splittable(bool to_objects);
bool selected_instances_of_same_object();
bool can_split_instances();
bool can_merge_to_multipart_object() const;
@ -328,7 +269,6 @@ public:
wxBoxSizer* get_sizer() {return m_sizer;}
int get_selected_obj_idx() const;
ModelConfig& get_item_config(const wxDataViewItem& item) const;
SettingsBundle get_item_settings_bundle(const DynamicPrintConfig* config, const bool is_object_settings);
void changed_object(const int obj_idx = -1) const;
void part_selection_changed();
@ -404,11 +344,9 @@ public:
void change_part_type();
void last_volume_is_deleted(const int obj_idx);
void update_settings_items();
void update_and_show_object_settings_item();
void update_settings_item_and_selection(wxDataViewItem item, wxDataViewItemArray& selections);
void update_object_list_by_printer_technology();
void update_object_menu();
void instances_to_separated_object(const int obj_idx, const std::set<int>& inst_idx);
void instances_to_separated_objects(const int obj_idx);
@ -433,7 +371,7 @@ public:
void update_printable_state(int obj_idx, int instance_idx);
void toggle_printable_state(wxDataViewItem item);
void show_multi_selection_menu();
void set_extruder_for_selected_items(const int extruder) const ;
private:
#ifdef __WXOSX__
@ -454,11 +392,6 @@ private:
#endif /* __WXMSW__ */
void OnEditingDone(wxDataViewEvent &event);
void extruder_selection();
void set_extruder_for_selected_items(const int extruder) const ;
std::vector<std::string> get_options(const bool is_part);
const std::vector<std::string>& get_options_for_bundle(const wxString& bundle_name);
void get_options_menu(settings_menu_hierarchy& settings_menu, const bool is_part);
};

View file

@ -1,5 +1,6 @@
#include "GUI_ObjectSettings.hpp"
#include "GUI_ObjectList.hpp"
#include "GUI_Factories.hpp"
#include "OptionsGroup.hpp"
#include "GUI_App.hpp"
@ -83,7 +84,7 @@ bool ObjectSettings::update_settings_list()
return false;
const bool is_object_settings = objects_model->GetItemType(objects_model->GetParent(item)) == itObject;
SettingsBundle cat_options = objects_ctrl->get_item_settings_bundle(&config->get(), is_object_settings);
SettingsFactory::Bundle cat_options = SettingsFactory::get_bundle(&config->get(), is_object_settings);
if (!cat_options.empty())
{

View file

@ -562,8 +562,6 @@ void MainFrame::init_tabpanel()
wxGetApp().plater_ = m_plater;
wxGetApp().obj_list()->create_popup_menus();
if (wxGetApp().is_editor())
create_preset_tabs();

View file

@ -2,7 +2,7 @@
#include "wxExtensions.hpp"
#include "BitmapCache.hpp"
#include "GUI_App.hpp"
#include "GUI_ObjectList.hpp"
#include "GUI_Factories.hpp"
#include "I18N.hpp"
#include "libslic3r/Model.hpp"
@ -44,8 +44,9 @@ void ObjectDataViewModelNode::init_container()
#endif //__WXGTK__
}
#define LAYER_ROOT_ICON "edit_layers_all"
#define LAYER_ICON "edit_layers_some"
static constexpr char LayerRootIcon[] = "edit_layers_all";
static constexpr char LayerIcon[] = "edit_layers_some";
static constexpr char WarningIcon[] = "exclamation";
ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const ItemType type) :
m_parent(parent),
@ -65,7 +66,7 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent
}
else if (type == itLayerRoot)
{
m_bmp = create_scaled_bitmap(LAYER_ROOT_ICON); // FIXME: pass window ptr
m_bmp = create_scaled_bitmap(LayerRootIcon); // FIXME: pass window ptr
m_name = _(L("Layers"));
}
@ -94,7 +95,7 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent
}
const std::string label_range = (boost::format(" %.2f-%.2f ") % layer_range.first % layer_range.second).str();
m_name = _(L("Range")) + label_range + "(" + _(L("mm")) + ")";
m_bmp = create_scaled_bitmap(LAYER_ICON); // FIXME: pass window ptr
m_bmp = create_scaled_bitmap(LayerIcon); // FIXME: pass window ptr
set_action_and_extruder_icons();
init_container();
@ -140,17 +141,14 @@ void ObjectDataViewModelNode::update_settings_digest_bitmaps()
{
m_bmp = m_empty_bmp;
std::map<std::string, wxBitmap>& categories_icon = Slic3r::GUI::wxGetApp().obj_list()->CATEGORY_ICON;
std::string scaled_bitmap_name = m_name.ToUTF8().data();
scaled_bitmap_name += "-em" + std::to_string(wxGetApp().em_unit()) + (wxGetApp().dark_mode() ? "-dm" : "");
wxBitmap *bmp = m_bitmap_cache->find(scaled_bitmap_name);
if (bmp == nullptr) {
std::vector<wxBitmap> bmps;
for (auto& cat : m_opt_categories)
bmps.emplace_back( categories_icon.find(cat) == categories_icon.end() ?
wxNullBitmap : categories_icon.at(cat));
for (auto& category : m_opt_categories)
bmps.emplace_back(SettingsFactory::get_category_bitmap(category));
bmp = m_bitmap_cache->insert(scaled_bitmap_name, bmps);
}
@ -249,6 +247,9 @@ static int get_root_idx(ObjectDataViewModelNode *parent_node, const ItemType roo
ObjectDataViewModel::ObjectDataViewModel()
{
m_bitmap_cache = new Slic3r::GUI::BitmapCache;
m_volume_bmps = MenuFactory::get_volume_bitmaps();
m_warning_bmp = create_scaled_bitmap(WarningIcon);
}
ObjectDataViewModel::~ObjectDataViewModel()
@ -267,7 +268,7 @@ wxDataViewItem ObjectDataViewModel::Add(const wxString &name,
auto root = new ObjectDataViewModelNode(name, extruder_str);
// Add error icon if detected auto-repaire
if (has_errors)
root->m_bmp = *m_warning_bmp;
root->m_bmp = m_warning_bmp;
m_objects.push_back(root);
// notify control
@ -317,7 +318,7 @@ wxDataViewItem ObjectDataViewModel::AddVolumeChild( const wxDataViewItem &parent
// if part with errors is added, but object wasn't marked, then mark it
if (!obj_errors && has_errors)
root->SetBitmap(*m_warning_bmp);
root->SetBitmap(m_warning_bmp);
// notify control
const wxDataViewItem child((void*)node);
@ -1434,10 +1435,20 @@ void ObjectDataViewModel::SetVolumeType(const wxDataViewItem &item, const Slic3r
return;
ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(item.GetID());
node->SetBitmap(*m_volume_bmps[int(type)]);
node->SetVolumeType(type);
node->SetBitmap(m_volume_bmps[int(type)]);
ItemChanged(item);
}
ModelVolumeType ObjectDataViewModel::GetVolumeType(const wxDataViewItem& item)
{
if (!item.IsOk() || GetItemType(item) != itVolume)
return ModelVolumeType::INVALID;
ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(item.GetID());
return node->GetVolumeType();
}
wxDataViewItem ObjectDataViewModel::SetPrintableState(
PrintIndicator printable,
int obj_idx,
@ -1480,6 +1491,9 @@ wxDataViewItem ObjectDataViewModel::SetObjectPrintableState(
void ObjectDataViewModel::Rescale()
{
m_volume_bmps = MenuFactory::get_volume_bitmaps();
m_warning_bmp = create_scaled_bitmap(WarningIcon);
wxDataViewItemArray all_items;
GetAllChildren(wxDataViewItem(0), all_items);
@ -1494,15 +1508,15 @@ void ObjectDataViewModel::Rescale()
switch (node->m_type)
{
case itObject:
if (node->m_bmp.IsOk()) node->m_bmp = *m_warning_bmp;
if (node->m_bmp.IsOk()) node->m_bmp = m_warning_bmp;
break;
case itVolume:
node->m_bmp = GetVolumeIcon(node->m_volume_type, node->m_bmp.GetWidth() != node->m_bmp.GetHeight());
break;
case itLayerRoot:
node->m_bmp = create_scaled_bitmap(LAYER_ROOT_ICON);
node->m_bmp = create_scaled_bitmap(LayerRootIcon);
case itLayer:
node->m_bmp = create_scaled_bitmap(LAYER_ICON);
node->m_bmp = create_scaled_bitmap(LayerIcon);
break;
default: break;
}
@ -1514,7 +1528,7 @@ void ObjectDataViewModel::Rescale()
wxBitmap ObjectDataViewModel::GetVolumeIcon(const Slic3r::ModelVolumeType vol_type, const bool is_marked/* = false*/)
{
if (!is_marked)
return *m_volume_bmps[static_cast<int>(vol_type)];
return m_volume_bmps[static_cast<int>(vol_type)];
std::string scaled_bitmap_name = "warning" + std::to_string(static_cast<int>(vol_type));
scaled_bitmap_name += "-em" + std::to_string(Slic3r::GUI::wxGetApp().em_unit());
@ -1523,8 +1537,8 @@ wxBitmap ObjectDataViewModel::GetVolumeIcon(const Slic3r::ModelVolumeType vol_ty
if (bmp == nullptr) {
std::vector<wxBitmap> bmps;
bmps.emplace_back(*m_warning_bmp);
bmps.emplace_back(*m_volume_bmps[static_cast<int>(vol_type)]);
bmps.emplace_back(m_warning_bmp);
bmps.emplace_back(m_volume_bmps[static_cast<int>(vol_type)]);
bmp = m_bitmap_cache->insert(scaled_bitmap_name, bmps);
}
@ -1543,7 +1557,7 @@ void ObjectDataViewModel::DeleteWarningIcon(const wxDataViewItem& item, const bo
return;
if (node->GetType() & itVolume) {
node->SetBitmap(*m_volume_bmps[static_cast<int>(node->volume_type())]);
node->SetBitmap(m_volume_bmps[static_cast<int>(node->volume_type())]);
return;
}

View file

@ -171,13 +171,14 @@ public:
}
bool SetValue(const wxVariant &variant, unsigned int col);
void SetVolumeType(ModelVolumeType type) { m_volume_type = type; }
void SetBitmap(const wxBitmap &icon) { m_bmp = icon; }
const wxBitmap& GetBitmap() const { return m_bmp; }
const wxString& GetName() const { return m_name; }
ItemType GetType() const { return m_type; }
void SetIdx(const int& idx);
int GetIdx() const { return m_idx; }
ModelVolumeType GetVolumeType() { return m_volume_type; }
t_layer_height_range GetLayerRange() const { return m_layer_range; }
PrintIndicator IsPrintable() const { return m_printable; }
@ -241,8 +242,8 @@ wxDECLARE_EVENT(wxCUSTOMEVT_LAST_VOLUME_IS_DELETED, wxCommandEvent);
class ObjectDataViewModel :public wxDataViewModel
{
std::vector<ObjectDataViewModelNode*> m_objects;
std::vector<wxBitmap*> m_volume_bmps;
wxBitmap* m_warning_bmp { nullptr };
std::vector<wxBitmap> m_volume_bmps;
wxBitmap m_warning_bmp;
wxDataViewCtrl* m_ctrl { nullptr };
@ -348,9 +349,8 @@ public:
void UpdateObjectPrintable(wxDataViewItem parent_item);
void UpdateInstancesPrintable(wxDataViewItem parent_item);
void SetVolumeBitmaps(const std::vector<wxBitmap*>& volume_bmps) { m_volume_bmps = volume_bmps; }
void SetWarningBitmap(wxBitmap* bitmap) { m_warning_bmp = bitmap; }
void SetVolumeType(const wxDataViewItem &item, const Slic3r::ModelVolumeType type);
ModelVolumeType GetVolumeType(const wxDataViewItem &item);
wxDataViewItem SetPrintableState( PrintIndicator printable, int obj_idx,
int subobj_idx = -1,
ItemType subobj_type = itInstance);

View file

@ -50,6 +50,7 @@
#include "GUI_ObjectManipulation.hpp"
#include "GUI_ObjectLayers.hpp"
#include "GUI_Utils.hpp"
#include "GUI_Factories.hpp"
#include "wxExtensions.hpp"
#include "MainFrame.hpp"
#include "format.hpp"
@ -1323,7 +1324,7 @@ void Sidebar::update_mode()
p->object_list->unselect_objects();
p->object_list->update_selections();
p->object_list->update_object_menu();
// p->object_list->update_object_menu();
Layout();
}
@ -1405,23 +1406,7 @@ struct Plater::priv
Plater *q;
MainFrame *main_frame;
// Object popup menu
MenuWithSeparators object_menu;
// Part popup menu
MenuWithSeparators part_menu;
// SLA-Object popup menu
MenuWithSeparators sla_object_menu;
// Default popup menu (when nothing is selected on 3DScene)
MenuWithSeparators default_menu;
// Removed/Prepended Items according to the view mode
std::vector<wxMenuItem*> items_increase;
std::vector<wxMenuItem*> items_decrease;
std::vector<wxMenuItem*> items_set_number_of_copies;
enum MenuIdentifier {
miObjectFFF=0,
miObjectSLA
};
MenuFactory menus;
// Data
Slic3r::DynamicPrintConfig *config; // FIXME: leak?
@ -1670,7 +1655,6 @@ struct Plater::priv
void on_update_geometry(Vec3dsEvent<2>&);
void on_3dcanvas_mouse_dragging_finished(SimpleEvent&);
void update_object_menu();
void show_action_buttons(const bool is_ready_to_slice) const;
// Set the bed shape to a single closed 2D polygon(array of two element arrays),
@ -1691,12 +1675,11 @@ struct Plater::priv
bool can_set_instance_to_object() const;
bool can_mirror() const;
bool can_reload_from_disk() const;
bool can_split(bool to_objects) const;
void generate_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background);
void generate_thumbnails(ThumbnailsList& thumbnails, const Vec2ds& sizes, bool printable_only, bool parts_only, bool show_bed, bool transparent_background);
void msw_rescale_object_menu();
void bring_instance_forward() const;
// returns the path to project file with the given extension (none if extension == wxEmptyString)
@ -1713,13 +1696,6 @@ struct Plater::priv
bool inside_snapshot_capture() { return m_prevent_snapshots != 0; }
bool process_completed_with_error { false };
private:
bool init_object_menu();
bool init_common_menu(wxMenu* menu, const bool is_part = false);
bool complit_init_object_menu();
bool complit_init_sla_object_menu();
bool complit_init_part_menu();
bool can_split() const;
bool layers_height_allowed() const;
void update_fff_scene();
@ -1829,7 +1805,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
hsizer->Add(sidebar, 0, wxEXPAND | wxLEFT | wxRIGHT, 0);
q->SetSizer(hsizer);
init_object_menu();
menus.init(q);
// Events:
@ -2725,19 +2701,19 @@ void Plater::priv::split_object()
Model new_model = model;
ModelObject* current_model_object = new_model.objects[obj_idx];
if (current_model_object->volumes.size() > 1)
{
Slic3r::GUI::warning_catcher(q, _L("The selected object can't be split because it contains more than one volume/material."));
return;
}
wxBusyCursor wait;
ModelObjectPtrs new_objects;
current_model_object->split(&new_objects);
if (new_objects.size() == 1)
Slic3r::GUI::warning_catcher(q, _L("The selected object couldn't be split because it contains only one part."));
// #ysFIXME use notification
Slic3r::GUI::warning_catcher(q, _L("The selected object couldn't be split because it contains only one solid part."));
else
{
if (current_model_object->volumes.size() != new_objects.size())
notification_manager->push_notification(NotificationType::CustomNotification,
NotificationManager::NotificationLevel::RegularNotification,
_u8L("All non-solid parts (modifiers) was deleted"));
Plater::TakeSnapshot snapshot(q, _L("Split to Objects"));
remove(obj_idx);
@ -3732,70 +3708,25 @@ void Plater::priv::on_right_click(RBtnEvent& evt)
wxMenu* menu = nullptr;
if (obj_idx == -1) // no one or several object are selected
{
if (obj_idx == -1) { // no one or several object are selected
if (evt.data.second) // right button was clicked on empty space
menu = &default_menu;
menu = menus.default_menu();
else
{
sidebar->obj_list()->show_multi_selection_menu();
return;
}
menu = menus.multi_selection_menu();
}
else
{
else {
// If in 3DScene is(are) selected volume(s), but right button was clicked on empty space
if (evt.data.second)
return;
int menu_item_convert_unit_position = 11;
return;
if (printer_technology == ptSLA)
menu = &sla_object_menu;
else
{
menu = menus.sla_object_menu();
else {
// show "Object menu" for each one or several FullInstance instead of FullObject
const bool is_some_full_instances = get_selection().is_single_full_instance() ||
get_selection().is_single_full_object() ||
get_selection().is_multiple_full_instance();
menu = is_some_full_instances ? &object_menu : &part_menu;
if (!is_some_full_instances)
menu_item_convert_unit_position = 2;
}
sidebar->obj_list()->append_menu_items_convert_unit(menu, menu_item_convert_unit_position);
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.
* Suppress to show those items for a Simple mode
*/
const MenuIdentifier id = printer_technology == ptSLA ? miObjectSLA : miObjectFFF;
if (wxGetApp().get_mode() == comSimple) {
if (menu->FindItem(_L("Add instance")) != wxNOT_FOUND)
{
/* Detach an items from the menu, but don't delete them
* so that they can be added back later
* (after switching to the Advanced/Expert mode)
*/
menu->Remove(items_increase[id]);
menu->Remove(items_decrease[id]);
menu->Remove(items_set_number_of_copies[id]);
}
}
else {
if (menu->FindItem(_L("Add instance")) == wxNOT_FOUND)
{
// Prepend items to the menu, if those aren't not there
menu->Prepend(items_set_number_of_copies[id]);
menu->Prepend(items_decrease[id]);
menu->Prepend(items_increase[id]);
}
}
menu = is_some_full_instances ? menus.object_menu() : menus.part_menu();
}
}
@ -3842,26 +3773,6 @@ void Plater::priv::on_3dcanvas_mouse_dragging_finished(SimpleEvent&)
}
}
bool Plater::priv::init_object_menu()
{
items_increase.reserve(2);
items_decrease.reserve(2);
items_set_number_of_copies.reserve(2);
init_common_menu(&object_menu);
complit_init_object_menu();
init_common_menu(&sla_object_menu);
complit_init_sla_object_menu();
init_common_menu(&part_menu, true);
complit_init_part_menu();
sidebar->obj_list()->create_default_popupmenu(&default_menu);
return true;
}
void Plater::priv::generate_thumbnail(ThumbnailData& data, unsigned int w, unsigned int h, bool printable_only, bool parts_only, bool show_bed, bool transparent_background)
{
view3D->get_canvas3d()->render_thumbnail(data, w, h, printable_only, parts_only, show_bed, transparent_background);
@ -3880,12 +3791,6 @@ void Plater::priv::generate_thumbnails(ThumbnailsList& thumbnails, const Vec2ds&
}
}
void Plater::priv::msw_rescale_object_menu()
{
for (MenuWithSeparators* menu : { &object_menu, &sla_object_menu, &part_menu, &default_menu })
msw_rescale_menu(dynamic_cast<wxMenu*>(menu));
}
wxString Plater::priv::get_project_filename(const wxString& extension) const
{
return m_project_filename.empty() ? "" : m_project_filename + extension;
@ -3914,144 +3819,6 @@ void Plater::priv::set_project_filename(const wxString& filename)
wxGetApp().mainframe->add_to_recent_projects(filename);
}
bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/)
{
if (is_part) {
append_menu_item(menu, wxID_ANY, _L("Delete") + "\tDel", _L("Remove the selected object"),
[this](wxCommandEvent&) { q->remove_selected(); }, "delete", nullptr, [this]() { return can_delete(); }, q);
append_menu_item(menu, wxID_ANY, _L("Reload from disk"), _L("Reload the selected volumes from disk"),
[this](wxCommandEvent&) { q->reload_from_disk(); }, "", menu, [this]() { return can_reload_from_disk(); }, q);
sidebar->obj_list()->append_menu_item_export_stl(menu);
}
else {
wxMenuItem* item_increase = append_menu_item(menu, wxID_ANY, _L("Add instance") + "\t+", _L("Add one more instance of the selected object"),
[this](wxCommandEvent&) { q->increase_instances(); }, "add_copies", nullptr, [this]() { return can_increase_instances(); }, q);
wxMenuItem* item_decrease = append_menu_item(menu, wxID_ANY, _L("Remove instance") + "\t-", _L("Remove one instance of the selected object"),
[this](wxCommandEvent&) { q->decrease_instances(); }, "remove_copies", nullptr, [this]() { return can_decrease_instances(); }, q);
wxMenuItem* item_set_number_of_copies = append_menu_item(menu, wxID_ANY, _L("Set number of instances") + dots, _L("Change the number of instances of the selected object"),
[this](wxCommandEvent&) { q->set_number_of_copies(); }, "number_of_copies", nullptr, [this]() { return can_increase_instances(); }, q);
append_menu_item(menu, wxID_ANY, _L("Fill bed with instances") + dots, _L("Fill the remaining area of bed with instances of the selected object"),
[this](wxCommandEvent&) { q->fill_bed_with_instances(); }, "", nullptr, [this]() { return can_increase_instances(); }, q);
items_increase.push_back(item_increase);
items_decrease.push_back(item_decrease);
items_set_number_of_copies.push_back(item_set_number_of_copies);
// Delete menu was moved to be after +/- instace to make it more difficult to be selected by mistake.
append_menu_item(menu, wxID_ANY, _L("Delete") + "\tDel", _L("Remove the selected object"),
[this](wxCommandEvent&) { q->remove_selected(); }, "delete", nullptr, [this]() { return can_delete(); }, q);
menu->AppendSeparator();
sidebar->obj_list()->append_menu_item_instance_to_object(menu, q);
menu->AppendSeparator();
wxMenuItem* menu_item_printable = sidebar->obj_list()->append_menu_item_printable(menu, q);
menu->AppendSeparator();
append_menu_item(menu, wxID_ANY, _L("Reload from disk"), _L("Reload the selected object from disk"),
[this](wxCommandEvent&) { reload_from_disk(); }, "", nullptr, [this]() { return can_reload_from_disk(); }, q);
append_menu_item(menu, wxID_ANY, _L("Export as STL") + dots, _L("Export the selected object as STL file"),
[this](wxCommandEvent&) { q->export_stl(false, true); }, "", nullptr,
[this]() {
const Selection& selection = get_selection();
return selection.is_single_full_instance() || selection.is_single_full_object();
}, q);
menu->AppendSeparator();
// "Scale to print volume" makes a sense just for whole object
sidebar->obj_list()->append_menu_item_scale_selection_to_fit_print_volume(menu);
q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) {
const Selection& selection = get_selection();
int instance_idx = selection.get_instance_idx();
evt.Enable(selection.is_single_full_instance() || selection.is_single_full_object());
if (instance_idx != -1)
{
evt.Check(model.objects[selection.get_object_idx()]->instances[instance_idx]->printable);
view3D->set_as_dirty();
}
}, menu_item_printable->GetId());
}
sidebar->obj_list()->append_menu_item_fix_through_netfabb(menu);
wxMenu* mirror_menu = new wxMenu();
if (mirror_menu == nullptr)
return false;
append_menu_item(mirror_menu, wxID_ANY, _L("Along X axis"), _L("Mirror the selected object along the X axis"),
[this](wxCommandEvent&) { mirror(X); }, "mark_X", menu);
append_menu_item(mirror_menu, wxID_ANY, _L("Along Y axis"), _L("Mirror the selected object along the Y axis"),
[this](wxCommandEvent&) { mirror(Y); }, "mark_Y", menu);
append_menu_item(mirror_menu, wxID_ANY, _L("Along Z axis"), _L("Mirror the selected object along the Z axis"),
[this](wxCommandEvent&) { mirror(Z); }, "mark_Z", menu);
append_submenu(menu, mirror_menu, wxID_ANY, _L("Mirror"), _L("Mirror the selected object"), "",
[this]() { return can_mirror(); }, q);
return true;
}
bool Plater::priv::complit_init_object_menu()
{
wxMenu* split_menu = new wxMenu();
if (split_menu == nullptr)
return false;
append_menu_item(split_menu, wxID_ANY, _L("To objects"), _L("Split the selected object into individual objects"),
[this](wxCommandEvent&) { split_object(); }, "split_object_SMALL", &object_menu, [this]() { return can_split(); }, q);
append_menu_item(split_menu, wxID_ANY, _L("To parts"), _L("Split the selected object into individual sub-parts"),
[this](wxCommandEvent&) { split_volume(); }, "split_parts_SMALL", &object_menu, [this]() { return can_split(); }, q);
append_submenu(&object_menu, split_menu, wxID_ANY, _L("Split"), _L("Split the selected object"), "",
[this]() { return can_split() && wxGetApp().get_mode() > comSimple; }, q);
object_menu.AppendSeparator();
// Layers Editing for object
sidebar->obj_list()->append_menu_item_layers_editing(&object_menu, q);
object_menu.AppendSeparator();
// "Add (volumes)" popupmenu will be added later in append_menu_items_add_volume()
return true;
}
bool Plater::priv::complit_init_sla_object_menu()
{
append_menu_item(&sla_object_menu, wxID_ANY, _L("Split"), _L("Split the selected object into individual objects"),
[this](wxCommandEvent&) { split_object(); }, "split_object_SMALL", nullptr, [this]() { return can_split(); }, q);
sla_object_menu.AppendSeparator();
// Add the automatic rotation sub-menu
append_menu_item(
&sla_object_menu, wxID_ANY, _(L("Optimize orientation")),
_(L("Optimize the rotation of the object for better print results.")),
[this](wxCommandEvent &) {
m_ui_jobs.optimize_rotation();
});
return true;
}
bool Plater::priv::complit_init_part_menu()
{
append_menu_item(&part_menu, wxID_ANY, _L("Split"), _L("Split the selected object into individual sub-parts"),
[this](wxCommandEvent&) { split_volume(); }, "split_parts_SMALL", nullptr, [this]() { return can_split(); }, q);
part_menu.AppendSeparator();
auto obj_list = sidebar->obj_list();
obj_list->append_menu_item_change_type(&part_menu, q);
return true;
}
void Plater::priv::set_current_canvas_as_dirty()
{
if (current_panel == view3D)
@ -4201,9 +3968,9 @@ bool Plater::priv::can_set_instance_to_object() const
return (0 <= obj_idx) && (obj_idx < (int)model.objects.size()) && (model.objects[obj_idx]->instances.size() > 1);
}
bool Plater::priv::can_split() const
bool Plater::priv::can_split(bool to_objects) const
{
return sidebar->obj_list()->is_splittable();
return sidebar->obj_list()->is_splittable(to_objects);
}
bool Plater::priv::layers_height_allowed() const
@ -4319,12 +4086,12 @@ bool Plater::priv::can_decrease_instances() const
bool Plater::priv::can_split_to_objects() const
{
return can_split();
return q->can_split(true);
}
bool Plater::priv::can_split_to_volumes() const
{
return (printer_technology != ptSLA) && can_split();
return (printer_technology != ptSLA) && q->can_split(false);
}
bool Plater::priv::can_arrange() const
@ -4337,11 +4104,6 @@ bool Plater::priv::can_layers_editing() const
return layers_height_allowed();
}
void Plater::priv::update_object_menu()
{
sidebar->obj_list()->append_menu_items_add_volume(&object_menu);
}
void Plater::priv::show_action_buttons(const bool ready_to_slice) const
{
// Cache this value, so that the callbacks from the RemovableDriveManager may repeat that value when calling show_action_buttons().
@ -6061,9 +5823,12 @@ void Plater::suppress_background_process(const bool stop_background_process)
}
void Plater::fix_through_netfabb(const int obj_idx, const int vol_idx/* = -1*/) { p->fix_through_netfabb(obj_idx, vol_idx); }
void Plater::update_object_menu() { p->update_object_menu(); }
void Plater::show_action_buttons(const bool ready_to_slice) const { p->show_action_buttons(ready_to_slice); }
void Plater::mirror(Axis axis) { p->mirror(axis); }
void Plater::split_object() { p->split_object(); }
void Plater::split_volume() { p->split_volume(); }
void Plater::optimize_rotation() { p->m_ui_jobs.optimize_rotation();}
void Plater::update_object_menu() { p->menus.update_object_menu(); }
void Plater::show_action_buttons(const bool ready_to_slice) const { p->show_action_buttons(ready_to_slice); }
void Plater::copy_selection_to_clipboard()
{
@ -6120,7 +5885,7 @@ void Plater::msw_rescale()
p->sidebar->msw_rescale();
p->msw_rescale_object_menu();
p->menus.msw_rescale();
Layout();
GetParent()->Layout();
@ -6132,7 +5897,7 @@ void Plater::sys_color_changed()
p->sidebar->sys_color_changed();
// msw_rescale_menu updates just icons, so use it
p->msw_rescale_object_menu();
p->menus.msw_rescale();
Layout();
GetParent()->Layout();
@ -6297,6 +6062,8 @@ bool Plater::can_copy_to_clipboard() const
bool Plater::can_undo() const { return p->undo_redo_stack().has_undo_snapshot(); }
bool Plater::can_redo() const { return p->undo_redo_stack().has_redo_snapshot(); }
bool Plater::can_reload_from_disk() const { return p->can_reload_from_disk(); }
bool Plater::can_mirror() const { return p->can_mirror(); }
bool Plater::can_split(bool to_objects) const { return p->can_split(to_objects); }
const UndoRedo::Stack& Plater::undo_redo_stack_main() const { return p->undo_redo_stack_main(); }
void Plater::clear_undo_redo_stack_main() { p->undo_redo_stack_main().clear(); }
void Plater::enter_gizmos_stack() { p->enter_gizmos_stack(); }
@ -6338,6 +6105,15 @@ void Plater::bring_instance_forward()
p->bring_instance_forward();
}
wxMenu* Plater::object_menu() { return p->menus.object_menu(); }
wxMenu* Plater::part_menu() { return p->menus.part_menu(); }
wxMenu* Plater::sla_object_menu() { return p->menus.sla_object_menu(); }
wxMenu* Plater::default_menu() { return p->menus.default_menu(); }
wxMenu* Plater::instance_menu() { return p->menus.instance_menu(); }
wxMenu* Plater::layer_menu() { return p->menus.layer_menu(); }
wxMenu* Plater::multi_selection_menu() { return p->menus.multi_selection_menu(); }
SuppressBackgroundProcessingUpdate::SuppressBackgroundProcessingUpdate() :
m_was_scheduled(wxGetApp().plater()->is_background_process_update_scheduled())
{

View file

@ -271,6 +271,10 @@ public:
void copy_selection_to_clipboard();
void paste_from_clipboard();
void search(bool plater_is_active);
void mirror(Axis axis);
void split_object();
void split_volume();
void optimize_rotation();
bool can_delete() const;
bool can_delete_all() const;
@ -287,6 +291,8 @@ public:
bool can_undo() const;
bool can_redo() const;
bool can_reload_from_disk() const;
bool can_mirror() const;
bool can_split(bool to_objects) const;
void msw_rescale();
void sys_color_changed();
@ -375,6 +381,15 @@ public:
bool PopupMenu(wxMenu *menu, const wxPoint& pos = wxDefaultPosition);
bool PopupMenu(wxMenu *menu, int x, int y) { return this->PopupMenu(menu, wxPoint(x, y)); }
// get same Plater/ObjectList menus
wxMenu* object_menu();
wxMenu* part_menu();
wxMenu* sla_object_menu();
wxMenu* default_menu();
wxMenu* instance_menu();
wxMenu* layer_menu();
wxMenu* multi_selection_menu();
private:
struct priv;
std::unique_ptr<priv> p;