2019-05-23 07:20:11 +00:00
# include "libslic3r/libslic3r.h"
2018-10-04 14:43:10 +00:00
# include "GUI_ObjectList.hpp"
2018-10-05 21:29:15 +00:00
# include "GUI_ObjectManipulation.hpp"
2019-05-28 14:38:04 +00:00
# include "GUI_ObjectLayers.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"
2019-08-22 09:47:58 +00:00
# ifdef __WXMSW__
# include "wx/uiaction.h"
# endif /* __WXMSW__ */
2018-10-04 14:43:10 +00:00
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
2019-09-02 07:41:12 +00:00
static SettingsBundle FREQ_SETTINGS_BUNDLE_FFF =
2019-01-25 15:39:50 +00:00
{
{ 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 " } } ,
2019-07-29 14:56:00 +00:00
{ L ( " Wipe options " ) , { " wipe_into_infill " , " wipe_into_objects " } }
2019-01-25 15:39:50 +00:00
} ;
// pt_SLA
2019-09-02 07:41:12 +00:00
static SettingsBundle FREQ_SETTINGS_BUNDLE_SLA =
2019-01-25 15:39:50 +00:00
{
{ 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
2019-09-02 07:41:12 +00:00
static std : : vector < std : : pair < std : : string , std : : string > > ADD_VOLUME_MENU_ITEMS = {
2019-05-09 12:53:01 +00:00
// 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
}
2019-07-11 14:00:01 +00:00
static void take_snapshot ( const wxString & snapshot_name )
2019-07-04 15:33:19 +00:00
{
wxGetApp ( ) . plater ( ) - > take_snapshot ( snapshot_name ) ;
}
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 " ) ;
2019-07-29 14:56:00 +00:00
CATEGORY_ICON [ L ( " Wipe options " ) ] = create_scaled_bitmap ( nullptr , " funnel " ) ;
2019-04-12 09:28:07 +00:00
// 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
*/
2019-08-22 09:47:58 +00:00
# ifdef __WXMSW__
// Workaround for entering the column editing mode on Windows. Simulate keyboard enter when another column of the active line is selected.
int new_selected_column = - 1 ;
2019-09-02 07:41:12 +00:00
# endif //__WXMSW__
2019-04-04 13:07:54 +00:00
if ( wxGetKeyState ( WXK_SHIFT ) )
{
wxDataViewItemArray sels ;
GetSelections ( sels ) ;
2019-09-28 07:57:26 +00:00
if ( ! sels . empty ( ) & & sels . front ( ) = = m_last_selected_item )
2019-04-04 13:07:54 +00:00
m_last_selected_item = sels . back ( ) ;
else
m_last_selected_item = event . GetItem ( ) ;
}
2019-08-22 09:47:58 +00:00
else {
wxDataViewItem new_selected_item = event . GetItem ( ) ;
# ifdef __WXMSW__
// Workaround for entering the column editing mode on Windows. Simulate keyboard enter when another column of the active line is selected.
wxDataViewItem item ;
wxDataViewColumn * col ;
this - > HitTest ( get_mouse_position_in_control ( ) , item , col ) ;
new_selected_column = ( col = = nullptr ) ? - 1 : ( int ) col - > GetModelColumn ( ) ;
if ( new_selected_item = = m_last_selected_item & & m_last_selected_column ! = - 1 & & m_last_selected_column ! = new_selected_column ) {
// Mouse clicked on another column of the active row. Simulate keyboard enter to enter the editing mode of the current column.
wxUIActionSimulator sim ;
sim . Char ( WXK_RETURN ) ;
}
2019-09-02 07:41:12 +00:00
# endif //__WXMSW__
2019-08-22 09:47:58 +00:00
m_last_selected_item = new_selected_item ;
}
# ifdef __WXMSW__
m_last_selected_column = new_selected_column ;
2019-09-02 07:41:12 +00:00
# endif //__WXMSW__
2019-04-04 13:07:54 +00:00
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 ( ) ) ;
2019-08-20 11:01:01 +00:00
# endif //__WXMSW__
# ifndef __WXOSX__
list_manipulation ( ) ;
# endif //__WXOSX__
2018-10-04 14:43:10 +00:00
} ) ;
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
2019-07-05 18:27:44 +00:00
wxAcceleratorEntry entries [ 8 ] ;
2019-04-29 14:02:39 +00:00
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 ) ;
2019-07-05 18:27:44 +00:00
entries [ 4 ] . Set ( wxACCEL_CTRL , ( int ) ' Z ' , wxID_UNDO ) ;
entries [ 5 ] . Set ( wxACCEL_CTRL , ( int ) ' Y ' , wxID_REDO ) ;
entries [ 6 ] . Set ( wxACCEL_NORMAL , WXK_DELETE , wxID_DELETE ) ;
entries [ 7 ] . Set ( wxACCEL_NORMAL , WXK_BACK , wxID_DELETE ) ;
wxAcceleratorTable accel ( 8 , entries ) ;
2019-04-29 14:02:39 +00:00
SetAcceleratorTable ( accel ) ;
2019-06-11 08:11:42 +00:00
this - > Bind ( wxEVT_MENU , [ this ] ( wxCommandEvent & evt ) { this - > copy ( ) ; } , wxID_COPY ) ;
this - > Bind ( wxEVT_MENU , [ this ] ( wxCommandEvent & evt ) { this - > 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-07-05 18:27:44 +00:00
this - > Bind ( wxEVT_MENU , [ this ] ( wxCommandEvent & evt ) { this - > undo ( ) ; } , wxID_UNDO ) ;
this - > Bind ( wxEVT_MENU , [ this ] ( wxCommandEvent & evt ) { this - > redo ( ) ; } , wxID_REDO ) ;
2019-04-29 14:02:39 +00:00
}
2019-09-02 07:41:12 +00:00
# else //__WXOSX__
2019-05-16 08:37:06 +00:00
Bind ( wxEVT_CHAR , [ this ] ( wxKeyEvent & event ) { key_event ( event ) ; } ) ; // doesn't work on OSX
# endif
# ifdef __WXMSW__
GetMainWindow ( ) - > Bind ( wxEVT_MOTION , [ this ] ( wxMouseEvent & event ) {
2019-08-20 11:01:01 +00:00
set_tooltip_for_item ( get_mouse_position_in_control ( ) ) ;
2019-05-16 08:37:06 +00:00
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 ) ;
2019-08-22 09:47:58 +00:00
# ifdef __WXMSW__
Bind ( wxEVT_DATAVIEW_ITEM_EDITING_STARTED , & ObjectList : : OnEditingStarted , this ) ;
# endif /* __WXMSW__ */
Bind ( wxEVT_DATAVIEW_ITEM_EDITING_DONE , & ObjectList : : OnEditingDone , this ) ;
2019-05-16 08:37:06 +00:00
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-08-06 17:53:20 +00:00
Bind ( wxEVT_SIZE , ( [ this ] ( wxSizeEvent & e ) {
# ifdef __WXGTK__
// On GTK, the EnsureVisible call is postponed to Idle processing (see wxDataViewCtrl::m_ensureVisibleDefered).
// So the postponed EnsureVisible() call is planned for an item, which may not exist at the Idle processing time, if this wxEVT_SIZE
// event is succeeded by a delete of the currently active item. We are trying our luck by postponing the wxEVT_SIZE triggered EnsureVisible(),
// which seems to be working as of now.
this - > CallAfter ( [ this ] ( ) { this - > EnsureVisible ( this - > GetCurrentItem ( ) ) ; } ) ;
# else
this - > EnsureVisible ( this - > GetCurrentItem ( ) ) ;
# endif
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
2019-09-20 09:30:29 +00:00
const int em = wxGetApp ( ) . em_unit ( ) ;
2019-08-01 12:58:04 +00:00
// column ItemName(Icon+Text) of the view control:
2018-10-04 14:43:10 +00:00
// And Icon can be consisting of several bitmaps
2019-04-24 23:45:00 +00:00
AppendColumn ( new wxDataViewColumn ( _ ( L ( " Name " ) ) , new BitmapTextRenderer ( ) ,
2019-09-20 09:30:29 +00:00
colName , 20 * em , wxALIGN_LEFT , wxDATAVIEW_COL_RESIZABLE ) ) ;
2018-10-04 14:43:10 +00:00
2019-08-01 12:58:04 +00:00
// column PrintableProperty (Icon) of the view control:
2019-09-20 09:30:29 +00:00
AppendBitmapColumn ( " " , colPrint , wxDATAVIEW_CELL_INERT , 3 * em ,
2019-08-01 12:58:04 +00:00
wxALIGN_CENTER_HORIZONTAL , wxDATAVIEW_COL_RESIZABLE ) ;
// column Extruder of the view control:
2019-10-01 16:19:28 +00:00
AppendColumn ( new wxDataViewColumn ( _ ( L ( " Extruder " ) ) , new BitmapChoiceRenderer ( ) ,
colExtruder , 8 * em , wxALIGN_CENTER_HORIZONTAL , wxDATAVIEW_COL_RESIZABLE ) ) ;
2018-10-04 14:43:10 +00:00
2019-08-01 12:58:04 +00:00
// column ItemEditing of the view control:
2019-09-20 09:30:29 +00:00
AppendBitmapColumn ( _ ( L ( " Editing " ) ) , colEditing , wxDATAVIEW_CELL_INERT , 3 * em ,
2018-10-04 14:43:10 +00:00
wxALIGN_CENTER_HORIZONTAL , wxDATAVIEW_COL_RESIZABLE ) ;
2019-09-20 09:30:29 +00:00
2019-09-23 12:24:53 +00:00
// For some reason under OSX on 4K(5K) monitors in wxDataViewColumn constructor doesn't set width of column.
// Therefore, force set column width.
2019-09-20 09:30:29 +00:00
if ( wxOSX )
{
GetColumn ( colName ) - > SetWidth ( 20 * em ) ;
GetColumn ( colPrint ) - > SetWidth ( 3 * em ) ;
GetColumn ( colExtruder ) - > SetWidth ( 8 * em ) ;
}
2018-10-04 14:43:10 +00:00
}
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-09-19 10:30:16 +00:00
create_default_popupmenu ( & m_menu_default ) ;
2019-01-30 09:05:54 +00:00
}
2019-09-02 07:41:12 +00:00
void ObjectList : : get_selected_item_indexes ( int & obj_idx , int & vol_idx , const wxDataViewItem & input_item /* = wxDataViewItem(nullptr)*/ )
2019-04-24 11:33:05 +00:00
{
2019-09-02 07:41:12 +00:00
const wxDataViewItem item = input_item = = wxDataViewItem ( nullptr ) ? GetSelection ( ) : input_item ;
2019-04-24 11:33:05 +00:00
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 ( ) :
2019-06-11 15:08:47 +00:00
( * 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
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 .
*/
2019-08-20 11:01:01 +00:00
if ( ! item | | GetSelectedItemsCount ( ) > 1 )
2019-05-20 11:52:58 +00:00
{
GetMainWindow ( ) - > SetToolTip ( " " ) ; // hide tooltip
return ;
}
2019-08-20 11:01:01 +00:00
wxString tooltip = " " ;
if ( col - > GetTitle ( ) = = _ ( L ( " Editing " ) ) )
# ifdef __WXOSX__
tooltip = _ ( L ( " Right button click the icon to change the object settings " ) ) ;
# else
tooltip = _ ( L ( " Click the icon to change the object settings " ) ) ;
2019-04-30 13:46:25 +00:00
# endif //__WXMSW__
2019-08-20 11:01:01 +00:00
else if ( col - > GetTitle ( ) = = " " )
# ifdef __WXOSX__
tooltip = _ ( L ( " Right button click the icon to change the object printable property " ) ) ;
# else
tooltip = _ ( L ( " Click the icon to change the object printable property " ) ) ;
# endif //__WXMSW__
else if ( col - > GetTitle ( ) = = _ ( " Name " ) & & ( pt . x > = 2 * wxGetApp ( ) . em_unit ( ) & & pt . x < = 4 * wxGetApp ( ) . em_unit ( ) ) )
{
2019-04-24 11:33:05 +00:00
int obj_idx , vol_idx ;
get_selected_item_indexes ( obj_idx , vol_idx , item ) ;
2019-08-20 11:01:01 +00:00
tooltip = get_mesh_errors_list ( obj_idx , vol_idx ) ;
2018-10-05 21:29:15 +00:00
}
2019-08-20 11:01:01 +00:00
GetMainWindow ( ) - > SetToolTip ( 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 ) ;
2019-07-22 07:41:34 +00:00
const int obj_idx = m_objects_model - > GetObjectIdByItem ( item ) ;
2019-03-28 15:28:34 +00:00
const int vol_idx = type & itVolume ? m_objects_model - > GetVolumeIdByItem ( item ) : - 1 ;
assert ( obj_idx > = 0 | | ( ( type & itVolume ) & & vol_idx > = 0 ) ) ;
2019-05-23 13:12:19 +00:00
return type & itVolume ? ( * m_objects ) [ obj_idx ] - > volumes [ vol_idx ] - > config :
2019-06-06 12:14:29 +00:00
type & itLayer ? ( * m_objects ) [ obj_idx ] - > layer_config_ranges [ m_objects_model - > GetLayerRangeByItem ( item ) ] :
2019-05-23 13:12:19 +00:00
( * m_objects ) [ obj_idx ] - > config ;
2019-03-28 15:28:34 +00:00
}
2019-09-06 15:46:55 +00:00
void ObjectList : : update_extruder_values_for_items ( const size_t max_extruder )
2018-12-10 16:00:28 +00:00
{
2019-09-06 15:46:55 +00:00
for ( size_t i = 0 ; i < m_objects - > size ( ) ; + + i )
2018-12-10 16:00:28 +00:00
{
wxDataViewItem item = m_objects_model - > GetItemById ( i ) ;
if ( ! item ) continue ;
auto object = ( * m_objects ) [ i ] ;
wxString extruder ;
if ( ! object - > config . has ( " extruder " ) | |
2019-10-29 09:40:34 +00:00
size_t ( 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 ) ;
2019-10-01 16:19:28 +00:00
m_objects_model - > SetExtruder ( extruder , item ) ;
2018-12-10 16:00:28 +00:00
if ( object - > volumes . size ( ) > 1 ) {
2019-09-06 15:46:55 +00:00
for ( size_t id = 0 ; id < object - > volumes . size ( ) ; id + + ) {
2018-12-10 16:00:28 +00:00
item = m_objects_model - > GetItemByVolumeId ( i , id ) ;
if ( ! item ) continue ;
if ( ! object - > volumes [ id ] - > config . has ( " extruder " ) | |
2019-10-29 09:40:34 +00:00
size_t ( 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 ) ;
2019-10-01 16:19:28 +00:00
m_objects_model - > SetExtruder ( extruder , item ) ;
2018-12-10 16:00:28 +00:00
}
}
}
}
2019-09-06 15:46:55 +00:00
void ObjectList : : update_objects_list_extruder_column ( size_t extruders_count )
2018-10-04 14:43:10 +00:00
{
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
m_prevent_update_extruder_in_config = true ;
if ( m_objects & & extruders_count > 1 )
update_extruder_values_for_items ( extruders_count ) ;
2019-10-01 16:19:28 +00:00
update_extruder_colors ( ) ;
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
2019-08-01 12:58:04 +00:00
GetColumn ( colEditing ) - > 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
}
2019-10-01 16:19:28 +00:00
void ObjectList : : update_extruder_colors ( )
{
m_objects_model - > UpdateColumValues ( colExtruder ) ;
}
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
{
2019-08-01 12:58:04 +00:00
GetColumn ( colExtruder ) - > 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 ;
2019-06-06 12:14:29 +00:00
const ItemType item_type = m_objects_model - > GetItemType ( item ) ;
if ( item_type & itObject ) {
2018-12-10 13:13:01 +00:00
const int obj_idx = m_objects_model - > GetIdByItem ( item ) ;
m_config = & ( * m_objects ) [ obj_idx ] - > config ;
}
else {
2019-06-06 12:14:29 +00:00
const int obj_idx = m_objects_model - > GetIdByItem ( m_objects_model - > GetTopParent ( item ) ) ;
if ( item_type & itVolume )
{
2018-12-10 13:13:01 +00:00
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 ;
2019-06-06 12:14:29 +00:00
}
else if ( item_type & itLayer )
m_config = & get_item_config ( item ) ;
2018-12-10 13:13:01 +00:00
}
2019-10-01 16:19:28 +00:00
if ( ! m_config )
2018-10-05 21:29:15 +00:00
return ;
2019-10-01 16:19:28 +00:00
const int extruder = m_objects_model - > GetExtruderNumber ( item ) ;
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 ;
2019-07-22 11:38:53 +00:00
const int volume_id = m_objects_model - > GetVolumeIdByItem ( item ) ;
2019-08-01 13:38:00 +00:00
take_snapshot ( volume_id < 0 ? _ ( L ( " Rename Object " ) ) : _ ( L ( " Rename Sub-object " ) ) ) ;
2018-12-12 13:35:18 +00:00
2019-07-22 11:38:53 +00:00
if ( m_objects_model - > GetItemType ( item ) & itObject ) {
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 ;
}
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 " ) ;
2019-07-29 14:56:00 +00:00
CATEGORY_ICON [ L ( " Wipe options " ) ] = create_scaled_bitmap ( nullptr , " funnel " ) ;
2019-04-16 08:05:45 +00:00
// 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 ) ;
}
2019-07-02 13:26:11 +00:00
if ( const wxDataViewItem item = GetSelection ( ) )
{
const ItemType type = m_objects_model - > GetItemType ( item ) ;
// to correct visual hints for layers editing on the Scene
if ( type & ( itLayer | itLayerRoot ) ) {
wxGetApp ( ) . obj_layers ( ) - > reset_selection ( ) ;
if ( type & itLayerRoot )
wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > handle_sidebar_focus_event ( " " , false ) ;
else {
wxGetApp ( ) . obj_layers ( ) - > set_selectable_range ( m_objects_model - > GetLayerRangeByItem ( item ) ) ;
wxGetApp ( ) . obj_layers ( ) - > update_scene_from_editor_selection ( ) ;
}
}
}
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-06-10 13:22:09 +00:00
void ObjectList : : fill_layer_config_ranges_cache ( )
{
wxDataViewItemArray sel_layers ;
GetSelections ( sel_layers ) ;
const int obj_idx = m_objects_model - > GetObjectIdByItem ( sel_layers [ 0 ] ) ;
if ( obj_idx < 0 | | ( int ) m_objects - > size ( ) < = obj_idx )
return ;
const t_layer_config_ranges & ranges = object ( obj_idx ) - > layer_config_ranges ;
m_layer_config_ranges_cache . clear ( ) ;
for ( const auto layer_item : sel_layers )
if ( m_objects_model - > GetItemType ( layer_item ) & itLayer ) {
auto range = m_objects_model - > GetLayerRangeByItem ( layer_item ) ;
auto it = ranges . find ( range ) ;
if ( it ! = ranges . end ( ) )
m_layer_config_ranges_cache [ it - > first ] = it - > second ;
}
}
void ObjectList : : paste_layers_into_list ( )
{
const int obj_idx = m_objects_model - > GetObjectIdByItem ( GetSelection ( ) ) ;
if ( obj_idx < 0 | | ( int ) m_objects - > size ( ) < = obj_idx | |
m_layer_config_ranges_cache . empty ( ) | | printer_technology ( ) = = ptSLA )
return ;
const wxDataViewItem object_item = m_objects_model - > GetItemById ( obj_idx ) ;
wxDataViewItem layers_item = m_objects_model - > GetLayerRootItem ( object_item ) ;
if ( layers_item )
m_objects_model - > Delete ( layers_item ) ;
t_layer_config_ranges & ranges = object ( obj_idx ) - > layer_config_ranges ;
// and create Layer item(s) according to the layer_config_ranges
for ( const auto range : m_layer_config_ranges_cache )
ranges . emplace ( range ) ;
layers_item = add_layer_root_item ( object_item ) ;
changed_object ( obj_idx ) ;
select_item ( layers_item ) ;
# ifndef __WXOSX__
selection_changed ( ) ;
# endif //no __WXOSX__
}
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 ;
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-07-11 21:46:23 +00:00
add_settings_item ( vol_item , & volume - > config ) ;
2019-04-10 06:40:58 +00:00
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 ;
2019-09-02 07:41:12 +00:00
m_last_selected_item = wxDataViewItem ( nullptr ) ;
2019-04-12 09:28:24 +00:00
}
2019-04-10 06:40:58 +00:00
select_items ( items ) ;
2019-09-24 12:13:03 +00:00
//#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
2019-04-10 06:40:58 +00:00
selection_changed ( ) ;
2019-09-24 12:13:03 +00:00
//#endif //no __WXOSX__ //__WXMSW__
2019-04-10 06:40:58 +00:00
}
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 ) ;
2019-09-24 12:13:03 +00:00
//#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
2019-04-10 13:55:32 +00:00
selection_changed ( ) ;
2019-09-24 12:13:03 +00:00
//#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 & )
2019-08-20 11:01:01 +00:00
{
2019-10-09 11:39:24 +00:00
// Do not show the context menu if the user pressed the right mouse button on the 3D scene and released it on the objects list
GLCanvas3D * canvas = wxGetApp ( ) . plater ( ) - > canvas3D ( ) ;
bool evt_context_menu = ( canvas ! = nullptr ) ? ! canvas - > is_mouse_dragging ( ) : true ;
if ( ! evt_context_menu )
canvas - > mouse_up_cleanup ( ) ;
list_manipulation ( evt_context_menu ) ;
2019-08-20 11:01:01 +00:00
}
2019-09-19 10:30:16 +00:00
void ObjectList : : list_manipulation ( bool evt_context_menu /* = false*/ )
2018-10-05 21:29:15 +00:00
{
wxDataViewItem item ;
2019-09-06 12:50:44 +00:00
wxDataViewColumn * col = nullptr ;
2018-10-05 21:29:15 +00:00
const wxPoint pt = get_mouse_position_in_control ( ) ;
2018-10-08 14:27:38 +00:00
HitTest ( pt , item , col ) ;
2019-08-05 09:02:56 +00:00
2019-10-02 09:53:50 +00:00
if ( m_extruder_editor )
m_extruder_editor - > Hide ( ) ;
2019-09-19 12:11:56 +00:00
/* Note: Under OSX right click doesn't send "selection changed" event.
* It means that Selection ( ) will be return still previously selected item .
* Thus under OSX we should force UnselectAll ( ) , when item and col are nullptr ,
* and select new item otherwise .
*/
2019-09-19 10:30:16 +00:00
if ( ! item ) {
2019-09-23 08:17:53 +00:00
if ( col = = nullptr ) {
if ( wxOSX )
UnselectAll ( ) ;
2019-09-24 12:32:59 +00:00
else if ( ! evt_context_menu )
// Case, when last item was deleted and under GTK was called wxEVT_DATAVIEW_SELECTION_CHANGED,
// which invoked next list_manipulation(false)
2019-09-23 08:17:53 +00:00
return ;
}
2019-09-19 10:30:16 +00:00
if ( evt_context_menu ) {
show_context_menu ( evt_context_menu ) ;
return ;
}
2019-08-05 09:02:56 +00:00
}
2019-09-19 12:11:56 +00:00
if ( wxOSX & & item & & col ) {
UnselectAll ( ) ;
Select ( item ) ;
}
2018-10-05 21:29:15 +00:00
const wxString title = col - > GetTitle ( ) ;
2019-08-05 08:05:28 +00:00
if ( title = = " " )
toggle_printable_state ( item ) ;
2019-08-01 12:58:04 +00:00
else if ( title = = _ ( " Editing " ) )
2019-09-19 10:30:16 +00:00
show_context_menu ( evt_context_menu ) ;
2019-04-29 13:27:59 +00:00
else if ( title = = _ ( " Name " ) )
2018-12-12 12:18:38 +00:00
{
2019-09-20 09:30:29 +00:00
if ( wxOSX )
show_context_menu ( evt_context_menu ) ; // return context menu under OSX (related to #2909)
if ( is_windows10 ( ) )
{
int obj_idx , vol_idx ;
get_selected_item_indexes ( obj_idx , vol_idx , item ) ;
2019-04-29 13:27:59 +00:00
2019-09-20 09:30:29 +00:00
if ( get_mesh_errors_count ( obj_idx , vol_idx ) > 0 & &
pt . x > 2 * wxGetApp ( ) . em_unit ( ) & & pt . x < 4 * wxGetApp ( ) . em_unit ( ) )
fix_through_netfabb ( ) ;
}
2018-12-12 12:18:38 +00:00
}
2019-10-02 11:05:34 +00:00
// workaround for extruder editing under OSX
else if ( wxOSX & & evt_context_menu & & title = = _ ( " Extruder " ) )
2019-10-02 09:53:50 +00:00
extruder_editing ( ) ;
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__
}
2019-09-19 10:30:16 +00:00
void ObjectList : : show_context_menu ( const bool evt_context_menu )
2018-10-05 21:29:15 +00:00
{
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 ( ) ;
2019-09-19 10:30:16 +00:00
wxMenu * menu { nullptr } ;
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 ) ;
2019-06-03 13:35:21 +00:00
if ( ! ( type & ( itObject | itVolume | itLayer | itInstance ) ) )
2018-10-05 21:29:15 +00:00
return ;
2019-01-23 15:01:37 +00:00
2019-09-19 10:30:16 +00:00
menu = type & itInstance ? & m_menu_instance :
2019-06-03 13:35:21 +00:00
type & itLayer ? & m_menu_layer :
2019-09-02 07:41:12 +00:00
m_objects_model - > GetParent ( item ) ! = wxDataViewItem ( nullptr ) ? & 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 ) ;
2019-09-19 10:30:16 +00:00
}
else if ( evt_context_menu )
menu = & m_menu_default ;
2018-12-07 16:50:48 +00:00
2019-09-19 10:30:16 +00:00
if ( menu )
2018-12-06 13:49:14 +00:00
wxGetApp ( ) . plater ( ) - > PopupMenu ( menu ) ;
2018-10-05 21:29:15 +00:00
}
2019-10-02 09:53:50 +00:00
void ObjectList : : extruder_editing ( )
{
wxDataViewItem item = GetSelection ( ) ;
if ( ! item | | ! ( m_objects_model - > GetItemType ( item ) & ( itVolume | itObject ) ) )
return ;
std : : vector < wxBitmap * > icons = get_extruder_color_icons ( ) ;
if ( icons . empty ( ) )
return ;
2019-10-02 14:14:40 +00:00
const int column_width = GetColumn ( colExtruder ) - > GetWidth ( ) + wxSystemSettings : : GetMetric ( wxSYS_VSCROLL_X ) + 5 ;
2019-10-02 09:53:50 +00:00
wxPoint pos = get_mouse_position_in_control ( ) ;
2019-10-02 13:02:13 +00:00
wxSize size = wxSize ( column_width , - 1 ) ;
2019-10-02 14:14:40 +00:00
pos . x = GetColumn ( colName ) - > GetWidth ( ) + GetColumn ( colPrint ) - > GetWidth ( ) + 5 ;
2019-10-02 13:02:13 +00:00
pos . y - = GetTextExtent ( " m " ) . y ;
2019-10-02 09:53:50 +00:00
if ( ! m_extruder_editor )
2019-10-02 13:02:13 +00:00
m_extruder_editor = new wxBitmapComboBox ( this , wxID_ANY , wxEmptyString , pos , size ,
2019-10-02 11:05:34 +00:00
0 , nullptr , wxCB_READONLY ) ;
2019-10-02 09:53:50 +00:00
else
{
m_extruder_editor - > SetPosition ( pos ) ;
2019-10-02 13:02:13 +00:00
m_extruder_editor - > SetMinSize ( size ) ;
m_extruder_editor - > SetSize ( size ) ;
2019-10-02 09:53:50 +00:00
m_extruder_editor - > Clear ( ) ;
m_extruder_editor - > Show ( ) ;
}
int i = 0 ;
for ( wxBitmap * bmp : icons ) {
if ( i = = 0 ) {
m_extruder_editor - > Append ( _ ( L ( " default " ) ) , * bmp ) ;
+ + i ;
}
m_extruder_editor - > Append ( wxString : : Format ( " %d " , i ) , * bmp ) ;
+ + i ;
}
m_extruder_editor - > SetSelection ( m_objects_model - > GetExtruderNumber ( item ) ) ;
2019-10-02 13:02:13 +00:00
auto set_extruder = [ this ] ( )
2019-10-02 09:53:50 +00:00
{
2019-10-02 13:02:13 +00:00
wxDataViewItem item = GetSelection ( ) ;
if ( ! item ) return ;
2019-10-02 09:53:50 +00:00
const int selection = m_extruder_editor - > GetSelection ( ) ;
if ( selection > = 0 )
m_objects_model - > SetExtruder ( m_extruder_editor - > GetString ( selection ) , item ) ;
m_extruder_editor - > Hide ( ) ;
} ;
// to avoid event propagation to other sidebar items
m_extruder_editor - > Bind ( wxEVT_COMBOBOX , [ set_extruder ] ( wxCommandEvent & evt )
{
set_extruder ( ) ;
evt . StopPropagation ( ) ;
} ) ;
2019-10-02 13:02:13 +00:00
/*
2019-10-02 09:53:50 +00:00
m_extruder_editor - > Bind ( wxEVT_KILL_FOCUS , [ set_extruder ] ( wxFocusEvent & evt )
{
set_extruder ( ) ;
evt . Skip ( ) ;
2019-10-02 13:02:13 +00:00
} ) ; */
2019-10-02 09:53:50 +00:00
}
2019-06-11 08:11:42 +00:00
void ObjectList : : copy ( )
{
2019-07-31 07:46:45 +00:00
// if (m_selection_mode & smLayer)
// fill_layer_config_ranges_cache();
// else {
// m_layer_config_ranges_cache.clear();
2019-06-11 08:11:42 +00:00
wxPostEvent ( ( wxEvtHandler * ) wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > get_wxglcanvas ( ) , SimpleEvent ( EVT_GLTOOLBAR_COPY ) ) ;
2019-07-31 07:46:45 +00:00
// }
2019-06-11 08:11:42 +00:00
}
void ObjectList : : paste ( )
{
2019-07-31 07:46:45 +00:00
// if (!m_layer_config_ranges_cache.empty())
// paste_layers_into_list();
// else
2019-06-11 08:11:42 +00:00
wxPostEvent ( ( wxEvtHandler * ) wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > get_wxglcanvas ( ) , SimpleEvent ( EVT_GLTOOLBAR_PASTE ) ) ;
}
2019-07-05 18:27:44 +00:00
void ObjectList : : undo ( )
{
wxGetApp ( ) . plater ( ) - > undo ( ) ;
}
void ObjectList : : redo ( )
{
wxGetApp ( ) . plater ( ) - > redo ( ) ;
}
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-06-11 08:11:42 +00:00
else if ( wxGetKeyState ( wxKeyCode ( ' C ' ) ) & & wxGetKeyState ( WXK_CONTROL ) )
copy ( ) ;
2019-04-16 11:47:37 +00:00
else if ( wxGetKeyState ( wxKeyCode ( ' V ' ) ) & & wxGetKeyState ( WXK_CONTROL ) )
2019-06-11 08:11:42 +00:00
paste ( ) ;
2019-07-05 18:27:44 +00:00
else if ( wxGetKeyState ( wxKeyCode ( ' Y ' ) ) & & wxGetKeyState ( WXK_CONTROL ) )
redo ( ) ;
else if ( wxGetKeyState ( wxKeyCode ( ' Z ' ) ) & & wxGetKeyState ( WXK_CONTROL ) )
undo ( ) ;
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 ( ) ;
2019-09-02 07:41:12 +00:00
if ( ( mult_sel & & ! selected_instances_of_same_object ( ) ) | |
( ! mult_sel & & ( GetSelection ( ) ! = item ) ) | |
m_objects_model - > GetParent ( item ) = = wxDataViewItem ( nullptr ) ) {
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
{
2019-09-02 07:41:12 +00:00
return ( m_dragged_data . type ( ) = = itInstance & & ! item . IsOk ( ) ) | |
( m_dragged_data . type ( ) = = itVolume & & item . IsOk ( ) & &
2019-01-22 15:40:10 +00:00
m_objects_model - > GetItemType ( item ) = = itVolume & &
2019-09-02 07:41:12 +00:00
m_dragged_data . obj_idx ( ) = = m_objects_model - > GetObjectIdByItem ( item ) ) ;
2019-01-22 15:40:10 +00:00
}
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-07-22 11:38:53 +00:00
Plater : : TakeSnapshot snapshot ( wxGetApp ( ) . plater ( ) , _ ( L ( " Instances to Separated Objects " ) ) ) ;
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-08-29 09:16:14 +00:00
take_snapshot ( _ ( ( m_dragged_data . type ( ) = = itVolume ) ? L ( " Volumes in Object reordered " ) : L ( " Object reordered " ) ) ) ;
2019-07-04 15:33:19 +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-07-11 21:46:23 +00:00
const SettingsBundle & 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-07-11 21:46:23 +00:00
SettingsBundle & 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-09-02 12:44:00 +00:00
static bool improper_category ( const std : : string & category , const int extruders_cnt , const bool is_object_settings = true )
2019-08-06 17:01:59 +00:00
{
2019-09-02 12:44:00 +00:00
return category . empty ( ) | |
2019-09-06 12:58:04 +00:00
( extruders_cnt = = 1 & & ( category = = " Extruders " | | category = = " Wipe options " ) ) | |
( ! is_object_settings & & category = = " Support material " ) ;
2019-08-06 17:01:59 +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 ;
2019-09-02 12:44:00 +00:00
if ( improper_category ( category , extruders_cnt , ! is_part ) )
2019-08-06 17:01:59 +00:00
continue ;
2018-10-05 21:29:15 +00:00
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 ;
2019-07-22 07:41:34 +00:00
wxDataViewItem item = GetSelection ( ) ;
2018-10-05 21:29:15 +00:00
2019-08-01 13:38:00 +00:00
const ItemType item_type = m_objects_model - > GetItemType ( item ) ;
2018-10-05 21:29:15 +00:00
settings_menu_hierarchy settings_menu ;
2019-08-01 13:38:00 +00:00
const bool is_part = item_type & ( itVolume | itLayer ) ;
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 ;
2019-07-22 07:41:34 +00:00
if ( ! m_config )
m_config = & get_item_config ( item ) ;
assert ( m_config ) ;
2018-10-05 21:29:15 +00:00
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-07-11 21:46:23 +00:00
SettingsBundle & 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
2019-08-01 13:38:00 +00:00
const wxString snapshot_text = item_type & itLayer ? _ ( L ( " Add Settings for Layers " ) ) :
item_type & itVolume ? _ ( L ( " Add Settings for Sub-object " ) ) :
_ ( L ( " Add Settings for Object " ) ) ;
take_snapshot ( snapshot_text ) ;
2019-07-10 09:28:11 +00:00
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
}
2019-07-11 21:46:23 +00:00
// Add settings item for object/sub-object and show them
2019-08-01 13:38:00 +00:00
if ( ! ( item_type & ( itObject | itVolume | itLayer ) ) )
2019-07-22 07:41:34 +00:00
item = m_objects_model - > GetTopParent ( item ) ;
show_settings ( add_settings_item ( item , m_config ) ) ;
2019-01-25 15:39:50 +00:00
}
void ObjectList : : get_freq_settings_choice ( const wxString & bundle_name )
{
2019-06-05 11:52:53 +00:00
std : : vector < std : : string > options = get_options_for_bundle ( bundle_name ) ;
2019-07-22 07:41:34 +00:00
wxDataViewItem item = GetSelection ( ) ;
2019-06-05 11:52:53 +00:00
2019-08-01 13:38:00 +00:00
ItemType item_type = m_objects_model - > GetItemType ( item ) ;
2019-06-05 14:47:09 +00:00
/* Because of we couldn't edited layer_height for ItVolume from settings list,
2019-06-05 11:52:53 +00:00
* correct options according to the selected item type :
* remove " layer_height " option
*/
2019-08-01 13:38:00 +00:00
if ( ( item_type & itVolume ) & & bundle_name = = _ ( " Layers and Perimeters " ) ) {
2019-06-05 11:52:53 +00:00
const auto layer_height_it = std : : find ( options . begin ( ) , options . end ( ) , " layer_height " ) ;
if ( layer_height_it ! = options . end ( ) )
options . erase ( layer_height_it ) ;
}
2019-01-25 15:39:50 +00:00
2019-07-22 07:41:34 +00:00
if ( ! m_config )
m_config = & get_item_config ( item ) ;
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-08-27 09:39:51 +00:00
const wxString snapshot_text = item_type & itLayer ? _ ( L ( " Add Settings Bundle for Height range " ) ) :
2019-08-01 13:38:00 +00:00
item_type & itVolume ? _ ( L ( " Add Settings Bundle for Sub-object " ) ) :
_ ( L ( " Add Settings Bundle for Object " ) ) ;
take_snapshot ( snapshot_text ) ;
2019-07-10 09:28:11 +00:00
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
}
2019-07-11 21:46:23 +00:00
// Add settings item for object/sub-object and show them
2019-08-01 13:38:00 +00:00
if ( ! ( item_type & ( itObject | itVolume | itLayer ) ) )
2019-07-22 07:41:34 +00:00
item = m_objects_model - > GetTopParent ( item ) ;
show_settings ( add_settings_item ( item , m_config ) ) ;
2019-01-25 15:39:50 +00:00
}
2019-07-11 21:46:23 +00:00
void ObjectList : : show_settings ( const wxDataViewItem settings_item )
2019-01-25 15:39:50 +00:00
{
2019-07-11 21:46:23 +00:00
if ( ! settings_item )
return ;
select_item ( settings_item ) ;
// update object selection on Plater
if ( ! m_prevent_canvas_selection_update )
update_selections_on_canvas ( ) ;
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-09-19 10:30:16 +00:00
if ( wxGetApp ( ) . get_mode ( ) = = comExpert & & type ! = ModelVolumeType : : INVALID ) {
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-09-19 10:30:16 +00:00
for ( auto & item : { L ( " Box " ) , L ( " Cylinder " ) , L ( " Sphere " ) , L ( " Slab " ) } )
{
2019-09-23 08:17:53 +00:00
if ( type = = ModelVolumeType : : INVALID & & strncmp ( item , " Slab " , 4 ) = = 0 )
2019-09-19 10:30:16 +00:00
continue ;
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-09-02 07:41:12 +00:00
for ( size_t 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-05-27 11:07:37 +00:00
wxMenuItem * ObjectList : : append_menu_item_layers_editing ( wxMenu * menu )
{
2019-08-27 09:39:51 +00:00
return append_menu_item ( menu , wxID_ANY , _ ( L ( " Height range Modifier " ) ) , " " ,
2019-07-30 13:45:32 +00:00
[ this ] ( wxCommandEvent & ) { layers_editing ( ) ; } , " edit_layers_all " , menu ) ;
2019-05-27 11:07:37 +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 | |
2019-09-02 07:41:12 +00:00
( 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
2019-09-16 09:55:05 +00:00
const bool is_object_settings = m_objects_model - > GetItemType ( GetSelection ( ) ) = = itObject ;
create_freq_settings_popupmenu ( menu , is_object_settings ) ;
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-09-02 07:41:12 +00:00
wxMenuItem * ObjectList : : append_menu_item_printable ( wxMenu * menu , wxWindow * /*parent*/ )
2019-07-31 08:12:13 +00:00
{
2019-09-02 07:41:12 +00:00
return append_menu_check_item ( menu , wxID_ANY , _ ( L ( " Printable " ) ) , " " , [ ] ( wxCommandEvent & ) {
2019-07-31 09:01:50 +00:00
wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > get_selection ( ) . toggle_instance_printable_state ( ) ;
2019-07-31 08:12:13 +00:00
} , menu ) ;
}
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-09-19 07:09:11 +00:00
void ObjectList : : append_menu_item_reload_from_disk ( wxMenu * menu ) const
{
append_menu_item ( menu , wxID_ANY , _ ( L ( " Reload from disk " ) ) , _ ( L ( " Reload the selected volumes from disk " ) ) ,
[ this ] ( wxCommandEvent & ) { wxGetApp ( ) . plater ( ) - > reload_from_disk ( ) ; } , " " , menu , [ ] ( ) { return wxGetApp ( ) . plater ( ) - > can_reload_from_disk ( ) ; } , wxGetApp ( ) . plater ( ) ) ;
}
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 ) ;
}
2019-05-23 07:20:11 +00:00
void ObjectList : : append_menu_item_scale_selection_to_fit_print_volume ( wxMenu * menu )
{
append_menu_item ( menu , wxID_ANY , _ ( L ( " Scale to print volume " ) ) , _ ( L ( " Scale the selected object to fit the print volume " ) ) ,
2019-09-02 07:41:12 +00:00
[ ] ( wxCommandEvent & ) { wxGetApp ( ) . plater ( ) - > scale_selection_to_fit_print_volume ( ) ; } , " " , menu ) ;
2019-05-23 07:20:11 +00:00
}
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-09-19 07:09:11 +00:00
append_menu_item_reload_from_disk ( menu ) ;
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-05-23 07:20:11 +00:00
append_menu_item_scale_selection_to_fit_print_volume ( menu ) ;
2019-01-30 15:27:07 +00:00
2018-11-02 11:35:26 +00:00
// Split object to parts
2019-05-27 11:07:37 +00:00
append_menu_item_split ( menu ) ;
menu - > AppendSeparator ( ) ;
// Layers Editing for object
append_menu_item_layers_editing ( 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
2019-09-19 07:09:11 +00:00
append_menu_item_reload_from_disk ( menu ) ;
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-09-19 07:09:11 +00:00
append_menu_item_reload_from_disk ( menu ) ;
2019-04-04 13:13:43 +00:00
append_menu_item_export_stl ( menu ) ;
2019-09-19 07:09:11 +00:00
append_menu_item_fix_through_netfabb ( menu ) ;
2019-01-30 15:27:07 +00:00
2019-05-27 11:07:37 +00:00
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-09-02 07:41:12 +00:00
wxGetApp ( ) . plater ( ) - > Bind ( wxEVT_UPDATE_UI , [ ] ( 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
}
2019-09-19 10:30:16 +00:00
void ObjectList : : create_default_popupmenu ( wxMenu * menu )
{
wxMenu * sub_menu = append_submenu_add_generic ( menu , ModelVolumeType : : INVALID ) ;
append_submenu ( menu , sub_menu , wxID_ANY , _ ( L ( " Add Shape " ) ) , " " , " add_part " ) ;
}
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 ;
2019-09-02 07:41:12 +00:00
const bool is_part = m_objects_model - > GetParent ( GetSelection ( ) ) ! = wxDataViewItem ( nullptr ) ;
2018-12-07 16:50:48 +00:00
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-09-02 12:44:00 +00:00
void ObjectList : : create_freq_settings_popupmenu ( wxMenu * menu , const bool is_object_settings /* = true*/ )
2019-01-25 12:16:32 +00:00
{
2019-01-28 11:13:53 +00:00
// Add default settings bundles
2019-07-11 21:46:23 +00:00
const SettingsBundle & 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 ) {
2019-09-02 12:44:00 +00:00
if ( improper_category ( it . first , extruders_cnt , is_object_settings ) )
2019-01-25 15:39:50 +00:00
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-07-11 21:46:23 +00:00
const SettingsBundle & 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 ) {
2019-08-06 17:01:59 +00:00
if ( improper_category ( it . first , extruders_cnt ) )
2019-01-28 11:13:53 +00:00
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
}
2019-07-25 15:24:00 +00:00
void ObjectList : : update_opt_keys ( t_config_option_keys & opt_keys , const bool is_object )
2018-11-29 14:00:23 +00:00
{
2019-07-25 15:24:00 +00:00
auto full_current_opts = get_options ( ! is_object ) ;
2018-11-29 14:00:23 +00:00
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
{
2019-06-17 13:33:58 +00:00
wxDataViewItem item = GetSelection ( ) ;
// we can add volumes for Object or Instance
if ( ! item | | ! ( m_objects_model - > GetItemType ( item ) & ( itObject | itInstance ) ) )
2018-10-05 21:29:15 +00:00
return ;
2019-06-17 13:33:58 +00:00
const int obj_idx = m_objects_model - > GetObjectIdByItem ( item ) ;
2018-10-05 21:29:15 +00:00
if ( obj_idx < 0 ) return ;
2019-06-17 13:33:58 +00:00
// Get object item, if Instance is selected
if ( m_objects_model - > GetItemType ( item ) & itInstance )
item = m_objects_model - > GetItemById ( obj_idx ) ;
2019-07-04 15:33:19 +00:00
take_snapshot ( _ ( L ( " Load Part " ) ) ) ;
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 ) ;
2019-08-16 11:14:51 +00:00
if ( type = = ModelVolumeType : : MODEL_PART )
// update printable state on canvas
wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > update_instance_printable_state_for_object ( ( size_t ) obj_idx ) ;
2019-04-29 13:27:59 +00:00
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 ) ;
2019-09-17 13:30:54 +00:00
2019-09-24 12:13:03 +00:00
//#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
2019-09-17 13:30:54 +00:00
selection_changed ( ) ;
2019-09-24 12:13:03 +00:00
//#endif //no __WXOSX__ //__WXMSW__
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 ) ;
2019-09-02 07:41:12 +00:00
for ( size_t 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 ) {
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-09-19 10:30:16 +00:00
static TriangleMesh create_mesh ( const std : : string & type_name , const BoundingBoxf3 & bb )
{
TriangleMesh mesh ;
const double side = wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > get_size_proportional_to_max_bed_size ( 0.1 ) ;
if ( type_name = = " Box " )
// Sitting on the print bed, left front front corner at (0, 0).
mesh = make_cube ( side , side , side ) ;
else if ( type_name = = " Cylinder " )
// 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 ) ;
else if ( type_name = = " Sphere " )
// 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 ( bb . size ( ) . x ( ) * 1.5 , bb . size ( ) . y ( ) * 1.5 , bb . size ( ) . z ( ) * 0.5 ) ;
mesh . repair ( ) ;
return mesh ;
}
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
{
2019-09-19 10:30:16 +00:00
if ( type = = ModelVolumeType : : INVALID ) {
load_shape_object ( type_name ) ;
return ;
}
2019-09-02 07:41:12 +00:00
const int 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 ;
2019-07-04 15:33:19 +00:00
take_snapshot ( _ ( L ( " Add Generic Subobject " ) ) ) ;
2019-02-28 10:20:01 +00:00
// 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-09-19 10:30:16 +00:00
TriangleMesh mesh = create_mesh ( type_name , instance_bb ) ;
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 ( 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.
2019-06-11 15:08:47 +00:00
const BoundingBoxf3 mesh_bb = new_volume - > mesh ( ) . bounding_box ( ) ;
2019-06-24 10:26:11 +00:00
new_volume - > set_transformation ( Geometry : : Transformation : : volume_to_bed_transformation ( v - > get_instance_transformation ( ) , mesh_bb ) ) ;
2019-02-28 10:20:01 +00:00
// 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
}
2019-09-19 10:30:16 +00:00
const wxString name = _ ( L ( " Generic " ) ) + " - " + _ ( type_name ) ;
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 ) ;
2019-08-16 11:14:51 +00:00
if ( type = = ModelVolumeType : : MODEL_PART )
// update printable state on canvas
wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > update_instance_printable_state_for_object ( ( size_t ) 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 ) ) ;
2019-09-24 12:13:03 +00:00
//#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
2018-10-11 13:57:09 +00:00
selection_changed ( ) ;
2019-09-24 12:13:03 +00:00
//#endif //no __WXOSX__ //__WXMSW__
2018-10-05 21:29:15 +00:00
}
2019-09-19 10:30:16 +00:00
void ObjectList : : load_shape_object ( const std : : string & type_name )
{
const Selection & selection = wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > get_selection ( ) ;
assert ( selection . get_object_idx ( ) = = - 1 ) ; // Add nothing is something is selected on 3DScene
if ( selection . get_object_idx ( ) ! = - 1 )
return ;
const int obj_idx = m_objects - > size ( ) ;
if ( obj_idx < 0 )
return ;
take_snapshot ( _ ( L ( " Add Shape " ) ) ) ;
// Create mesh
BoundingBoxf3 bb ;
TriangleMesh mesh = create_mesh ( type_name , bb ) ;
// Add mesh to model as a new object
Model & model = wxGetApp ( ) . plater ( ) - > model ( ) ;
const wxString name = _ ( L ( " Shape " ) ) + " - " + _ ( type_name ) ;
# ifdef _DEBUG
check_model_ids_validity ( model ) ;
# endif /* _DEBUG */
std : : vector < size_t > object_idxs ;
ModelObject * new_object = model . add_object ( ) ;
new_object - > name = into_u8 ( name ) ;
new_object - > add_instance ( ) ; // each object should have at list one instance
ModelVolume * new_volume = new_object - > add_volume ( mesh ) ;
new_volume - > name = into_u8 ( name ) ;
// set a default extruder value, since user can't add it manually
new_volume - > config . set_key_value ( " extruder " , new ConfigOptionInt ( 0 ) ) ;
new_object - > invalidate_bounding_box ( ) ;
2019-09-25 09:25:14 +00:00
new_object - > center_around_origin ( ) ;
new_object - > ensure_on_bed ( ) ;
2019-09-19 10:30:16 +00:00
const BoundingBoxf bed_shape = wxGetApp ( ) . plater ( ) - > bed_shape_bb ( ) ;
new_object - > instances [ 0 ] - > set_offset ( Slic3r : : to_3d ( bed_shape . center ( ) . cast < double > ( ) , - new_object - > origin_translation ( 2 ) ) ) ;
object_idxs . push_back ( model . objects . size ( ) - 1 ) ;
# ifdef _DEBUG
check_model_ids_validity ( model ) ;
# endif /* _DEBUG */
paste_objects_into_list ( object_idxs ) ;
# ifdef _DEBUG
check_model_ids_validity ( model ) ;
# endif /* _DEBUG */
}
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 ) ;
2019-07-23 15:09:19 +00:00
if ( type = = itUndef )
2018-10-05 21:29:15 +00:00
return ;
2019-06-06 12:14:29 +00:00
if ( type & itSettings )
del_settings_from_config ( m_objects_model - > GetParent ( item ) ) ;
else if ( type & itInstanceRoot & & obj_idx ! = - 1 )
2018-10-16 09:08:37 +00:00
del_instances_from_object ( obj_idx ) ;
2019-06-06 12:14:29 +00:00
else if ( type & itLayerRoot & & obj_idx ! = - 1 )
2019-05-30 14:53:17 +00:00
del_layers_from_object ( obj_idx ) ;
2019-06-06 12:14:29 +00:00
else if ( type & itLayer & & obj_idx ! = - 1 )
del_layer_from_object ( obj_idx , m_objects_model - > GetLayerRangeByItem ( item ) ) ;
2018-10-16 09:08:37 +00:00
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
2019-06-06 12:14:29 +00:00
if ( type & itVolume & & ( * m_objects ) [ obj_idx ] - > get_mesh_errors_count ( ) = = 0 )
2019-04-29 13:27:59 +00:00
m_objects_model - > DeleteWarningIcon ( m_objects_model - > GetParent ( item ) ) ;
2019-08-02 15:53:12 +00:00
// If last two Instances of object is selected, show the message about impossible action
bool show_msg = false ;
if ( type & itInstance ) {
wxDataViewItemArray instances ;
m_objects_model - > GetChildren ( m_objects_model - > GetParent ( item ) , instances ) ;
if ( instances . Count ( ) = = 2 & & IsSelected ( instances [ 0 ] ) & & IsSelected ( instances [ 1 ] ) )
show_msg = true ;
}
2018-10-12 10:00:37 +00:00
m_objects_model - > Delete ( item ) ;
2019-08-02 15:53:12 +00:00
if ( show_msg )
2019-08-05 12:54:29 +00:00
Slic3r : : GUI : : show_error ( nullptr , _ ( L ( " Last instance of an object cannot be deleted. " ) ) ) ;
2018-10-05 21:29:15 +00:00
}
2019-06-06 12:14:29 +00:00
void ObjectList : : del_settings_from_config ( const wxDataViewItem & parent_item )
2018-10-05 21:29:15 +00:00
{
2019-06-06 12:14:29 +00:00
const bool is_layer_settings = m_objects_model - > GetItemType ( parent_item ) = = itLayer ;
2019-09-02 07:41:12 +00:00
const size_t opt_cnt = m_config - > keys ( ) . size ( ) ;
if ( ( opt_cnt = = 1 & & m_config - > has ( " extruder " ) ) | |
( is_layer_settings & & opt_cnt = = 2 & & m_config - > has ( " extruder " ) & & m_config - > has ( " layer_height " ) ) )
2018-10-05 21:29:15 +00:00
return ;
2019-06-06 12:14:29 +00:00
2019-07-11 16:42:02 +00:00
take_snapshot ( _ ( L ( " Delete Settings " ) ) ) ;
2018-10-05 21:29:15 +00:00
int extruder = - 1 ;
if ( m_config - > has ( " extruder " ) )
extruder = m_config - > option < ConfigOptionInt > ( " extruder " ) - > value ;
2019-06-06 12:14:29 +00:00
coordf_t layer_height = 0.0 ;
if ( is_layer_settings )
layer_height = m_config - > opt_float ( " layer_height " ) ;
2018-10-05 21:29:15 +00:00
m_config - > clear ( ) ;
if ( extruder > = 0 )
m_config - > set_key_value ( " extruder " , new ConfigOptionInt ( extruder ) ) ;
2019-06-06 12:14:29 +00:00
if ( is_layer_settings )
m_config - > set_key_value ( " layer_height " , new ConfigOptionFloat ( layer_height ) ) ;
2018-10-05 21:29:15 +00:00
}
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 ;
2019-07-04 15:33:19 +00:00
take_snapshot ( _ ( L ( " Delete All Instances from Object " ) ) ) ;
2018-10-16 09:08:37 +00:00
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
}
2019-06-06 12:14:29 +00:00
void ObjectList : : del_layer_from_object ( const int obj_idx , const t_layer_height_range & layer_range )
{
const auto del_range = object ( obj_idx ) - > layer_config_ranges . find ( layer_range ) ;
if ( del_range = = object ( obj_idx ) - > layer_config_ranges . end ( ) )
return ;
2019-07-11 16:42:02 +00:00
2019-08-27 09:39:51 +00:00
take_snapshot ( _ ( L ( " Delete Height Range " ) ) ) ;
2019-06-06 12:14:29 +00:00
object ( obj_idx ) - > layer_config_ranges . erase ( del_range ) ;
changed_object ( obj_idx ) ;
}
2019-05-30 14:53:17 +00:00
void ObjectList : : del_layers_from_object ( const int obj_idx )
{
2019-06-03 13:35:21 +00:00
object ( obj_idx ) - > layer_config_ranges . clear ( ) ;
2019-05-30 14:53:17 +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 ) {
2019-08-02 15:53:12 +00:00
Slic3r : : GUI : : show_error ( nullptr , _ ( L ( " From Object List You can't delete the last solid part from object. " ) ) ) ;
2018-10-16 09:08:37 +00:00
return false ;
}
2019-07-04 15:33:19 +00:00
take_snapshot ( _ ( L ( " Delete Subobject " ) ) ) ;
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 ) {
2019-08-05 12:54:29 +00:00
Slic3r : : GUI : : show_error ( nullptr , _ ( L ( " Last instance of an object cannot be deleted. " ) ) ) ;
2018-10-18 08:40:26 +00:00
return false ;
}
2019-07-04 15:33:19 +00:00
take_snapshot ( _ ( L ( " Delete Instance " ) ) ) ;
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 ( ) ;
2019-08-22 13:42:23 +00:00
if ( ! volume - > is_splittable ( ) ) {
2018-10-05 21:29:15 +00:00
wxMessageBox ( _ ( L ( " The selected object couldn't be split because it contains only one part. " ) ) ) ;
return ;
}
2019-07-04 15:33:19 +00:00
take_snapshot ( _ ( L ( " Split to Parts " ) ) ) ;
2019-08-22 13:42:23 +00:00
volume - > split ( nozzle_dmrs_cnt ) ;
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-07-11 21:46:23 +00:00
add_settings_item ( vol_item , & volume - > config ) ;
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
}
2019-05-27 11:07:37 +00:00
void ObjectList : : layers_editing ( )
{
const auto item = GetSelection ( ) ;
const int obj_idx = get_selected_obj_idx ( ) ;
if ( ! item | | obj_idx < 0 )
return ;
2019-05-31 13:29:09 +00:00
const wxDataViewItem obj_item = m_objects_model - > GetTopParent ( item ) ;
2019-05-31 08:54:52 +00:00
wxDataViewItem layers_item = m_objects_model - > GetLayerRootItem ( obj_item ) ;
2019-05-31 13:29:09 +00:00
// if it doesn't exist now
2019-05-27 11:07:37 +00:00
if ( ! layers_item . IsOk ( ) )
2019-05-28 14:38:04 +00:00
{
2019-06-03 13:35:21 +00:00
t_layer_config_ranges & ranges = object ( obj_idx ) - > layer_config_ranges ;
2019-06-10 08:48:43 +00:00
// set some default value
2019-07-11 16:42:02 +00:00
if ( ranges . empty ( ) ) {
take_snapshot ( _ ( L ( " Add Layers " ) ) ) ;
2019-07-02 13:26:11 +00:00
ranges [ { 0.0f , 2.0f } ] = get_default_layer_config ( obj_idx ) ;
2019-07-11 16:42:02 +00:00
}
2019-05-27 11:07:37 +00:00
2019-06-10 08:48:43 +00:00
// create layer root item
layers_item = add_layer_root_item ( obj_item ) ;
2019-05-30 12:41:16 +00:00
}
2019-06-10 08:48:43 +00:00
if ( ! layers_item . IsOk ( ) )
return ;
2019-05-30 12:41:16 +00:00
2019-07-04 12:25:40 +00:00
// to correct visual hints for layers editing on the Scene, reset previous selection
wxGetApp ( ) . obj_layers ( ) - > reset_selection ( ) ;
wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > handle_sidebar_focus_event ( " " , false ) ;
2019-05-31 13:29:09 +00:00
// select LayerRoor item and expand
2019-05-27 11:07:37 +00:00
select_item ( layers_item ) ;
2019-05-31 13:29:09 +00:00
Expand ( layers_item ) ;
2019-05-27 11:07:37 +00:00
}
2019-06-10 08:48:43 +00:00
wxDataViewItem ObjectList : : add_layer_root_item ( const wxDataViewItem obj_item )
{
const int obj_idx = m_objects_model - > GetIdByItem ( obj_item ) ;
if ( obj_idx < 0 | |
object ( obj_idx ) - > layer_config_ranges . empty ( ) | |
printer_technology ( ) = = ptSLA )
2019-09-02 07:41:12 +00:00
return wxDataViewItem ( nullptr ) ;
2019-06-10 08:48:43 +00:00
// create LayerRoot item
wxDataViewItem layers_item = m_objects_model - > AddLayersRoot ( obj_item ) ;
// and create Layer item(s) according to the layer_config_ranges
2019-09-02 07:41:12 +00:00
for ( const auto & range : object ( obj_idx ) - > layer_config_ranges )
2019-06-10 08:48:43 +00:00
add_layer_item ( range . first , layers_item ) ;
2019-07-11 16:42:02 +00:00
Expand ( layers_item ) ;
2019-06-10 08:48:43 +00:00
return layers_item ;
}
2019-06-05 14:47:09 +00:00
DynamicPrintConfig ObjectList : : get_default_layer_config ( const int obj_idx )
{
DynamicPrintConfig config ;
coordf_t layer_height = object ( obj_idx ) - > config . has ( " layer_height " ) ?
object ( obj_idx ) - > config . opt_float ( " layer_height " ) :
wxGetApp ( ) . preset_bundle - > prints . get_edited_preset ( ) . config . opt_float ( " layer_height " ) ;
config . set_key_value ( " layer_height " , new ConfigOptionFloat ( layer_height ) ) ;
config . set_key_value ( " extruder " , new ConfigOptionInt ( 0 ) ) ;
return config ;
}
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 ( )
{
2019-10-10 14:13:07 +00:00
if ( m_extruder_editor ) m_extruder_editor - > Hide ( ) ;
2018-10-05 21:29:15 +00:00
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 ;
2019-05-28 14:38:04 +00:00
bool update_and_show_layers = false ;
2018-11-08 14:45:55 +00:00
2019-03-29 13:36:09 +00:00
const auto item = GetSelection ( ) ;
2019-09-02 07:41:12 +00:00
if ( multiple_selection ( ) | | ( item & & m_objects_model - > GetItemType ( item ) = = itInstanceRoot ) )
2019-03-29 13:36:09 +00:00
{
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 )
{
2019-09-02 07:41:12 +00:00
if ( m_objects_model - > GetParent ( item ) = = wxDataViewItem ( nullptr ) ) {
2018-11-08 14:45:55 +00:00
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 {
2019-06-05 14:47:09 +00:00
obj_idx = m_objects_model - > GetObjectIdByItem ( item ) ;
2019-05-28 14:38:04 +00:00
const ItemType type = m_objects_model - > GetItemType ( item ) ;
if ( type & itSettings ) {
2019-06-05 14:47:09 +00:00
const auto parent = m_objects_model - > GetParent ( item ) ;
const ItemType parent_type = m_objects_model - > GetItemType ( parent ) ;
if ( parent_type & itObject ) {
2018-11-08 14:45:55 +00:00
og_name = _ ( L ( " Object Settings to modify " ) ) ;
m_config = & ( * m_objects ) [ obj_idx ] - > config ;
}
2019-06-05 14:47:09 +00:00
else if ( parent_type & itVolume ) {
2018-11-08 14:45:55 +00:00
og_name = _ ( L ( " Part Settings to modify " ) ) ;
2019-06-05 14:47:09 +00:00
volume_id = m_objects_model - > GetVolumeIdByItem ( parent ) ;
2018-11-08 14:45:55 +00:00
m_config = & ( * m_objects ) [ obj_idx ] - > volumes [ volume_id ] - > config ;
}
2019-06-05 14:47:09 +00:00
else if ( parent_type & itLayer ) {
og_name = _ ( L ( " Layer range Settings to modify " ) ) ;
2019-06-06 12:14:29 +00:00
m_config = & get_item_config ( parent ) ;
2019-06-05 14:47:09 +00:00
}
2018-11-09 17:39:07 +00:00
update_and_show_settings = true ;
2018-10-05 21:29:15 +00:00
}
2019-05-28 14:38:04 +00:00
else if ( type & itVolume ) {
2018-11-08 14:45:55 +00:00
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
}
2019-05-28 14:38:04 +00:00
else if ( type & itInstance ) {
2018-11-08 14:45:55 +00:00
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
2019-06-05 14:47:09 +00:00
m_config = & ( * m_objects ) [ obj_idx ] - > config ;
2018-11-08 14:45:55 +00:00
}
2019-05-28 14:38:04 +00:00
else if ( type & ( itLayerRoot | itLayer ) ) {
2019-08-27 09:39:51 +00:00
og_name = type & itLayerRoot ? _ ( L ( " Height ranges " ) ) : _ ( L ( " Settings for height range " ) ) ;
2019-05-28 14:38:04 +00:00
update_and_show_layers = true ;
2019-06-05 14:47:09 +00:00
2019-06-06 12:14:29 +00:00
if ( type & itLayer )
m_config = & get_item_config ( item ) ;
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 ) {
2019-09-18 13:10:36 +00:00
// wxGetApp().obj_manipul()->get_og()->set_value("object_name", m_objects_model->GetName(item));
wxGetApp ( ) . obj_manipul ( ) - > update_item_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 + " " ) ;
2019-06-10 08:48:43 +00:00
if ( printer_technology ( ) = = ptSLA )
update_and_show_layers = false ;
else if ( update_and_show_layers )
2019-05-28 14:38:04 +00:00
wxGetApp ( ) . obj_layers ( ) - > 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
2019-07-02 08:34:30 +00:00
wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > handle_sidebar_focus_event ( " " , false ) ;
2018-11-09 17:39:07 +00:00
wxGetApp ( ) . obj_manipul ( ) - > UpdateAndShow ( update_and_show_manipulations ) ;
wxGetApp ( ) . obj_settings ( ) - > UpdateAndShow ( update_and_show_settings ) ;
2019-05-28 14:38:04 +00:00
wxGetApp ( ) . obj_layers ( ) - > UpdateAndShow ( update_and_show_layers ) ;
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
}
2019-07-25 15:24:00 +00:00
SettingsBundle ObjectList : : get_item_settings_bundle ( const DynamicPrintConfig * config , const bool is_object_settings )
2019-07-11 21:46:23 +00:00
{
auto opt_keys = config - > keys ( ) ;
if ( opt_keys . empty ( ) )
return SettingsBundle ( ) ;
2019-07-25 15:24:00 +00:00
update_opt_keys ( opt_keys , is_object_settings ) ; // update options list according to print technology
2019-07-11 21:46:23 +00:00
2019-07-25 15:24:00 +00:00
if ( opt_keys . empty ( ) )
2019-07-11 21:46:23 +00:00
return SettingsBundle ( ) ;
const int extruders_cnt = wxGetApp ( ) . extruders_edited_cnt ( ) ;
SettingsBundle bundle ;
for ( auto & opt_key : opt_keys )
{
auto category = config - > def ( ) - > get ( opt_key ) - > category ;
2019-09-02 12:44:00 +00:00
if ( improper_category ( category , extruders_cnt , is_object_settings ) )
2019-07-11 21:46:23 +00:00
continue ;
std : : vector < std : : string > new_category ;
auto & cat_opt = bundle . find ( category ) = = bundle . end ( ) ? new_category : bundle . at ( category ) ;
cat_opt . push_back ( opt_key ) ;
if ( cat_opt . size ( ) = = 1 )
bundle [ category ] = cat_opt ;
}
return bundle ;
}
2019-07-12 11:55:46 +00:00
// Add new SettingsItem for parent_item if it doesn't exist, or just update a digest according to new config
2019-07-11 21:46:23 +00:00
wxDataViewItem ObjectList : : add_settings_item ( wxDataViewItem parent_item , const DynamicPrintConfig * config )
{
2019-09-02 07:41:12 +00:00
wxDataViewItem ret = wxDataViewItem ( nullptr ) ;
2019-07-11 21:46:23 +00:00
if ( ! parent_item )
return ret ;
2019-07-25 15:24:00 +00:00
const bool is_object_settings = m_objects_model - > GetItemType ( parent_item ) = = itObject ;
SettingsBundle cat_options = get_item_settings_bundle ( config , is_object_settings ) ;
2019-07-11 21:46:23 +00:00
if ( cat_options . empty ( ) )
return ret ;
std : : vector < std : : string > categories ;
categories . reserve ( cat_options . size ( ) ) ;
for ( auto & cat : cat_options )
categories . push_back ( cat . first ) ;
if ( m_objects_model - > GetItemType ( parent_item ) & itInstance )
parent_item = m_objects_model - > GetTopParent ( parent_item ) ;
ret = m_objects_model - > IsSettingsItem ( parent_item ) ? parent_item : m_objects_model - > GetSettingsItem ( parent_item ) ;
if ( ! ret ) ret = m_objects_model - > AddSettingsChild ( parent_item ) ;
m_objects_model - > UpdateSettingsDigest ( ret , categories ) ;
Expand ( parent_item ) ;
return ret ;
}
2019-07-05 17:06:19 +00:00
void ObjectList : : add_object_to_list ( size_t obj_idx , bool call_selection_changed )
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-07-11 21:46:23 +00:00
add_settings_item ( vol_item , & volume - > config ) ;
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 )
2019-08-01 12:58:04 +00:00
{
std : : vector < bool > print_idicator ( model_object - > instances . size ( ) ) ;
2019-09-02 07:41:12 +00:00
for ( size_t i = 0 ; i < model_object - > instances . size ( ) ; + + i )
2019-08-20 13:26:57 +00:00
print_idicator [ i ] = model_object - > instances [ i ] - > printable ;
2019-08-01 12:58:04 +00:00
2019-08-05 12:57:30 +00:00
const wxDataViewItem object_item = m_objects_model - > GetItemById ( obj_idx ) ;
m_objects_model - > AddInstanceChild ( object_item , print_idicator ) ;
Expand ( m_objects_model - > GetInstanceRootItem ( object_item ) ) ;
2019-08-01 12:58:04 +00:00
}
2019-08-05 06:44:55 +00:00
else
2019-08-20 13:26:57 +00:00
m_objects_model - > SetPrintableState ( model_object - > instances [ 0 ] - > printable ? piPrintable : piUnprintable , obj_idx ) ;
2018-11-01 15:22:16 +00:00
2018-11-06 08:06:26 +00:00
// add settings to the object, if it has those
2019-07-11 21:46:23 +00:00
add_settings_item ( item , & model_object - > config ) ;
2018-11-06 08:06:26 +00:00
2019-06-10 13:22:09 +00:00
// Add layers if it has
add_layer_root_item ( item ) ;
2018-10-05 21:29:15 +00:00
# ifndef __WXOSX__
2019-07-05 17:06:19 +00:00
if ( call_selection_changed )
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 ;
2019-09-02 07:41:12 +00:00
if ( m_objects_model - > GetParent ( item ) = = wxDataViewItem ( nullptr ) )
2018-10-12 10:00:37 +00:00
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 ;
2019-07-04 15:33:19 +00:00
take_snapshot ( _ ( L ( " Delete Selected Item " ) ) ) ;
2018-11-13 13:17:35 +00:00
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 ) ;
2019-10-01 16:19:28 +00:00
m_objects_model - > SetExtruder ( extruder , m_objects_model - > GetItemById ( item - > obj_idx ) ) ;
2019-03-13 15:40:11 +00:00
}
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 ( )
{
2019-05-20 16:49:32 +00:00
m_prevent_list_events = true ;
this - > UnselectAll ( ) ;
2018-10-05 21:29:15 +00:00
m_objects_model - > DeleteAll ( ) ;
2019-05-20 16:49:32 +00:00
m_prevent_list_events = false ;
2018-10-05 21:29:15 +00:00
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 ;
2019-08-23 10:29:47 +00:00
auto delete_item = [ this ] ( wxDataViewItem item )
2018-10-12 10:00:37 +00:00
{
2019-08-23 10:29:47 +00:00
wxDataViewItem parent = m_objects_model - > GetParent ( item ) ;
2019-09-04 13:15:35 +00:00
ItemType type = m_objects_model - > GetItemType ( item ) ;
if ( type & itObject )
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 {
2019-09-04 13:15:35 +00:00
if ( type & ( itLayer | itInstance ) ) {
// In case there is just one layer or two instances and we delete it, del_subobject_item will
// also remove the parent item. Selection should therefore pass to the top parent (object).
2019-06-17 11:09:11 +00:00
wxDataViewItemArray children ;
2019-09-04 13:15:35 +00:00
if ( m_objects_model - > GetChildren ( parent , children ) = = ( type & itLayer ? 1 : 2 ) )
2019-06-17 11:09:11 +00:00
parent = m_objects_model - > GetTopParent ( item ) ;
2019-05-30 14:53:17 +00:00
}
2019-09-04 13:15:35 +00:00
2018-10-12 10:00:37 +00:00
del_subobject_item ( item ) ;
2019-03-21 08:04:11 +00:00
}
2019-08-23 10:29:47 +00:00
return parent ;
} ;
wxDataViewItemArray sels ;
GetSelections ( sels ) ;
2019-09-02 07:41:12 +00:00
wxDataViewItem parent = wxDataViewItem ( nullptr ) ;
2019-08-23 10:29:47 +00:00
if ( sels . Count ( ) = = 1 )
parent = delete_item ( GetSelection ( ) ) ;
else
{
Plater : : TakeSnapshot snapshot = Plater : : TakeSnapshot ( wxGetApp ( ) . plater ( ) , _ ( L ( " Delete Selected " ) ) ) ;
for ( auto & item : sels )
{
if ( m_objects_model - > InvalidItem ( item ) ) // item can be deleted for this moment (like last 2 Instances or Volumes)
continue ;
parent = delete_item ( item ) ;
}
2018-10-05 21:29:15 +00:00
}
2019-06-17 11:09:11 +00:00
2019-08-23 10:29:47 +00:00
if ( parent & & ! m_objects_model - > InvalidItem ( parent ) ) {
2019-06-17 11:09:11 +00:00
select_item ( parent ) ;
2019-08-23 10:29:47 +00:00
update_selections_on_canvas ( ) ;
}
2018-10-05 21:29:15 +00:00
}
2019-06-06 12:14:29 +00:00
void ObjectList : : del_layer_range ( const t_layer_height_range & range )
2019-05-31 08:54:52 +00:00
{
const int obj_idx = get_selected_obj_idx ( ) ;
if ( obj_idx < 0 ) return ;
2019-06-05 09:03:46 +00:00
t_layer_config_ranges & ranges = object ( obj_idx ) - > layer_config_ranges ;
2019-05-31 08:54:52 +00:00
wxDataViewItem selectable_item = GetSelection ( ) ;
if ( ranges . size ( ) = = 1 )
selectable_item = m_objects_model - > GetParent ( selectable_item ) ;
2019-06-06 12:14:29 +00:00
wxDataViewItem layer_item = m_objects_model - > GetItemByLayerRange ( obj_idx , range ) ;
2019-05-31 08:54:52 +00:00
del_subobject_item ( layer_item ) ;
select_item ( selectable_item ) ;
}
2019-08-06 17:01:59 +00:00
static double get_min_layer_height ( const int extruder_idx )
2019-06-12 14:28:25 +00:00
{
const DynamicPrintConfig & config = wxGetApp ( ) . preset_bundle - > printers . get_edited_preset ( ) . config ;
return config . opt_float ( " min_layer_height " , extruder_idx < = 0 ? 0 : extruder_idx - 1 ) ;
}
2019-08-06 17:01:59 +00:00
static double get_max_layer_height ( const int extruder_idx )
2019-06-12 14:28:25 +00:00
{
const DynamicPrintConfig & config = wxGetApp ( ) . preset_bundle - > printers . get_edited_preset ( ) . config ;
2019-09-10 10:34:03 +00:00
int extruder_idx_zero_based = extruder_idx < = 0 ? 0 : extruder_idx - 1 ;
double max_layer_height = config . opt_float ( " max_layer_height " , extruder_idx_zero_based ) ;
// In case max_layer_height is set to zero, it should default to 75 % of nozzle diameter:
if ( max_layer_height < EPSILON )
max_layer_height = 0.75 * config . opt_float ( " nozzle_diameter " , extruder_idx_zero_based ) ;
return max_layer_height ;
2019-06-12 14:28:25 +00:00
}
2019-06-06 12:14:29 +00:00
void ObjectList : : add_layer_range_after_current ( const t_layer_height_range & current_range )
2019-05-31 13:29:09 +00:00
{
const int obj_idx = get_selected_obj_idx ( ) ;
if ( obj_idx < 0 ) return ;
2019-06-06 12:14:29 +00:00
const wxDataViewItem layers_item = GetSelection ( ) ;
2019-05-31 13:29:09 +00:00
2019-06-03 13:35:21 +00:00
t_layer_config_ranges & ranges = object ( obj_idx ) - > layer_config_ranges ;
2019-05-31 13:29:09 +00:00
2019-06-06 12:14:29 +00:00
const t_layer_height_range & last_range = ( - - ranges . end ( ) ) - > first ;
2019-05-31 13:29:09 +00:00
2019-06-06 12:14:29 +00:00
if ( current_range = = last_range )
2019-05-31 13:29:09 +00:00
{
2019-08-27 09:39:51 +00:00
take_snapshot ( _ ( L ( " Add Height Range " ) ) ) ;
2019-07-11 16:42:02 +00:00
2019-09-02 07:41:12 +00:00
const t_layer_height_range & new_range = { last_range . second , last_range . second + 2. } ;
2019-06-05 14:47:09 +00:00
ranges [ new_range ] = get_default_layer_config ( obj_idx ) ;
2019-05-31 13:29:09 +00:00
add_layer_item ( new_range , layers_item ) ;
}
else
{
2019-06-06 12:14:29 +00:00
const t_layer_height_range & next_range = ( + + ranges . find ( current_range ) ) - > first ;
2019-05-31 13:29:09 +00:00
2019-06-06 12:14:29 +00:00
if ( current_range . second > next_range . first )
return ; // range division has no sense
2019-06-04 15:30:44 +00:00
2019-06-06 12:14:29 +00:00
const int layer_idx = m_objects_model - > GetItemIdByLayerRange ( obj_idx , next_range ) ;
if ( layer_idx < 0 )
return ;
if ( current_range . second = = next_range . first )
2019-05-31 13:29:09 +00:00
{
2019-06-12 14:28:25 +00:00
const auto old_config = ranges . at ( next_range ) ;
2019-06-06 12:14:29 +00:00
const coordf_t delta = ( next_range . second - next_range . first ) ;
2019-06-12 14:28:25 +00:00
if ( delta < get_min_layer_height ( old_config . opt_int ( " extruder " ) ) /*0.05f*/ ) // next range division has no sense
2019-05-31 13:29:09 +00:00
return ;
2019-09-02 07:41:12 +00:00
const coordf_t midl_layer = next_range . first + 0.5 * delta ;
2019-06-06 12:14:29 +00:00
t_layer_height_range new_range = { midl_layer , next_range . second } ;
2019-05-31 13:29:09 +00:00
2019-08-27 09:39:51 +00:00
Plater : : TakeSnapshot snapshot ( wxGetApp ( ) . plater ( ) , _ ( L ( " Add Height Range " ) ) ) ;
2019-07-11 16:42:02 +00:00
// create new 2 layers instead of deleted one
2019-05-31 13:29:09 +00:00
// delete old layer
2019-06-06 12:14:29 +00:00
wxDataViewItem layer_item = m_objects_model - > GetItemByLayerRange ( obj_idx , next_range ) ;
2019-05-31 13:29:09 +00:00
del_subobject_item ( layer_item ) ;
2019-06-03 13:35:21 +00:00
ranges [ new_range ] = old_config ;
2019-05-31 13:29:09 +00:00
add_layer_item ( new_range , layers_item , layer_idx ) ;
2019-06-06 12:14:29 +00:00
new_range = { current_range . second , midl_layer } ;
2019-06-05 14:47:09 +00:00
ranges [ new_range ] = get_default_layer_config ( obj_idx ) ;
2019-05-31 13:29:09 +00:00
add_layer_item ( new_range , layers_item , layer_idx ) ;
}
else
{
2019-08-27 09:39:51 +00:00
take_snapshot ( _ ( L ( " Add Height Range " ) ) ) ;
2019-07-11 16:42:02 +00:00
2019-06-06 12:14:29 +00:00
const t_layer_height_range new_range = { current_range . second , next_range . first } ;
2019-06-05 14:47:09 +00:00
ranges [ new_range ] = get_default_layer_config ( obj_idx ) ;
2019-05-31 13:29:09 +00:00
add_layer_item ( new_range , layers_item , layer_idx ) ;
}
}
changed_object ( obj_idx ) ;
// select item to update layers sizer
select_item ( layers_item ) ;
}
void ObjectList : : add_layer_item ( const t_layer_height_range & range ,
const wxDataViewItem layers_item ,
const int layer_idx /* = -1*/ )
{
2019-06-10 08:48:43 +00:00
const int obj_idx = m_objects_model - > GetObjectIdByItem ( layers_item ) ;
2019-06-05 14:47:09 +00:00
if ( obj_idx < 0 ) return ;
const DynamicPrintConfig & config = object ( obj_idx ) - > layer_config_ranges [ range ] ;
2019-06-07 09:32:46 +00:00
if ( ! config . has ( " extruder " ) )
return ;
const auto layer_item = m_objects_model - > AddLayersChild ( layers_item ,
range ,
config . opt_int ( " extruder " ) ,
layer_idx ) ;
2019-07-11 21:46:23 +00:00
add_settings_item ( layer_item , & config ) ;
2019-05-31 13:29:09 +00:00
}
2019-06-12 14:28:25 +00:00
bool ObjectList : : edit_layer_range ( const t_layer_height_range & range , coordf_t layer_height )
2019-05-31 08:54:52 +00:00
{
2019-06-04 13:22:29 +00:00
const int obj_idx = get_selected_obj_idx ( ) ;
2019-06-12 14:28:25 +00:00
if ( obj_idx < 0 )
return false ;
2019-06-04 13:22:29 +00:00
2019-06-12 14:28:25 +00:00
DynamicPrintConfig * config = & object ( obj_idx ) - > layer_config_ranges [ range ] ;
if ( fabs ( layer_height - config - > opt_float ( " layer_height " ) ) < EPSILON )
return false ;
2019-05-31 08:54:52 +00:00
2019-06-12 14:28:25 +00:00
const int extruder_idx = config - > opt_int ( " extruder " ) ;
if ( layer_height > = get_min_layer_height ( extruder_idx ) & &
layer_height < = get_max_layer_height ( extruder_idx ) )
{
config - > set_key_value ( " layer_height " , new ConfigOptionFloat ( layer_height ) ) ;
return true ;
}
return false ;
2019-05-31 08:54:52 +00:00
}
2019-06-12 14:28:25 +00:00
bool ObjectList : : edit_layer_range ( const t_layer_height_range & range , const t_layer_height_range & new_range )
2019-06-04 15:30:44 +00:00
{
const int obj_idx = get_selected_obj_idx ( ) ;
2019-06-12 14:28:25 +00:00
if ( obj_idx < 0 ) return false ;
2019-06-04 15:30:44 +00:00
2019-08-27 09:39:51 +00:00
take_snapshot ( _ ( L ( " Edit Height Range " ) ) ) ;
2019-07-11 16:42:02 +00:00
2019-06-17 11:46:56 +00:00
const ItemType sel_type = m_objects_model - > GetItemType ( GetSelection ( ) ) ;
2019-06-04 15:30:44 +00:00
t_layer_config_ranges & ranges = object ( obj_idx ) - > layer_config_ranges ;
const DynamicPrintConfig config = ranges [ range ] ;
ranges . erase ( range ) ;
ranges [ new_range ] = config ;
wxDataViewItem root_item = m_objects_model - > GetLayerRootItem ( m_objects_model - > GetItemById ( obj_idx ) ) ;
2019-08-09 15:47:35 +00:00
// To avoid update selection after deleting of a selected item (under GTK)
// set m_prevent_list_events to true
m_prevent_list_events = true ;
2019-06-04 15:30:44 +00:00
m_objects_model - > DeleteChildren ( root_item ) ;
if ( root_item . IsOk ( ) )
// create Layer item(s) according to the layer_config_ranges
2019-09-02 07:41:12 +00:00
for ( const auto & r : ranges )
2019-06-04 15:30:44 +00:00
add_layer_item ( r . first , root_item ) ;
2019-06-17 11:46:56 +00:00
select_item ( sel_type & itLayer ? m_objects_model - > GetItemByLayerRange ( obj_idx , new_range ) : root_item ) ;
2019-06-04 15:30:44 +00:00
Expand ( root_item ) ;
2019-06-12 14:28:25 +00:00
return true ;
2018-10-05 21:29:15 +00:00
}
void ObjectList : : init_objects ( )
{
2019-07-18 15:41:47 +00:00
m_objects = & wxGetApp ( ) . model ( ) . objects ;
2018-10-05 21:29:15 +00:00
}
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 ;
}
2019-07-24 10:32:38 +00:00
int ObjectList : : get_selected_layers_range_idx ( ) const
2019-07-23 16:17:57 +00:00
{
const wxDataViewItem & item = GetSelection ( ) ;
if ( ! item )
2019-07-24 10:32:38 +00:00
return - 1 ;
2019-07-23 16:17:57 +00:00
const ItemType type = m_objects_model - > GetItemType ( item ) ;
if ( type & itSettings & & m_objects_model - > GetItemType ( m_objects_model - > GetParent ( item ) ) ! = itLayer )
2019-07-24 10:32:38 +00:00
return - 1 ;
2019-07-23 16:17:57 +00:00
2019-07-24 10:32:38 +00:00
return m_objects_model - > GetLayerIdByItem ( type & itLayer ? item : m_objects_model - > GetParent ( item ) ) ;
2019-07-23 16:17:57 +00:00
}
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-07-23 16:17:57 +00:00
if ( ( m_selection_mode & ( smSettings | smLayer | smLayerRoot ) ) = = 0 )
2019-07-23 14:17:37 +00:00
m_selection_mode = smInstance ;
2019-04-02 14:33:52 +00:00
2018-12-18 14:29:09 +00:00
// We doesn't update selection if SettingsItem for the current object/part is selected
2019-05-27 14:13:24 +00:00
// if (GetSelectedItemsCount() == 1 && m_objects_model->GetItemType(GetSelection()) == itSettings )
if ( GetSelectedItemsCount ( ) = = 1 & & m_objects_model - > GetItemType ( GetSelection ( ) ) & ( itSettings | itLayerRoot | itLayer ) )
2018-12-18 14:29:09 +00:00
{
const auto item = GetSelection ( ) ;
2019-06-13 13:35:10 +00:00
if ( selection . is_single_full_object ( ) ) {
2019-06-13 14:17:54 +00:00
if ( m_objects_model - > GetObjectIdByItem ( item ) = = selection . get_object_idx ( ) )
2019-06-13 13:35:10 +00:00
return ;
sels . Add ( m_objects_model - > GetItemById ( selection . get_object_idx ( ) ) ) ;
}
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 ( ) ;
2019-07-23 16:17:57 +00:00
if ( m_selection_mode & ( smSettings | smLayer | smLayerRoot ) )
2019-07-23 14:17:37 +00:00
{
2019-07-23 16:17:57 +00:00
auto obj_idx = objects_content . begin ( ) - > first ;
wxDataViewItem obj_item = m_objects_model - > GetItemById ( obj_idx ) ;
if ( m_selection_mode & smSettings )
{
2019-07-24 10:32:38 +00:00
if ( m_selected_layers_range_idx < 0 )
2019-07-23 16:17:57 +00:00
sels . Add ( m_objects_model - > GetSettingsItem ( obj_item ) ) ;
else
2019-07-24 10:32:38 +00:00
sels . Add ( m_objects_model - > GetSettingsItem ( m_objects_model - > GetItemByLayerId ( obj_idx , m_selected_layers_range_idx ) ) ) ;
2019-07-23 16:17:57 +00:00
}
else if ( m_selection_mode & smLayerRoot )
sels . Add ( m_objects_model - > GetLayerRootItem ( obj_item ) ) ;
2019-08-23 10:29:47 +00:00
else if ( m_selection_mode & smLayer ) {
if ( m_selected_layers_range_idx > = 0 )
sels . Add ( m_objects_model - > GetItemByLayerId ( obj_idx , m_selected_layers_range_idx ) ) ;
else
sels . Add ( obj_item ) ;
}
2019-07-23 14:17:37 +00:00
}
else {
2019-03-29 13:36:09 +00:00
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 ) ) ;
}
2019-07-23 14:17:37 +00:00
} }
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
{
2019-07-23 14:17:37 +00:00
if ( m_selection_mode & smSettings )
{
const auto idx = * selection . get_volume_idxs ( ) . begin ( ) ;
const auto gl_vol = selection . get_volume ( idx ) ;
if ( gl_vol - > volume_idx ( ) > = 0 ) {
// 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).
wxDataViewItem vol_item = m_objects_model - > GetItemByVolumeId ( gl_vol - > object_idx ( ) , gl_vol - > volume_idx ( ) ) ;
sels . Add ( m_objects_model - > GetSettingsItem ( vol_item ) ) ;
}
}
else {
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-07-23 14:17:37 +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
2019-07-23 14:17:37 +00:00
if ( sels . size ( ) = = 0 | | m_selection_mode & smSettings )
2019-04-02 14:33:52 +00:00
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 ) {
2019-07-23 13:14:08 +00:00
selection . remove_all ( ) ;
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-07-23 13:14:08 +00:00
std : : vector < unsigned int > volume_idxs ;
Selection : : EMode mode = Selection : : Volume ;
2019-07-31 09:52:24 +00:00
bool single_selection = sel_cnt = = 1 ;
auto add_to_selection = [ this , & volume_idxs , & single_selection ] ( const wxDataViewItem & item , const Selection & selection , int instance_idx , Selection : : EMode & mode )
2019-03-19 12:30:21 +00:00
{
2019-04-02 14:33:52 +00:00
const ItemType & type = m_objects_model - > GetItemType ( item ) ;
2019-06-10 13:22:09 +00:00
const int obj_idx = m_objects_model - > GetObjectIdByItem ( item ) ;
2018-10-11 13:57:09 +00:00
2019-04-02 14:33:52 +00:00
if ( type = = itVolume ) {
2018-10-18 08:40:26 +00:00
const int vol_idx = m_objects_model - > GetVolumeIdByItem ( item ) ;
2019-07-23 13:14:08 +00:00
std : : vector < unsigned int > idxs = selection . get_volume_idxs_from_volume ( obj_idx , std : : max ( instance_idx , 0 ) , vol_idx ) ;
volume_idxs . insert ( volume_idxs . end ( ) , idxs . begin ( ) , idxs . end ( ) ) ;
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 inst_idx = m_objects_model - > GetInstanceIdByItem ( item ) ;
2019-07-23 13:14:08 +00:00
mode = Selection : : Instance ;
std : : vector < unsigned int > idxs = selection . get_volume_idxs_from_instance ( obj_idx , inst_idx ) ;
volume_idxs . insert ( volume_idxs . end ( ) , idxs . begin ( ) , idxs . end ( ) ) ;
2018-10-18 08:40:26 +00:00
}
2019-06-10 13:22:09 +00:00
else
2019-07-23 13:14:08 +00:00
{
mode = Selection : : Instance ;
2019-07-31 13:30:03 +00:00
single_selection & = ( obj_idx ! = selection . get_object_idx ( ) ) ;
2019-07-23 13:14:08 +00:00
std : : vector < unsigned int > idxs = selection . get_volume_idxs_from_object ( obj_idx ) ;
volume_idxs . insert ( volume_idxs . end ( ) , idxs . begin ( ) , idxs . end ( ) ) ;
}
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 ( ) ;
2019-07-23 13:14:08 +00:00
if ( m_objects_model - > GetItemType ( item ) & ( itSettings | itInstanceRoot | itLayerRoot | itLayer ) )
add_to_selection ( m_objects_model - > GetParent ( item ) , selection , instance_idx , mode ) ;
else
add_to_selection ( item , selection , instance_idx , mode ) ;
2018-10-11 13:57:09 +00:00
}
2019-07-23 13:14:08 +00:00
else
{
wxDataViewItemArray sels ;
GetSelections ( sels ) ;
2019-08-06 07:41:09 +00:00
// clear selection before adding new elements
selection . clear ( ) ; //OR remove_all()?
2019-07-23 13:14:08 +00:00
for ( auto item : sels )
{
add_to_selection ( item , selection , instance_idx , mode ) ;
}
}
if ( selection . contains_all_volumes ( volume_idxs ) )
{
// remove
volume_idxs = selection . get_missing_volume_idxs_from ( volume_idxs ) ;
if ( volume_idxs . size ( ) > 0 )
{
2019-07-26 09:32:44 +00:00
Plater : : TakeSnapshot snapshot ( wxGetApp ( ) . plater ( ) , _ ( L ( " Selection-Remove from list " ) ) ) ;
2019-07-23 13:14:08 +00:00
selection . remove_volumes ( mode , volume_idxs ) ;
}
}
else
{
// add
volume_idxs = selection . get_unselected_volume_idxs_from ( volume_idxs ) ;
2019-07-26 09:32:44 +00:00
Plater : : TakeSnapshot snapshot ( wxGetApp ( ) . plater ( ) , _ ( L ( " Selection-Add from list " ) ) ) ;
2019-07-31 09:52:24 +00:00
selection . add_volumes ( mode , volume_idxs , single_selection ) ;
2019-07-23 13:14:08 +00:00
}
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 ) {
2019-09-02 07:41:12 +00:00
for ( size_t i = 0 ; i < m_objects - > size ( ) ; i + + )
2018-11-08 14:45:55 +00:00
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 ( ) ;
2019-06-10 13:22:09 +00:00
const ItemType item_type = m_objects_model - > GetItemType ( item ) ;
// Some volume/layer/instance is selected => select all volumes/layers/instances inside the current object
if ( item_type & ( itVolume | itInstance | itLayer ) )
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
2019-06-10 13:22:09 +00:00
m_selection_mode = item_type & itVolume ? smVolume :
item_type & itLayer ? smLayer : 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 ( )
{
2019-07-31 07:46:45 +00:00
m_selected_layers_range_idx = - 1 ;
2019-04-02 14:33:52 +00:00
// All items are unselected
if ( ! GetSelection ( ) )
{
2019-09-02 07:41:12 +00:00
m_last_selected_item = wxDataViewItem ( nullptr ) ;
2019-04-02 14:33:52 +00:00
m_selection_mode = smUndef ;
return ;
}
const ItemType type = m_objects_model - > GetItemType ( GetSelection ( ) ) ;
2019-06-10 13:22:09 +00:00
m_selection_mode = type & itSettings ? smUndef :
type & itLayer ? smLayer :
type & itVolume ? smVolume : smInstance ;
2019-04-02 14:33:52 +00:00
}
// 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
2019-06-10 13:22:09 +00:00
/* We can't mix Volumes, Layers 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
2019-06-10 13:22:09 +00:00
// check a case of a selection of the same type items from different Objects
auto impossible_multi_selection = [ type , this ] ( const ItemType item_type , const SELECTION_MODE selection_mode ) {
if ( ! ( type & item_type & & m_selection_mode & selection_mode ) )
return false ;
2019-04-04 13:07:54 +00:00
wxDataViewItemArray sels ;
GetSelections ( sels ) ;
2019-06-10 13:22:09 +00:00
for ( const auto & sel : sels )
if ( sel ! = m_last_selected_item & &
m_objects_model - > GetTopParent ( sel ) ! = m_objects_model - > GetTopParent ( m_last_selected_item ) )
return true ;
2019-04-04 13:07:54 +00:00
2019-06-10 13:22:09 +00:00
return false ;
} ;
2019-04-04 13:07:54 +00:00
2019-06-10 13:22:09 +00:00
if ( impossible_multi_selection ( itVolume , smVolume ) | |
impossible_multi_selection ( itLayer , smLayer ) | |
2019-04-04 13:07:54 +00:00
type & itSettings | |
2019-09-02 07:41:12 +00:00
( type & itVolume & & ! ( m_selection_mode & smVolume ) ) | |
( type & itLayer & & ! ( m_selection_mode & smLayer ) ) | |
( type & itInstance & & ! ( m_selection_mode & smInstance ) )
2019-06-10 13:22:09 +00:00
)
2019-04-02 14:33:52 +00:00
{
// Inform user why selection isn't complited
2019-06-10 13:22:09 +00:00
const wxString item_type = m_selection_mode & smInstance ? _ ( L ( " Object or Instance " ) ) :
m_selection_mode & smVolume ? _ ( L ( " Part " ) ) : _ ( L ( " Layer " ) ) ;
2019-04-02 14:33:52 +00:00
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-06-10 13:22:09 +00:00
if ( m_selection_mode & ( smVolume | smLayer ) )
2019-04-04 13:07:54 +00:00
{
// 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-06-10 13:22:09 +00:00
const ItemType item_type = m_selection_mode & smVolume ? itVolume : itLayer ;
2019-09-02 07:41:12 +00:00
for ( const auto & child : children )
2019-06-10 13:22:09 +00:00
if ( IsSelected ( child ) & & m_objects_model - > GetItemType ( child ) & item_type )
2019-04-04 13:07:54 +00:00
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
{
2019-09-02 07:41:12 +00:00
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 ) ;
2019-09-02 07:41:12 +00:00
if ( parent ! = wxDataViewItem ( nullptr ) & & IsSelected ( parent ) )
2019-04-04 13:07:54 +00:00
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 ) ;
2019-09-02 07:41:12 +00:00
for ( const auto & unsel_item : unsels )
2019-04-04 13:07:54 +00:00
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 ) )
2019-09-02 07:41:12 +00:00
m_last_selected_item = wxDataViewItem ( nullptr ) ;
2019-04-04 13:07:54 +00:00
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 ;
2019-07-22 11:38:53 +00:00
take_snapshot ( _ ( L ( " Change Part Type " ) ) ) ;
2019-07-04 15:33:19 +00:00
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 ) ) {
2019-07-11 21:46:23 +00:00
add_settings_item ( item , & volume - > config ) ;
2018-11-05 07:55:44 +00:00
}
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 )
{
2019-09-06 15:46:55 +00:00
if ( obj_idx < 0 | | size_t ( obj_idx ) > = m_objects - > size ( ) | | ( * m_objects ) [ obj_idx ] - > volumes . size ( ) ! = 1 )
2018-11-12 12:47:24 +00:00
return ;
2019-07-05 17:06:19 +00:00
auto volume = ( * m_objects ) [ obj_idx ] - > volumes . front ( ) ;
2018-11-12 12:47:24 +00:00
// 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 ) ) ;
}
2019-07-12 11:55:46 +00:00
void ObjectList : : update_and_show_object_settings_item ( )
{
const wxDataViewItem item = GetSelection ( ) ;
if ( ! item ) return ;
const wxDataViewItem & obj_item = m_objects_model - > IsSettingsItem ( item ) ? m_objects_model - > GetParent ( item ) : item ;
select_item ( add_settings_item ( obj_item , & get_item_config ( obj_item ) ) ) ;
}
2018-11-29 14:00:23 +00:00
2019-06-10 08:48:43 +00:00
// Update settings item for item had it
2019-06-10 13:22:09 +00:00
void ObjectList : : update_settings_item_and_selection ( wxDataViewItem item , wxDataViewItemArray & selections )
2019-06-10 08:48:43 +00:00
{
2019-07-12 11:55:46 +00:00
const wxDataViewItem old_settings_item = m_objects_model - > GetSettingsItem ( item ) ;
const wxDataViewItem new_settings_item = add_settings_item ( item , & get_item_config ( item ) ) ;
if ( ! new_settings_item & & old_settings_item )
m_objects_model - > Delete ( old_settings_item ) ;
// if ols settings item was is selected area
if ( selections . Index ( old_settings_item ) ! = wxNOT_FOUND )
{
// If settings item was just updated
if ( old_settings_item = = new_settings_item )
{
Sidebar & panel = wxGetApp ( ) . sidebar ( ) ;
panel . Freeze ( ) ;
2019-06-10 08:48:43 +00:00
2019-07-12 11:55:46 +00:00
// update settings list
wxGetApp ( ) . obj_settings ( ) - > UpdateAndShow ( true ) ;
2019-06-10 08:48:43 +00:00
2019-07-12 11:55:46 +00:00
panel . Layout ( ) ;
panel . Thaw ( ) ;
}
else
// If settings item was deleted from the list,
// it's need to be deleted from selection array, if it was there
{
selections . Remove ( old_settings_item ) ;
// Select item, if settings_item doesn't exist for item anymore, but was selected
if ( selections . Index ( item ) = = wxNOT_FOUND ) {
selections . Add ( item ) ;
select_item ( item ) ; // to correct update of the SettingsList and ManipulationPanel sizers
}
}
2019-06-10 08:48:43 +00:00
}
}
void ObjectList : : update_object_list_by_printer_technology ( )
{
m_prevent_canvas_selection_update = true ;
wxDataViewItemArray sel ;
GetSelections ( sel ) ; // stash selection
wxDataViewItemArray object_items ;
2019-09-02 07:41:12 +00:00
m_objects_model - > GetChildren ( wxDataViewItem ( nullptr ) , object_items ) ;
2019-06-10 08:48:43 +00:00
for ( auto & object_item : object_items ) {
// Update Settings Item for object
2019-06-10 13:22:09 +00:00
update_settings_item_and_selection ( object_item , sel ) ;
2019-06-10 08:48:43 +00:00
// Update settings for Volumes
wxDataViewItemArray all_object_subitems ;
m_objects_model - > GetChildren ( object_item , all_object_subitems ) ;
for ( auto item : all_object_subitems )
if ( m_objects_model - > GetItemType ( item ) & itVolume )
// update settings for volume
2019-06-10 13:22:09 +00:00
update_settings_item_and_selection ( item , sel ) ;
2019-06-10 08:48:43 +00:00
// Update Layers Items
wxDataViewItem layers_item = m_objects_model - > GetLayerRootItem ( object_item ) ;
if ( ! layers_item )
layers_item = add_layer_root_item ( object_item ) ;
else if ( printer_technology ( ) = = ptSLA ) {
// If layers root item will be deleted from the list, so
// it's need to be deleted from selection array, if it was there
wxDataViewItemArray del_items ;
bool some_layers_was_selected = false ;
m_objects_model - > GetAllChildren ( layers_item , del_items ) ;
for ( auto & del_item : del_items )
if ( sel . Index ( del_item ) ! = wxNOT_FOUND ) {
some_layers_was_selected = true ;
sel . Remove ( del_item ) ;
}
if ( sel . Index ( layers_item ) ! = wxNOT_FOUND ) {
some_layers_was_selected = true ;
sel . Remove ( layers_item ) ;
}
// delete all "layers" items
m_objects_model - > Delete ( layers_item ) ;
// Select object_item, if layers_item doesn't exist for item anymore, but was some of layer items was/were selected
if ( some_layers_was_selected )
sel . Add ( object_item ) ;
}
else {
wxDataViewItemArray all_obj_layers ;
m_objects_model - > GetChildren ( layers_item , all_obj_layers ) ;
for ( auto item : all_obj_layers )
// update settings for layer
2019-06-10 13:22:09 +00:00
update_settings_item_and_selection ( item , sel ) ;
2019-06-10 08:48:43 +00:00
}
}
// restore selection:
SetSelections ( sel ) ;
m_prevent_canvas_selection_update = false ;
}
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-09-03 08:27:16 +00:00
for ( int inst_idx = int ( 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
2019-08-05 12:57:30 +00:00
const size_t new_obj_indx = static_cast < size_t > ( m_objects - > size ( ) - 1 ) ;
add_object_to_list ( new_obj_indx ) ;
2019-01-22 15:40:10 +00:00
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-08-05 12:57:30 +00:00
// update printable state for new volumes on canvas3D
2019-08-16 11:14:51 +00:00
wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > update_instance_printable_state_for_object ( new_obj_indx ) ;
2019-01-23 15:01:37 +00:00
}
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 ( ) ;
2019-08-05 12:57:30 +00:00
std : : vector < size_t > object_idxs ;
2019-04-04 16:01:53 +00:00
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
2019-08-05 12:57:30 +00:00
const size_t new_obj_indx = static_cast < size_t > ( m_objects - > size ( ) - 1 ) ;
add_object_to_list ( new_obj_indx ) ;
object_idxs . push_back ( new_obj_indx ) ;
2019-04-04 16:01:53 +00:00
// delete current instance from the initial object
del_subobject_from_object ( obj_idx , i , itInstance ) ;
delete_instance_from_list ( obj_idx , i ) ;
}
2019-08-05 12:57:30 +00:00
// update printable state for new volumes on canvas3D
wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > update_instance_printable_state_for_objects ( object_idxs ) ;
2019-04-04 16:01:53 +00:00
}
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-07-22 11:38:53 +00:00
Plater : : TakeSnapshot snapshot ( wxGetApp ( ) . plater ( ) , _ ( L ( " Instances to Separated Objects " ) ) ) ;
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 ;
2019-08-01 12:58:04 +00:00
m_objects_model - > GetValue ( valueOld , item , colName ) ;
2019-01-30 10:35:37 +00:00
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 ;
2019-08-01 12:58:04 +00:00
m_objects_model - > SetValue ( value , item , colName ) ;
2019-01-30 10:35:37 +00:00
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-09-23 12:24:53 +00:00
GetColumn ( colName ) - > SetWidth ( 20 * em ) ;
GetColumn ( colPrint ) - > SetWidth ( 3 * em ) ;
2019-08-01 12:58:04 +00:00
GetColumn ( colExtruder ) - > SetWidth ( 8 * em ) ;
2019-09-23 12:24:53 +00:00
GetColumn ( colEditing ) - > SetWidth ( 3 * 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 ,
2019-06-03 13:35:21 +00:00
& m_menu_instance ,
2019-09-19 10:30:16 +00:00
& m_menu_layer ,
& m_menu_default } )
2019-05-09 12:53:01 +00:00
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
{
2019-08-01 12:58:04 +00:00
if ( event . GetColumn ( ) = = colName )
2018-12-12 13:35:18 +00:00
update_name_in_model ( event . GetItem ( ) ) ;
2019-08-01 12:58:04 +00:00
else if ( event . GetColumn ( ) = = colExtruder )
2018-12-12 13:35:18 +00:00
update_extruder_in_config ( event . GetItem ( ) ) ;
}
2019-08-22 09:47:58 +00:00
# ifdef __WXMSW__
// Workaround for entering the column editing mode on Windows. Simulate keyboard enter when another column of the active line is selected.
// Here the last active column is forgotten, so when leaving the editing mode, the next mouse click will not enter the editing mode of the newly selected column.
void ObjectList : : OnEditingStarted ( wxDataViewEvent & event )
{
m_last_selected_column = - 1 ;
}
2019-09-02 07:41:12 +00:00
# endif //__WXMSW__
2019-08-22 09:47:58 +00:00
2018-12-12 13:35:18 +00:00
void ObjectList : : OnEditingDone ( wxDataViewEvent & event )
{
2019-08-01 12:58:04 +00:00
if ( event . GetColumn ( ) ! = colName )
2018-12-12 13:35:18 +00:00
return ;
2019-08-01 12:58:04 +00:00
const auto renderer = dynamic_cast < BitmapTextRenderer * > ( GetColumn ( colName ) - > GetRenderer ( ) ) ;
2018-12-12 13:35:18 +00:00
if ( renderer - > WasCanceled ( ) )
2019-05-23 10:18:28 +00:00
wxTheApp - > CallAfter ( [ this ] {
show_error ( this , _ ( L ( " The supplied name is not valid; " ) ) + " \n " +
_ ( L ( " the following characters are not allowed: " ) ) + " <>:/ \\ |?* \" " ) ;
} ) ;
2019-08-22 09:47:58 +00:00
# ifdef __WXMSW__
// Workaround for entering the column editing mode on Windows. Simulate keyboard enter when another column of the active line is selected.
// Here the last active column is forgotten, so when leaving the editing mode, the next mouse click will not enter the editing mode of the newly selected column.
m_last_selected_column = - 1 ;
2019-09-02 07:41:12 +00:00
# endif //__WXMSW__
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
*/
2019-10-01 16:19:28 +00:00
m_objects_model - > SetExtruder ( extruder_str , type & itInstance ? m_objects_model - > GetTopParent ( item ) : item ) ;
2019-03-28 15:28:34 +00:00
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 ( ) ;
}
2019-07-11 16:42:02 +00:00
void ObjectList : : update_after_undo_redo ( )
2019-07-04 15:33:19 +00:00
{
m_prevent_canvas_selection_update = true ;
2019-07-17 13:48:53 +00:00
Plater : : SuppressSnapshots suppress ( wxGetApp ( ) . plater ( ) ) ;
2019-07-11 16:42:02 +00:00
2019-07-05 17:06:19 +00:00
// Unselect all objects before deleting them, so that no change of selection is emitted during deletion.
2019-07-23 14:17:37 +00:00
unselect_objects ( ) ; //this->UnselectAll();
2019-07-04 15:33:19 +00:00
m_objects_model - > DeleteAll ( ) ;
size_t obj_idx = 0 ;
2019-08-07 12:28:46 +00:00
std : : vector < size_t > obj_idxs ;
obj_idxs . reserve ( m_objects - > size ( ) ) ;
2019-07-04 15:33:19 +00:00
while ( obj_idx < m_objects - > size ( ) ) {
2019-07-05 17:06:19 +00:00
add_object_to_list ( obj_idx , false ) ;
2019-08-07 12:28:46 +00:00
obj_idxs . push_back ( obj_idx ) ;
2019-07-04 15:33:19 +00:00
+ + obj_idx ;
}
2019-07-11 16:42:02 +00:00
update_selections ( ) ;
2019-07-04 15:33:19 +00:00
m_prevent_canvas_selection_update = false ;
2019-08-07 12:28:46 +00:00
// update printable states on canvas
wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > update_instance_printable_state_for_objects ( obj_idxs ) ;
// update scene
wxGetApp ( ) . plater ( ) - > update ( ) ;
2019-07-04 15:33:19 +00:00
}
2019-08-05 06:44:55 +00:00
void ObjectList : : update_printable_state ( int obj_idx , int instance_idx )
{
ModelObject * object = ( * m_objects ) [ obj_idx ] ;
2019-08-07 12:11:41 +00:00
const PrintIndicator printable = object - > instances [ instance_idx ] - > printable ? piPrintable : piUnprintable ;
2019-08-05 06:44:55 +00:00
if ( object - > instances . size ( ) = = 1 )
instance_idx = - 1 ;
2019-08-05 08:05:28 +00:00
m_objects_model - > SetPrintableState ( printable , obj_idx , instance_idx ) ;
}
void ObjectList : : toggle_printable_state ( wxDataViewItem item )
{
const ItemType type = m_objects_model - > GetItemType ( item ) ;
if ( ! ( type & ( itObject | itInstance /*|itVolume*/ ) ) )
return ;
2019-08-07 12:11:41 +00:00
if ( type & itObject )
{
const int obj_idx = m_objects_model - > GetObjectIdByItem ( item ) ;
ModelObject * object = ( * m_objects ) [ obj_idx ] ;
// get object's printable and change it
2019-08-07 13:39:46 +00:00
const bool printable = ! m_objects_model - > IsPrintable ( item ) ;
const wxString snapshot_text = wxString : : Format ( " %s %s " ,
printable ? _ ( L ( " Set Printable " ) ) : _ ( L ( " Set Unprintable " ) ) ,
object - > name ) ;
take_snapshot ( snapshot_text ) ;
2019-08-07 12:11:41 +00:00
// set printable value for all instances in object
for ( auto inst : object - > instances )
inst - > printable = printable ;
// update printable state on canvas
2019-08-16 11:14:51 +00:00
wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > update_instance_printable_state_for_object ( ( size_t ) obj_idx ) ;
2019-08-07 12:11:41 +00:00
// update printable state in ObjectList
m_objects_model - > SetObjectPrintableState ( printable ? piPrintable : piUnprintable , item ) ;
}
else
wxGetApp ( ) . plater ( ) - > canvas3D ( ) - > get_selection ( ) . toggle_instance_printable_state ( ) ;
2019-08-05 08:05:28 +00:00
// update scene
wxGetApp ( ) . plater ( ) - > update ( ) ;
2019-08-05 06:44:55 +00:00
}
2019-07-04 18:49:46 +00:00
ModelObject * ObjectList : : object ( const int obj_idx ) const
{
if ( obj_idx < 0 )
return nullptr ;
return ( * m_objects ) [ obj_idx ] ;
}
2018-10-04 14:43:10 +00:00
} //namespace GUI
2019-08-06 17:53:20 +00:00
} //namespace Slic3r