2018-10-04 14:43:10 +00:00
# include "GUI_ObjectList.hpp"
2018-10-05 21:29:15 +00:00
# include "GUI_ObjectManipulation.hpp"
2018-10-04 14:43:10 +00:00
# include "GUI_App.hpp"
2018-11-26 13:41:58 +00:00
# include "I18N.hpp"
2018-10-04 14:43:10 +00:00
# include "OptionsGroup.hpp"
# include "PresetBundle.hpp"
# include "Tab.hpp"
# include "wxExtensions.hpp"
2018-11-26 13:41:58 +00:00
# include "libslic3r/Model.hpp"
2018-10-05 21:29:15 +00:00
# include "LambdaObjectDialog.hpp"
2018-10-11 13:57:09 +00:00
# include "GLCanvas3D.hpp"
2019-03-19 12:30:21 +00:00
# include "Selection.hpp"
2018-10-04 14:43:10 +00:00
# include <boost/algorithm/string.hpp>
# include "slic3r/Utils/FixModelByWin10.hpp"
namespace Slic3r
{
namespace GUI
{
2018-11-01 13:02:38 +00:00
wxDEFINE_EVENT ( EVT_OBJ_LIST_OBJECT_SELECT , SimpleEvent ) ;
2018-11-01 11:33:56 +00:00
2019-01-25 15:39:50 +00:00
// pt_FFF
FreqSettingsBundle FREQ_SETTINGS_BUNDLE_FFF =
{
{ L ( " Layers and Perimeters " ) , { " layer_height " , " perimeters " , " top_solid_layers " , " bottom_solid_layers " } } ,
{ L ( " Infill " ) , { " fill_density " , " fill_pattern " } } ,
{ L ( " Support material " ) , { " support_material " , " support_material_auto " , " support_material_threshold " ,
" support_material_pattern " , " support_material_buildplate_only " ,
" support_material_spacing " } } ,
{ L ( " Extruders " ) , { " wipe_into_infill " , " wipe_into_objects " } }
} ;
// pt_SLA
FreqSettingsBundle FREQ_SETTINGS_BUNDLE_SLA =
{
{ L ( " Pad and Support " ) , { " supports_enable " , " pad_enable " } }
} ;
2019-05-09 12:53:01 +00:00
// Note: id accords to type of the sub-object (adding volume), so sequence of the menu items is important
std : : vector < std : : pair < std : : string , std : : string > > ADD_VOLUME_MENU_ITEMS = {
// menu_item Name menu_item bitmap name
{ L ( " Add part " ) , " add_part " } , // ~ModelVolumeType::MODEL_PART
{ L ( " Add modifier " ) , " add_modifier " } , // ~ModelVolumeType::PARAMETER_MODIFIER
{ L ( " Add support enforcer " ) , " support_enforcer " } , // ~ModelVolumeType::SUPPORT_ENFORCER
{ L ( " Add support blocker " ) , " support_blocker " } // ~ModelVolumeType::SUPPORT_BLOCKER
} ;
2019-03-05 14:33:38 +00:00
static PrinterTechnology printer_technology ( )
{
return wxGetApp ( ) . preset_bundle - > printers . get_selected_preset ( ) . printer_technology ( ) ;
}
2019-03-14 12:15:04 +00:00
// Config from current edited printer preset
2019-03-14 14:45:52 +00:00
static DynamicPrintConfig & printer_config ( )
2019-03-14 12:15:04 +00:00
{
return wxGetApp ( ) . preset_bundle - > printers . get_edited_preset ( ) . config ;
}
2019-03-14 14:45:52 +00:00
static int extruders_count ( )
2019-03-14 12:15:04 +00:00
{
2019-03-19 13:36:32 +00:00
return wxGetApp ( ) . extruders_cnt ( ) ;
2019-03-14 12:15:04 +00:00
}
2018-10-04 14:43:10 +00:00
ObjectList : : ObjectList ( wxWindow * parent ) :
2018-12-06 13:49:14 +00:00
wxDataViewCtrl ( parent , wxID_ANY , wxDefaultPosition , wxDefaultSize , wxDV_MULTIPLE ) ,
m_parent ( parent )
2018-10-04 14:43:10 +00:00
{
2018-10-05 21:29:15 +00:00
// Fill CATEGORY_ICON
{
2019-04-12 09:28:07 +00:00
// Note: `this` isn't passed to create_scaled_bitmap() here because of bugs in the widget,
// see note in PresetBundle::load_compatible_bitmaps()
2018-11-22 09:33:16 +00:00
// ptFFF
2019-04-12 09:28:07 +00:00
CATEGORY_ICON [ L ( " Layers and Perimeters " ) ] = create_scaled_bitmap ( nullptr , " layers " ) ;
CATEGORY_ICON [ L ( " Infill " ) ] = create_scaled_bitmap ( nullptr , " infill " ) ;
CATEGORY_ICON [ L ( " Support material " ) ] = create_scaled_bitmap ( nullptr , " support " ) ;
CATEGORY_ICON [ L ( " Speed " ) ] = create_scaled_bitmap ( nullptr , " time " ) ;
CATEGORY_ICON [ L ( " Extruders " ) ] = create_scaled_bitmap ( nullptr , " funnel " ) ;
CATEGORY_ICON [ L ( " Extrusion Width " ) ] = create_scaled_bitmap ( nullptr , " funnel " ) ;
// CATEGORY_ICON[L("Skirt and brim")] = create_scaled_bitmap(nullptr, "skirt+brim");
// CATEGORY_ICON[L("Speed > Acceleration")] = create_scaled_bitmap(nullptr, "time");
CATEGORY_ICON [ L ( " Advanced " ) ] = create_scaled_bitmap ( nullptr , " wrench " ) ;
// ptSLA
2019-04-12 15:10:04 +00:00
CATEGORY_ICON [ L ( " Supports " ) ] = create_scaled_bitmap ( nullptr , " support " /*"sla_supports"*/ ) ;
CATEGORY_ICON [ L ( " Pad " ) ] = create_scaled_bitmap ( nullptr , " pad " ) ;
2018-10-05 21:29:15 +00:00
}
2018-10-04 14:43:10 +00:00
// create control
create_objects_ctrl ( ) ;
2018-11-02 22:27:31 +00:00
init_icons ( ) ;
2018-10-04 14:43:10 +00:00
// describe control behavior
2019-04-02 14:33:52 +00:00
Bind ( wxEVT_DATAVIEW_SELECTION_CHANGED , [ this ] ( wxDataViewEvent & event ) {
2019-01-31 13:12:07 +00:00
# ifndef __APPLE__
// On Windows and Linux, forces a kill focus emulation on the object manipulator fields because this event handler is called
// before the kill focus event handler on the object manipulator when changing selection in the list, invalidating the object
// manipulator cache with the following call to selection_changed()
wxGetApp ( ) . obj_manipul ( ) - > emulate_kill_focus ( ) ;
2019-04-09 13:43:16 +00:00
# else
2019-04-08 09:06:15 +00:00
// To avoid selection update from SetSelection() and UnselectAll() under osx
if ( m_prevent_list_events )
return ;
2019-01-31 13:12:07 +00:00
# endif // __APPLE__
2019-04-04 13:07:54 +00:00
/* For multiple selection with pressed SHIFT,
* event . GetItem ( ) returns value of a first item in selection list
* instead of real last clicked item .
* So , let check last selected item in such strange way
*/
if ( wxGetKeyState ( WXK_SHIFT ) )
{
wxDataViewItemArray sels ;
GetSelections ( sels ) ;
if ( sels . front ( ) = = m_last_selected_item )
m_last_selected_item = sels . back ( ) ;
else
m_last_selected_item = event . GetItem ( ) ;
}
else
m_last_selected_item = event . GetItem ( ) ;
2018-10-11 13:57:09 +00:00
selection_changed ( ) ;
2018-10-04 14:43:10 +00:00
# ifndef __WXMSW__
set_tooltip_for_item ( get_mouse_position_in_control ( ) ) ;
# endif //__WXMSW__
} ) ;
2018-12-12 07:40:10 +00:00
# ifdef __WXOSX__
2019-05-16 08:37:06 +00:00
// Key events are not correctly processed by the wxDataViewCtrl on OSX.
// Our patched wxWidgets process the keyboard accelerators.
// On the other hand, using accelerators will break in-place editing on Windows & Linux/GTK (there is no in-place editing working on OSX for wxDataViewCtrl for now).
2019-04-29 14:02:39 +00:00
// Bind(wxEVT_KEY_DOWN, &ObjectList::OnChar, this);
{
// Accelerators
wxAcceleratorEntry entries [ 6 ] ;
entries [ 0 ] . Set ( wxACCEL_CTRL , ( int ) ' C ' , wxID_COPY ) ;
entries [ 1 ] . Set ( wxACCEL_CTRL , ( int ) ' X ' , wxID_CUT ) ;
entries [ 2 ] . Set ( wxACCEL_CTRL , ( int ) ' V ' , wxID_PASTE ) ;
entries [ 3 ] . Set ( wxACCEL_CTRL , ( int ) ' A ' , wxID_SELECTALL ) ;
entries [ 4 ] . Set ( wxACCEL_NORMAL , WXK_DELETE , wxID_DELETE ) ;
entries [ 5 ] . Set ( wxACCEL_NORMAL , WXK_BACK , wxID_DELETE ) ;
wxAcceleratorTable accel ( 6 , entries ) ;
SetAcceleratorTable ( accel ) ;
this - > Bind ( wxEVT_MENU , [ this ] ( wxCommandEvent & evt ) { wxPostEvent ( ( wxEvtHandler * ) wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > get_wxglcanvas ( ) , SimpleEvent ( EVT_GLTOOLBAR_COPY ) ) ; } , wxID_COPY ) ;
this - > Bind ( wxEVT_MENU , [ this ] ( wxCommandEvent & evt ) { wxPostEvent ( ( wxEvtHandler * ) wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > get_wxglcanvas ( ) , SimpleEvent ( EVT_GLTOOLBAR_PASTE ) ) ; } , wxID_PASTE ) ;
this - > Bind ( wxEVT_MENU , [ this ] ( wxCommandEvent & evt ) { this - > select_item_all_children ( ) ; } , wxID_SELECTALL ) ;
this - > Bind ( wxEVT_MENU , [ this ] ( wxCommandEvent & evt ) { this - > remove ( ) ; } , wxID_DELETE ) ;
}
2019-05-16 08:37:06 +00:00
# else __WXOSX__
Bind ( wxEVT_CHAR , [ this ] ( wxKeyEvent & event ) { key_event ( event ) ; } ) ; // doesn't work on OSX
# endif
# ifdef __WXMSW__
GetMainWindow ( ) - > Bind ( wxEVT_MOTION , [ this ] ( wxMouseEvent & event ) {
set_tooltip_for_item ( /*event.GetPosition()*/ get_mouse_position_in_control ( ) ) ;
event . Skip ( ) ;
} ) ;
# endif //__WXMSW__
Bind ( wxEVT_DATAVIEW_ITEM_CONTEXT_MENU , & ObjectList : : OnContextMenu , this ) ;
Bind ( wxEVT_DATAVIEW_ITEM_BEGIN_DRAG , & ObjectList : : OnBeginDrag , this ) ;
Bind ( wxEVT_DATAVIEW_ITEM_DROP_POSSIBLE , & ObjectList : : OnDropPossible , this ) ;
Bind ( wxEVT_DATAVIEW_ITEM_DROP , & ObjectList : : OnDrop , this ) ;
Bind ( wxEVT_DATAVIEW_ITEM_EDITING_DONE , & ObjectList : : OnEditingDone , this ) ;
Bind ( wxEVT_DATAVIEW_ITEM_VALUE_CHANGED , & ObjectList : : ItemValueChanged , this ) ;
Bind ( wxCUSTOMEVT_LAST_VOLUME_IS_DELETED , [ this ] ( wxCommandEvent & e ) { last_volume_is_deleted ( e . GetInt ( ) ) ; } ) ;
2019-04-29 14:02:39 +00:00
2019-04-09 11:13:42 +00:00
Bind ( wxEVT_SIZE , ( [ this ] ( wxSizeEvent & e ) { this - > EnsureVisible ( this - > GetCurrentItem ( ) ) ; e . Skip ( ) ; } ) ) ;
2018-10-05 21:29:15 +00:00
}
ObjectList : : ~ ObjectList ( )
{
2018-10-04 14:43:10 +00:00
}
void ObjectList : : create_objects_ctrl ( )
{
2019-03-26 17:01:44 +00:00
/* Temporary workaround for the correct behavior of the Scrolled sidebar panel:
* 1. set a height of the list to some big value
* 2. change it to the normal min value ( 15 * wxGetApp ( ) . em_unit ( ) ) after first whole Mainframe updating / layouting
*/
SetMinSize ( wxSize ( - 1 , 3000 ) ) ;
2018-10-04 14:43:10 +00:00
m_sizer = new wxBoxSizer ( wxVERTICAL ) ;
2019-02-07 13:44:05 +00:00
m_sizer - > Add ( this , 1 , wxGROW ) ;
2018-10-04 14:43:10 +00:00
2019-04-24 23:45:00 +00:00
m_objects_model = new ObjectDataViewModel ;
2018-10-08 14:27:38 +00:00
AssociateModel ( m_objects_model ) ;
2018-11-12 12:47:24 +00:00
m_objects_model - > SetAssociatedControl ( this ) ;
2018-10-04 14:43:10 +00:00
# if wxUSE_DRAG_AND_DROP && wxUSE_UNICODE
2018-10-08 14:27:38 +00:00
EnableDragSource ( wxDF_UNICODETEXT ) ;
EnableDropTarget ( wxDF_UNICODETEXT ) ;
2018-10-04 14:43:10 +00:00
# endif // wxUSE_DRAG_AND_DROP && wxUSE_UNICODE
// column 0(Icon+Text) of the view control:
// And Icon can be consisting of several bitmaps
2019-04-24 23:45:00 +00:00
AppendColumn ( new wxDataViewColumn ( _ ( L ( " Name " ) ) , new BitmapTextRenderer ( ) ,
2019-02-06 10:07:32 +00:00
0 , 20 * wxGetApp ( ) . em_unit ( ) /*200*/ , wxALIGN_LEFT , wxDATAVIEW_COL_RESIZABLE ) ) ;
2018-10-04 14:43:10 +00:00
// column 1 of the view control:
2018-10-08 14:27:38 +00:00
AppendColumn ( create_objects_list_extruder_column ( 4 ) ) ;
2018-10-04 14:43:10 +00:00
2018-10-18 09:28:31 +00:00
// column 2 of the view control:
2019-02-06 10:07:32 +00:00
AppendBitmapColumn ( " " , 2 , wxDATAVIEW_CELL_INERT , int ( 2.5 * wxGetApp ( ) . em_unit ( ) ) /*25*/ ,
2018-10-04 14:43:10 +00:00
wxALIGN_CENTER_HORIZONTAL , wxDATAVIEW_COL_RESIZABLE ) ;
}
2019-01-30 09:05:54 +00:00
void ObjectList : : create_popup_menus ( )
{
// create popup menus for object and part
create_object_popupmenu ( & m_menu_object ) ;
create_part_popupmenu ( & m_menu_part ) ;
create_sla_object_popupmenu ( & m_menu_sla_object ) ;
create_instance_popupmenu ( & m_menu_instance ) ;
}
2019-04-24 11:33:05 +00:00
void ObjectList : : get_selected_item_indexes ( int & obj_idx , int & vol_idx , const wxDataViewItem & input_item /* = wxDataViewItem(0)*/ )
{
const wxDataViewItem item = input_item = = wxDataViewItem ( 0 ) ? GetSelection ( ) : input_item ;
if ( ! item )
{
obj_idx = vol_idx = - 1 ;
return ;
}
const ItemType type = m_objects_model - > GetItemType ( item ) ;
obj_idx = type & itObject ? m_objects_model - > GetIdByItem ( item ) :
type & itVolume ? m_objects_model - > GetIdByItem ( m_objects_model - > GetTopParent ( item ) ) : - 1 ;
vol_idx = type & itVolume ? m_objects_model - > GetVolumeIdByItem ( item ) : - 1 ;
}
int ObjectList : : get_mesh_errors_count ( const int obj_idx , const int vol_idx /*= -1*/ ) const
{
if ( obj_idx < 0 )
return 0 ;
2019-04-24 14:04:47 +00:00
return ( * m_objects ) [ obj_idx ] - > get_mesh_errors_count ( vol_idx ) ;
2019-04-24 11:33:05 +00:00
}
wxString ObjectList : : get_mesh_errors_list ( const int obj_idx , const int vol_idx /*= -1*/ ) const
{
const int errors = get_mesh_errors_count ( obj_idx , vol_idx ) ;
if ( errors = = 0 )
return " " ; // hide tooltip
// Create tooltip string, if there are errors
wxString tooltip = wxString : : Format ( _ ( L ( " Auto-repaired (%d errors): \n " ) ) , errors ) ;
2019-04-24 14:04:47 +00:00
const stl_stats & stats = vol_idx = = - 1 ?
( * m_objects ) [ obj_idx ] - > get_object_stl_stats ( ) :
( * m_objects ) [ obj_idx ] - > volumes [ vol_idx ] - > mesh . stl . stats ;
2019-04-24 11:33:05 +00:00
std : : map < std : : string , int > error_msg = {
2019-04-24 14:04:47 +00:00
{ L ( " degenerate facets " ) , stats . degenerate_facets } ,
{ L ( " edges fixed " ) , stats . edges_fixed } ,
{ L ( " facets removed " ) , stats . facets_removed } ,
{ L ( " facets added " ) , stats . facets_added } ,
{ L ( " facets reversed " ) , stats . facets_reversed } ,
{ L ( " backwards edges " ) , stats . backwards_edges }
2019-04-24 11:33:05 +00:00
} ;
for ( const auto & error : error_msg )
if ( error . second > 0 )
2019-04-30 13:46:25 +00:00
tooltip + = wxString : : Format ( " \t %d %s \n " , error . second , _ ( error . first ) ) ;
2019-04-24 11:33:05 +00:00
if ( is_windows10 ( ) )
tooltip + = _ ( L ( " Right button click the icon to fix STL through Netfabb " ) ) ;
return tooltip ;
}
wxString ObjectList : : get_mesh_errors_list ( )
{
if ( ! GetSelection ( ) )
return " " ;
int obj_idx , vol_idx ;
get_selected_item_indexes ( obj_idx , vol_idx ) ;
return get_mesh_errors_list ( obj_idx , vol_idx ) ;
}
2018-10-04 14:43:10 +00:00
void ObjectList : : set_tooltip_for_item ( const wxPoint & pt )
{
wxDataViewItem item ;
wxDataViewColumn * col ;
2018-10-08 14:27:38 +00:00
HitTest ( pt , item , col ) ;
2018-10-04 14:43:10 +00:00
if ( ! item ) return ;
2019-04-30 14:59:40 +00:00
/* GetMainWindow() return window, associated with wxDataViewCtrl.
* And for this window we should to set tooltips .
* Just this - > SetToolTip ( tooltip ) = > has no effect .
*/
2018-10-12 10:00:37 +00:00
if ( col - > GetTitle ( ) = = " " & & GetSelectedItemsCount ( ) < 2 )
2018-10-08 14:27:38 +00:00
GetMainWindow ( ) - > SetToolTip ( _ ( L ( " Right button click the icon to change the object settings " ) ) ) ;
2019-04-30 13:46:25 +00:00
else if ( col - > GetTitle ( ) = = _ ( " Name " ) )
2019-04-24 11:33:05 +00:00
{
2019-04-30 13:46:25 +00:00
# ifdef __WXMSW__
if ( pt . x < 2 * wxGetApp ( ) . em_unit ( ) | | pt . x > 4 * wxGetApp ( ) . em_unit ( ) ) {
GetMainWindow ( ) - > SetToolTip ( " " ) ; // hide tooltip
return ;
2018-10-05 21:29:15 +00:00
}
2019-04-30 13:46:25 +00:00
# endif //__WXMSW__
2019-04-24 11:33:05 +00:00
int obj_idx , vol_idx ;
get_selected_item_indexes ( obj_idx , vol_idx , item ) ;
GetMainWindow ( ) - > SetToolTip ( get_mesh_errors_list ( obj_idx , vol_idx ) ) ;
2018-10-05 21:29:15 +00:00
}
2018-10-04 14:43:10 +00:00
else
2018-10-08 14:27:38 +00:00
GetMainWindow ( ) - > SetToolTip ( " " ) ; // hide tooltip
2018-10-04 14:43:10 +00:00
}
2018-10-31 14:41:27 +00:00
wxPoint ObjectList : : get_mouse_position_in_control ( )
{
2018-10-04 14:43:10 +00:00
const wxPoint & pt = wxGetMousePosition ( ) ;
2018-10-08 14:27:38 +00:00
// wxWindow* win = GetMainWindow();
// wxPoint screen_pos = win->GetScreenPosition();
return wxPoint ( pt . x - /*win->*/ GetScreenPosition ( ) . x , pt . y - /*win->*/ GetScreenPosition ( ) . y ) ;
2018-10-04 14:43:10 +00:00
}
2018-10-12 10:00:37 +00:00
int ObjectList : : get_selected_obj_idx ( ) const
{
2018-10-31 14:41:27 +00:00
if ( GetSelectedItemsCount ( ) = = 1 )
return m_objects_model - > GetIdByItem ( m_objects_model - > GetTopParent ( GetSelection ( ) ) ) ;
2018-10-12 10:00:37 +00:00
return - 1 ;
}
2019-03-28 15:28:34 +00:00
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 ;
}
2018-10-04 14:43:10 +00:00
wxDataViewColumn * ObjectList : : create_objects_list_extruder_column ( int extruders_count )
{
wxArrayString choices ;
2019-05-10 10:54:20 +00:00
choices . Add ( _ ( L ( " default " ) ) ) ;
2018-10-04 14:43:10 +00:00
for ( int i = 1 ; i < = extruders_count ; + + i )
choices . Add ( wxString : : Format ( " %d " , i ) ) ;
wxDataViewChoiceRenderer * c =
new wxDataViewChoiceRenderer ( choices , wxDATAVIEW_CELL_EDITABLE , wxALIGN_CENTER_HORIZONTAL ) ;
2019-02-06 10:07:32 +00:00
wxDataViewColumn * column = new wxDataViewColumn ( _ ( L ( " Extruder " ) ) , c , 1 ,
8 * wxGetApp ( ) . em_unit ( ) /*80*/ , wxALIGN_CENTER_HORIZONTAL , wxDATAVIEW_COL_RESIZABLE ) ;
2018-10-04 14:43:10 +00:00
return column ;
}
2018-12-10 16:00:28 +00:00
void ObjectList : : update_extruder_values_for_items ( const int max_extruder )
{
for ( int i = 0 ; i < m_objects - > size ( ) ; + + i )
{
wxDataViewItem item = m_objects_model - > GetItemById ( i ) ;
if ( ! item ) continue ;
auto object = ( * m_objects ) [ i ] ;
wxString extruder ;
if ( ! object - > config . has ( " extruder " ) | |
object - > config . option < ConfigOptionInt > ( " extruder " ) - > value > max_extruder )
2019-05-10 10:54:20 +00:00
extruder = _ ( L ( " default " ) ) ;
2018-12-10 16:00:28 +00:00
else
extruder = wxString : : Format ( " %d " , object - > config . option < ConfigOptionInt > ( " extruder " ) - > value ) ;
m_objects_model - > SetValue ( extruder , item , 1 ) ;
if ( object - > volumes . size ( ) > 1 ) {
for ( auto id = 0 ; id < object - > volumes . size ( ) ; id + + ) {
item = m_objects_model - > GetItemByVolumeId ( i , id ) ;
if ( ! item ) continue ;
if ( ! object - > volumes [ id ] - > config . has ( " extruder " ) | |
object - > volumes [ id ] - > config . option < ConfigOptionInt > ( " extruder " ) - > value > max_extruder )
2019-05-10 10:54:20 +00:00
extruder = _ ( L ( " default " ) ) ;
2018-12-10 16:00:28 +00:00
else
extruder = wxString : : Format ( " %d " , object - > volumes [ id ] - > config . option < ConfigOptionInt > ( " extruder " ) - > value ) ;
m_objects_model - > SetValue ( extruder , item , 1 ) ;
}
}
}
}
2018-10-04 14:43:10 +00:00
void ObjectList : : update_objects_list_extruder_column ( int extruders_count )
{
2018-10-08 14:27:38 +00:00
if ( ! this ) return ; // #ys_FIXME
2019-03-05 09:46:57 +00:00
if ( printer_technology ( ) = = ptSLA )
2018-10-04 14:43:10 +00:00
extruders_count = 1 ;
2018-12-10 16:00:28 +00:00
wxDataViewChoiceRenderer * ch_render = dynamic_cast < wxDataViewChoiceRenderer * > ( GetColumn ( 1 ) - > GetRenderer ( ) ) ;
if ( ch_render - > GetChoices ( ) . GetCount ( ) - 1 = = extruders_count )
return ;
m_prevent_update_extruder_in_config = true ;
if ( m_objects & & extruders_count > 1 )
update_extruder_values_for_items ( extruders_count ) ;
2018-10-18 09:28:31 +00:00
// delete old 2nd column
DeleteColumn ( GetColumn ( 1 ) ) ;
2018-10-04 14:43:10 +00:00
// insert new created 3rd column
2018-10-18 09:28:31 +00:00
InsertColumn ( 1 , create_objects_list_extruder_column ( extruders_count ) ) ;
2018-10-04 14:43:10 +00:00
// set show/hide for this column
set_extruder_column_hidden ( extruders_count < = 1 ) ;
2018-12-04 13:27:39 +00:00
//a workaround for a wrong last column width updating under OSX
GetColumn ( 2 ) - > SetWidth ( 25 ) ;
2018-12-10 16:00:28 +00:00
m_prevent_update_extruder_in_config = false ;
2018-10-04 14:43:10 +00:00
}
2018-12-11 08:37:58 +00:00
void ObjectList : : set_extruder_column_hidden ( const bool hide ) const
2018-10-05 21:29:15 +00:00
{
2018-10-18 09:28:31 +00:00
GetColumn ( 1 ) - > SetHidden ( hide ) ;
2018-10-05 21:29:15 +00:00
}
2018-12-10 16:00:28 +00:00
void ObjectList : : update_extruder_in_config ( const wxDataViewItem & item )
2018-10-05 21:29:15 +00:00
{
2018-12-10 16:00:28 +00:00
if ( m_prevent_update_extruder_in_config )
return ;
2018-12-10 13:13:01 +00:00
if ( m_objects_model - > GetParent ( item ) = = wxDataViewItem ( 0 ) ) {
const int obj_idx = m_objects_model - > GetIdByItem ( item ) ;
m_config = & ( * m_objects ) [ obj_idx ] - > config ;
}
else {
const int obj_idx = m_objects_model - > GetIdByItem ( m_objects_model - > GetParent ( item ) ) ;
const int volume_id = m_objects_model - > GetVolumeIdByItem ( item ) ;
if ( obj_idx < 0 | | volume_id < 0 )
return ;
m_config = & ( * m_objects ) [ obj_idx ] - > volumes [ volume_id ] - > config ;
}
wxVariant variant ;
m_objects_model - > GetValue ( variant , item , 1 ) ;
const wxString selection = variant . GetString ( ) ;
2018-10-05 21:29:15 +00:00
if ( ! m_config | | selection . empty ( ) )
return ;
2018-12-10 13:13:01 +00:00
const int extruder = selection . size ( ) > 1 ? 0 : atoi ( selection . c_str ( ) ) ;
2018-10-05 21:29:15 +00:00
m_config - > set_key_value ( " extruder " , new ConfigOptionInt ( extruder ) ) ;
2018-10-15 08:53:47 +00:00
// update scene
wxGetApp ( ) . plater ( ) - > update ( ) ;
2018-10-05 21:29:15 +00:00
}
2019-01-30 10:35:37 +00:00
void ObjectList : : update_name_in_model ( const wxDataViewItem & item ) const
2018-12-12 13:35:18 +00:00
{
const int obj_idx = m_objects_model - > GetObjectIdByItem ( item ) ;
if ( obj_idx < 0 ) return ;
if ( m_objects_model - > GetParent ( item ) = = wxDataViewItem ( 0 ) ) {
2019-01-03 13:34:53 +00:00
( * m_objects ) [ obj_idx ] - > name = m_objects_model - > GetName ( item ) . ToUTF8 ( ) . data ( ) ;
2018-12-12 13:35:18 +00:00
return ;
}
const int volume_id = m_objects_model - > GetVolumeIdByItem ( item ) ;
if ( volume_id < 0 ) return ;
2019-01-03 13:34:53 +00:00
( * m_objects ) [ obj_idx ] - > volumes [ volume_id ] - > name = m_objects_model - > GetName ( item ) . ToUTF8 ( ) . data ( ) ;
2018-12-12 13:35:18 +00:00
}
2018-10-31 11:56:08 +00:00
void ObjectList : : init_icons ( )
{
2019-05-09 12:53:01 +00:00
m_bmp_solidmesh = ScalableBitmap ( nullptr , ADD_VOLUME_MENU_ITEMS [ int ( ModelVolumeType : : MODEL_PART ) ] . second ) ;
m_bmp_modifiermesh = ScalableBitmap ( nullptr , ADD_VOLUME_MENU_ITEMS [ int ( ModelVolumeType : : PARAMETER_MODIFIER ) ] . second ) ;
m_bmp_support_enforcer = ScalableBitmap ( nullptr , ADD_VOLUME_MENU_ITEMS [ int ( ModelVolumeType : : SUPPORT_ENFORCER ) ] . second ) ;
m_bmp_support_blocker = ScalableBitmap ( nullptr , ADD_VOLUME_MENU_ITEMS [ int ( ModelVolumeType : : SUPPORT_BLOCKER ) ] . second ) ;
2018-11-02 11:35:26 +00:00
m_bmp_vector . reserve ( 4 ) ; // bitmaps for different types of parts
2019-04-16 08:05:45 +00:00
m_bmp_vector . push_back ( & m_bmp_solidmesh . bmp ( ) ) ;
m_bmp_vector . push_back ( & m_bmp_modifiermesh . bmp ( ) ) ;
m_bmp_vector . push_back ( & m_bmp_support_enforcer . bmp ( ) ) ;
m_bmp_vector . push_back ( & m_bmp_support_blocker . bmp ( ) ) ;
// Set volumes default bitmaps for the model
2018-11-02 22:27:31 +00:00
m_objects_model - > SetVolumeBitmaps ( m_bmp_vector ) ;
2018-10-05 21:29:15 +00:00
// init icon for manifold warning
2019-04-24 23:45:00 +00:00
m_bmp_manifold_warning = ScalableBitmap ( nullptr , " exclamation " ) ;
2019-04-29 13:27:59 +00:00
// Set warning bitmap for the model
m_objects_model - > SetWarningBitmap ( & m_bmp_manifold_warning . bmp ( ) ) ;
2018-10-05 21:29:15 +00:00
// init bitmap for "Add Settings" context menu
2019-04-24 23:45:00 +00:00
m_bmp_cog = ScalableBitmap ( nullptr , " cog " ) ;
2019-04-16 08:05:45 +00:00
}
2019-05-09 12:53:01 +00:00
void ObjectList : : msw_rescale_icons ( )
2019-04-16 08:05:45 +00:00
{
m_bmp_vector . clear ( ) ;
m_bmp_vector . reserve ( 4 ) ; // bitmaps for different types of parts
2019-05-09 12:53:01 +00:00
for ( ScalableBitmap * bitmap : { & m_bmp_solidmesh , // Add part
2019-04-29 13:27:59 +00:00
& m_bmp_modifiermesh , // Add modifier
2019-04-16 08:05:45 +00:00
& m_bmp_support_enforcer , // Add support enforcer
& m_bmp_support_blocker } ) // Add support blocker
{
2019-04-24 23:45:00 +00:00
bitmap - > msw_rescale ( ) ;
2019-04-16 08:05:45 +00:00
m_bmp_vector . push_back ( & bitmap - > bmp ( ) ) ;
}
// Set volumes default bitmaps for the model
m_objects_model - > SetVolumeBitmaps ( m_bmp_vector ) ;
2019-04-24 23:45:00 +00:00
m_bmp_manifold_warning . msw_rescale ( ) ;
2019-04-29 13:27:59 +00:00
// Set warning bitmap for the model
m_objects_model - > SetWarningBitmap ( & m_bmp_manifold_warning . bmp ( ) ) ;
2019-04-24 23:45:00 +00:00
m_bmp_cog . msw_rescale ( ) ;
2019-04-16 08:05:45 +00:00
// Update CATEGORY_ICON according to new scale
{
// Note: `this` isn't passed to create_scaled_bitmap() here because of bugs in the widget,
// see note in PresetBundle::load_compatible_bitmaps()
// ptFFF
CATEGORY_ICON [ L ( " Layers and Perimeters " ) ] = create_scaled_bitmap ( nullptr , " layers " ) ;
CATEGORY_ICON [ L ( " Infill " ) ] = create_scaled_bitmap ( nullptr , " infill " ) ;
CATEGORY_ICON [ L ( " Support material " ) ] = create_scaled_bitmap ( nullptr , " support " ) ;
CATEGORY_ICON [ L ( " Speed " ) ] = create_scaled_bitmap ( nullptr , " time " ) ;
CATEGORY_ICON [ L ( " Extruders " ) ] = create_scaled_bitmap ( nullptr , " funnel " ) ;
CATEGORY_ICON [ L ( " Extrusion Width " ) ] = create_scaled_bitmap ( nullptr , " funnel " ) ;
// CATEGORY_ICON[L("Skirt and brim")] = create_scaled_bitmap(nullptr, "skirt+brim");
// CATEGORY_ICON[L("Speed > Acceleration")] = create_scaled_bitmap(nullptr, "time");
CATEGORY_ICON [ L ( " Advanced " ) ] = create_scaled_bitmap ( nullptr , " wrench " ) ;
// ptSLA
CATEGORY_ICON [ L ( " Supports " ) ] = create_scaled_bitmap ( nullptr , " support " /*"sla_supports"*/ ) ;
CATEGORY_ICON [ L ( " Pad " ) ] = create_scaled_bitmap ( nullptr , " pad " ) ;
}
2018-10-05 21:29:15 +00:00
}
2018-10-11 13:57:09 +00:00
void ObjectList : : selection_changed ( )
2018-10-05 21:29:15 +00:00
{
if ( m_prevent_list_events ) return ;
2018-10-11 13:57:09 +00:00
fix_multiselection_conflicts ( ) ;
2018-10-05 21:29:15 +00:00
2018-10-11 13:57:09 +00:00
// update object selection on Plater
2019-03-04 08:41:25 +00:00
if ( ! m_prevent_canvas_selection_update )
update_selections_on_canvas ( ) ;
2018-10-05 21:29:15 +00:00
2018-11-01 11:33:56 +00:00
// to update the toolbar and info sizer
if ( ! GetSelection ( ) | | m_objects_model - > GetItemType ( GetSelection ( ) ) = = itObject ) {
auto event = SimpleEvent ( EVT_OBJ_LIST_OBJECT_SELECT ) ;
event . SetEventObject ( this ) ;
wxPostEvent ( this , event ) ;
}
2018-10-11 13:57:09 +00:00
part_selection_changed ( ) ;
2018-12-11 08:37:58 +00:00
}
2018-10-05 21:29:15 +00:00
2019-04-10 06:40:58 +00:00
void ObjectList : : paste_volumes_into_list ( int obj_idx , const ModelVolumePtrs & volumes )
{
if ( ( obj_idx < 0 ) | | ( ( int ) m_objects - > size ( ) < = obj_idx ) )
return ;
if ( volumes . empty ( ) )
return ;
ModelObject & model_object = * ( * m_objects ) [ obj_idx ] ;
const auto object_item = m_objects_model - > GetItemById ( obj_idx ) ;
wxDataViewItemArray items ;
for ( const ModelVolume * volume : volumes )
{
2019-05-15 15:16:31 +00:00
const wxDataViewItem & vol_item = m_objects_model - > AddVolumeChild ( object_item , wxString : : FromUTF8 ( volume - > name . c_str ( ) ) , volume - > type ( ) ,
2019-04-29 13:27:59 +00:00
volume - > get_mesh_errors_count ( ) > 0 ,
2019-04-10 07:27:42 +00:00
volume - > config . has ( " extruder " ) ? volume - > config . option < ConfigOptionInt > ( " extruder " ) - > value : 0 ) ;
2019-04-10 06:40:58 +00:00
auto opt_keys = volume - > config . keys ( ) ;
if ( ! opt_keys . empty ( ) & & ! ( ( opt_keys . size ( ) = = 1 ) & & ( opt_keys [ 0 ] = = " extruder " ) ) )
select_item ( m_objects_model - > AddSettingsChild ( vol_item ) ) ;
items . Add ( vol_item ) ;
}
2019-04-21 23:51:10 +00:00
changed_object ( obj_idx ) ;
2019-04-10 06:40:58 +00:00
2019-04-12 09:28:24 +00:00
if ( items . size ( ) > 1 )
{
m_selection_mode = smVolume ;
m_last_selected_item = wxDataViewItem ( 0 ) ;
}
2019-04-10 06:40:58 +00:00
select_items ( items ) ;
# ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
selection_changed ( ) ;
# endif //no __WXOSX__ //__WXMSW__
}
2019-04-10 13:55:32 +00:00
void ObjectList : : paste_objects_into_list ( const std : : vector < size_t > & object_idxs )
2019-04-10 06:40:58 +00:00
{
2019-04-10 13:55:32 +00:00
if ( object_idxs . empty ( ) )
return ;
wxDataViewItemArray items ;
for ( const size_t object : object_idxs )
{
add_object_to_list ( object ) ;
items . Add ( m_objects_model - > GetItemById ( object ) ) ;
}
2019-04-15 13:40:40 +00:00
wxGetApp ( ) . plater ( ) - > changed_objects ( object_idxs ) ;
2019-04-10 13:55:32 +00:00
select_items ( items ) ;
# ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
selection_changed ( ) ;
# endif //no __WXOSX__ //__WXMSW__
2019-04-10 06:40:58 +00:00
}
2019-05-16 08:37:06 +00:00
# ifdef __WXOSX__
/*
2018-12-11 08:37:58 +00:00
void ObjectList : : OnChar ( wxKeyEvent & event )
{
2018-12-12 07:40:10 +00:00
if ( event . GetKeyCode ( ) = = WXK_BACK ) {
2018-12-11 08:37:58 +00:00
remove ( ) ;
}
else if ( wxGetKeyState ( wxKeyCode ( ' A ' ) ) & & wxGetKeyState ( WXK_SHIFT ) )
select_item_all_children ( ) ;
2018-12-12 07:40:10 +00:00
event . Skip ( ) ;
2018-10-05 21:29:15 +00:00
}
2019-05-16 08:37:06 +00:00
*/
# endif /* __WXOSX__ */
2018-10-05 21:29:15 +00:00
2018-12-11 08:37:58 +00:00
void ObjectList : : OnContextMenu ( wxDataViewEvent & )
2018-10-05 21:29:15 +00:00
{
wxDataViewItem item ;
wxDataViewColumn * col ;
const wxPoint pt = get_mouse_position_in_control ( ) ;
2018-10-08 14:27:38 +00:00
HitTest ( pt , item , col ) ;
2018-10-05 21:29:15 +00:00
if ( ! item )
# ifdef __WXOSX__ // #ys_FIXME temporary workaround for OSX
// after Yosemite OS X version, HitTest return undefined item
2018-10-08 14:27:38 +00:00
item = GetSelection ( ) ;
2018-10-05 21:29:15 +00:00
if ( item )
show_context_menu ( ) ;
else
printf ( " undefined item \n " ) ;
return ;
# else
return ;
# endif // __WXOSX__
const wxString title = col - > GetTitle ( ) ;
if ( title = = " " )
show_context_menu ( ) ;
2019-04-29 13:27:59 +00:00
else if ( title = = _ ( " Name " ) )
2018-12-12 12:18:38 +00:00
{
2019-04-24 11:33:05 +00:00
int obj_idx , vol_idx ;
get_selected_item_indexes ( obj_idx , vol_idx , item ) ;
2019-04-29 13:27:59 +00:00
if ( is_windows10 ( ) & & get_mesh_errors_count ( obj_idx , vol_idx ) > 0 & &
pt . x > 2 * wxGetApp ( ) . em_unit ( ) & & pt . x < 4 * wxGetApp ( ) . em_unit ( ) )
2019-03-13 14:34:27 +00:00
fix_through_netfabb ( ) ;
2018-12-12 12:18:38 +00:00
}
2019-03-14 12:15:04 +00:00
2018-10-05 21:29:15 +00:00
# ifndef __WXMSW__
2018-10-08 14:27:38 +00:00
GetMainWindow ( ) - > SetToolTip ( " " ) ; // hide tooltip
2018-10-05 21:29:15 +00:00
# endif //__WXMSW__
}
void ObjectList : : show_context_menu ( )
{
2019-03-14 12:15:04 +00:00
if ( multiple_selection ( ) )
2019-01-23 15:01:37 +00:00
{
2019-03-14 12:15:04 +00:00
if ( selected_instances_of_same_object ( ) )
wxGetApp ( ) . plater ( ) - > PopupMenu ( & m_menu_instance ) ;
else
2019-03-21 08:04:11 +00:00
show_multi_selection_menu ( ) ;
2019-03-14 12:15:04 +00:00
2019-01-23 15:01:37 +00:00
return ;
}
2018-10-08 14:27:38 +00:00
const auto item = GetSelection ( ) ;
2018-10-05 21:29:15 +00:00
if ( item )
{
2019-01-23 15:01:37 +00:00
const ItemType type = m_objects_model - > GetItemType ( item ) ;
if ( ! ( type & ( itObject | itVolume | itInstance ) ) )
2018-10-05 21:29:15 +00:00
return ;
2019-01-23 15:01:37 +00:00
wxMenu * menu = type & itInstance ? & m_menu_instance :
m_objects_model - > GetParent ( item ) ! = wxDataViewItem ( 0 ) ? & m_menu_part :
2019-03-05 09:46:57 +00:00
printer_technology ( ) = = ptFFF ? & m_menu_object : & m_menu_sla_object ;
2018-12-06 13:49:14 +00:00
2019-01-23 15:01:37 +00:00
if ( ! ( type & itInstance ) )
append_menu_item_settings ( menu ) ;
2018-12-07 16:50:48 +00:00
2018-12-06 13:49:14 +00:00
wxGetApp ( ) . plater ( ) - > PopupMenu ( menu ) ;
2018-10-05 21:29:15 +00:00
}
}
2019-05-16 08:37:06 +00:00
# ifndef __WXOSX__
2018-10-11 13:57:09 +00:00
void ObjectList : : key_event ( wxKeyEvent & event )
2018-10-05 21:29:15 +00:00
{
if ( event . GetKeyCode ( ) = = WXK_TAB )
2018-10-08 14:27:38 +00:00
Navigate ( event . ShiftDown ( ) ? wxNavigationKeyEvent : : IsBackward : wxNavigationKeyEvent : : IsForward ) ;
2018-10-05 21:29:15 +00:00
else if ( event . GetKeyCode ( ) = = WXK_DELETE
# ifdef __WXOSX__
| | event . GetKeyCode ( ) = = WXK_BACK
# endif //__WXOSX__
2018-10-31 11:56:08 +00:00
) {
2018-10-05 21:29:15 +00:00
remove ( ) ;
}
2019-04-04 13:07:54 +00:00
else if ( wxGetKeyState ( wxKeyCode ( ' A ' ) ) & & wxGetKeyState ( WXK_CONTROL /*WXK_SHIFT*/ ) )
2018-11-08 14:45:55 +00:00
select_item_all_children ( ) ;
2019-04-16 11:47:37 +00:00
else if ( wxGetKeyState ( wxKeyCode ( ' C ' ) ) & & wxGetKeyState ( WXK_CONTROL ) )
wxPostEvent ( ( wxEvtHandler * ) wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > get_wxglcanvas ( ) , SimpleEvent ( EVT_GLTOOLBAR_COPY ) ) ;
else if ( wxGetKeyState ( wxKeyCode ( ' V ' ) ) & & wxGetKeyState ( WXK_CONTROL ) )
wxPostEvent ( ( wxEvtHandler * ) wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > get_wxglcanvas ( ) , SimpleEvent ( EVT_GLTOOLBAR_PASTE ) ) ;
2018-10-05 21:29:15 +00:00
else
event . Skip ( ) ;
}
2019-05-16 08:37:06 +00:00
# endif /* __WXOSX__ */
2018-10-05 21:29:15 +00:00
2018-12-11 08:37:58 +00:00
void ObjectList : : OnBeginDrag ( wxDataViewEvent & event )
2018-10-05 21:29:15 +00:00
{
2018-12-12 09:34:34 +00:00
const wxDataViewItem item ( event . GetItem ( ) ) ;
2018-10-05 21:29:15 +00:00
2019-01-23 15:01:37 +00:00
const bool mult_sel = multiple_selection ( ) ;
if ( mult_sel & & ! selected_instances_of_same_object ( ) | |
! mult_sel & & ( GetSelection ( ) ! = item | |
m_objects_model - > GetParent ( item ) = = wxDataViewItem ( 0 ) ) ) {
2019-01-22 15:40:10 +00:00
event . Veto ( ) ;
return ;
}
const ItemType & type = m_objects_model - > GetItemType ( item ) ;
if ( ! ( type & ( itVolume | itInstance ) ) ) {
2018-10-05 21:29:15 +00:00
event . Veto ( ) ;
return ;
}
2019-01-23 15:01:37 +00:00
if ( mult_sel )
{
m_dragged_data . init ( m_objects_model - > GetObjectIdByItem ( item ) , type ) ;
std : : set < int > & sub_obj_idxs = m_dragged_data . inst_idxs ( ) ;
wxDataViewItemArray sels ;
GetSelections ( sels ) ;
for ( auto sel : sels )
sub_obj_idxs . insert ( m_objects_model - > GetInstanceIdByItem ( sel ) ) ;
}
else
m_dragged_data . init ( m_objects_model - > GetObjectIdByItem ( item ) ,
2019-01-22 15:40:10 +00:00
type & itVolume ? m_objects_model - > GetVolumeIdByItem ( item ) :
m_objects_model - > GetInstanceIdByItem ( item ) ,
type ) ;
2018-12-13 12:19:11 +00:00
2018-10-05 21:29:15 +00:00
/* Under MSW or OSX, DnD moves an item to the place of another selected item
* But under GTK , DnD moves an item between another two items .
* And as a result - call EVT_CHANGE_SELECTION to unselect all items .
2018-12-11 08:37:58 +00:00
* To prevent such behavior use m_prevent_list_events
2018-10-05 21:29:15 +00:00
* */
m_prevent_list_events = true ; //it's needed for GTK
2018-12-13 12:19:11 +00:00
/* Under GTK, DnD requires to the wxTextDataObject been initialized with some valid value,
* so set some nonempty string
*/
wxTextDataObject * obj = new wxTextDataObject ;
obj - > SetText ( " Some text " ) ; //it's needed for GTK
2018-12-12 07:40:10 +00:00
2018-12-13 12:19:11 +00:00
event . SetDataObject ( obj ) ;
2018-12-12 07:40:10 +00:00
event . SetDragFlags ( wxDrag_DefaultMove ) ; // allows both copy and move;
2018-10-05 21:29:15 +00:00
}
2019-01-22 15:40:10 +00:00
bool ObjectList : : can_drop ( const wxDataViewItem & item ) const
{
return m_dragged_data . type ( ) = = itInstance & & ! item . IsOk ( ) | |
m_dragged_data . type ( ) = = itVolume & & item . IsOk ( ) & &
m_objects_model - > GetItemType ( item ) = = itVolume & &
m_dragged_data . obj_idx ( ) = = m_objects_model - > GetObjectIdByItem ( item ) ;
}
2018-12-11 08:37:58 +00:00
void ObjectList : : OnDropPossible ( wxDataViewEvent & event )
2018-10-05 21:29:15 +00:00
{
2019-01-22 15:40:10 +00:00
const wxDataViewItem & item = event . GetItem ( ) ;
2018-10-05 21:29:15 +00:00
2019-01-22 15:40:10 +00:00
if ( ! can_drop ( item ) )
2018-10-05 21:29:15 +00:00
event . Veto ( ) ;
}
2018-12-11 08:37:58 +00:00
void ObjectList : : OnDrop ( wxDataViewEvent & event )
2018-10-05 21:29:15 +00:00
{
2019-01-22 15:40:10 +00:00
const wxDataViewItem & item = event . GetItem ( ) ;
2018-10-05 21:29:15 +00:00
2019-01-22 15:40:10 +00:00
if ( ! can_drop ( item ) )
{
2018-10-05 21:29:15 +00:00
event . Veto ( ) ;
2018-12-12 07:40:10 +00:00
m_dragged_data . clear ( ) ;
2018-10-05 21:29:15 +00:00
return ;
}
2019-01-22 15:40:10 +00:00
if ( m_dragged_data . type ( ) = = itInstance )
{
2019-01-23 15:01:37 +00:00
instances_to_separated_object ( m_dragged_data . obj_idx ( ) , m_dragged_data . inst_idxs ( ) ) ;
2019-01-22 15:40:10 +00:00
m_dragged_data . clear ( ) ;
return ;
}
const int from_volume_id = m_dragged_data . sub_obj_idx ( ) ;
2018-10-05 21:29:15 +00:00
int to_volume_id = m_objects_model - > GetVolumeIdByItem ( item ) ;
2018-12-13 12:19:11 +00:00
// It looks like a fixed in current version of the wxWidgets
// #ifdef __WXGTK__
// /* Under GTK, DnD moves an item between another two items.
// * And event.GetItem() return item, which is under "insertion line"
// * So, if we move item down we should to decrease the to_volume_id value
// **/
// if (to_volume_id > from_volume_id) to_volume_id--;
// #endif // __WXGTK__
2018-10-05 21:29:15 +00:00
2019-01-22 15:40:10 +00:00
auto & volumes = ( * m_objects ) [ m_dragged_data . obj_idx ( ) ] - > volumes ;
2018-10-05 21:29:15 +00:00
auto delta = to_volume_id < from_volume_id ? - 1 : 1 ;
int cnt = 0 ;
for ( int id = from_volume_id ; cnt < abs ( from_volume_id - to_volume_id ) ; id + = delta , cnt + + )
std : : swap ( volumes [ id ] , volumes [ id + delta ] ) ;
2018-10-11 13:57:09 +00:00
select_item ( m_objects_model - > ReorganizeChildren ( from_volume_id , to_volume_id ,
m_objects_model - > GetParent ( item ) ) ) ;
2019-04-21 23:51:10 +00:00
changed_object ( m_dragged_data . obj_idx ( ) ) ;
2018-10-05 21:29:15 +00:00
2018-12-12 07:40:10 +00:00
m_dragged_data . clear ( ) ;
2018-10-05 21:29:15 +00:00
}
// Context Menu
2019-01-28 11:13:53 +00:00
std : : vector < std : : string > ObjectList : : get_options ( const bool is_part )
2018-10-05 21:29:15 +00:00
{
2019-03-05 09:46:57 +00:00
if ( printer_technology ( ) = = ptSLA ) {
2018-11-22 09:33:16 +00:00
SLAPrintObjectConfig full_sla_config ;
auto options = full_sla_config . keys ( ) ;
options . erase ( find ( options . begin ( ) , options . end ( ) , " layer_height " ) ) ;
return options ;
}
2018-10-05 21:29:15 +00:00
PrintRegionConfig reg_config ;
auto options = reg_config . keys ( ) ;
if ( ! is_part ) {
PrintObjectConfig obj_config ;
std : : vector < std : : string > obj_options = obj_config . keys ( ) ;
options . insert ( options . end ( ) , obj_options . begin ( ) , obj_options . end ( ) ) ;
}
return options ;
}
2019-01-25 15:39:50 +00:00
2019-01-28 11:13:53 +00:00
const std : : vector < std : : string > & ObjectList : : get_options_for_bundle ( const wxString & bundle_name )
2019-01-25 15:39:50 +00:00
{
2019-03-05 09:46:57 +00:00
const FreqSettingsBundle & bundle = printer_technology ( ) = = ptSLA ?
2019-01-25 15:39:50 +00:00
FREQ_SETTINGS_BUNDLE_SLA : FREQ_SETTINGS_BUNDLE_FFF ;
for ( auto & it : bundle )
{
if ( bundle_name = = _ ( it . first ) )
return it . second ;
}
2019-01-28 11:13:53 +00:00
#if 0
// if "Quick menu" is selected
2019-03-05 09:46:57 +00:00
FreqSettingsBundle & bundle_quick = printer_technology ( ) = = ptSLA ?
2019-01-28 11:13:53 +00:00
m_freq_settings_sla : m_freq_settings_fff ;
for ( auto & it : bundle_quick )
{
if ( bundle_name = = wxString : : Format ( _ ( L ( " Quick Add Settings (%s) " ) ) , _ ( it . first ) ) )
return it . second ;
}
# endif
2019-01-26 17:51:34 +00:00
static std : : vector < std : : string > empty ;
return empty ;
2019-01-25 15:39:50 +00:00
}
2018-12-06 13:49:14 +00:00
2019-01-28 11:13:53 +00:00
void ObjectList : : get_options_menu ( settings_menu_hierarchy & settings_menu , const bool is_part )
2018-10-05 21:29:15 +00:00
{
2019-01-28 11:13:53 +00:00
auto options = get_options ( is_part ) ;
2018-10-05 21:29:15 +00:00
2019-03-14 12:15:04 +00:00
const int extruders_cnt = extruders_count ( ) ;
2018-10-05 21:29:15 +00:00
DynamicPrintConfig config ;
for ( auto & option : options )
{
auto const opt = config . def ( ) - > get ( option ) ;
auto category = opt - > category ;
if ( category . empty ( ) | |
( category = = " Extruders " & & extruders_cnt = = 1 ) ) continue ;
2019-03-14 08:19:21 +00:00
const std : : string & label = ! opt - > full_label . empty ( ) ? opt - > full_label : opt - > label ;
2018-11-22 09:33:16 +00:00
std : : pair < std : : string , std : : string > option_label ( option , label ) ;
2018-10-05 21:29:15 +00:00
std : : vector < std : : pair < std : : string , std : : string > > new_category ;
auto & cat_opt_label = settings_menu . find ( category ) = = settings_menu . end ( ) ? new_category : settings_menu . at ( category ) ;
cat_opt_label . push_back ( option_label ) ;
if ( cat_opt_label . size ( ) = = 1 )
settings_menu [ category ] = cat_opt_label ;
}
}
2018-12-07 16:50:48 +00:00
void ObjectList : : get_settings_choice ( const wxString & category_name )
2018-12-06 13:49:14 +00:00
{
2018-10-05 21:29:15 +00:00
wxArrayString names ;
wxArrayInt selections ;
settings_menu_hierarchy settings_menu ;
2018-12-07 16:50:48 +00:00
const bool is_part = m_objects_model - > GetParent ( GetSelection ( ) ) ! = wxDataViewItem ( 0 ) ;
2018-10-05 21:29:15 +00:00
get_options_menu ( settings_menu , is_part ) ;
std : : vector < std : : pair < std : : string , std : : string > > * settings_list = nullptr ;
auto opt_keys = m_config - > keys ( ) ;
for ( auto & cat : settings_menu )
{
if ( _ ( cat . first ) = = category_name ) {
int sel = 0 ;
for ( auto & pair : cat . second ) {
names . Add ( _ ( pair . second ) ) ;
if ( find ( opt_keys . begin ( ) , opt_keys . end ( ) , pair . first ) ! = opt_keys . end ( ) )
selections . Add ( sel ) ;
sel + + ;
}
settings_list = & cat . second ;
break ;
}
}
if ( ! settings_list )
return ;
if ( wxGetSelectedChoices ( selections , _ ( L ( " Select showing settings " ) ) , category_name , names ) = = - 1 )
return ;
2019-01-28 11:13:53 +00:00
const int selection_cnt = selections . size ( ) ;
#if 0
if ( selection_cnt > 0 )
{
// Add selected items to the "Quick menu"
2019-03-05 09:46:57 +00:00
FreqSettingsBundle & freq_settings = printer_technology ( ) = = ptSLA ?
2019-01-28 11:13:53 +00:00
m_freq_settings_sla : m_freq_settings_fff ;
bool changed_existing = false ;
std : : vector < std : : string > tmp_freq_cat = { } ;
for ( auto & cat : freq_settings )
{
if ( _ ( cat . first ) = = category_name )
{
std : : vector < std : : string > & freq_settings_category = cat . second ;
freq_settings_category . clear ( ) ;
freq_settings_category . reserve ( selection_cnt ) ;
for ( auto sel : selections )
freq_settings_category . push_back ( ( * settings_list ) [ sel ] . first ) ;
changed_existing = true ;
break ;
}
}
if ( ! changed_existing )
{
// Create new "Quick menu" item
for ( auto & cat : settings_menu )
{
if ( _ ( cat . first ) = = category_name )
{
freq_settings [ cat . first ] = std : : vector < std : : string > { } ;
std : : vector < std : : string > & freq_settings_category = freq_settings . find ( cat . first ) - > second ;
freq_settings_category . reserve ( selection_cnt ) ;
for ( auto sel : selections )
freq_settings_category . push_back ( ( * settings_list ) [ sel ] . first ) ;
break ;
}
}
}
}
# endif
2018-10-05 21:29:15 +00:00
std : : vector < std : : string > selected_options ;
2019-01-28 11:13:53 +00:00
selected_options . reserve ( selection_cnt ) ;
2018-10-05 21:29:15 +00:00
for ( auto sel : selections )
selected_options . push_back ( ( * settings_list ) [ sel ] . first ) ;
2019-03-05 09:46:57 +00:00
const DynamicPrintConfig & from_config = printer_technology ( ) = = ptFFF ?
wxGetApp ( ) . preset_bundle - > prints . get_edited_preset ( ) . config :
wxGetApp ( ) . preset_bundle - > sla_prints . get_edited_preset ( ) . config ;
2019-01-28 11:13:53 +00:00
2018-10-05 21:29:15 +00:00
for ( auto & setting : ( * settings_list ) )
{
auto & opt_key = setting . first ;
if ( find ( opt_keys . begin ( ) , opt_keys . end ( ) , opt_key ) ! = opt_keys . end ( ) & &
find ( selected_options . begin ( ) , selected_options . end ( ) , opt_key ) = = selected_options . end ( ) )
m_config - > erase ( opt_key ) ;
if ( find ( opt_keys . begin ( ) , opt_keys . end ( ) , opt_key ) = = opt_keys . end ( ) & &
2019-01-28 11:13:53 +00:00
find ( selected_options . begin ( ) , selected_options . end ( ) , opt_key ) ! = selected_options . end ( ) ) {
const ConfigOption * option = from_config . option ( opt_key ) ;
if ( ! option ) {
// if current option doesn't exist in prints.get_edited_preset(),
2019-01-30 13:45:18 +00:00
// get it from default config values
option = DynamicPrintConfig : : new_from_defaults_keys ( { opt_key } ) - > option ( opt_key ) ;
2019-01-28 11:13:53 +00:00
}
m_config - > set_key_value ( opt_key , option - > clone ( ) ) ;
}
2018-10-05 21:29:15 +00:00
}
// Add settings item for object
2019-01-25 15:39:50 +00:00
update_settings_item ( ) ;
}
void ObjectList : : get_freq_settings_choice ( const wxString & bundle_name )
{
const std : : vector < std : : string > & options = get_options_for_bundle ( bundle_name ) ;
2019-05-03 14:05:49 +00:00
assert ( m_config ) ;
2019-01-25 15:39:50 +00:00
auto opt_keys = m_config - > keys ( ) ;
2019-01-28 11:13:53 +00:00
const DynamicPrintConfig & from_config = wxGetApp ( ) . preset_bundle - > prints . get_edited_preset ( ) . config ;
2019-01-25 15:39:50 +00:00
for ( auto & opt_key : options )
{
2019-01-28 11:13:53 +00:00
if ( find ( opt_keys . begin ( ) , opt_keys . end ( ) , opt_key ) = = opt_keys . end ( ) ) {
const ConfigOption * option = from_config . option ( opt_key ) ;
if ( ! option ) {
// if current option doesn't exist in prints.get_edited_preset(),
2019-01-30 13:45:18 +00:00
// get it from default config values
option = DynamicPrintConfig : : new_from_defaults_keys ( { opt_key } ) - > option ( opt_key ) ;
2019-01-28 11:13:53 +00:00
}
m_config - > set_key_value ( opt_key , option - > clone ( ) ) ;
}
2019-01-25 15:39:50 +00:00
}
// Add settings item for object
update_settings_item ( ) ;
}
void ObjectList : : update_settings_item ( )
{
2019-01-09 09:30:29 +00:00
auto item = GetSelection ( ) ;
2018-10-05 21:29:15 +00:00
if ( item ) {
2019-01-09 09:30:29 +00:00
if ( m_objects_model - > GetItemType ( item ) = = itInstance )
item = m_objects_model - > GetTopParent ( item ) ;
2019-01-07 09:32:33 +00:00
const auto settings_item = m_objects_model - > IsSettingsItem ( item ) ? item : m_objects_model - > GetSettingsItem ( item ) ;
2018-10-11 13:57:09 +00:00
select_item ( settings_item ? settings_item :
2018-10-05 21:29:15 +00:00
m_objects_model - > AddSettingsChild ( item ) ) ;
2019-05-03 12:29:28 +00:00
// update object selection on Plater
if ( ! m_prevent_canvas_selection_update )
update_selections_on_canvas ( ) ;
2018-10-05 21:29:15 +00:00
}
2018-11-09 17:39:07 +00:00
else {
auto panel = wxGetApp ( ) . sidebar ( ) . scrolled_panel ( ) ;
panel - > Freeze ( ) ;
2019-01-25 15:39:50 +00:00
wxGetApp ( ) . obj_settings ( ) - > UpdateAndShow ( true ) ;
2018-11-09 17:39:07 +00:00
panel - > Thaw ( ) ;
}
2018-10-05 21:29:15 +00:00
}
2019-05-09 12:53:01 +00:00
wxMenu * ObjectList : : append_submenu_add_generic ( wxMenu * menu , const ModelVolumeType type ) {
2018-10-05 21:29:15 +00:00
auto sub_menu = new wxMenu ;
2019-01-25 09:34:32 +00:00
if ( wxGetApp ( ) . get_mode ( ) = = comExpert ) {
2018-12-06 13:49:14 +00:00
append_menu_item ( sub_menu , wxID_ANY , _ ( L ( " Load " ) ) + " " + dots , " " ,
2019-05-09 12:53:01 +00:00
[ this , type ] ( wxCommandEvent & ) { load_subobject ( type ) ; } , " " , menu ) ;
2018-11-06 14:34:44 +00:00
sub_menu - > AppendSeparator ( ) ;
2019-01-25 09:34:32 +00:00
}
2018-11-06 14:34:44 +00:00
2019-02-22 11:12:10 +00:00
for ( auto & item : { L ( " Box " ) , L ( " Cylinder " ) , L ( " Sphere " ) , L ( " Slab " ) } ) {
2018-12-06 13:49:14 +00:00
append_menu_item ( sub_menu , wxID_ANY , _ ( item ) , " " ,
2019-05-09 12:53:01 +00:00
[ this , type , item ] ( wxCommandEvent & ) { load_generic_subobject ( item , type ) ; } , " " , menu ) ;
2018-12-06 13:49:14 +00:00
}
2018-10-05 21:29:15 +00:00
2019-05-09 12:53:01 +00:00
return sub_menu ;
2018-10-05 21:29:15 +00:00
}
2019-01-25 12:16:32 +00:00
void ObjectList : : append_menu_items_add_volume ( wxMenu * menu )
2018-12-07 16:50:48 +00:00
{
// Update "add" items(delete old & create new) settings popupmenu
2019-05-09 12:53:01 +00:00
for ( auto & item : ADD_VOLUME_MENU_ITEMS ) {
const auto settings_id = menu - > FindItem ( _ ( item . first ) ) ;
2018-12-07 16:50:48 +00:00
if ( settings_id ! = wxNOT_FOUND )
menu - > Destroy ( settings_id ) ;
}
2019-01-25 09:34:32 +00:00
const ConfigOptionMode mode = wxGetApp ( ) . get_mode ( ) ;
2019-05-09 12:53:01 +00:00
if ( mode = = comAdvanced ) {
append_menu_item ( menu , wxID_ANY , _ ( ADD_VOLUME_MENU_ITEMS [ int ( ModelVolumeType : : MODEL_PART ) ] . first ) , " " ,
[ this ] ( wxCommandEvent & ) { load_subobject ( ModelVolumeType : : MODEL_PART ) ; } , ADD_VOLUME_MENU_ITEMS [ int ( ModelVolumeType : : MODEL_PART ) ] . second ) ;
2019-01-25 09:34:32 +00:00
}
if ( mode = = comSimple ) {
2019-05-09 12:53:01 +00:00
append_menu_item ( menu , wxID_ANY , _ ( ADD_VOLUME_MENU_ITEMS [ int ( ModelVolumeType : : SUPPORT_ENFORCER ) ] . first ) , " " ,
2019-02-22 11:12:10 +00:00
[ this ] ( wxCommandEvent & ) { load_generic_subobject ( L ( " Box " ) , ModelVolumeType : : SUPPORT_ENFORCER ) ; } ,
2019-05-09 12:53:01 +00:00
ADD_VOLUME_MENU_ITEMS [ int ( ModelVolumeType : : SUPPORT_ENFORCER ) ] . second ) ;
append_menu_item ( menu , wxID_ANY , _ ( ADD_VOLUME_MENU_ITEMS [ int ( ModelVolumeType : : SUPPORT_BLOCKER ) ] . first ) , " " ,
2019-02-22 11:12:10 +00:00
[ this ] ( wxCommandEvent & ) { load_generic_subobject ( L ( " Box " ) , ModelVolumeType : : SUPPORT_BLOCKER ) ; } ,
2019-05-09 12:53:01 +00:00
ADD_VOLUME_MENU_ITEMS [ int ( ModelVolumeType : : SUPPORT_BLOCKER ) ] . second ) ;
2018-12-07 16:50:48 +00:00
return ;
}
2019-01-25 09:34:32 +00:00
2019-05-09 12:53:01 +00:00
for ( int type = mode = = comExpert ? 0 : 1 ; type < ADD_VOLUME_MENU_ITEMS . size ( ) ; type + + )
2018-12-07 16:50:48 +00:00
{
2019-05-09 12:53:01 +00:00
auto & item = ADD_VOLUME_MENU_ITEMS [ type ] ;
2018-12-07 16:50:48 +00:00
2019-05-09 12:53:01 +00:00
wxMenu * sub_menu = append_submenu_add_generic ( menu , ModelVolumeType ( type ) ) ;
append_submenu ( menu , sub_menu , wxID_ANY , _ ( item . first ) , " " , item . second ) ;
2018-12-07 16:50:48 +00:00
}
}
wxMenuItem * ObjectList : : append_menu_item_split ( wxMenu * menu )
{
2018-12-06 13:49:14 +00:00
return append_menu_item ( menu , wxID_ANY , _ ( L ( " Split to parts " ) ) , " " ,
2019-05-13 12:27:51 +00:00
[ this ] ( wxCommandEvent & ) { split ( ) ; } , " split_parts_SMALL " , menu ,
[ this ] ( ) { return is_splittable ( ) ; } , wxGetApp ( ) . plater ( ) ) ;
2018-10-05 21:29:15 +00:00
}
2019-01-25 12:16:32 +00:00
wxMenuItem * ObjectList : : append_menu_item_settings ( wxMenu * menu_ )
2018-12-07 16:50:48 +00:00
{
2019-04-24 23:45:00 +00:00
MenuWithSeparators * menu = dynamic_cast < MenuWithSeparators * > ( menu_ ) ;
2019-03-28 15:28:34 +00:00
const wxString menu_name = _ ( L ( " Add settings " ) ) ;
2019-01-25 15:39:50 +00:00
// Delete old items from settings popupmenu
2019-03-28 15:28:34 +00:00
auto settings_id = menu - > FindItem ( menu_name ) ;
2018-12-07 16:50:48 +00:00
if ( settings_id ! = wxNOT_FOUND )
menu - > Destroy ( settings_id ) ;
2019-01-25 15:39:50 +00:00
for ( auto & it : FREQ_SETTINGS_BUNDLE_FFF )
{
settings_id = menu - > FindItem ( _ ( it . first ) ) ;
if ( settings_id ! = wxNOT_FOUND )
menu - > Destroy ( settings_id ) ;
}
for ( auto & it : FREQ_SETTINGS_BUNDLE_SLA )
{
settings_id = menu - > FindItem ( _ ( it . first ) ) ;
if ( settings_id ! = wxNOT_FOUND )
menu - > Destroy ( settings_id ) ;
}
2019-01-28 11:13:53 +00:00
#if 0
for ( auto & it : m_freq_settings_fff )
{
settings_id = menu - > FindItem ( wxString : : Format ( _ ( L ( " Quick Add Settings (%s) " ) ) , _ ( it . first ) ) ) ;
if ( settings_id ! = wxNOT_FOUND )
menu - > Destroy ( settings_id ) ;
}
for ( auto & it : m_freq_settings_sla )
{
settings_id = menu - > FindItem ( wxString : : Format ( _ ( L ( " Quick Add Settings (%s) " ) ) , _ ( it . first ) ) ) ;
if ( settings_id ! = wxNOT_FOUND )
menu - > Destroy ( settings_id ) ;
}
# endif
2019-01-25 12:16:32 +00:00
menu - > DestroySeparators ( ) ; // delete old separators
const auto sel_vol = get_selected_model_volume ( ) ;
2019-02-22 11:12:10 +00:00
if ( sel_vol & & sel_vol - > type ( ) > = ModelVolumeType : : SUPPORT_ENFORCER )
2019-01-25 12:16:32 +00:00
return nullptr ;
const ConfigOptionMode mode = wxGetApp ( ) . get_mode ( ) ;
if ( mode = = comSimple )
return nullptr ;
2019-01-25 15:39:50 +00:00
// Create new items for settings popupmenu
2019-03-07 11:09:23 +00:00
if ( printer_technology ( ) = = ptFFF | |
menu - > GetMenuItems ( ) . size ( ) > 0 & & ! menu - > GetMenuItems ( ) . back ( ) - > IsSeparator ( ) )
2019-04-24 23:45:00 +00:00
menu - > SetFirstSeparator ( ) ;
2019-01-25 12:16:32 +00:00
// Add frequently settings
create_freq_settings_popupmenu ( menu ) ;
2018-12-07 16:50:48 +00:00
2019-01-25 12:16:32 +00:00
if ( mode = = comAdvanced )
2018-12-07 16:50:48 +00:00
return nullptr ;
2019-04-24 23:45:00 +00:00
menu - > SetSecondSeparator ( ) ;
2019-01-25 12:16:32 +00:00
// Add full settings list
2019-03-28 15:28:34 +00:00
auto menu_item = new wxMenuItem ( menu , wxID_ANY , menu_name ) ;
2019-04-16 08:05:45 +00:00
menu_item - > SetBitmap ( m_bmp_cog . bmp ( ) ) ;
2018-10-05 21:29:15 +00:00
2019-03-28 15:28:34 +00:00
menu_item - > SetSubMenu ( create_settings_popupmenu ( menu ) ) ;
2018-12-07 16:50:48 +00:00
return menu - > Append ( menu_item ) ;
}
wxMenuItem * ObjectList : : append_menu_item_change_type ( wxMenu * menu )
{
return append_menu_item ( menu , wxID_ANY , _ ( L ( " Change type " ) ) , " " ,
[ this ] ( wxCommandEvent & ) { change_part_type ( ) ; } , " " , menu ) ;
2018-12-06 13:49:14 +00:00
2018-10-05 21:29:15 +00:00
}
2019-05-13 12:27:51 +00:00
wxMenuItem * ObjectList : : append_menu_item_instance_to_object ( wxMenu * menu , wxWindow * parent )
2019-01-23 15:01:37 +00:00
{
return append_menu_item ( menu , wxID_ANY , _ ( L ( " Set as a Separated Object " ) ) , " " ,
2019-05-13 12:27:51 +00:00
[ this ] ( wxCommandEvent & ) { split_instances ( ) ; } , " " , menu , [ ] ( ) { return wxGetApp ( ) . plater ( ) - > can_set_instance_to_object ( ) ; } , parent ) ;
2019-01-23 15:01:37 +00:00
}
2019-03-21 08:04:11 +00:00
void ObjectList : : append_menu_items_osx ( wxMenu * menu )
2019-01-30 10:35:37 +00:00
{
2019-01-30 15:27:07 +00:00
append_menu_item ( menu , wxID_ANY , _ ( L ( " Rename " ) ) , " " ,
2019-01-30 10:35:37 +00:00
[ this ] ( wxCommandEvent & ) { rename_item ( ) ; } , " " , menu ) ;
2019-03-21 08:04:11 +00:00
2019-01-30 15:27:07 +00:00
menu - > AppendSeparator ( ) ;
}
2019-04-24 14:04:47 +00:00
wxMenuItem * ObjectList : : append_menu_item_fix_through_netfabb ( wxMenu * menu )
2019-01-30 15:27:07 +00:00
{
if ( ! is_windows10 ( ) )
2019-04-25 14:19:50 +00:00
return nullptr ;
2019-05-13 12:27:51 +00:00
Plater * plater = wxGetApp ( ) . plater ( ) ;
2019-04-24 14:04:47 +00:00
wxMenuItem * menu_item = append_menu_item ( menu , wxID_ANY , _ ( L ( " Fix through the Netfabb " ) ) , " " ,
2019-05-13 12:27:51 +00:00
[ this ] ( wxCommandEvent & ) { fix_through_netfabb ( ) ; } , " " , menu ,
[ plater ] ( ) { return plater - > can_fix_through_netfabb ( ) ; } , plater ) ;
2019-01-30 15:27:07 +00:00
menu - > AppendSeparator ( ) ;
2019-04-24 14:04:47 +00:00
return menu_item ;
2019-01-30 10:35:37 +00:00
}
2019-03-07 11:09:23 +00:00
void ObjectList : : append_menu_item_export_stl ( wxMenu * menu ) const
{
2019-04-04 13:13:43 +00:00
append_menu_item ( menu , wxID_ANY , _ ( L ( " Export as STL " ) ) + dots , " " ,
2019-05-02 11:46:39 +00:00
[ ] ( wxCommandEvent & ) { wxGetApp ( ) . plater ( ) - > export_stl ( false , true ) ; } , " " , menu ) ;
2019-03-07 11:09:23 +00:00
menu - > AppendSeparator ( ) ;
}
2019-03-28 15:28:34 +00:00
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 " ) ) ) ;
}
}
2019-04-02 14:33:52 +00:00
void ObjectList : : append_menu_item_delete ( wxMenu * menu )
{
append_menu_item ( menu , wxID_ANY , _ ( L ( " Delete " ) ) , " " ,
[ this ] ( wxCommandEvent & ) { remove ( ) ; } , " " , menu ) ;
}
2018-12-06 13:49:14 +00:00
void ObjectList : : create_object_popupmenu ( wxMenu * menu )
2018-10-05 21:29:15 +00:00
{
2019-01-30 10:35:37 +00:00
# ifdef __WXOSX__
2019-03-21 08:04:11 +00:00
append_menu_items_osx ( menu ) ;
2019-01-30 10:35:37 +00:00
# endif // __WXOSX__
2019-03-07 11:09:23 +00:00
append_menu_item_export_stl ( menu ) ;
2019-01-30 15:27:07 +00:00
append_menu_item_fix_through_netfabb ( menu ) ;
2018-11-02 11:35:26 +00:00
// Split object to parts
2018-12-07 16:50:48 +00:00
m_menu_item_split = append_menu_item_split ( menu ) ;
2018-10-05 21:29:15 +00:00
menu - > AppendSeparator ( ) ;
2019-01-25 09:34:32 +00:00
// rest of a object_menu will be added later in:
// - append_menu_items_add_volume() -> for "Add (volumes)"
// - append_menu_item_settings() -> for "Add (settings)"
2018-10-05 21:29:15 +00:00
}
2018-12-06 13:49:14 +00:00
void ObjectList : : create_sla_object_popupmenu ( wxMenu * menu )
2018-10-05 21:29:15 +00:00
{
2019-01-30 12:26:02 +00:00
# ifdef __WXOSX__
2019-03-21 08:04:11 +00:00
append_menu_items_osx ( menu ) ;
2019-01-30 12:26:02 +00:00
# endif // __WXOSX__
2019-03-07 11:09:23 +00:00
append_menu_item_export_stl ( menu ) ;
2019-01-30 15:27:07 +00:00
append_menu_item_fix_through_netfabb ( menu ) ;
2019-01-25 09:34:32 +00:00
// rest of a object_sla_menu will be added later in:
// - append_menu_item_settings() -> for "Add (settings)"
2018-12-06 13:49:14 +00:00
}
2018-10-05 21:29:15 +00:00
2018-12-06 13:49:14 +00:00
void ObjectList : : create_part_popupmenu ( wxMenu * menu )
{
2019-01-30 10:35:37 +00:00
# ifdef __WXOSX__
2019-03-21 08:04:11 +00:00
append_menu_items_osx ( menu ) ;
2019-01-30 10:35:37 +00:00
# endif // __WXOSX__
2019-01-30 15:27:07 +00:00
append_menu_item_fix_through_netfabb ( menu ) ;
2019-04-04 13:13:43 +00:00
append_menu_item_export_stl ( menu ) ;
2019-01-30 15:27:07 +00:00
2018-12-07 16:50:48 +00:00
m_menu_item_split_part = append_menu_item_split ( menu ) ;
2018-10-05 21:29:15 +00:00
2018-11-02 22:27:31 +00:00
// Append change part type
2018-10-05 21:29:15 +00:00
menu - > AppendSeparator ( ) ;
2018-12-07 16:50:48 +00:00
append_menu_item_change_type ( menu ) ;
2018-11-02 22:27:31 +00:00
2019-01-25 12:16:32 +00:00
// rest of a object_sla_menu will be added later in:
// - append_menu_item_settings() -> for "Add (settings)"
2018-10-05 21:29:15 +00:00
}
2019-01-23 15:01:37 +00:00
void ObjectList : : create_instance_popupmenu ( wxMenu * menu )
{
2019-05-13 12:27:51 +00:00
m_menu_item_split_instances = append_menu_item_instance_to_object ( menu , wxGetApp ( ) . plater ( ) ) ;
2019-01-30 09:05:54 +00:00
2019-04-04 16:01:53 +00:00
/* New behavior logic:
* 1. Split Object to several separated object , if ALL instances are selected
* 2. Separate selected instances from the initial object to the separated object ,
* if some ( not all ) instances are selected
*/
2019-01-30 09:05:54 +00:00
wxGetApp ( ) . plater ( ) - > Bind ( wxEVT_UPDATE_UI , [ this ] ( wxUpdateUIEvent & evt ) {
2019-04-04 16:01:53 +00:00
// evt.Enable(can_split_instances()); }, m_menu_item_split_instances->GetId());
evt . SetText ( wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > get_selection ( ) . is_single_full_object ( ) ?
_ ( L ( " Set as a Separated Objects " ) ) : _ ( L ( " Set as a Separated Object " ) ) ) ;
} , m_menu_item_split_instances - > GetId ( ) ) ;
2019-01-23 15:01:37 +00:00
}
2018-12-07 16:50:48 +00:00
wxMenu * ObjectList : : create_settings_popupmenu ( wxMenu * parent_menu )
2018-10-05 21:29:15 +00:00
{
wxMenu * menu = new wxMenu ;
settings_menu_hierarchy settings_menu ;
2018-12-07 16:50:48 +00:00
const bool is_part = m_objects_model - > GetParent ( GetSelection ( ) ) ! = wxDataViewItem ( 0 ) ;
get_options_menu ( settings_menu , is_part ) ;
2018-10-05 21:29:15 +00:00
2018-12-06 13:49:14 +00:00
for ( auto cat : settings_menu ) {
append_menu_item ( menu , wxID_ANY , _ ( cat . first ) , " " ,
2018-12-07 16:50:48 +00:00
[ menu , this ] ( wxCommandEvent & event ) { get_settings_choice ( menu - > GetLabel ( event . GetId ( ) ) ) ; } ,
2018-12-06 13:49:14 +00:00
CATEGORY_ICON . find ( cat . first ) = = CATEGORY_ICON . end ( ) ? wxNullBitmap : CATEGORY_ICON . at ( cat . first ) , parent_menu ) ;
2018-10-05 21:29:15 +00:00
}
2018-12-06 13:49:14 +00:00
2018-10-05 21:29:15 +00:00
return menu ;
}
2019-01-25 15:39:50 +00:00
void ObjectList : : create_freq_settings_popupmenu ( wxMenu * menu )
2019-01-25 12:16:32 +00:00
{
2019-01-28 11:13:53 +00:00
// Add default settings bundles
2019-03-05 09:46:57 +00:00
const FreqSettingsBundle & bundle = printer_technology ( ) = = ptFFF ?
2019-01-25 15:39:50 +00:00
FREQ_SETTINGS_BUNDLE_FFF : FREQ_SETTINGS_BUNDLE_SLA ;
2019-03-14 12:15:04 +00:00
const int extruders_cnt = extruders_count ( ) ;
2019-01-25 12:16:32 +00:00
2019-01-25 15:39:50 +00:00
for ( auto & it : bundle ) {
if ( it . first . empty ( ) | | it . first = = " Extruders " & & extruders_cnt = = 1 )
continue ;
append_menu_item ( menu , wxID_ANY , _ ( it . first ) , " " ,
[ menu , this ] ( wxCommandEvent & event ) { get_freq_settings_choice ( menu - > GetLabel ( event . GetId ( ) ) ) ; } ,
CATEGORY_ICON . find ( it . first ) = = CATEGORY_ICON . end ( ) ? wxNullBitmap : CATEGORY_ICON . at ( it . first ) , menu ) ;
}
2019-01-28 11:13:53 +00:00
#if 0
// Add "Quick" settings bundles
2019-03-05 09:46:57 +00:00
const FreqSettingsBundle & bundle_quick = printer_technology ( ) = = ptFFF ?
2019-01-28 11:13:53 +00:00
m_freq_settings_fff : m_freq_settings_sla ;
for ( auto & it : bundle_quick ) {
if ( it . first . empty ( ) | | it . first = = " Extruders " & & extruders_cnt = = 1 )
continue ;
append_menu_item ( menu , wxID_ANY , wxString : : Format ( _ ( L ( " Quick Add Settings (%s) " ) ) , _ ( it . first ) ) , " " ,
[ menu , this ] ( wxCommandEvent & event ) { get_freq_settings_choice ( menu - > GetLabel ( event . GetId ( ) ) ) ; } ,
CATEGORY_ICON . find ( it . first ) = = CATEGORY_ICON . end ( ) ? wxNullBitmap : CATEGORY_ICON . at ( it . first ) , menu ) ;
}
# endif
2019-01-25 12:16:32 +00:00
}
2018-11-29 14:00:23 +00:00
void ObjectList : : update_opt_keys ( t_config_option_keys & opt_keys )
{
auto full_current_opts = get_options ( false ) ;
for ( int i = opt_keys . size ( ) - 1 ; i > = 0 ; - - i )
if ( find ( full_current_opts . begin ( ) , full_current_opts . end ( ) , opt_keys [ i ] ) = = full_current_opts . end ( ) )
opt_keys . erase ( opt_keys . begin ( ) + i ) ;
}
2019-02-22 11:12:10 +00:00
void ObjectList : : load_subobject ( ModelVolumeType type )
2018-10-05 21:29:15 +00:00
{
2018-10-08 14:27:38 +00:00
auto item = GetSelection ( ) ;
2018-11-02 11:35:26 +00:00
if ( ! item | | m_objects_model - > GetParent ( item ) ! = wxDataViewItem ( 0 ) )
2018-10-05 21:29:15 +00:00
return ;
2018-11-02 11:35:26 +00:00
int obj_idx = m_objects_model - > GetIdByItem ( item ) ;
2018-10-05 21:29:15 +00:00
if ( obj_idx < 0 ) return ;
2019-04-29 13:27:59 +00:00
std : : vector < std : : pair < wxString , bool > > volumes_info ;
load_part ( ( * m_objects ) [ obj_idx ] , volumes_info , type ) ;
2018-10-05 21:29:15 +00:00
2018-10-11 13:57:09 +00:00
2019-04-29 13:27:59 +00:00
changed_object ( obj_idx ) ;
wxDataViewItem sel_item ;
for ( const auto & volume : volumes_info )
sel_item = m_objects_model - > AddVolumeChild ( item , volume . first , type , volume . second ) ;
if ( sel_item )
select_item ( sel_item ) ;
2018-10-05 21:29:15 +00:00
}
void ObjectList : : load_part ( ModelObject * model_object ,
2019-04-29 13:27:59 +00:00
std : : vector < std : : pair < wxString , bool > > & volumes_info ,
2019-02-22 11:12:10 +00:00
ModelVolumeType type )
2018-10-05 21:29:15 +00:00
{
wxWindow * parent = wxGetApp ( ) . tab_panel ( ) - > GetPage ( 0 ) ;
wxArrayString input_files ;
2018-11-15 14:27:39 +00:00
wxGetApp ( ) . import_model ( parent , input_files ) ;
2018-10-05 21:29:15 +00:00
for ( int i = 0 ; i < input_files . size ( ) ; + + i ) {
2019-01-03 13:34:53 +00:00
std : : string input_file = input_files . Item ( i ) . ToUTF8 ( ) . data ( ) ;
2018-10-05 21:29:15 +00:00
Model model ;
try {
model = Model : : read_from_file ( input_file ) ;
}
catch ( std : : exception & e ) {
2019-05-11 21:29:25 +00:00
auto msg = _ ( L ( " Error! " ) ) + " " + input_file + " : " + e . what ( ) + " . " ;
2018-10-05 21:29:15 +00:00
show_error ( parent , msg ) ;
exit ( 1 ) ;
}
for ( auto object : model . objects ) {
Vec3d delta = Vec3d : : Zero ( ) ;
if ( model_object - > origin_translation ! = Vec3d : : Zero ( ) )
{
object - > center_around_origin ( ) ;
delta = model_object - > origin_translation - object - > origin_translation ;
}
for ( auto volume : object - > volumes ) {
2019-01-18 11:52:09 +00:00
# if !ENABLE_VOLUMES_CENTERING_FIXES
2018-11-12 07:54:22 +00:00
volume - > center_geometry ( ) ;
2019-01-18 11:52:09 +00:00
# endif // !ENABLE_VOLUMES_CENTERING_FIXES
2018-11-12 07:54:22 +00:00
volume - > translate ( delta ) ;
2018-10-05 21:29:15 +00:00
auto new_volume = model_object - > add_volume ( * volume ) ;
2019-02-22 11:12:10 +00:00
new_volume - > set_type ( type ) ;
2018-10-05 21:29:15 +00:00
new_volume - > name = boost : : filesystem : : path ( input_file ) . filename ( ) . string ( ) ;
2019-04-29 13:27:59 +00:00
volumes_info . push_back ( std : : make_pair ( from_u8 ( new_volume - > name ) , new_volume - > get_mesh_errors_count ( ) > 0 ) ) ;
2018-10-05 21:29:15 +00:00
// set a default extruder value, since user can't add it manually
new_volume - > config . set_key_value ( " extruder " , new ConfigOptionInt ( 0 ) ) ;
}
}
}
}
2019-02-28 10:20:01 +00:00
// Find volume transformation, so that the chained (instance_trafo * volume_trafo) will be as close to identity
// as possible in least squares norm in regard to the 8 corners of bbox.
// Bounding box is expected to be centered around zero in all axes.
Geometry : : Transformation volume_to_bed_transformation ( const Geometry : : Transformation & instance_transformation , const BoundingBoxf3 & bbox )
{
Geometry : : Transformation out ;
if ( instance_transformation . is_scaling_uniform ( ) ) {
// No need to run the non-linear least squares fitting for uniform scaling.
// Just set the inverse.
out . set_from_transform ( instance_transformation . get_matrix ( true ) . inverse ( ) ) ;
}
2019-04-26 15:28:31 +00:00
else if ( Geometry : : is_rotation_ninety_degrees ( instance_transformation . get_rotation ( ) ) )
2019-03-01 09:09:20 +00:00
{
// Anisotropic scaling, rotation by multiples of ninety degrees.
2019-02-28 10:20:01 +00:00
Eigen : : Matrix3d instance_rotation_trafo =
( Eigen : : AngleAxisd ( instance_transformation . get_rotation ( ) . z ( ) , Vec3d : : UnitZ ( ) ) *
Eigen : : AngleAxisd ( instance_transformation . get_rotation ( ) . y ( ) , Vec3d : : UnitY ( ) ) *
Eigen : : AngleAxisd ( instance_transformation . get_rotation ( ) . x ( ) , Vec3d : : UnitX ( ) ) ) . toRotationMatrix ( ) ;
2019-03-01 09:09:20 +00:00
Eigen : : Matrix3d volume_rotation_trafo =
( Eigen : : AngleAxisd ( - instance_transformation . get_rotation ( ) . x ( ) , Vec3d : : UnitX ( ) ) *
Eigen : : AngleAxisd ( - instance_transformation . get_rotation ( ) . y ( ) , Vec3d : : UnitY ( ) ) *
Eigen : : AngleAxisd ( - instance_transformation . get_rotation ( ) . z ( ) , Vec3d : : UnitZ ( ) ) ) . toRotationMatrix ( ) ;
2019-02-28 10:20:01 +00:00
// 8 corners of the bounding box.
auto pts = Eigen : : MatrixXd ( 8 , 3 ) ;
pts ( 0 , 0 ) = bbox . min . x ( ) ; pts ( 0 , 1 ) = bbox . min . y ( ) ; pts ( 0 , 2 ) = bbox . min . z ( ) ;
pts ( 1 , 0 ) = bbox . min . x ( ) ; pts ( 1 , 1 ) = bbox . min . y ( ) ; pts ( 1 , 2 ) = bbox . max . z ( ) ;
pts ( 2 , 0 ) = bbox . min . x ( ) ; pts ( 2 , 1 ) = bbox . max . y ( ) ; pts ( 2 , 2 ) = bbox . min . z ( ) ;
pts ( 3 , 0 ) = bbox . min . x ( ) ; pts ( 3 , 1 ) = bbox . max . y ( ) ; pts ( 3 , 2 ) = bbox . max . z ( ) ;
pts ( 4 , 0 ) = bbox . max . x ( ) ; pts ( 4 , 1 ) = bbox . min . y ( ) ; pts ( 4 , 2 ) = bbox . min . z ( ) ;
pts ( 5 , 0 ) = bbox . max . x ( ) ; pts ( 5 , 1 ) = bbox . min . y ( ) ; pts ( 5 , 2 ) = bbox . max . z ( ) ;
pts ( 6 , 0 ) = bbox . max . x ( ) ; pts ( 6 , 1 ) = bbox . max . y ( ) ; pts ( 6 , 2 ) = bbox . min . z ( ) ;
pts ( 7 , 0 ) = bbox . max . x ( ) ; pts ( 7 , 1 ) = bbox . max . y ( ) ; pts ( 7 , 2 ) = bbox . max . z ( ) ;
2019-03-01 09:09:20 +00:00
// Corners of the bounding box transformed into the modifier mesh coordinate space, with inverse rotation applied to the modifier.
auto qs = pts *
( instance_rotation_trafo *
Eigen : : Scaling ( instance_transformation . get_scaling_factor ( ) . cwiseProduct ( instance_transformation . get_mirror ( ) ) ) *
volume_rotation_trafo ) . inverse ( ) . transpose ( ) ;
// Fill in scaling based on least squares fitting of the bounding box corners.
Vec3d scale ;
for ( int i = 0 ; i < 3 ; + + i )
scale ( i ) = pts . col ( i ) . dot ( qs . col ( i ) ) / pts . col ( i ) . dot ( pts . col ( i ) ) ;
out . set_rotation ( Geometry : : extract_euler_angles ( volume_rotation_trafo ) ) ;
out . set_scaling_factor ( Vec3d ( std : : abs ( scale ( 0 ) ) , std : : abs ( scale ( 1 ) ) , std : : abs ( scale ( 2 ) ) ) ) ;
out . set_mirror ( Vec3d ( scale ( 0 ) > 0 ? 1. : - 1 , scale ( 1 ) > 0 ? 1. : - 1 , scale ( 2 ) > 0 ? 1. : - 1 ) ) ;
2019-02-28 10:20:01 +00:00
}
2019-03-01 09:09:20 +00:00
else
{
// General anisotropic scaling, general rotation.
// Keep the modifier mesh in the instance coordinate system, so the modifier mesh will not be aligned with the world.
// Scale it to get the required size.
out . set_scaling_factor ( instance_transformation . get_scaling_factor ( ) . cwiseInverse ( ) ) ;
}
2019-02-28 10:20:01 +00:00
return out ;
}
2019-02-22 11:12:10 +00:00
void ObjectList : : load_generic_subobject ( const std : : string & type_name , const ModelVolumeType type )
2018-10-05 21:29:15 +00:00
{
2018-11-06 16:26:33 +00:00
const auto obj_idx = get_selected_obj_idx ( ) ;
2019-02-28 10:20:01 +00:00
if ( obj_idx < 0 )
return ;
2019-03-19 12:30:21 +00:00
const Selection & selection = wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > get_selection ( ) ;
2019-02-28 10:20:01 +00:00
assert ( obj_idx = = selection . get_object_idx ( ) ) ;
2019-03-07 09:08:21 +00:00
/** Any changes of the Object's composition is duplicated for all Object's Instances
* So , It ' s enough to take a bounding box of a first selected Instance and calculate Part ( generic_subobject ) position
*/
int instance_idx = * selection . get_instance_idxs ( ) . begin ( ) ;
2019-02-28 10:20:01 +00:00
assert ( instance_idx ! = - 1 ) ;
if ( instance_idx = = - 1 )
return ;
// Selected object
ModelObject & model_object = * ( * m_objects ) [ obj_idx ] ;
// Bounding box of the selected instance in world coordinate system including the translation, without modifiers.
BoundingBoxf3 instance_bb = model_object . instance_bounding_box ( instance_idx ) ;
2018-10-05 21:29:15 +00:00
2019-02-22 13:33:01 +00:00
const wxString name = _ ( L ( " Generic " ) ) + " - " + _ ( type_name ) ;
2018-10-05 21:29:15 +00:00
TriangleMesh mesh ;
2019-04-12 13:31:33 +00:00
double side = wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > get_size_proportional_to_max_bed_size ( 0.1 ) ;
2018-11-06 16:26:33 +00:00
2019-02-28 10:20:01 +00:00
if ( type_name = = " Box " )
// Sitting on the print bed, left front front corner at (0, 0).
2018-11-06 16:26:33 +00:00
mesh = make_cube ( side , side , side ) ;
2019-02-22 11:12:10 +00:00
else if ( type_name = = " Cylinder " )
2019-02-28 10:20:01 +00:00
// Centered around 0, sitting on the print bed.
// The cylinder has the same volume as the box above.
mesh = make_cylinder ( 0.564 * side , side ) ;
2019-02-22 11:12:10 +00:00
else if ( type_name = = " Sphere " )
2019-02-28 10:20:01 +00:00
// Centered around 0, half the sphere below the print bed, half above.
// The sphere has the same volume as the box above.
mesh = make_sphere ( 0.62 * side , PI / 18 ) ;
else if ( type_name = = " Slab " )
// Sitting on the print bed, left front front corner at (0, 0).
mesh = make_cube ( instance_bb . size ( ) . x ( ) * 1.5 , instance_bb . size ( ) . y ( ) * 1.5 , instance_bb . size ( ) . z ( ) * 0.5 ) ;
2018-10-05 21:29:15 +00:00
mesh . repair ( ) ;
2018-11-12 07:54:22 +00:00
2019-02-28 10:20:01 +00:00
// Mesh will be centered when loading.
ModelVolume * new_volume = model_object . add_volume ( std : : move ( mesh ) ) ;
2019-02-22 11:12:10 +00:00
new_volume - > set_type ( type ) ;
2018-10-05 21:29:15 +00:00
2019-01-14 12:29:06 +00:00
# if !ENABLE_GENERIC_SUBPARTS_PLACEMENT
2019-02-28 10:20:01 +00:00
new_volume - > set_offset ( Vec3d ( 0.0 , 0.0 , model_object . origin_translation ( 2 ) - mesh . stl . stats . min ( 2 ) ) ) ;
2019-01-14 12:29:06 +00:00
# endif // !ENABLE_GENERIC_SUBPARTS_PLACEMENT
2019-01-18 11:52:09 +00:00
# if !ENABLE_VOLUMES_CENTERING_FIXES
2018-11-12 07:54:22 +00:00
new_volume - > center_geometry ( ) ;
2019-01-18 11:52:09 +00:00
# endif // !ENABLE_VOLUMES_CENTERING_FIXES
2018-11-12 07:54:22 +00:00
2019-01-14 12:29:06 +00:00
# if ENABLE_GENERIC_SUBPARTS_PLACEMENT
if ( instance_idx ! = - 1 )
{
2019-02-28 10:20:01 +00:00
// First (any) GLVolume of the selected instance. They all share the same instance matrix.
2019-01-14 12:29:06 +00:00
const GLVolume * v = selection . get_volume ( * selection . get_volume_idxs ( ) . begin ( ) ) ;
2019-02-28 10:20:01 +00:00
// Transform the new modifier to be aligned with the print bed.
const BoundingBoxf3 mesh_bb = new_volume - > mesh . bounding_box ( ) ;
new_volume - > set_transformation ( volume_to_bed_transformation ( v - > get_instance_transformation ( ) , mesh_bb ) ) ;
// Set the modifier position.
auto offset = ( type_name = = " Slab " ) ?
// Slab: Lift to print bed
Vec3d ( 0. , 0. , 0.5 * mesh_bb . size ( ) . z ( ) + instance_bb . min . z ( ) - v - > get_instance_offset ( ) . z ( ) ) :
// Translate the new modifier to be pickable: move to the left front corner of the instance's bounding box, lift to print bed.
Vec3d ( instance_bb . max ( 0 ) , instance_bb . min ( 1 ) , instance_bb . min ( 2 ) ) + 0.5 * mesh_bb . size ( ) - v - > get_instance_offset ( ) ;
new_volume - > set_offset ( v - > get_instance_transformation ( ) . get_matrix ( true ) . inverse ( ) * offset ) ;
2019-01-14 12:29:06 +00:00
}
# endif // ENABLE_GENERIC_SUBPARTS_PLACEMENT
2019-02-22 13:33:01 +00:00
new_volume - > name = into_u8 ( name ) ;
2018-10-05 21:29:15 +00:00
// set a default extruder value, since user can't add it manually
new_volume - > config . set_key_value ( " extruder " , new ConfigOptionInt ( 0 ) ) ;
2019-04-21 23:51:10 +00:00
changed_object ( obj_idx ) ;
2018-10-05 21:29:15 +00:00
2019-01-09 09:30:29 +00:00
const auto object_item = m_objects_model - > GetTopParent ( GetSelection ( ) ) ;
2019-04-29 13:27:59 +00:00
select_item ( m_objects_model - > AddVolumeChild ( object_item , name , type ,
new_volume - > get_mesh_errors_count ( ) > 0 ) ) ;
2018-10-05 21:29:15 +00:00
# ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
2018-10-11 13:57:09 +00:00
selection_changed ( ) ;
2018-10-05 21:29:15 +00:00
# endif //no __WXOSX__ //__WXMSW__
}
2018-11-13 13:17:35 +00:00
void ObjectList : : del_object ( const int obj_idx )
{
wxGetApp ( ) . plater ( ) - > delete_object_from_model ( obj_idx ) ;
}
2018-10-05 21:29:15 +00:00
// Delete subobject
2018-10-12 10:00:37 +00:00
void ObjectList : : del_subobject_item ( wxDataViewItem & item )
2018-10-05 21:29:15 +00:00
{
if ( ! item ) return ;
2018-10-16 09:08:37 +00:00
int obj_idx , idx ;
ItemType type ;
2018-10-12 10:00:37 +00:00
2018-10-16 09:08:37 +00:00
m_objects_model - > GetItemInfo ( item , type , obj_idx , idx ) ;
if ( type = = itUndef )
2018-10-05 21:29:15 +00:00
return ;
2018-10-16 09:08:37 +00:00
if ( type = = itSettings )
2018-10-05 21:29:15 +00:00
del_settings_from_config ( ) ;
2018-10-16 09:08:37 +00:00
else if ( type = = itInstanceRoot & & obj_idx ! = - 1 )
del_instances_from_object ( obj_idx ) ;
else if ( idx = = - 1 )
return ;
else if ( ! del_subobject_from_object ( obj_idx , idx , type ) )
2018-10-05 21:29:15 +00:00
return ;
2019-04-29 13:27:59 +00:00
// If last volume item with warning was deleted, unmark object item
if ( type = = itVolume & & ( * m_objects ) [ obj_idx ] - > get_mesh_errors_count ( ) = = 0 )
m_objects_model - > DeleteWarningIcon ( m_objects_model - > GetParent ( item ) ) ;
2018-10-12 10:00:37 +00:00
m_objects_model - > Delete ( item ) ;
2018-10-05 21:29:15 +00:00
}
void ObjectList : : del_settings_from_config ( )
{
auto opt_keys = m_config - > keys ( ) ;
if ( opt_keys . size ( ) = = 1 & & opt_keys [ 0 ] = = " extruder " )
return ;
int extruder = - 1 ;
if ( m_config - > has ( " extruder " ) )
extruder = m_config - > option < ConfigOptionInt > ( " extruder " ) - > value ;
m_config - > clear ( ) ;
if ( extruder > = 0 )
m_config - > set_key_value ( " extruder " , new ConfigOptionInt ( extruder ) ) ;
}
2018-10-16 09:08:37 +00:00
void ObjectList : : del_instances_from_object ( const int obj_idx )
2018-10-05 21:29:15 +00:00
{
2018-10-19 09:02:50 +00:00
auto & instances = ( * m_objects ) [ obj_idx ] - > instances ;
2018-10-16 09:08:37 +00:00
if ( instances . size ( ) < = 1 )
return ;
while ( instances . size ( ) > 1 )
instances . pop_back ( ) ;
( * m_objects ) [ obj_idx ] - > invalidate_bounding_box ( ) ; // ? #ys_FIXME
2019-04-21 23:51:10 +00:00
changed_object ( obj_idx ) ;
2018-10-16 09:08:37 +00:00
}
bool ObjectList : : del_subobject_from_object ( const int obj_idx , const int idx , const int type )
{
2018-12-18 18:12:59 +00:00
if ( obj_idx = = 1000 )
// Cannot delete a wipe tower.
return false ;
2019-03-13 15:40:11 +00:00
ModelObject * object = ( * m_objects ) [ obj_idx ] ;
2018-10-16 09:08:37 +00:00
if ( type = = itVolume ) {
2019-03-13 15:40:11 +00:00
const auto volume = object - > volumes [ idx ] ;
2018-10-16 09:08:37 +00:00
// if user is deleting the last solid part, throw error
int solid_cnt = 0 ;
2019-03-13 15:40:11 +00:00
for ( auto vol : object - > volumes )
2018-10-16 09:08:37 +00:00
if ( vol - > is_model_part ( ) )
+ + solid_cnt ;
if ( volume - > is_model_part ( ) & & solid_cnt = = 1 ) {
2018-10-18 08:40:26 +00:00
Slic3r : : GUI : : show_error ( nullptr , _ ( L ( " You can't delete the last solid part from object. " ) ) ) ;
2018-10-16 09:08:37 +00:00
return false ;
}
2019-03-13 15:40:11 +00:00
object - > delete_volume ( idx ) ;
if ( object - > volumes . size ( ) = = 1 )
{
const auto last_volume = object - > volumes [ 0 ] ;
if ( ! last_volume - > config . empty ( ) ) {
object - > config . apply ( last_volume - > config ) ;
last_volume - > config . clear ( ) ;
}
}
2018-10-05 21:29:15 +00:00
}
2018-10-18 08:40:26 +00:00
else if ( type = = itInstance ) {
2019-03-13 15:40:11 +00:00
if ( object - > instances . size ( ) = = 1 ) {
2018-10-18 08:40:26 +00:00
Slic3r : : GUI : : show_error ( nullptr , _ ( L ( " You can't delete the last intance from object. " ) ) ) ;
return false ;
}
2019-03-13 15:40:11 +00:00
object - > delete_instance ( idx ) ;
2018-10-18 08:40:26 +00:00
}
2018-10-16 09:08:37 +00:00
else
return false ;
2018-10-05 21:29:15 +00:00
2019-04-21 23:51:10 +00:00
changed_object ( obj_idx ) ;
2018-10-05 21:29:15 +00:00
return true ;
}
2018-12-06 13:49:14 +00:00
void ObjectList : : split ( )
2018-10-05 21:29:15 +00:00
{
2018-10-08 14:27:38 +00:00
const auto item = GetSelection ( ) ;
2018-11-06 08:06:26 +00:00
const int obj_idx = get_selected_obj_idx ( ) ;
if ( ! item | | obj_idx < 0 )
2018-10-05 21:29:15 +00:00
return ;
2018-11-06 08:06:26 +00:00
2018-10-05 21:29:15 +00:00
ModelVolume * volume ;
2018-12-06 13:49:14 +00:00
if ( ! get_volume_by_item ( item , volume ) ) return ;
2019-03-14 12:15:04 +00:00
DynamicPrintConfig & config = printer_config ( ) ;
2018-11-08 19:44:07 +00:00
const ConfigOption * nozzle_dmtrs_opt = config . option ( " nozzle_diameter " , false ) ;
const auto nozzle_dmrs_cnt = ( nozzle_dmtrs_opt = = nullptr ) ? size_t ( 1 ) : dynamic_cast < const ConfigOptionFloats * > ( nozzle_dmtrs_opt ) - > values . size ( ) ;
2018-10-05 21:29:15 +00:00
if ( volume - > split ( nozzle_dmrs_cnt ) = = 1 ) {
wxMessageBox ( _ ( L ( " The selected object couldn't be split because it contains only one part. " ) ) ) ;
return ;
}
2019-02-05 19:23:24 +00:00
wxBusyCursor wait ;
2018-11-06 08:06:26 +00:00
auto model_object = ( * m_objects ) [ obj_idx ] ;
2018-10-05 21:29:15 +00:00
2018-11-06 08:06:26 +00:00
auto parent = m_objects_model - > GetTopParent ( item ) ;
if ( parent )
m_objects_model - > DeleteVolumeChildren ( parent ) ;
else
parent = item ;
2019-04-29 13:27:59 +00:00
for ( const ModelVolume * volume : model_object - > volumes ) {
const wxDataViewItem & vol_item = m_objects_model - > AddVolumeChild ( parent , from_u8 ( volume - > name ) ,
volume - > is_modifier ( ) ? ModelVolumeType : : PARAMETER_MODIFIER : ModelVolumeType : : MODEL_PART ,
volume - > get_mesh_errors_count ( ) > 0 ,
volume - > config . has ( " extruder " ) ?
volume - > config . option < ConfigOptionInt > ( " extruder " ) - > value : 0 ,
2019-04-11 09:09:32 +00:00
false ) ;
2018-11-06 08:06:26 +00:00
// add settings to the part, if it has those
2019-04-29 13:27:59 +00:00
auto opt_keys = volume - > config . keys ( ) ;
2018-11-06 08:06:26 +00:00
if ( ! ( opt_keys . size ( ) = = 1 & & opt_keys [ 0 ] = = " extruder " ) ) {
select_item ( m_objects_model - > AddSettingsChild ( vol_item ) ) ;
2019-04-29 13:27:59 +00:00
Expand ( vol_item ) ;
2018-11-06 08:06:26 +00:00
}
2018-10-05 21:29:15 +00:00
}
2018-11-06 14:34:44 +00:00
if ( parent = = item )
Expand ( parent ) ;
2019-04-21 23:51:10 +00:00
changed_object ( obj_idx ) ;
2018-10-05 21:29:15 +00:00
}
2018-12-06 13:49:14 +00:00
bool ObjectList : : get_volume_by_item ( const wxDataViewItem & item , ModelVolume * & volume )
2018-10-05 21:29:15 +00:00
{
2018-11-06 08:06:26 +00:00
auto obj_idx = get_selected_obj_idx ( ) ;
if ( ! item | | obj_idx < 0 )
2018-10-05 21:29:15 +00:00
return false ;
const auto volume_id = m_objects_model - > GetVolumeIdByItem ( item ) ;
2018-12-06 13:49:14 +00:00
const bool split_part = m_objects_model - > GetItemType ( item ) = = itVolume ;
2018-11-06 08:06:26 +00:00
// object is selected
2018-10-05 21:29:15 +00:00
if ( volume_id < 0 ) {
2018-11-06 08:06:26 +00:00
if ( split_part | | ( * m_objects ) [ obj_idx ] - > volumes . size ( ) > 1 )
return false ;
volume = ( * m_objects ) [ obj_idx ] - > volumes [ 0 ] ;
2018-10-05 21:29:15 +00:00
}
2018-11-06 08:06:26 +00:00
// volume is selected
2018-10-05 21:29:15 +00:00
else
2018-11-06 08:06:26 +00:00
volume = ( * m_objects ) [ obj_idx ] - > volumes [ volume_id ] ;
return true ;
2018-10-05 21:29:15 +00:00
}
2018-12-06 13:49:14 +00:00
bool ObjectList : : is_splittable ( )
2018-10-05 21:29:15 +00:00
{
2018-10-08 14:27:38 +00:00
const wxDataViewItem item = GetSelection ( ) ;
2018-10-05 21:29:15 +00:00
if ( ! item ) return false ;
ModelVolume * volume ;
2018-12-06 13:49:14 +00:00
if ( ! get_volume_by_item ( item , volume ) | | ! volume )
2018-10-05 21:29:15 +00:00
return false ;
2019-03-13 13:04:59 +00:00
return volume - > is_splittable ( ) ;
2018-10-05 21:29:15 +00:00
}
2019-01-23 15:01:37 +00:00
bool ObjectList : : selected_instances_of_same_object ( )
{
wxDataViewItemArray sels ;
GetSelections ( sels ) ;
const int obj_idx = m_objects_model - > GetObjectIdByItem ( sels . front ( ) ) ;
for ( auto item : sels ) {
if ( ! ( m_objects_model - > GetItemType ( item ) & itInstance ) | |
obj_idx ! = m_objects_model - > GetObjectIdByItem ( item ) )
return false ;
}
return true ;
}
bool ObjectList : : can_split_instances ( )
{
2019-03-19 12:30:21 +00:00
const Selection & selection = wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > get_selection ( ) ;
2019-01-23 15:01:37 +00:00
return selection . is_multiple_full_instance ( ) | | selection . is_single_full_instance ( ) ;
}
2019-04-21 23:51:10 +00:00
// NO_PARAMETERS function call means that changed object index will be determine from Selection()
void ObjectList : : changed_object ( const int obj_idx /* = -1*/ ) const
2018-10-31 14:41:27 +00:00
{
2019-04-21 23:51:10 +00:00
wxGetApp ( ) . plater ( ) - > changed_object ( obj_idx < 0 ? get_selected_obj_idx ( ) : obj_idx ) ;
2018-10-05 21:29:15 +00:00
}
void ObjectList : : part_selection_changed ( )
{
int obj_idx = - 1 ;
2019-04-24 11:33:05 +00:00
int volume_id = - 1 ;
2018-10-05 21:29:15 +00:00
m_config = nullptr ;
2018-11-09 17:39:07 +00:00
wxString og_name = wxEmptyString ;
bool update_and_show_manipulations = false ;
bool update_and_show_settings = false ;
2018-11-08 14:45:55 +00:00
2019-03-29 13:36:09 +00:00
const auto item = GetSelection ( ) ;
if ( multiple_selection ( ) | | item & & m_objects_model - > GetItemType ( item ) = = itInstanceRoot )
{
2018-11-09 17:39:07 +00:00
og_name = _ ( L ( " Group manipulation " ) ) ;
2019-03-29 13:36:09 +00:00
const Selection & selection = wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > get_selection ( ) ;
// don't show manipulation panel for case of all Object's parts selection
update_and_show_manipulations = ! selection . is_single_full_instance ( ) ;
2018-11-09 17:39:07 +00:00
}
2018-11-08 14:45:55 +00:00
else
2018-10-05 21:29:15 +00:00
{
2018-11-08 14:45:55 +00:00
if ( item )
{
if ( m_objects_model - > GetParent ( item ) = = wxDataViewItem ( 0 ) ) {
obj_idx = m_objects_model - > GetIdByItem ( item ) ;
og_name = _ ( L ( " Object manipulation " ) ) ;
m_config = & ( * m_objects ) [ obj_idx ] - > config ;
2018-11-09 17:39:07 +00:00
update_and_show_manipulations = true ;
2018-11-08 14:45:55 +00:00
}
else {
auto parent = m_objects_model - > GetParent ( item ) ;
// Take ID of the parent object to "inform" perl-side which object have to be selected on the scene
obj_idx = m_objects_model - > GetIdByItem ( parent ) ;
2018-11-09 17:39:07 +00:00
if ( m_objects_model - > GetItemType ( item ) = = itSettings ) {
2018-11-08 14:45:55 +00:00
if ( m_objects_model - > GetParent ( parent ) = = wxDataViewItem ( 0 ) ) {
og_name = _ ( L ( " Object Settings to modify " ) ) ;
m_config = & ( * m_objects ) [ obj_idx ] - > config ;
}
else {
og_name = _ ( L ( " Part Settings to modify " ) ) ;
auto main_parent = m_objects_model - > GetParent ( parent ) ;
obj_idx = m_objects_model - > GetIdByItem ( main_parent ) ;
const auto volume_id = m_objects_model - > GetVolumeIdByItem ( parent ) ;
m_config = & ( * m_objects ) [ obj_idx ] - > volumes [ volume_id ] - > config ;
}
2018-11-09 17:39:07 +00:00
update_and_show_settings = true ;
2018-10-05 21:29:15 +00:00
}
2018-11-08 14:45:55 +00:00
else if ( m_objects_model - > GetItemType ( item ) = = itVolume ) {
og_name = _ ( L ( " Part manipulation " ) ) ;
2019-04-24 11:33:05 +00:00
volume_id = m_objects_model - > GetVolumeIdByItem ( item ) ;
2018-10-05 21:29:15 +00:00
m_config = & ( * m_objects ) [ obj_idx ] - > volumes [ volume_id ] - > config ;
2018-11-09 17:39:07 +00:00
update_and_show_manipulations = true ;
2018-10-05 21:29:15 +00:00
}
2018-11-08 14:45:55 +00:00
else if ( m_objects_model - > GetItemType ( item ) = = itInstance ) {
og_name = _ ( L ( " Instance manipulation " ) ) ;
2018-11-09 17:39:07 +00:00
update_and_show_manipulations = true ;
2019-01-09 09:30:29 +00:00
// fill m_config by object's values
const int obj_idx_ = m_objects_model - > GetObjectIdByItem ( item ) ;
m_config = & ( * m_objects ) [ obj_idx_ ] - > config ;
2018-11-08 14:45:55 +00:00
}
2018-10-05 21:29:15 +00:00
}
2018-11-08 14:45:55 +00:00
}
2018-10-05 21:29:15 +00:00
}
m_selected_object_id = obj_idx ;
2018-11-09 17:39:07 +00:00
if ( update_and_show_manipulations ) {
wxGetApp ( ) . obj_manipul ( ) - > get_og ( ) - > set_name ( " " + og_name + " " ) ;
2019-04-24 11:33:05 +00:00
if ( item ) {
wxGetApp ( ) . obj_manipul ( ) - > get_og ( ) - > set_value ( " object_name " , m_objects_model - > GetName ( item ) ) ;
2019-05-02 07:54:18 +00:00
wxGetApp ( ) . obj_manipul ( ) - > update_warning_icon_state ( get_mesh_errors_list ( obj_idx , volume_id ) ) ;
2019-04-24 11:33:05 +00:00
}
2018-11-09 17:39:07 +00:00
}
if ( update_and_show_settings )
wxGetApp ( ) . obj_settings ( ) - > get_og ( ) - > set_name ( " " + og_name + " " ) ;
2018-11-13 11:19:56 +00:00
Sidebar & panel = wxGetApp ( ) . sidebar ( ) ;
panel . Freeze ( ) ;
2018-11-09 17:39:07 +00:00
wxGetApp ( ) . obj_manipul ( ) - > UpdateAndShow ( update_and_show_manipulations ) ;
wxGetApp ( ) . obj_settings ( ) - > UpdateAndShow ( update_and_show_settings ) ;
2018-11-13 11:19:56 +00:00
wxGetApp ( ) . sidebar ( ) . show_info_sizer ( ) ;
2018-11-09 17:39:07 +00:00
2018-11-13 11:19:56 +00:00
panel . Layout ( ) ;
panel . Thaw ( ) ;
2018-10-05 21:29:15 +00:00
}
2018-10-08 14:27:38 +00:00
void ObjectList : : add_object_to_list ( size_t obj_idx )
2018-10-05 21:29:15 +00:00
{
2018-10-08 14:27:38 +00:00
auto model_object = ( * m_objects ) [ obj_idx ] ;
2019-04-24 11:33:05 +00:00
const wxString & item_name = from_u8 ( model_object - > name ) ;
2018-12-11 07:53:18 +00:00
const auto item = m_objects_model - > Add ( item_name ,
! model_object - > config . has ( " extruder " ) ? 0 :
2019-04-29 13:27:59 +00:00
model_object - > config . option < ConfigOptionInt > ( " extruder " ) - > value ,
get_mesh_errors_count ( obj_idx ) > 0 ) ;
2018-10-05 21:29:15 +00:00
2018-11-06 08:06:26 +00:00
// add volumes to the object
2018-10-05 21:29:15 +00:00
if ( model_object - > volumes . size ( ) > 1 ) {
2019-04-29 13:27:59 +00:00
for ( const ModelVolume * volume : model_object - > volumes ) {
const wxDataViewItem & vol_item = m_objects_model - > AddVolumeChild ( item ,
from_u8 ( volume - > name ) ,
volume - > type ( ) ,
volume - > get_mesh_errors_count ( ) > 0 ,
! volume - > config . has ( " extruder " ) ? 0 :
volume - > config . option < ConfigOptionInt > ( " extruder " ) - > value ,
2018-12-10 09:38:32 +00:00
false ) ;
2019-04-29 13:27:59 +00:00
auto opt_keys = volume - > config . keys ( ) ;
2018-12-10 09:38:32 +00:00
if ( ! opt_keys . empty ( ) & & ! ( opt_keys . size ( ) = = 1 & & opt_keys [ 0 ] = = " extruder " ) ) {
select_item ( m_objects_model - > AddSettingsChild ( vol_item ) ) ;
2019-04-29 13:27:59 +00:00
Expand ( vol_item ) ;
2018-12-10 09:38:32 +00:00
}
}
2018-10-08 14:27:38 +00:00
Expand ( item ) ;
2018-10-05 21:29:15 +00:00
}
2018-11-06 08:06:26 +00:00
// add instances to the object, if it has those
2018-11-01 15:22:16 +00:00
if ( model_object - > instances . size ( ) > 1 )
increase_object_instances ( obj_idx , model_object - > instances . size ( ) ) ;
2018-11-06 08:06:26 +00:00
// add settings to the object, if it has those
auto opt_keys = model_object - > config . keys ( ) ;
2018-11-07 12:40:24 +00:00
if ( ! opt_keys . empty ( ) & & ! ( opt_keys . size ( ) = = 1 & & opt_keys [ 0 ] = = " extruder " ) ) {
2018-11-06 08:06:26 +00:00
select_item ( m_objects_model - > AddSettingsChild ( item ) ) ;
2019-04-29 13:27:59 +00:00
Expand ( item ) ;
2018-11-06 08:06:26 +00:00
}
2018-10-05 21:29:15 +00:00
# ifndef __WXOSX__
2018-10-11 13:57:09 +00:00
selection_changed ( ) ;
2018-10-05 21:29:15 +00:00
# endif //__WXMSW__
}
void ObjectList : : delete_object_from_list ( )
{
2018-10-08 14:27:38 +00:00
auto item = GetSelection ( ) ;
2018-10-12 10:00:37 +00:00
if ( ! item )
2018-10-05 21:29:15 +00:00
return ;
2018-10-12 10:00:37 +00:00
if ( m_objects_model - > GetParent ( item ) = = wxDataViewItem ( 0 ) )
select_item ( m_objects_model - > Delete ( item ) ) ;
else
select_item ( m_objects_model - > Delete ( m_objects_model - > GetParent ( item ) ) ) ;
}
2018-10-05 21:29:15 +00:00
2018-10-12 10:00:37 +00:00
void ObjectList : : delete_object_from_list ( const size_t obj_idx )
{
select_item ( m_objects_model - > Delete ( m_objects_model - > GetItemById ( obj_idx ) ) ) ;
}
void ObjectList : : delete_volume_from_list ( const size_t obj_idx , const size_t vol_idx )
{
select_item ( m_objects_model - > Delete ( m_objects_model - > GetItemByVolumeId ( obj_idx , vol_idx ) ) ) ;
2018-10-05 21:29:15 +00:00
}
2018-11-13 12:34:31 +00:00
void ObjectList : : delete_instance_from_list ( const size_t obj_idx , const size_t inst_idx )
{
select_item ( m_objects_model - > Delete ( m_objects_model - > GetItemByInstanceId ( obj_idx , inst_idx ) ) ) ;
}
2018-11-13 13:17:35 +00:00
void ObjectList : : delete_from_model_and_list ( const ItemType type , const int obj_idx , const int sub_obj_idx )
{
if ( ! ( type & ( itObject | itVolume | itInstance ) ) )
return ;
if ( type & itObject ) {
del_object ( obj_idx ) ;
delete_object_from_list ( obj_idx ) ;
}
else {
del_subobject_from_object ( obj_idx , sub_obj_idx , type ) ;
type = = itVolume ? delete_volume_from_list ( obj_idx , sub_obj_idx ) :
delete_instance_from_list ( obj_idx , sub_obj_idx ) ;
}
}
2018-11-14 07:53:56 +00:00
void ObjectList : : delete_from_model_and_list ( const std : : vector < ItemForDelete > & items_for_delete )
2018-11-13 13:17:35 +00:00
{
2018-11-14 10:22:13 +00:00
if ( items_for_delete . empty ( ) )
return ;
for ( std : : vector < ItemForDelete > : : const_reverse_iterator item = items_for_delete . rbegin ( ) ; item ! = items_for_delete . rend ( ) ; + + item )
2018-11-13 13:17:35 +00:00
{
2018-11-14 10:22:13 +00:00
if ( ! ( item - > type & ( itObject | itVolume | itInstance ) ) )
2018-11-13 13:17:35 +00:00
continue ;
2018-11-14 10:22:13 +00:00
if ( item - > type & itObject ) {
del_object ( item - > obj_idx ) ;
m_objects_model - > Delete ( m_objects_model - > GetItemById ( item - > obj_idx ) ) ;
2018-11-13 13:17:35 +00:00
}
else {
2018-11-23 10:54:06 +00:00
if ( ! del_subobject_from_object ( item - > obj_idx , item - > sub_obj_idx , item - > type ) )
continue ;
2018-11-14 10:22:13 +00:00
if ( item - > type & itVolume )
2018-11-21 11:27:20 +00:00
{
2018-11-14 10:22:13 +00:00
m_objects_model - > Delete ( m_objects_model - > GetItemByVolumeId ( item - > obj_idx , item - > sub_obj_idx ) ) ;
2019-03-14 08:22:15 +00:00
if ( ( * m_objects ) [ item - > obj_idx ] - > volumes . size ( ) = = 1 & &
( * m_objects ) [ item - > obj_idx ] - > config . has ( " extruder " ) )
2019-03-13 15:40:11 +00:00
{
const wxString extruder = wxString : : Format ( " %d " , ( * m_objects ) [ item - > obj_idx ] - > config . option < ConfigOptionInt > ( " extruder " ) - > value ) ;
m_objects_model - > SetValue ( extruder , m_objects_model - > GetItemById ( item - > obj_idx ) , 1 ) ;
}
2018-11-23 11:47:32 +00:00
wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > ensure_on_bed ( item - > obj_idx ) ;
2018-11-21 11:27:20 +00:00
}
2018-11-13 13:17:35 +00:00
else
2018-11-14 10:22:13 +00:00
m_objects_model - > Delete ( m_objects_model - > GetItemByInstanceId ( item - > obj_idx , item - > sub_obj_idx ) ) ;
2018-11-13 13:17:35 +00:00
}
}
part_selection_changed ( ) ;
}
2018-10-05 21:29:15 +00:00
void ObjectList : : delete_all_objects_from_list ( )
{
m_objects_model - > DeleteAll ( ) ;
part_selection_changed ( ) ;
}
2018-10-18 08:40:26 +00:00
void ObjectList : : increase_object_instances ( const size_t obj_idx , const size_t num )
{
select_item ( m_objects_model - > AddInstanceChild ( m_objects_model - > GetItemById ( obj_idx ) , num ) ) ;
}
void ObjectList : : decrease_object_instances ( const size_t obj_idx , const size_t num )
2018-10-05 21:29:15 +00:00
{
2018-10-18 08:40:26 +00:00
select_item ( m_objects_model - > DeleteLastInstance ( m_objects_model - > GetItemById ( obj_idx ) , num ) ) ;
2018-10-05 21:29:15 +00:00
}
void ObjectList : : unselect_objects ( )
{
2018-10-08 14:27:38 +00:00
if ( ! GetSelection ( ) )
2018-10-05 21:29:15 +00:00
return ;
m_prevent_list_events = true ;
2018-10-08 14:27:38 +00:00
UnselectAll ( ) ;
2018-10-05 21:29:15 +00:00
part_selection_changed ( ) ;
m_prevent_list_events = false ;
}
void ObjectList : : select_current_object ( int idx )
{
m_prevent_list_events = true ;
2018-10-08 14:27:38 +00:00
UnselectAll ( ) ;
2018-10-05 21:29:15 +00:00
if ( idx > = 0 )
2018-10-08 14:27:38 +00:00
Select ( m_objects_model - > GetItemById ( idx ) ) ;
2018-10-05 21:29:15 +00:00
part_selection_changed ( ) ;
m_prevent_list_events = false ;
}
void ObjectList : : select_current_volume ( int idx , int vol_idx )
{
if ( vol_idx < 0 ) {
select_current_object ( idx ) ;
return ;
}
m_prevent_list_events = true ;
2018-10-08 14:27:38 +00:00
UnselectAll ( ) ;
2018-10-05 21:29:15 +00:00
if ( idx > = 0 )
2018-10-08 14:27:38 +00:00
Select ( m_objects_model - > GetItemByVolumeId ( idx , vol_idx ) ) ;
2018-10-05 21:29:15 +00:00
part_selection_changed ( ) ;
m_prevent_list_events = false ;
}
void ObjectList : : remove ( )
{
2018-10-12 10:00:37 +00:00
if ( GetSelectedItemsCount ( ) = = 0 )
2018-10-05 21:29:15 +00:00
return ;
2018-10-12 10:00:37 +00:00
wxDataViewItemArray sels ;
GetSelections ( sels ) ;
for ( auto & item : sels )
{
if ( m_objects_model - > GetParent ( item ) = = wxDataViewItem ( 0 ) )
2018-11-23 10:54:06 +00:00
delete_from_model_and_list ( itObject , m_objects_model - > GetIdByItem ( item ) , - 1 ) ;
2019-03-21 08:04:11 +00:00
else {
if ( sels . size ( ) = = 1 )
select_item ( m_objects_model - > GetParent ( item ) ) ;
2018-10-12 10:00:37 +00:00
del_subobject_item ( item ) ;
2019-03-21 08:04:11 +00:00
}
2018-10-05 21:29:15 +00:00
}
}
void ObjectList : : init_objects ( )
{
m_objects = wxGetApp ( ) . model_objects ( ) ;
}
2018-10-04 14:43:10 +00:00
2018-10-10 14:22:20 +00:00
bool ObjectList : : multiple_selection ( ) const
{
2018-10-11 13:57:09 +00:00
return GetSelectedItemsCount ( ) > 1 ;
}
2019-03-29 13:36:09 +00:00
bool ObjectList : : is_selected ( const ItemType type ) const
{
const wxDataViewItem & item = GetSelection ( ) ;
if ( item )
return m_objects_model - > GetItemType ( item ) = = type ;
return false ;
}
2018-10-11 13:57:09 +00:00
void ObjectList : : update_selections ( )
{
2019-03-19 12:30:21 +00:00
const Selection & selection = wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > get_selection ( ) ;
2018-10-11 13:57:09 +00:00
wxDataViewItemArray sels ;
2019-04-02 14:33:52 +00:00
m_selection_mode = smInstance ;
2018-12-18 14:29:09 +00:00
// We doesn't update selection if SettingsItem for the current object/part is selected
if ( GetSelectedItemsCount ( ) = = 1 & & m_objects_model - > GetItemType ( GetSelection ( ) ) = = itSettings )
{
const auto item = GetSelection ( ) ;
if ( selection . is_single_full_object ( ) & &
m_objects_model - > GetIdByItem ( m_objects_model - > GetParent ( item ) ) = = selection . get_object_idx ( ) )
return ;
2019-04-09 13:42:00 +00:00
if ( selection . is_single_volume ( ) | | selection . is_any_modifier ( ) ) {
2018-12-18 14:29:09 +00:00
const auto gl_vol = selection . get_volume ( * selection . get_volume_idxs ( ) . begin ( ) ) ;
if ( m_objects_model - > GetVolumeIdByItem ( m_objects_model - > GetParent ( item ) ) = = gl_vol - > volume_idx ( ) )
return ;
}
2019-05-03 14:05:49 +00:00
// but if there is selected only one of several instances by context menu,
// then select this instance in ObjectList
if ( selection . is_single_full_instance ( ) )
sels . Add ( m_objects_model - > GetItemByInstanceId ( selection . get_object_idx ( ) , selection . get_instance_idx ( ) ) ) ;
2018-12-18 14:29:09 +00:00
}
2019-03-29 13:36:09 +00:00
else if ( selection . is_single_full_object ( ) | | selection . is_multiple_full_object ( ) )
2018-11-08 14:45:55 +00:00
{
2019-03-29 13:36:09 +00:00
const Selection : : ObjectIdxsToInstanceIdxsMap & objects_content = selection . get_content ( ) ;
for ( const auto & object : objects_content ) {
if ( object . second . size ( ) = = 1 ) // object with 1 instance
sels . Add ( m_objects_model - > GetItemById ( object . first ) ) ;
else if ( object . second . size ( ) > 1 ) // object with several instances
{
wxDataViewItemArray current_sels ;
GetSelections ( current_sels ) ;
const wxDataViewItem frst_inst_item = m_objects_model - > GetItemByInstanceId ( object . first , 0 ) ;
bool root_is_selected = false ;
for ( const auto & item : current_sels )
2019-04-02 14:33:52 +00:00
if ( item = = m_objects_model - > GetParent ( frst_inst_item ) | |
item = = m_objects_model - > GetTopParent ( frst_inst_item ) ) {
2019-03-29 13:36:09 +00:00
root_is_selected = true ;
2019-04-02 14:33:52 +00:00
sels . Add ( item ) ;
2019-03-29 13:36:09 +00:00
break ;
}
if ( root_is_selected )
continue ;
const Selection : : InstanceIdxsList & instances = object . second ;
for ( const auto & inst : instances )
sels . Add ( m_objects_model - > GetItemByInstanceId ( object . first , inst ) ) ;
}
}
2018-11-08 14:45:55 +00:00
}
2019-04-09 13:42:00 +00:00
else if ( selection . is_any_volume ( ) | | selection . is_any_modifier ( ) )
2019-03-29 13:36:09 +00:00
{
2018-11-05 12:53:30 +00:00
for ( auto idx : selection . get_volume_idxs ( ) ) {
const auto gl_vol = selection . get_volume ( idx ) ;
2019-03-29 13:36:09 +00:00
if ( gl_vol - > volume_idx ( ) > = 0 )
2018-11-17 16:23:56 +00:00
// Only add GLVolumes with non-negative volume_ids. GLVolumes with negative volume ids
// are not associated with ModelVolumes, but they are temporarily generated by the backend
// (for example, SLA supports or SLA pad).
2018-11-08 14:45:55 +00:00
sels . Add ( m_objects_model - > GetItemByVolumeId ( gl_vol - > object_idx ( ) , gl_vol - > volume_idx ( ) ) ) ;
2018-11-05 12:53:30 +00:00
}
2019-04-02 14:33:52 +00:00
m_selection_mode = smVolume ;
2018-11-05 12:53:30 +00:00
}
2019-03-29 13:36:09 +00:00
else if ( selection . is_single_full_instance ( ) | | selection . is_multiple_full_instance ( ) )
{
2018-11-05 12:53:30 +00:00
for ( auto idx : selection . get_instance_idxs ( ) ) {
sels . Add ( m_objects_model - > GetItemByInstanceId ( selection . get_object_idx ( ) , idx ) ) ;
}
2018-10-11 13:57:09 +00:00
}
2018-11-30 10:21:25 +00:00
else if ( selection . is_mixed ( ) )
{
2019-04-02 14:33:52 +00:00
const Selection : : ObjectIdxsToInstanceIdxsMap & objects_content_list = selection . get_content ( ) ;
2018-11-30 10:21:25 +00:00
for ( auto idx : selection . get_volume_idxs ( ) ) {
const auto gl_vol = selection . get_volume ( idx ) ;
const auto & glv_obj_idx = gl_vol - > object_idx ( ) ;
const auto & glv_ins_idx = gl_vol - > instance_idx ( ) ;
bool is_selected = false ;
for ( auto obj_ins : objects_content_list ) {
if ( obj_ins . first = = glv_obj_idx ) {
if ( obj_ins . second . find ( glv_ins_idx ) ! = obj_ins . second . end ( ) ) {
if ( glv_ins_idx = = 0 & & ( * m_objects ) [ glv_obj_idx ] - > instances . size ( ) = = 1 )
sels . Add ( m_objects_model - > GetItemById ( glv_obj_idx ) ) ;
else
sels . Add ( m_objects_model - > GetItemByInstanceId ( glv_obj_idx , glv_ins_idx ) ) ;
is_selected = true ;
break ;
}
}
}
if ( is_selected )
continue ;
const auto & glv_vol_idx = gl_vol - > volume_idx ( ) ;
if ( glv_vol_idx = = 0 & & ( * m_objects ) [ glv_obj_idx ] - > volumes . size ( ) = = 1 )
sels . Add ( m_objects_model - > GetItemById ( glv_obj_idx ) ) ;
else
sels . Add ( m_objects_model - > GetItemByVolumeId ( glv_obj_idx , glv_vol_idx ) ) ;
}
}
2019-04-02 14:33:52 +00:00
if ( sels . size ( ) = = 0 )
m_selection_mode = smUndef ;
2018-11-05 12:53:30 +00:00
2018-10-11 13:57:09 +00:00
select_items ( sels ) ;
2018-12-13 12:05:47 +00:00
2019-03-07 14:26:19 +00:00
// Scroll selected Item in the middle of an object list
2019-04-09 11:13:42 +00:00
this - > EnsureVisible ( this - > GetCurrentItem ( ) ) ;
2018-10-11 13:57:09 +00:00
}
void ObjectList : : update_selections_on_canvas ( )
{
2019-03-19 12:30:21 +00:00
Selection & selection = wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > get_selection ( ) ;
2018-10-11 13:57:09 +00:00
const int sel_cnt = GetSelectedItemsCount ( ) ;
if ( sel_cnt = = 0 ) {
selection . clear ( ) ;
2018-12-03 12:29:07 +00:00
wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > update_gizmos_on_off_state ( ) ;
2018-10-11 13:57:09 +00:00
return ;
}
2019-03-29 09:48:20 +00:00
auto add_to_selection = [ this ] ( const wxDataViewItem & item , Selection & selection , int instance_idx , bool as_single_selection )
2019-03-19 12:30:21 +00:00
{
2019-04-02 14:33:52 +00:00
const ItemType & type = m_objects_model - > GetItemType ( item ) ;
if ( type = = itInstanceRoot | | m_objects_model - > GetParent ( item ) = = wxDataViewItem ( 0 ) ) {
wxDataViewItem obj_item = type = = itInstanceRoot ? m_objects_model - > GetParent ( item ) : item ;
selection . add_object ( m_objects_model - > GetIdByItem ( obj_item ) , as_single_selection ) ;
2018-10-11 13:57:09 +00:00
return ;
}
2019-04-02 14:33:52 +00:00
if ( type = = itVolume ) {
2018-10-18 08:40:26 +00:00
const int obj_idx = m_objects_model - > GetIdByItem ( m_objects_model - > GetParent ( item ) ) ;
const int vol_idx = m_objects_model - > GetVolumeIdByItem ( item ) ;
2019-03-29 09:48:20 +00:00
selection . add_volume ( obj_idx , vol_idx , std : : max ( instance_idx , 0 ) , as_single_selection ) ;
2018-10-18 08:40:26 +00:00
}
2019-04-02 14:33:52 +00:00
else if ( type = = itInstance ) {
2018-10-18 08:40:26 +00:00
const int obj_idx = m_objects_model - > GetIdByItem ( m_objects_model - > GetTopParent ( item ) ) ;
const int inst_idx = m_objects_model - > GetInstanceIdByItem ( item ) ;
selection . add_instance ( obj_idx , inst_idx , as_single_selection ) ;
}
2018-10-11 13:57:09 +00:00
} ;
2019-04-04 07:35:13 +00:00
// stores current instance idx before to clear the selection
int instance_idx = selection . get_instance_idx ( ) ;
2018-10-11 13:57:09 +00:00
if ( sel_cnt = = 1 ) {
wxDataViewItem item = GetSelection ( ) ;
2018-10-18 08:40:26 +00:00
if ( m_objects_model - > GetItemType ( item ) & ( itSettings | itInstanceRoot ) )
2019-04-02 14:33:52 +00:00
add_to_selection ( m_objects_model - > GetParent ( item ) , selection , instance_idx , true ) ;
2018-10-11 13:57:09 +00:00
else
2019-04-04 07:35:13 +00:00
add_to_selection ( item , selection , instance_idx , true ) ;
2019-03-29 09:48:20 +00:00
2018-12-03 12:29:07 +00:00
wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > update_gizmos_on_off_state ( ) ;
2019-04-09 09:38:56 +00:00
wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > render ( ) ;
2018-10-11 13:57:09 +00:00
return ;
}
wxDataViewItemArray sels ;
GetSelections ( sels ) ;
selection . clear ( ) ;
for ( auto item : sels )
2019-03-29 09:48:20 +00:00
add_to_selection ( item , selection , instance_idx , false ) ;
2018-10-11 13:57:09 +00:00
2018-12-03 12:29:07 +00:00
wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > update_gizmos_on_off_state ( ) ;
2019-04-10 12:03:40 +00:00
wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > render ( ) ;
2018-10-11 13:57:09 +00:00
}
void ObjectList : : select_item ( const wxDataViewItem & item )
{
2019-03-18 15:18:28 +00:00
if ( ! item . IsOk ( ) ) { return ; }
2018-10-11 13:57:09 +00:00
m_prevent_list_events = true ;
UnselectAll ( ) ;
Select ( item ) ;
part_selection_changed ( ) ;
m_prevent_list_events = false ;
}
void ObjectList : : select_items ( const wxDataViewItemArray & sels )
{
m_prevent_list_events = true ;
UnselectAll ( ) ;
SetSelections ( sels ) ;
part_selection_changed ( ) ;
m_prevent_list_events = false ;
}
2018-10-12 10:00:37 +00:00
void ObjectList : : select_all ( )
{
SelectAll ( ) ;
selection_changed ( ) ;
}
2018-11-08 14:45:55 +00:00
void ObjectList : : select_item_all_children ( )
{
wxDataViewItemArray sels ;
// There is no selection before OR some object is selected => select all objects
if ( ! GetSelection ( ) | | m_objects_model - > GetItemType ( GetSelection ( ) ) = = itObject ) {
for ( int i = 0 ; i < m_objects - > size ( ) ; i + + )
sels . Add ( m_objects_model - > GetItemById ( i ) ) ;
2019-04-02 14:33:52 +00:00
m_selection_mode = smInstance ;
2018-11-08 14:45:55 +00:00
}
else {
const auto item = GetSelection ( ) ;
// Some volume(instance) is selected => select all volumes(instances) inside the current object
2019-04-02 14:33:52 +00:00
if ( m_objects_model - > GetItemType ( item ) & ( itVolume | itInstance ) )
2018-11-08 14:45:55 +00:00
m_objects_model - > GetChildren ( m_objects_model - > GetParent ( item ) , sels ) ;
2019-04-02 14:33:52 +00:00
m_selection_mode = m_objects_model - > GetItemType ( item ) & itVolume ? smVolume : smInstance ;
2018-11-08 14:45:55 +00:00
}
SetSelections ( sels ) ;
selection_changed ( ) ;
}
2019-04-02 14:33:52 +00:00
// update selection mode for non-multiple selection
void ObjectList : : update_selection_mode ( )
{
// All items are unselected
if ( ! GetSelection ( ) )
{
2019-04-04 13:07:54 +00:00
m_last_selected_item = wxDataViewItem ( 0 ) ;
2019-04-02 14:33:52 +00:00
m_selection_mode = smUndef ;
return ;
}
const ItemType type = m_objects_model - > GetItemType ( GetSelection ( ) ) ;
m_selection_mode = type & itSettings ? smUndef :
type & itVolume ? smVolume : smInstance ;
}
// check last selected item. If is it possible to select it
2019-04-04 13:07:54 +00:00
bool ObjectList : : check_last_selection ( wxString & msg_str )
2019-04-02 14:33:52 +00:00
{
if ( ! m_last_selected_item )
return true ;
2019-04-04 13:07:54 +00:00
const bool is_shift_pressed = wxGetKeyState ( WXK_SHIFT ) ;
2019-04-02 14:33:52 +00:00
/* We can't mix Parts and Objects/Instances.
2019-04-04 13:07:54 +00:00
* So , show information about it
2019-04-02 14:33:52 +00:00
*/
const ItemType type = m_objects_model - > GetItemType ( m_last_selected_item ) ;
2019-04-04 13:07:54 +00:00
// check a case of a selection of the Parts from different Objects
bool impossible_multipart_selection = false ;
if ( type & itVolume & & m_selection_mode = = smVolume )
{
wxDataViewItemArray sels ;
GetSelections ( sels ) ;
for ( const auto & sel : sels )
if ( sel ! = m_last_selected_item & &
m_objects_model - > GetParent ( sel ) ! = m_objects_model - > GetParent ( m_last_selected_item ) )
{
impossible_multipart_selection = true ;
break ;
}
}
if ( impossible_multipart_selection | |
type & itSettings | |
2019-04-02 14:33:52 +00:00
type & itVolume & & m_selection_mode = = smInstance | |
! ( type & itVolume ) & & m_selection_mode = = smVolume )
{
// Inform user why selection isn't complited
const wxString item_type = m_selection_mode = = smInstance ? _ ( L ( " Object or Instance " ) ) : _ ( L ( " Part " ) ) ;
2019-04-04 13:07:54 +00:00
msg_str = wxString : : Format ( _ ( L ( " Unsupported selection " ) ) + " \n \n " +
_ ( L ( " You started your selection with %s Item. " ) ) + " \n " +
_ ( L ( " In this mode you can select only other %s Items%s " ) ) ,
item_type , item_type ,
m_selection_mode = = smInstance ? " . " :
" " + _ ( L ( " of a current Object " ) ) ) ;
// Unselect last selected item, if selection is without SHIFT
if ( ! is_shift_pressed ) {
Unselect ( m_last_selected_item ) ;
show_info ( this , msg_str , _ ( L ( " Info " ) ) ) ;
}
return is_shift_pressed ;
2019-04-02 14:33:52 +00:00
}
return true ;
}
2018-10-11 13:57:09 +00:00
void ObjectList : : fix_multiselection_conflicts ( )
{
2019-04-02 14:33:52 +00:00
if ( GetSelectedItemsCount ( ) < = 1 ) {
update_selection_mode ( ) ;
return ;
}
2019-04-04 13:07:54 +00:00
wxString msg_string ;
if ( ! check_last_selection ( msg_string ) )
2018-10-11 13:57:09 +00:00
return ;
m_prevent_list_events = true ;
2018-10-10 14:22:20 +00:00
wxDataViewItemArray sels ;
GetSelections ( sels ) ;
2018-10-11 13:57:09 +00:00
2019-04-04 13:07:54 +00:00
if ( m_selection_mode = = smVolume )
{
// identify correct parent of the initial selected item
const wxDataViewItem & parent = m_objects_model - > GetParent ( m_last_selected_item = = sels . front ( ) ? sels . back ( ) : sels . front ( ) ) ;
2019-03-29 13:36:09 +00:00
2019-04-04 13:07:54 +00:00
sels . clear ( ) ;
wxDataViewItemArray children ; // selected volumes from current parent
m_objects_model - > GetChildren ( parent , children ) ;
2019-03-29 13:36:09 +00:00
2019-04-04 13:07:54 +00:00
for ( const auto child : children )
if ( IsSelected ( child ) & & m_objects_model - > GetItemType ( child ) & itVolume )
sels . Add ( child ) ;
2019-03-29 13:36:09 +00:00
2019-04-04 13:07:54 +00:00
// If some part is selected, unselect all items except of selected parts of the current object
UnselectAll ( ) ;
SetSelections ( sels ) ;
}
else
{
for ( const auto item : sels )
2019-03-29 13:36:09 +00:00
{
2019-04-04 13:07:54 +00:00
if ( ! IsSelected ( item ) ) // if this item is unselected now (from previous actions)
continue ;
2019-04-02 14:33:52 +00:00
2019-04-04 13:07:54 +00:00
if ( m_objects_model - > GetItemType ( item ) & itSettings ) {
Unselect ( item ) ;
continue ;
}
2019-04-02 14:33:52 +00:00
2019-04-04 13:07:54 +00:00
const wxDataViewItem & parent = m_objects_model - > GetParent ( item ) ;
if ( parent ! = wxDataViewItem ( 0 ) & & IsSelected ( parent ) )
Unselect ( parent ) ;
else
2019-04-02 14:33:52 +00:00
{
2019-04-04 13:07:54 +00:00
wxDataViewItemArray unsels ;
m_objects_model - > GetAllChildren ( item , unsels ) ;
for ( const auto unsel_item : unsels )
Unselect ( unsel_item ) ;
2019-04-02 14:33:52 +00:00
}
2019-04-04 13:07:54 +00:00
if ( m_objects_model - > GetItemType ( item ) & itVolume )
Unselect ( item ) ;
2019-04-02 14:33:52 +00:00
2019-04-04 13:07:54 +00:00
m_selection_mode = smInstance ;
2019-03-29 13:36:09 +00:00
}
2018-10-11 13:57:09 +00:00
}
2019-04-04 13:07:54 +00:00
if ( ! msg_string . IsEmpty ( ) )
show_info ( this , msg_string , _ ( L ( " Info " ) ) ) ;
if ( ! IsSelected ( m_last_selected_item ) )
m_last_selected_item = wxDataViewItem ( 0 ) ;
2018-10-11 13:57:09 +00:00
m_prevent_list_events = false ;
2018-10-10 14:22:20 +00:00
}
2018-11-02 22:27:31 +00:00
ModelVolume * ObjectList : : get_selected_model_volume ( )
{
auto item = GetSelection ( ) ;
if ( ! item | | m_objects_model - > GetItemType ( item ) ! = itVolume )
return nullptr ;
const auto vol_idx = m_objects_model - > GetVolumeIdByItem ( item ) ;
const auto obj_idx = get_selected_obj_idx ( ) ;
if ( vol_idx < 0 | | obj_idx < 0 )
return nullptr ;
return ( * m_objects ) [ obj_idx ] - > volumes [ vol_idx ] ;
}
void ObjectList : : change_part_type ( )
{
ModelVolume * volume = get_selected_model_volume ( ) ;
if ( ! volume )
return ;
2018-12-10 09:38:32 +00:00
2019-02-22 11:12:10 +00:00
const ModelVolumeType type = volume - > type ( ) ;
if ( type = = ModelVolumeType : : MODEL_PART )
2018-12-10 09:38:32 +00:00
{
const int obj_idx = get_selected_obj_idx ( ) ;
if ( obj_idx < 0 ) return ;
int model_part_cnt = 0 ;
for ( auto vol : ( * m_objects ) [ obj_idx ] - > volumes ) {
2019-02-22 11:12:10 +00:00
if ( vol - > type ( ) = = ModelVolumeType : : MODEL_PART )
2018-12-10 09:38:32 +00:00
+ + model_part_cnt ;
}
if ( model_part_cnt = = 1 ) {
Slic3r : : GUI : : show_error ( nullptr , _ ( L ( " You can't change a type of the last solid part of the object. " ) ) ) ;
return ;
}
}
2018-11-02 22:27:31 +00:00
2019-05-13 12:27:51 +00:00
const wxString names [ ] = { _ ( L ( " Part " ) ) , _ ( L ( " Modifier " ) ) , _ ( L ( " Support Enforcer " ) ) , _ ( L ( " Support Blocker " ) ) } ;
2018-11-02 22:27:31 +00:00
2019-05-13 13:07:53 +00:00
auto new_type = ModelVolumeType ( wxGetSingleChoiceIndex ( _ ( L ( " Type: " ) ) , _ ( L ( " Select type of part " ) ) , wxArrayString ( 4 , names ) , int ( type ) ) ) ;
2018-11-02 22:27:31 +00:00
2019-02-22 11:12:10 +00:00
if ( new_type = = type | | new_type = = ModelVolumeType : : INVALID )
2018-11-02 22:27:31 +00:00
return ;
2018-11-05 07:55:44 +00:00
const auto item = GetSelection ( ) ;
2019-02-22 11:12:10 +00:00
volume - > set_type ( new_type ) ;
2018-11-05 07:55:44 +00:00
m_objects_model - > SetVolumeType ( item , new_type ) ;
2018-11-02 22:27:31 +00:00
2019-04-21 23:51:10 +00:00
changed_object ( get_selected_obj_idx ( ) ) ;
2018-11-05 07:55:44 +00:00
// Update settings showing, if we have it
//(we show additional settings for Part and Modifier and hide it for Support Blocker/Enforcer)
const auto settings_item = m_objects_model - > GetSettingsItem ( item ) ;
if ( settings_item & &
2019-02-22 11:12:10 +00:00
( new_type = = ModelVolumeType : : SUPPORT_ENFORCER | | new_type = = ModelVolumeType : : SUPPORT_BLOCKER ) ) {
2018-11-05 07:55:44 +00:00
m_objects_model - > Delete ( settings_item ) ;
}
else if ( ! settings_item & &
2019-02-22 11:12:10 +00:00
( new_type = = ModelVolumeType : : MODEL_PART | | new_type = = ModelVolumeType : : PARAMETER_MODIFIER ) ) {
2018-11-05 07:55:44 +00:00
select_item ( m_objects_model - > AddSettingsChild ( item ) ) ;
}
2018-11-02 22:27:31 +00:00
}
2018-11-12 12:47:24 +00:00
void ObjectList : : last_volume_is_deleted ( const int obj_idx )
{
2018-12-14 15:07:28 +00:00
if ( obj_idx < 0 | | m_objects - > empty ( ) | |
obj_idx < = m_objects - > size ( ) | |
( * m_objects ) [ obj_idx ] - > volumes . empty ( ) )
2018-11-12 12:47:24 +00:00
return ;
auto volume = ( * m_objects ) [ obj_idx ] - > volumes [ 0 ] ;
// clear volume's config values
volume - > config . clear ( ) ;
// set a default extruder value, since user can't add it manually
volume - > config . set_key_value ( " extruder " , new ConfigOptionInt ( 0 ) ) ;
}
2018-11-29 11:33:04 +00:00
bool ObjectList : : has_multi_part_objects ( )
{
if ( ! m_objects_model - > IsEmpty ( ) ) {
wxDataViewItemArray items ;
m_objects_model - > GetChildren ( wxDataViewItem ( 0 ) , items ) ;
for ( auto & item : items )
if ( m_objects_model - > GetItemByType ( item , itVolume ) )
return true ;
}
return false ;
}
2018-11-29 14:00:23 +00:00
void ObjectList : : update_settings_items ( )
{
2019-03-04 08:41:25 +00:00
m_prevent_canvas_selection_update = true ;
wxDataViewItemArray sel ;
GetSelections ( sel ) ; // stash selection
2018-11-29 14:00:23 +00:00
wxDataViewItemArray items ;
m_objects_model - > GetChildren ( wxDataViewItem ( 0 ) , items ) ;
for ( auto & item : items ) {
const wxDataViewItem & settings_item = m_objects_model - > GetSettingsItem ( item ) ;
select_item ( settings_item ? settings_item : m_objects_model - > AddSettingsChild ( item ) ) ;
2019-03-06 08:28:55 +00:00
// If settings item was deleted from the list,
// it's need to be deleted from selection array, if it was there
if ( settings_item ! = m_objects_model - > GetSettingsItem ( item ) & &
sel . Index ( settings_item ) ! = wxNOT_FOUND ) {
sel . Remove ( settings_item ) ;
}
2018-11-29 14:00:23 +00:00
}
2019-03-06 08:28:55 +00:00
2019-03-04 08:41:25 +00:00
// restore selection:
SetSelections ( sel ) ;
m_prevent_canvas_selection_update = false ;
2018-11-29 14:00:23 +00:00
}
2019-01-25 09:34:32 +00:00
void ObjectList : : update_object_menu ( )
{
2019-01-25 12:16:32 +00:00
append_menu_items_add_volume ( & m_menu_object ) ;
2019-01-25 09:34:32 +00:00
}
2019-01-23 15:01:37 +00:00
void ObjectList : : instances_to_separated_object ( const int obj_idx , const std : : set < int > & inst_idxs )
2019-01-22 15:40:10 +00:00
{
2019-04-05 07:04:52 +00:00
if ( ( * m_objects ) [ obj_idx ] - > instances . size ( ) = = inst_idxs . size ( ) )
{
instances_to_separated_objects ( obj_idx ) ;
return ;
}
2019-01-22 15:40:10 +00:00
// create new object from selected instance
ModelObject * model_object = ( * m_objects ) [ obj_idx ] - > get_model ( ) - > add_object ( * ( * m_objects ) [ obj_idx ] ) ;
2019-01-23 15:01:37 +00:00
for ( int inst_idx = model_object - > instances . size ( ) - 1 ; inst_idx > = 0 ; inst_idx - - )
2019-01-22 15:40:10 +00:00
{
2019-01-23 15:01:37 +00:00
if ( find ( inst_idxs . begin ( ) , inst_idxs . end ( ) , inst_idx ) ! = inst_idxs . end ( ) )
2019-01-22 15:40:10 +00:00
continue ;
2019-01-23 15:01:37 +00:00
model_object - > delete_instance ( inst_idx ) ;
2019-01-22 15:40:10 +00:00
}
// Add new object to the object_list
add_object_to_list ( m_objects - > size ( ) - 1 ) ;
2019-01-23 15:01:37 +00:00
for ( std : : set < int > : : const_reverse_iterator it = inst_idxs . rbegin ( ) ; it ! = inst_idxs . rend ( ) ; + + it )
{
// delete selected instance from the object
del_subobject_from_object ( obj_idx , * it , itInstance ) ;
delete_instance_from_list ( obj_idx , * it ) ;
}
}
2019-04-04 16:01:53 +00:00
void ObjectList : : instances_to_separated_objects ( const int obj_idx )
{
const int inst_cnt = ( * m_objects ) [ obj_idx ] - > instances . size ( ) ;
for ( int i = inst_cnt - 1 ; i > 0 ; i - - )
{
// create new object from initial
ModelObject * object = ( * m_objects ) [ obj_idx ] - > get_model ( ) - > add_object ( * ( * m_objects ) [ obj_idx ] ) ;
for ( int inst_idx = object - > instances . size ( ) - 1 ; inst_idx > = 0 ; inst_idx - - )
{
if ( inst_idx = = i )
continue ;
// delete unnecessary instances
object - > delete_instance ( inst_idx ) ;
}
// Add new object to the object_list
add_object_to_list ( m_objects - > size ( ) - 1 ) ;
// delete current instance from the initial object
del_subobject_from_object ( obj_idx , i , itInstance ) ;
delete_instance_from_list ( obj_idx , i ) ;
}
}
2019-01-23 15:01:37 +00:00
void ObjectList : : split_instances ( )
{
2019-03-19 12:30:21 +00:00
const Selection & selection = wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > get_selection ( ) ;
2019-01-23 15:01:37 +00:00
const int obj_idx = selection . get_object_idx ( ) ;
if ( obj_idx = = - 1 )
return ;
2019-04-04 16:01:53 +00:00
if ( selection . is_single_full_object ( ) )
{
instances_to_separated_objects ( obj_idx ) ;
return ;
}
2019-01-23 15:01:37 +00:00
const int inst_idx = selection . get_instance_idx ( ) ;
const std : : set < int > inst_idxs = inst_idx < 0 ?
selection . get_instance_idxs ( ) :
std : : set < int > { inst_idx } ;
instances_to_separated_object ( obj_idx , inst_idxs ) ;
2019-01-22 15:40:10 +00:00
}
2019-01-30 10:35:37 +00:00
void ObjectList : : rename_item ( )
{
const wxDataViewItem item = GetSelection ( ) ;
if ( ! item | | ! ( m_objects_model - > GetItemType ( item ) & ( itVolume | itObject ) ) )
return ;
const wxString new_name = wxGetTextFromUser ( _ ( L ( " Enter new name " ) ) + " : " , _ ( L ( " Renaming " ) ) ,
m_objects_model - > GetName ( item ) , this ) ;
2019-01-30 12:26:02 +00:00
if ( new_name . IsEmpty ( ) )
return ;
2019-01-30 10:35:37 +00:00
bool is_unusable_symbol = false ;
std : : string chosen_name = Slic3r : : normalize_utf8_nfc ( new_name . ToUTF8 ( ) ) ;
const char * unusable_symbols = " <>:/ \\ |?* \" " ;
for ( size_t i = 0 ; i < std : : strlen ( unusable_symbols ) ; i + + ) {
if ( chosen_name . find_first_of ( unusable_symbols [ i ] ) ! = std : : string : : npos ) {
is_unusable_symbol = true ;
}
}
if ( is_unusable_symbol ) {
show_error ( this , _ ( L ( " The supplied name is not valid; " ) ) + " \n " +
_ ( L ( " the following characters are not allowed: " ) ) + " <>:/ \\ |?* \" " ) ;
return ;
}
// The icon can't be edited so get its old value and reuse it.
wxVariant valueOld ;
m_objects_model - > GetValue ( valueOld , item , 0 ) ;
2019-04-24 23:45:00 +00:00
DataViewBitmapText bmpText ;
2019-01-30 10:35:37 +00:00
bmpText < < valueOld ;
// But replace the text with the value entered by user.
bmpText . SetText ( new_name ) ;
wxVariant value ;
value < < bmpText ;
m_objects_model - > SetValue ( value , item , 0 ) ;
m_objects_model - > ItemChanged ( item ) ;
update_name_in_model ( item ) ;
}
2019-04-24 11:33:05 +00:00
void ObjectList : : fix_through_netfabb ( )
2019-01-30 15:27:07 +00:00
{
2019-04-24 11:33:05 +00:00
int obj_idx , vol_idx ;
get_selected_item_indexes ( obj_idx , vol_idx ) ;
2019-03-13 14:34:27 +00:00
wxGetApp ( ) . plater ( ) - > fix_through_netfabb ( obj_idx , vol_idx ) ;
2019-01-30 15:27:07 +00:00
2019-03-13 14:34:27 +00:00
update_item_error_icon ( obj_idx , vol_idx ) ;
}
void ObjectList : : update_item_error_icon ( const int obj_idx , const int vol_idx ) const
{
const wxDataViewItem item = vol_idx < 0 ? m_objects_model - > GetItemById ( obj_idx ) :
m_objects_model - > GetItemByVolumeId ( obj_idx , vol_idx ) ;
if ( ! item )
return ;
2019-04-29 13:27:59 +00:00
if ( get_mesh_errors_count ( obj_idx , vol_idx ) = = 0 )
{
// if whole object has no errors more,
if ( get_mesh_errors_count ( obj_idx ) = = 0 )
// unmark all items in the object
m_objects_model - > DeleteWarningIcon ( vol_idx > = 0 ? m_objects_model - > GetParent ( item ) : item , true ) ;
else
// unmark fixed item only
m_objects_model - > DeleteWarningIcon ( item ) ;
2019-03-13 14:34:27 +00:00
}
2019-01-30 15:27:07 +00:00
}
2019-04-24 23:45:00 +00:00
void ObjectList : : msw_rescale ( )
2019-04-13 21:46:52 +00:00
{
2019-04-25 14:19:50 +00:00
const int em = wxGetApp ( ) . em_unit ( ) ;
2019-04-16 08:05:45 +00:00
// update min size !!! A width of control shouldn't be a wxDefaultCoord
2019-04-25 14:19:50 +00:00
SetMinSize ( wxSize ( 1 , 15 * em ) ) ;
2019-04-13 21:46:52 +00:00
2019-04-25 14:19:50 +00:00
GetColumn ( 0 ) - > SetWidth ( 19 * em ) ;
GetColumn ( 1 ) - > SetWidth ( 8 * em ) ;
GetColumn ( 2 ) - > SetWidth ( 2 * em ) ;
2019-04-13 21:46:52 +00:00
2019-04-16 08:05:45 +00:00
// rescale all icons, used by ObjectList
2019-05-09 12:53:01 +00:00
msw_rescale_icons ( ) ;
2019-04-16 08:05:45 +00:00
2019-05-09 12:53:01 +00:00
// rescale/update existing items with bitmaps
2019-04-16 08:05:45 +00:00
m_objects_model - > Rescale ( ) ;
2019-05-09 12:53:01 +00:00
// rescale menus
for ( MenuWithSeparators * menu : { & m_menu_object ,
& m_menu_part ,
& m_menu_sla_object ,
& m_menu_instance } )
msw_rescale_menu ( menu ) ;
2019-04-13 21:46:52 +00:00
Layout ( ) ;
}
2018-12-10 12:39:56 +00:00
void ObjectList : : ItemValueChanged ( wxDataViewEvent & event )
2018-12-04 13:27:39 +00:00
{
2018-12-12 13:35:18 +00:00
if ( event . GetColumn ( ) = = 0 )
update_name_in_model ( event . GetItem ( ) ) ;
else if ( event . GetColumn ( ) = = 1 )
update_extruder_in_config ( event . GetItem ( ) ) ;
}
void ObjectList : : OnEditingDone ( wxDataViewEvent & event )
{
if ( event . GetColumn ( ) ! = 0 )
return ;
2019-04-24 23:45:00 +00:00
const auto renderer = dynamic_cast < BitmapTextRenderer * > ( GetColumn ( 0 ) - > GetRenderer ( ) ) ;
2018-12-12 13:35:18 +00:00
if ( renderer - > WasCanceled ( ) )
show_error ( this , _ ( L ( " The supplied name is not valid; " ) ) + " \n " +
_ ( L ( " the following characters are not allowed: " ) ) + " <>:/ \\ |?* \" " ) ;
2018-12-04 13:27:39 +00:00
}
2019-03-21 08:04:11 +00:00
void ObjectList : : show_multi_selection_menu ( )
2019-03-14 12:15:04 +00:00
{
wxDataViewItemArray sels ;
GetSelections ( sels ) ;
for ( const wxDataViewItem & item : sels )
if ( ! ( m_objects_model - > GetItemType ( item ) & ( itVolume | itObject ) ) )
// show this menu only for Object(s)/Volume(s) selection
return ;
wxMenu * menu = new wxMenu ( ) ;
2019-03-21 08:04:11 +00:00
if ( extruders_count ( ) > 1 )
append_menu_item ( menu , wxID_ANY , _ ( L ( " Set extruder for selected items " ) ) ,
_ ( L ( " Select extruder number for selected objects and/or parts " ) ) ,
[ this ] ( wxCommandEvent & ) { extruder_selection ( ) ; } , " " , menu ) ;
2019-03-14 12:15:04 +00:00
PopupMenu ( menu ) ;
}
void ObjectList : : extruder_selection ( )
{
wxArrayString choices ;
2019-05-10 10:54:20 +00:00
choices . Add ( _ ( L ( " default " ) ) ) ;
2019-03-14 12:15:04 +00:00
for ( int i = 1 ; i < = extruders_count ( ) ; + + i )
choices . Add ( wxString : : Format ( " %d " , i ) ) ;
const wxString & selected_extruder = wxGetSingleChoice ( _ ( L ( " Select extruder number: " ) ) ,
_ ( L ( " This extruder will be set for selected items " ) ) ,
choices , 0 , this ) ;
if ( selected_extruder . IsEmpty ( ) )
return ;
2019-05-10 10:54:20 +00:00
const int extruder_num = selected_extruder = = _ ( L ( " default " ) ) ? 0 : atoi ( selected_extruder . c_str ( ) ) ;
2019-03-14 12:15:04 +00:00
// /* Another variant for an extruder selection */
// extruder_num = wxGetNumberFromUser(_(L("Attention!!! \n"
// "It's a possibile to set an extruder number \n"
// "for whole Object(s) and/or object Part(s), \n"
// "not for an Instance. ")),
// _(L("Enter extruder number:")),
// _(L("This extruder will be set for selected items")),
// 1, 1, 5, this);
set_extruder_for_selected_items ( extruder_num ) ;
}
void ObjectList : : set_extruder_for_selected_items ( const int extruder ) const
{
wxDataViewItemArray sels ;
GetSelections ( sels ) ;
for ( const wxDataViewItem & item : sels )
{
2019-03-28 15:28:34 +00:00
DynamicPrintConfig & config = get_item_config ( item ) ;
2019-03-14 12:15:04 +00:00
if ( config . has ( " extruder " ) ) {
if ( extruder = = 0 )
config . erase ( " extruder " ) ;
else
config . option < ConfigOptionInt > ( " extruder " ) - > value = extruder ;
}
else if ( extruder > 0 )
config . set_key_value ( " extruder " , new ConfigOptionInt ( extruder ) ) ;
2019-05-10 10:54:20 +00:00
const wxString extruder_str = extruder = = 0 ? wxString ( _ ( L ( " default " ) ) ) :
2019-03-14 12:15:04 +00:00
wxString : : Format ( " %d " , config . option < ConfigOptionInt > ( " extruder " ) - > value ) ;
2019-03-28 15:28:34 +00:00
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 ) ) ;
2019-03-14 12:15:04 +00:00
wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > ensure_on_bed ( obj_idx ) ;
}
// update scene
wxGetApp ( ) . plater ( ) - > update ( ) ;
}
2018-10-04 14:43:10 +00:00
} //namespace GUI
} //namespace Slic3r