2018-09-17 10:15:11 +00:00
# include "Plater.hpp"
# include <cstddef>
# include <algorithm>
# include <vector>
# include <string>
# include <regex>
2018-12-06 16:32:49 +00:00
# include <boost/algorithm/string/predicate.hpp>
# include <boost/algorithm/string/trim.hpp>
2018-10-04 09:12:55 +00:00
# include <boost/optional.hpp>
2018-09-17 10:15:11 +00:00
# include <boost/filesystem/path.hpp>
# include <wx/sizer.h>
# include <wx/stattext.h>
# include <wx/button.h>
# include <wx/bmpcbox.h>
# include <wx/statbox.h>
# include <wx/statbmp.h>
# include <wx/filedlg.h>
# include <wx/dnd.h>
# include <wx/progdlg.h>
2018-10-01 14:48:08 +00:00
# include <wx/wupdlock.h>
2018-10-10 11:53:45 +00:00
# include <wx/colordlg.h>
2018-10-18 13:13:38 +00:00
# include <wx/numdlg.h>
# include <wx/debug.h>
2018-09-17 10:15:11 +00:00
2018-10-09 07:35:19 +00:00
# include "libslic3r/libslic3r.h"
2018-11-26 13:41:58 +00:00
# include "libslic3r/Format/STL.hpp"
# include "libslic3r/Format/AMF.hpp"
# include "libslic3r/Format/3mf.hpp"
# include "libslic3r/GCode/PreviewData.hpp"
2018-09-17 10:15:11 +00:00
# include "libslic3r/Model.hpp"
2018-11-12 13:52:52 +00:00
# include "libslic3r/ModelArrange.hpp"
2018-11-26 13:41:58 +00:00
# include "libslic3r/Polygon.hpp"
2018-09-17 10:15:11 +00:00
# include "libslic3r/Print.hpp"
2018-11-26 13:41:58 +00:00
# include "libslic3r/PrintConfig.hpp"
2018-11-08 19:18:40 +00:00
# include "libslic3r/SLAPrint.hpp"
2018-11-26 13:41:58 +00:00
# include "libslic3r/SLA/SLARotfinder.hpp"
2018-09-17 10:15:11 +00:00
# include "libslic3r/Utils.hpp"
2018-11-26 13:41:58 +00:00
2019-04-04 14:03:23 +00:00
# include "libnest2d/optimizers/nlopt/genetic.hpp"
2018-09-17 10:15:11 +00:00
# include "GUI.hpp"
# include "GUI_App.hpp"
2018-10-04 14:43:10 +00:00
# include "GUI_ObjectList.hpp"
# include "GUI_ObjectManipulation.hpp"
2018-10-04 09:12:55 +00:00
# include "GUI_Utils.hpp"
2018-10-17 10:17:25 +00:00
# include "wxExtensions.hpp"
2018-09-17 10:15:11 +00:00
# include "MainFrame.hpp"
# include "3DScene.hpp"
2018-10-03 09:34:39 +00:00
# include "GLCanvas3D.hpp"
2019-03-19 12:30:21 +00:00
# include "Selection.hpp"
2018-09-17 10:15:11 +00:00
# include "GLToolbar.hpp"
# include "GUI_Preview.hpp"
2019-02-19 14:15:27 +00:00
# include "3DBed.hpp"
2019-03-06 14:46:19 +00:00
# include "Camera.hpp"
2018-09-17 10:15:11 +00:00
# include "Tab.hpp"
# include "PresetBundle.hpp"
# include "BackgroundSlicingProcess.hpp"
# include "ProgressStatusBar.hpp"
2018-12-11 09:33:11 +00:00
# include "PrintHostDialogs.hpp"
2019-03-22 14:45:51 +00:00
# include "ConfigWizard.hpp"
2018-11-26 13:41:58 +00:00
# include "../Utils/ASCIIFolding.hpp"
2018-12-11 09:33:11 +00:00
# include "../Utils/PrintHost.hpp"
2018-11-07 12:40:24 +00:00
# include "../Utils/FixModelByWin10.hpp"
2018-09-17 10:15:11 +00:00
# include <wx/glcanvas.h> // Needs to be last because reasons :-/
2018-10-03 13:14:52 +00:00
# include "WipeTowerDialog.hpp"
2018-09-17 10:15:11 +00:00
2018-10-04 09:12:55 +00:00
using boost : : optional ;
2018-09-17 10:15:11 +00:00
namespace fs = boost : : filesystem ;
using Slic3r : : _3DScene ;
using Slic3r : : Preset ;
2018-12-11 09:33:11 +00:00
using Slic3r : : PrintHostJob ;
2018-09-17 10:15:11 +00:00
namespace Slic3r {
namespace GUI {
2018-11-26 13:41:58 +00:00
wxDEFINE_EVENT ( EVT_SCHEDULE_BACKGROUND_PROCESS , SimpleEvent ) ;
wxDEFINE_EVENT ( EVT_SLICING_UPDATE , SlicingStatusEvent ) ;
wxDEFINE_EVENT ( EVT_SLICING_COMPLETED , wxCommandEvent ) ;
wxDEFINE_EVENT ( EVT_PROCESS_COMPLETED , wxCommandEvent ) ;
2018-09-17 10:15:11 +00:00
// Sidebar widgets
// struct InfoBox : public wxStaticBox
// {
// InfoBox(wxWindow *parent, const wxString &label) :
// wxStaticBox(parent, wxID_ANY, label)
// {
// SetFont(GUI::small_font().Bold());
// }
// };
class ObjectInfo : public wxStaticBoxSizer
{
public :
ObjectInfo ( wxWindow * parent ) ;
2018-10-05 21:29:15 +00:00
wxStaticBitmap * manifold_warning_icon ;
2018-09-17 10:15:11 +00:00
wxStaticText * info_size ;
wxStaticText * info_volume ;
wxStaticText * info_facets ;
wxStaticText * info_materials ;
wxStaticText * info_manifold ;
2019-02-19 11:14:13 +00:00
wxStaticText * label_volume ;
wxStaticText * label_materials ;
2019-02-21 14:46:04 +00:00
std : : vector < wxStaticText * > sla_hidden_items ;
2019-02-19 11:14:13 +00:00
2018-11-01 11:33:56 +00:00
bool showing_manifold_warning_icon ;
void show_sizer ( bool show ) ;
2019-04-24 23:45:00 +00:00
void msw_rescale ( ) ;
2018-09-17 10:15:11 +00:00
} ;
ObjectInfo : : ObjectInfo ( wxWindow * parent ) :
wxStaticBoxSizer ( new wxStaticBox ( parent , wxID_ANY , _ ( L ( " Info " ) ) ) , wxVERTICAL )
{
2018-10-01 13:09:31 +00:00
GetStaticBox ( ) - > SetFont ( wxGetApp ( ) . bold_font ( ) ) ;
2018-09-17 10:15:11 +00:00
2019-04-13 21:46:52 +00:00
auto * grid_sizer = new wxFlexGridSizer ( 4 , 5 , 15 ) ;
2018-09-17 10:15:11 +00:00
grid_sizer - > SetFlexibleDirection ( wxHORIZONTAL ) ;
2019-04-13 21:46:52 +00:00
// grid_sizer->AddGrowableCol(1, 1);
// grid_sizer->AddGrowableCol(3, 1);
2018-09-17 10:15:11 +00:00
auto init_info_label = [ parent , grid_sizer ] ( wxStaticText * * info_label , wxString text_label ) {
2019-01-21 11:34:28 +00:00
auto * text = new wxStaticText ( parent , wxID_ANY , text_label + " : " ) ;
2018-10-01 13:09:31 +00:00
text - > SetFont ( wxGetApp ( ) . small_font ( ) ) ;
2018-09-17 10:15:11 +00:00
* info_label = new wxStaticText ( parent , wxID_ANY , " " ) ;
2018-10-01 13:09:31 +00:00
( * info_label ) - > SetFont ( wxGetApp ( ) . small_font ( ) ) ;
2018-09-17 10:15:11 +00:00
grid_sizer - > Add ( text , 0 ) ;
grid_sizer - > Add ( * info_label , 0 ) ;
2019-02-19 11:14:13 +00:00
return text ;
2018-09-17 10:15:11 +00:00
} ;
2019-01-21 11:34:28 +00:00
init_info_label ( & info_size , _ ( L ( " Size " ) ) ) ;
2019-02-19 11:14:13 +00:00
label_volume = init_info_label ( & info_volume , _ ( L ( " Volume " ) ) ) ;
2019-01-21 11:34:28 +00:00
init_info_label ( & info_facets , _ ( L ( " Facets " ) ) ) ;
2019-02-19 11:14:13 +00:00
label_materials = init_info_label ( & info_materials , _ ( L ( " Materials " ) ) ) ;
2018-11-01 11:33:56 +00:00
Add ( grid_sizer , 0 , wxEXPAND ) ;
2018-09-17 10:15:11 +00:00
2019-02-19 11:14:13 +00:00
auto * info_manifold_text = new wxStaticText ( parent , wxID_ANY , _ ( L ( " Manifold " ) ) + " : " ) ;
2018-10-01 13:09:31 +00:00
info_manifold_text - > SetFont ( wxGetApp ( ) . small_font ( ) ) ;
2018-09-17 10:15:11 +00:00
info_manifold = new wxStaticText ( parent , wxID_ANY , " " ) ;
2018-10-01 13:09:31 +00:00
info_manifold - > SetFont ( wxGetApp ( ) . small_font ( ) ) ;
2019-04-12 15:10:04 +00:00
manifold_warning_icon = new wxStaticBitmap ( parent , wxID_ANY , create_scaled_bitmap ( parent , " exclamation " ) ) ;
2018-09-17 10:15:11 +00:00
auto * sizer_manifold = new wxBoxSizer ( wxHORIZONTAL ) ;
sizer_manifold - > Add ( info_manifold_text , 0 ) ;
sizer_manifold - > Add ( manifold_warning_icon , 0 , wxLEFT , 2 ) ;
sizer_manifold - > Add ( info_manifold , 0 , wxLEFT , 2 ) ;
2018-11-01 11:33:56 +00:00
Add ( sizer_manifold , 0 , wxEXPAND | wxTOP , 4 ) ;
2019-02-19 11:14:13 +00:00
2019-02-21 14:46:04 +00:00
sla_hidden_items = { label_volume , info_volume , label_materials , info_materials } ;
2018-11-01 11:33:56 +00:00
}
2018-09-17 10:15:11 +00:00
2018-11-01 11:33:56 +00:00
void ObjectInfo : : show_sizer ( bool show )
{
Show ( show ) ;
if ( show )
manifold_warning_icon - > Show ( showing_manifold_warning_icon & & show ) ;
2018-09-17 10:15:11 +00:00
}
2019-04-24 23:45:00 +00:00
void ObjectInfo : : msw_rescale ( )
2019-04-13 21:46:52 +00:00
{
2019-04-16 08:05:45 +00:00
manifold_warning_icon - > SetBitmap ( create_scaled_bitmap ( nullptr , " exclamation " ) ) ;
2019-04-13 21:46:52 +00:00
}
2018-10-31 11:26:57 +00:00
enum SlisedInfoIdx
{
siFilament_m ,
siFilament_mm3 ,
siFilament_g ,
2019-02-12 15:34:42 +00:00
siMateril_unit ,
2018-10-31 11:26:57 +00:00
siCost ,
2018-11-20 09:33:54 +00:00
siEstimatedTime ,
2018-10-31 11:26:57 +00:00
siWTNumbetOfToolchanges ,
siCount
} ;
2018-09-17 10:15:11 +00:00
class SlicedInfo : public wxStaticBoxSizer
{
public :
SlicedInfo ( wxWindow * parent ) ;
2018-11-20 09:33:54 +00:00
void SetTextAndShow ( SlisedInfoIdx idx , const wxString & text , const wxString & new_label = " " ) ;
2018-09-17 10:15:11 +00:00
private :
2018-10-31 11:26:57 +00:00
std : : vector < std : : pair < wxStaticText * , wxStaticText * > > info_vec ;
2018-09-17 10:15:11 +00:00
} ;
SlicedInfo : : SlicedInfo ( wxWindow * parent ) :
wxStaticBoxSizer ( new wxStaticBox ( parent , wxID_ANY , _ ( L ( " Sliced Info " ) ) ) , wxVERTICAL )
{
2018-10-01 13:09:31 +00:00
GetStaticBox ( ) - > SetFont ( wxGetApp ( ) . bold_font ( ) ) ;
2018-09-17 10:15:11 +00:00
2018-11-20 09:33:54 +00:00
auto * grid_sizer = new wxFlexGridSizer ( 2 , 5 , 15 ) ;
grid_sizer - > SetFlexibleDirection ( wxVERTICAL ) ;
2018-09-17 10:15:11 +00:00
2018-10-31 11:26:57 +00:00
info_vec . reserve ( siCount ) ;
auto init_info_label = [ this , parent , grid_sizer ] ( wxString text_label ) {
2018-09-17 10:15:11 +00:00
auto * text = new wxStaticText ( parent , wxID_ANY , text_label ) ;
2018-10-01 13:09:31 +00:00
text - > SetFont ( wxGetApp ( ) . small_font ( ) ) ;
2018-10-31 11:26:57 +00:00
auto info_label = new wxStaticText ( parent , wxID_ANY , " N/A " ) ;
2018-10-01 13:09:31 +00:00
info_label - > SetFont ( wxGetApp ( ) . small_font ( ) ) ;
2018-09-17 10:15:11 +00:00
grid_sizer - > Add ( text , 0 ) ;
grid_sizer - > Add ( info_label , 0 ) ;
2018-10-31 11:26:57 +00:00
info_vec . push_back ( std : : pair < wxStaticText * , wxStaticText * > ( text , info_label ) ) ;
2018-09-17 10:15:11 +00:00
} ;
2018-10-31 11:26:57 +00:00
init_info_label ( _ ( L ( " Used Filament (m) " ) ) ) ;
init_info_label ( _ ( L ( " Used Filament (mm³) " ) ) ) ;
init_info_label ( _ ( L ( " Used Filament (g) " ) ) ) ;
2019-02-12 15:34:42 +00:00
init_info_label ( _ ( L ( " Used Material (unit) " ) ) ) ;
2018-10-31 11:26:57 +00:00
init_info_label ( _ ( L ( " Cost " ) ) ) ;
2018-11-20 09:33:54 +00:00
init_info_label ( _ ( L ( " Estimated printing time " ) ) ) ;
2018-10-31 11:26:57 +00:00
init_info_label ( _ ( L ( " Number of tool changes " ) ) ) ;
2018-09-17 10:15:11 +00:00
Add ( grid_sizer , 0 , wxEXPAND ) ;
2018-10-31 11:26:57 +00:00
this - > Show ( false ) ;
}
2018-11-20 09:33:54 +00:00
void SlicedInfo : : SetTextAndShow ( SlisedInfoIdx idx , const wxString & text , const wxString & new_label /*=""*/ )
2018-10-31 11:26:57 +00:00
{
const bool show = text ! = " N/A " ;
if ( show )
info_vec [ idx ] . second - > SetLabelText ( text ) ;
2018-11-20 09:33:54 +00:00
if ( ! new_label . IsEmpty ( ) )
info_vec [ idx ] . first - > SetLabelText ( new_label ) ;
2018-10-31 11:26:57 +00:00
info_vec [ idx ] . first - > Show ( show ) ;
info_vec [ idx ] . second - > Show ( show ) ;
2018-09-17 10:15:11 +00:00
}
PresetComboBox : : PresetComboBox ( wxWindow * parent , Preset : : Type preset_type ) :
2019-02-04 09:35:16 +00:00
wxBitmapComboBox ( parent , wxID_ANY , wxEmptyString , wxDefaultPosition , wxSize ( 15 * wxGetApp ( ) . em_unit ( ) , - 1 ) , 0 , nullptr , wxCB_READONLY ) ,
2018-09-17 10:15:11 +00:00
preset_type ( preset_type ) ,
2019-04-23 14:33:06 +00:00
last_selected ( wxNOT_FOUND ) ,
m_em_unit ( wxGetApp ( ) . em_unit ( ) )
2018-09-17 10:15:11 +00:00
{
Bind ( wxEVT_COMBOBOX , [ this ] ( wxCommandEvent & evt ) {
auto selected_item = this - > GetSelection ( ) ;
auto marker = reinterpret_cast < Marker > ( this - > GetClientData ( selected_item ) ) ;
2019-03-22 14:45:51 +00:00
if ( marker = = LABEL_ITEM_MARKER | | marker = = LABEL_ITEM_CONFIG_WIZARD ) {
2018-09-17 10:15:11 +00:00
this - > SetSelection ( this - > last_selected ) ;
evt . StopPropagation ( ) ;
2019-03-22 14:45:51 +00:00
if ( marker = = LABEL_ITEM_CONFIG_WIZARD )
wxTheApp - > CallAfter ( [ ] ( ) { Slic3r : : GUI : : config_wizard ( Slic3r : : GUI : : ConfigWizard : : RR_USER ) ; } ) ;
2018-12-21 09:58:00 +00:00
} else if ( this - > last_selected ! = selected_item | |
wxGetApp ( ) . get_tab ( this - > preset_type ) - > get_presets ( ) - > current_is_dirty ( ) ) {
2018-09-17 10:15:11 +00:00
this - > last_selected = selected_item ;
evt . SetInt ( this - > preset_type ) ;
2018-10-09 10:41:05 +00:00
evt . Skip ( ) ;
2018-09-17 10:15:11 +00:00
} else {
evt . StopPropagation ( ) ;
}
} ) ;
2018-10-10 11:53:45 +00:00
if ( preset_type = = Slic3r : : Preset : : TYPE_FILAMENT )
{
Bind ( wxEVT_LEFT_DOWN , [ this ] ( wxMouseEvent & event ) {
if ( extruder_idx < 0 | | event . GetLogicalPosition ( wxClientDC ( this ) ) . x > 24 ) {
// Let the combo box process the mouse click.
event . Skip ( ) ;
return ;
}
// Swallow the mouse click and open the color picker.
auto data = new wxColourData ( ) ;
data - > SetChooseFull ( 1 ) ;
2019-01-02 16:54:54 +00:00
auto dialog = new wxColourDialog ( /* wxGetApp().mainframe */ this , data ) ;
dialog - > CenterOnParent ( ) ;
2018-10-10 11:53:45 +00:00
if ( dialog - > ShowModal ( ) = = wxID_OK ) {
DynamicPrintConfig cfg = * wxGetApp ( ) . get_tab ( Preset : : TYPE_PRINTER ) - > get_config ( ) ;
2018-10-17 09:12:38 +00:00
//FIXME this is too expensive to call full_config to get just the extruder color!
2018-10-10 11:53:45 +00:00
auto colors = static_cast < ConfigOptionStrings * > ( wxGetApp ( ) . preset_bundle - > full_config ( ) . option ( " extruder_colour " ) - > clone ( ) ) ;
colors - > values [ extruder_idx ] = dialog - > GetColourData ( ) . GetColour ( ) . GetAsString ( wxC2S_HTML_SYNTAX ) ;
cfg . set_key_value ( " extruder_colour " , colors ) ;
wxGetApp ( ) . get_tab ( Preset : : TYPE_PRINTER ) - > load_config ( cfg ) ;
2019-04-23 14:33:06 +00:00
wxGetApp ( ) . preset_bundle - > update_platter_filament_ui ( extruder_idx , this ) ;
2018-10-17 09:12:38 +00:00
wxGetApp ( ) . plater ( ) - > on_config_change ( cfg ) ;
2018-10-10 11:53:45 +00:00
}
dialog - > Destroy ( ) ;
} ) ;
}
2019-03-18 14:10:40 +00:00
2019-04-24 23:45:00 +00:00
edit_btn = new ScalableButton ( parent , wxID_ANY , " cog " ) ;
2019-03-20 09:14:49 +00:00
edit_btn - > SetToolTip ( _ ( L ( " Click to edit preset " ) ) ) ;
2019-03-18 14:10:40 +00:00
edit_btn - > Bind ( wxEVT_BUTTON , ( [ preset_type , this ] ( wxCommandEvent )
{
Tab * tab = wxGetApp ( ) . get_tab ( preset_type ) ;
if ( ! tab )
return ;
int page_id = wxGetApp ( ) . tab_panel ( ) - > FindPage ( tab ) ;
if ( page_id = = wxNOT_FOUND )
return ;
wxGetApp ( ) . tab_panel ( ) - > ChangeSelection ( page_id ) ;
2019-03-19 13:36:32 +00:00
/* In a case of a multi-material printing, for editing another Filament Preset
* it ' s needed to select this preset for the " Filament settings " Tab
*/
if ( preset_type = = Preset : : TYPE_FILAMENT & & wxGetApp ( ) . extruders_cnt ( ) > 1 )
{
const std : : string & selected_preset = GetString ( GetSelection ( ) ) . ToUTF8 ( ) . data ( ) ;
// Call select_preset() only if there is new preset and not just modified
2019-03-20 09:14:49 +00:00
if ( ! boost : : algorithm : : ends_with ( selected_preset , Preset : : suffix_modified ( ) ) )
2019-03-19 13:36:32 +00:00
tab - > select_preset ( selected_preset ) ;
}
2019-03-18 14:10:40 +00:00
} ) ) ;
2018-09-17 10:15:11 +00:00
}
2019-03-18 14:10:40 +00:00
PresetComboBox : : ~ PresetComboBox ( )
{
if ( edit_btn )
edit_btn - > Destroy ( ) ;
}
2018-09-17 10:15:11 +00:00
2019-03-22 14:45:51 +00:00
void PresetComboBox : : set_label_marker ( int item , LabelItemType label_item_type )
2018-10-09 10:41:05 +00:00
{
2019-03-22 14:45:51 +00:00
this - > SetClientData ( item , ( void * ) label_item_type ) ;
2018-10-09 10:41:05 +00:00
}
2018-12-03 14:16:33 +00:00
void PresetComboBox : : check_selection ( )
{
2019-03-23 09:04:44 +00:00
this - > last_selected = GetSelection ( ) ;
2018-12-03 14:16:33 +00:00
}
2019-04-24 23:45:00 +00:00
void PresetComboBox : : msw_rescale ( )
2019-04-13 21:46:52 +00:00
{
2019-04-23 14:33:06 +00:00
m_em_unit = wxGetApp ( ) . em_unit ( ) ;
2019-04-24 23:45:00 +00:00
edit_btn - > msw_rescale ( ) ;
2019-04-13 21:46:52 +00:00
}
2018-10-04 14:43:10 +00:00
// Frequently changed parameters
class FreqChangedParams : public OG_Settings
{
double m_brim_width = 0.0 ;
wxButton * m_wiping_dialog_button { nullptr } ;
2019-01-15 08:31:53 +00:00
wxSizer * m_sizer { nullptr } ;
std : : shared_ptr < ConfigOptionsGroup > m_og_sla ;
2018-10-04 14:43:10 +00:00
public :
FreqChangedParams ( wxWindow * parent , const int label_width ) ;
~ FreqChangedParams ( ) { }
wxButton * get_wiping_dialog_button ( ) { return m_wiping_dialog_button ; }
2019-01-15 08:31:53 +00:00
wxSizer * get_sizer ( ) override ;
ConfigOptionsGroup * get_og ( const bool is_fff ) ;
void Show ( const bool is_fff ) ;
2018-10-04 14:43:10 +00:00
} ;
FreqChangedParams : : FreqChangedParams ( wxWindow * parent , const int label_width ) :
OG_Settings ( parent , false )
{
DynamicPrintConfig * config = & wxGetApp ( ) . preset_bundle - > prints . get_edited_preset ( ) . config ;
2019-01-15 08:31:53 +00:00
// Frequently changed parameters for FFF_technology
2018-10-04 14:43:10 +00:00
m_og - > set_config ( config ) ;
2019-02-07 13:44:05 +00:00
m_og - > label_width = label_width = = 0 ? 1 : label_width ;
2018-10-04 14:43:10 +00:00
2018-10-31 11:56:08 +00:00
m_og - > m_on_change = [ config , this ] ( t_config_option_key opt_key , boost : : any value ) {
2019-01-15 08:31:53 +00:00
Tab * tab_print = wxGetApp ( ) . get_tab ( Preset : : TYPE_PRINT ) ;
if ( ! tab_print ) return ;
2018-10-04 14:43:10 +00:00
2018-10-31 11:56:08 +00:00
if ( opt_key = = " fill_density " ) {
2018-10-04 14:43:10 +00:00
value = m_og - > get_config_value ( * config , opt_key ) ;
tab_print - > set_value ( opt_key , value ) ;
tab_print - > update ( ) ;
}
else {
DynamicPrintConfig new_conf = * config ;
2018-10-31 11:56:08 +00:00
if ( opt_key = = " brim " ) {
2018-10-04 14:43:10 +00:00
double new_val ;
double brim_width = config - > opt_float ( " brim_width " ) ;
if ( boost : : any_cast < bool > ( value ) = = true )
{
2018-12-11 15:33:43 +00:00
new_val = m_brim_width = = 0.0 ? 5 :
2018-10-04 14:43:10 +00:00
m_brim_width < 0.0 ? m_brim_width * ( - 1 ) :
m_brim_width ;
}
2018-12-11 15:33:43 +00:00
else {
2018-10-04 14:43:10 +00:00
m_brim_width = brim_width * ( - 1 ) ;
new_val = 0 ;
}
new_conf . set_key_value ( " brim_width " , new ConfigOptionFloat ( new_val ) ) ;
}
2018-12-11 15:33:43 +00:00
else { //(opt_key == "support")
2018-10-04 14:43:10 +00:00
const wxString & selection = boost : : any_cast < wxString > ( value ) ;
auto support_material = selection = = _ ( " None " ) ? false : true ;
new_conf . set_key_value ( " support_material " , new ConfigOptionBool ( support_material ) ) ;
if ( selection = = _ ( " Everywhere " ) )
new_conf . set_key_value ( " support_material_buildplate_only " , new ConfigOptionBool ( false ) ) ;
else if ( selection = = _ ( " Support on build plate only " ) )
new_conf . set_key_value ( " support_material_buildplate_only " , new ConfigOptionBool ( true ) ) ;
}
tab_print - > load_config ( new_conf ) ;
}
tab_print - > update_dirty ( ) ;
} ;
2019-02-07 13:44:05 +00:00
Line line = Line { " " , " " } ;
2018-10-04 14:43:10 +00:00
2019-03-11 15:00:13 +00:00
ConfigOptionDef support_def ;
support_def . label = L ( " Supports " ) ;
support_def . type = coStrings ;
support_def . gui_type = " select_open " ;
support_def . tooltip = L ( " Select what kind of support do you need " ) ;
support_def . enum_labels . push_back ( L ( " None " ) ) ;
support_def . enum_labels . push_back ( L ( " Support on build plate only " ) ) ;
support_def . enum_labels . push_back ( L ( " Everywhere " ) ) ;
std : : string selection = ! config - > opt_bool ( " support_material " ) ?
" None " : config - > opt_bool ( " support_material_buildplate_only " ) ?
" Support on build plate only " :
" Everywhere " ;
support_def . default_value = new ConfigOptionStrings { selection } ;
Option option = Option ( support_def , " support " ) ;
2018-10-04 14:43:10 +00:00
option . opt . full_width = true ;
2019-02-07 13:44:05 +00:00
line . append_option ( option ) ;
m_og - > append_line ( line ) ;
line = Line { " " , " " } ;
option = m_og - > get_option ( " fill_density " ) ;
option . opt . label = L ( " Infill " ) ;
2019-04-13 21:46:52 +00:00
option . opt . width = 6 ;
2019-02-07 13:44:05 +00:00
option . opt . sidetext = " " ;
line . append_option ( option ) ;
2018-10-04 14:43:10 +00:00
m_brim_width = config - > opt_float ( " brim_width " ) ;
2019-03-11 15:00:13 +00:00
ConfigOptionDef def ;
2018-10-04 14:43:10 +00:00
def . label = L ( " Brim " ) ;
def . type = coBool ;
def . tooltip = L ( " This flag enables the brim that will be printed around each object on the first layer. " ) ;
def . gui_type = " " ;
def . default_value = new ConfigOptionBool { m_brim_width > 0.0 ? true : false } ;
option = Option ( def , " brim " ) ;
2019-02-07 13:44:05 +00:00
option . opt . sidetext = " " ;
line . append_option ( option ) ;
2018-10-04 14:43:10 +00:00
2019-02-07 13:44:05 +00:00
auto wiping_dialog_btn = [ config , this ] ( wxWindow * parent ) {
2018-10-04 14:43:10 +00:00
m_wiping_dialog_button = new wxButton ( parent , wxID_ANY , _ ( L ( " Purging volumes " ) ) + dots , wxDefaultPosition , wxDefaultSize , wxBU_EXACTFIT ) ;
auto sizer = new wxBoxSizer ( wxHORIZONTAL ) ;
sizer - > Add ( m_wiping_dialog_button ) ;
m_wiping_dialog_button - > Bind ( wxEVT_BUTTON , ( [ parent ] ( wxCommandEvent & e )
{
auto & config = wxGetApp ( ) . preset_bundle - > project_config ;
const std : : vector < double > & init_matrix = ( config . option < ConfigOptionFloats > ( " wiping_volumes_matrix " ) ) - > values ;
const std : : vector < double > & init_extruders = ( config . option < ConfigOptionFloats > ( " wiping_volumes_extruders " ) ) - > values ;
WipingDialog dlg ( parent , cast < float > ( init_matrix ) , cast < float > ( init_extruders ) ) ;
if ( dlg . ShowModal ( ) = = wxID_OK ) {
std : : vector < float > matrix = dlg . get_matrix ( ) ;
std : : vector < float > extruders = dlg . get_extruders ( ) ;
( config . option < ConfigOptionFloats > ( " wiping_volumes_matrix " ) ) - > values = std : : vector < double > ( matrix . begin ( ) , matrix . end ( ) ) ;
( config . option < ConfigOptionFloats > ( " wiping_volumes_extruders " ) ) - > values = std : : vector < double > ( extruders . begin ( ) , extruders . end ( ) ) ;
2019-02-07 13:44:05 +00:00
wxPostEvent ( parent , SimpleEvent ( EVT_SCHEDULE_BACKGROUND_PROCESS , parent ) ) ;
2018-10-04 14:43:10 +00:00
}
} ) ) ;
return sizer ;
} ;
2019-02-07 13:44:05 +00:00
line . append_widget ( wiping_dialog_btn ) ;
2019-01-15 08:31:53 +00:00
2019-02-07 13:44:05 +00:00
m_og - > append_line ( line ) ;
2019-01-15 08:31:53 +00:00
2019-03-11 15:00:13 +00:00
2019-01-15 08:31:53 +00:00
// Frequently changed parameters for SLA_technology
m_og_sla = std : : make_shared < ConfigOptionsGroup > ( parent , " " ) ;
DynamicPrintConfig * config_sla = & wxGetApp ( ) . preset_bundle - > sla_prints . get_edited_preset ( ) . config ;
m_og_sla - > set_config ( config_sla ) ;
2019-02-07 13:44:05 +00:00
m_og_sla - > label_width = label_width = = 0 ? 1 : label_width ;
2019-01-15 08:31:53 +00:00
m_og_sla - > m_on_change = [ config_sla , this ] ( t_config_option_key opt_key , boost : : any value ) {
Tab * tab = wxGetApp ( ) . get_tab ( Preset : : TYPE_SLA_PRINT ) ;
if ( ! tab ) return ;
2019-03-11 15:00:13 +00:00
if ( opt_key = = " pad_enable " ) {
tab - > set_value ( opt_key , value ) ;
tab - > update ( ) ;
}
else //(opt_key == "support")
{
DynamicPrintConfig new_conf = * config_sla ;
const wxString & selection = boost : : any_cast < wxString > ( value ) ;
2019-01-15 08:31:53 +00:00
2019-03-11 15:00:13 +00:00
const bool supports_enable = selection = = _ ( " None " ) ? false : true ;
new_conf . set_key_value ( " supports_enable " , new ConfigOptionBool ( supports_enable ) ) ;
if ( selection = = _ ( " Everywhere " ) )
new_conf . set_key_value ( " support_buildplate_only " , new ConfigOptionBool ( false ) ) ;
else if ( selection = = _ ( " Support on build plate only " ) )
new_conf . set_key_value ( " support_buildplate_only " , new ConfigOptionBool ( true ) ) ;
2019-01-15 08:31:53 +00:00
2019-03-11 15:00:13 +00:00
tab - > load_config ( new_conf ) ;
}
tab - > update_dirty ( ) ;
} ;
2019-02-07 13:44:05 +00:00
line = Line { " " , " " } ;
2019-03-11 15:00:13 +00:00
selection = ! config_sla - > opt_bool ( " supports_enable " ) ?
" None " : config_sla - > opt_bool ( " support_buildplate_only " ) ?
" Support on build plate only " :
" Everywhere " ;
support_def . default_value = new ConfigOptionStrings { selection } ;
option = Option ( support_def , " support " ) ;
option . opt . full_width = true ;
2019-02-07 13:44:05 +00:00
line . append_option ( option ) ;
2019-03-11 15:00:13 +00:00
m_og_sla - > append_line ( line ) ;
line = Line { " " , " " } ;
2019-02-07 13:44:05 +00:00
option = m_og_sla - > get_option ( " pad_enable " ) ;
option . opt . sidetext = " " ;
line . append_option ( option ) ;
m_og_sla - > append_line ( line ) ;
2019-01-15 08:31:53 +00:00
m_sizer = new wxBoxSizer ( wxVERTICAL ) ;
m_sizer - > Add ( m_og - > sizer , 0 , wxEXPAND ) ;
2019-02-07 13:44:05 +00:00
m_sizer - > Add ( m_og_sla - > sizer , 0 , wxEXPAND ) ;
2018-10-04 14:43:10 +00:00
}
2019-01-15 08:31:53 +00:00
wxSizer * FreqChangedParams : : get_sizer ( )
{
return m_sizer ;
}
void FreqChangedParams : : Show ( const bool is_fff )
2018-10-24 10:57:23 +00:00
{
2019-01-15 08:31:53 +00:00
const bool is_wdb_shown = m_wiping_dialog_button - > IsShown ( ) ;
m_og - > Show ( is_fff ) ;
m_og_sla - > Show ( ! is_fff ) ;
2018-10-24 10:57:23 +00:00
// correct showing of the FreqChangedParams sizer when m_wiping_dialog_button is hidden
2019-01-15 08:31:53 +00:00
if ( is_fff & & ! is_wdb_shown )
2018-10-24 10:57:23 +00:00
m_wiping_dialog_button - > Hide ( ) ;
}
2019-01-15 08:31:53 +00:00
ConfigOptionsGroup * FreqChangedParams : : get_og ( const bool is_fff )
{
return is_fff ? m_og . get ( ) : m_og_sla . get ( ) ;
}
2018-09-17 10:15:11 +00:00
// Sidebar / private
2019-03-01 10:00:34 +00:00
enum class ActionButtonType : int {
abReslice ,
abExport ,
abSendGCode
} ;
2018-09-17 10:15:11 +00:00
struct Sidebar : : priv
{
2018-10-04 09:12:55 +00:00
Plater * plater ;
2018-09-17 10:15:11 +00:00
wxScrolledWindow * scrolled ;
2019-03-13 12:13:18 +00:00
wxPanel * presets_panel ; // Used for MSW better layouts
2018-09-17 10:15:11 +00:00
2019-04-24 23:45:00 +00:00
ModeSizer * mode_sizer ;
2018-09-17 10:15:11 +00:00
wxFlexGridSizer * sizer_presets ;
PresetComboBox * combo_print ;
std : : vector < PresetComboBox * > combos_filament ;
wxBoxSizer * sizer_filaments ;
2018-11-16 16:36:23 +00:00
PresetComboBox * combo_sla_print ;
2018-09-17 10:15:11 +00:00
PresetComboBox * combo_sla_material ;
PresetComboBox * combo_printer ;
wxBoxSizer * sizer_params ;
2018-10-04 14:43:10 +00:00
FreqChangedParams * frequently_changed_parameters ;
ObjectList * object_list ;
ObjectManipulation * object_manipulation ;
2018-11-09 17:39:07 +00:00
ObjectSettings * object_settings ;
2018-09-17 10:15:11 +00:00
ObjectInfo * object_info ;
SlicedInfo * sliced_info ;
wxButton * btn_export_gcode ;
wxButton * btn_reslice ;
wxButton * btn_send_gcode ;
2018-10-04 09:12:55 +00:00
priv ( Plater * plater ) : plater ( plater ) { }
2018-10-09 06:30:48 +00:00
2018-10-10 11:53:45 +00:00
void show_preset_comboboxes ( ) ;
2018-09-17 10:15:11 +00:00
} ;
2018-10-10 11:53:45 +00:00
void Sidebar : : priv : : show_preset_comboboxes ( )
{
2019-02-22 08:38:56 +00:00
const bool showSLA = wxGetApp ( ) . preset_bundle - > printers . get_edited_preset ( ) . printer_technology ( ) = = ptSLA ;
2018-10-10 11:53:45 +00:00
2018-11-15 15:22:25 +00:00
for ( size_t i = 0 ; i < 4 ; + + i )
sizer_presets - > Show ( i , ! showSLA ) ;
2018-10-10 11:53:45 +00:00
2018-11-16 16:36:23 +00:00
for ( size_t i = 4 ; i < 8 ; + + i ) {
2018-11-09 17:39:07 +00:00
if ( sizer_presets - > IsShown ( i ) ! = showSLA )
sizer_presets - > Show ( i , showSLA ) ;
}
2018-10-10 11:53:45 +00:00
2018-11-15 15:22:25 +00:00
frequently_changed_parameters - > Show ( ! showSLA ) ;
2018-10-10 11:53:45 +00:00
2018-11-15 10:15:24 +00:00
scrolled - > GetParent ( ) - > Layout ( ) ;
scrolled - > Refresh ( ) ;
2018-10-10 11:53:45 +00:00
}
2018-09-17 10:15:11 +00:00
// Sidebar / public
2018-10-04 09:12:55 +00:00
Sidebar : : Sidebar ( Plater * parent )
2019-04-13 21:46:52 +00:00
: wxPanel ( parent , wxID_ANY , wxDefaultPosition , wxSize ( 40 * wxGetApp ( ) . em_unit ( ) , - 1 ) ) , p ( new priv ( parent ) )
2018-09-17 10:15:11 +00:00
{
2019-04-13 21:46:52 +00:00
p - > scrolled = new wxScrolledWindow ( this , wxID_ANY /*, wxDefaultPosition, wxSize(40 * wxGetApp().em_unit(), -1)*/ ) ;
2018-12-18 12:22:22 +00:00
p - > scrolled - > SetScrollbars ( 0 , 20 , 1 , 2 ) ;
2018-11-09 17:39:07 +00:00
2019-03-12 10:39:16 +00:00
2018-11-09 17:39:07 +00:00
// Sizer in the scrolled area
auto * scrolled_sizer = new wxBoxSizer ( wxVERTICAL ) ;
p - > scrolled - > SetSizer ( scrolled_sizer ) ;
2018-09-17 10:15:11 +00:00
2019-01-10 10:05:58 +00:00
// Sizer with buttons for mode changing
2019-04-24 23:45:00 +00:00
p - > mode_sizer = new ModeSizer ( p - > scrolled , 2 * wxGetApp ( ) . em_unit ( ) ) ;
2019-01-10 10:05:58 +00:00
2018-09-17 10:15:11 +00:00
// The preset chooser
2019-02-07 13:44:05 +00:00
p - > sizer_presets = new wxFlexGridSizer ( 10 , 1 , 1 , 2 ) ;
p - > sizer_presets - > AddGrowableCol ( 0 , 1 ) ;
2018-10-10 11:53:45 +00:00
p - > sizer_presets - > SetFlexibleDirection ( wxBOTH ) ;
2019-03-13 12:13:18 +00:00
bool is_msw = false ;
# ifdef __WINDOWS__
p - > scrolled - > SetDoubleBuffered ( true ) ;
p - > presets_panel = new wxPanel ( p - > scrolled , wxID_ANY , wxDefaultPosition , wxDefaultSize , wxTAB_TRAVERSAL ) ;
p - > presets_panel - > SetSizer ( p - > sizer_presets ) ;
is_msw = true ;
# else
2019-03-13 12:37:36 +00:00
p - > presets_panel = p - > scrolled ;
2019-03-13 12:13:18 +00:00
# endif //__WINDOWS__
2018-09-17 10:15:11 +00:00
p - > sizer_filaments = new wxBoxSizer ( wxVERTICAL ) ;
auto init_combo = [ this ] ( PresetComboBox * * combo , wxString label , Preset : : Type preset_type , bool filament ) {
2019-03-13 12:13:18 +00:00
auto * text = new wxStaticText ( p - > presets_panel , wxID_ANY , label + " : " ) ;
2018-10-01 13:09:31 +00:00
text - > SetFont ( wxGetApp ( ) . small_font ( ) ) ;
2019-03-13 12:13:18 +00:00
* combo = new PresetComboBox ( p - > presets_panel , preset_type ) ;
2018-09-17 10:15:11 +00:00
2019-03-18 14:10:40 +00:00
auto combo_and_btn_sizer = new wxBoxSizer ( wxHORIZONTAL ) ;
combo_and_btn_sizer - > Add ( * combo , 1 , wxEXPAND ) ;
if ( ( * combo ) - > edit_btn )
combo_and_btn_sizer - > Add ( ( * combo ) - > edit_btn , 0 , wxLEFT | wxRIGHT , int ( 0.3 * wxGetApp ( ) . em_unit ( ) ) ) ;
2018-09-17 10:15:11 +00:00
auto * sizer_presets = this - > p - > sizer_presets ;
auto * sizer_filaments = this - > p - > sizer_filaments ;
2019-02-07 13:44:05 +00:00
sizer_presets - > Add ( text , 0 , wxALIGN_LEFT | wxEXPAND | wxRIGHT , 4 ) ;
2018-09-17 10:15:11 +00:00
if ( ! filament ) {
2019-03-18 14:10:40 +00:00
sizer_presets - > Add ( combo_and_btn_sizer , 0 , wxEXPAND | wxBOTTOM , 1 ) ;
2018-09-17 10:15:11 +00:00
} else {
2019-03-18 14:10:40 +00:00
sizer_filaments - > Add ( combo_and_btn_sizer , 0 , wxEXPAND | wxBOTTOM , 1 ) ;
2018-10-10 11:53:45 +00:00
( * combo ) - > set_extruder_idx ( 0 ) ;
2018-09-17 10:15:11 +00:00
sizer_presets - > Add ( sizer_filaments , 1 , wxEXPAND ) ;
}
} ;
p - > combos_filament . push_back ( nullptr ) ;
2018-11-16 16:36:23 +00:00
init_combo ( & p - > combo_print , _ ( L ( " Print settings " ) ) , Preset : : TYPE_PRINT , false ) ;
init_combo ( & p - > combos_filament [ 0 ] , _ ( L ( " Filament " ) ) , Preset : : TYPE_FILAMENT , true ) ;
init_combo ( & p - > combo_sla_print , _ ( L ( " SLA print " ) ) , Preset : : TYPE_SLA_PRINT , false ) ;
init_combo ( & p - > combo_sla_material , _ ( L ( " SLA material " ) ) , Preset : : TYPE_SLA_MATERIAL , false ) ;
init_combo ( & p - > combo_printer , _ ( L ( " Printer " ) ) , Preset : : TYPE_PRINTER , false ) ;
2018-09-17 10:15:11 +00:00
2019-02-07 13:44:05 +00:00
const int margin_5 = int ( 0.5 * wxGetApp ( ) . em_unit ( ) ) ; // 5;
2019-04-13 21:46:52 +00:00
const int margin_10 = 10 ; //int(1.5*wxGetApp().em_unit());// 15;
2018-10-01 13:09:31 +00:00
2018-09-17 10:15:11 +00:00
p - > sizer_params = new wxBoxSizer ( wxVERTICAL ) ;
2018-10-04 14:43:10 +00:00
// Frequently changed parameters
2019-02-07 13:44:05 +00:00
p - > frequently_changed_parameters = new FreqChangedParams ( p - > scrolled , 0 /*label_width*/ ) ;
p - > sizer_params - > Add ( p - > frequently_changed_parameters - > get_sizer ( ) , 0 , wxEXPAND | wxTOP | wxBOTTOM , margin_10 ) ;
2018-10-03 13:14:52 +00:00
// Object List
2018-10-04 14:43:10 +00:00
p - > object_list = new ObjectList ( p - > scrolled ) ;
2019-02-07 13:44:05 +00:00
p - > sizer_params - > Add ( p - > object_list - > get_sizer ( ) , 1 , wxEXPAND ) ;
2018-10-04 14:43:10 +00:00
2018-11-09 17:39:07 +00:00
// Object Manipulations
2018-10-04 14:43:10 +00:00
p - > object_manipulation = new ObjectManipulation ( p - > scrolled ) ;
2018-11-09 17:39:07 +00:00
p - > object_manipulation - > Hide ( ) ;
2019-02-07 13:44:05 +00:00
p - > sizer_params - > Add ( p - > object_manipulation - > get_sizer ( ) , 0 , wxEXPAND | wxTOP , margin_5 ) ;
2018-09-17 10:15:11 +00:00
2018-11-09 17:39:07 +00:00
// Frequently Object Settings
p - > object_settings = new ObjectSettings ( p - > scrolled ) ;
p - > object_settings - > Hide ( ) ;
2019-02-07 13:44:05 +00:00
p - > sizer_params - > Add ( p - > object_settings - > get_sizer ( ) , 0 , wxEXPAND | wxTOP , margin_5 ) ;
2018-11-09 17:39:07 +00:00
2018-09-17 10:15:11 +00:00
// Info boxes
2018-10-01 13:09:31 +00:00
p - > object_info = new ObjectInfo ( p - > scrolled ) ;
p - > sliced_info = new SlicedInfo ( p - > scrolled ) ;
2018-09-17 10:15:11 +00:00
// Sizer in the scrolled area
2019-02-07 13:44:05 +00:00
scrolled_sizer - > Add ( p - > mode_sizer , 0 , wxALIGN_CENTER_HORIZONTAL /*RIGHT | wxBOTTOM | wxRIGHT, 5*/ ) ;
2019-03-13 12:13:18 +00:00
is_msw ?
scrolled_sizer - > Add ( p - > presets_panel , 0 , wxEXPAND | wxLEFT , margin_5 ) :
scrolled_sizer - > Add ( p - > sizer_presets , 0 , wxEXPAND | wxLEFT , margin_5 ) ;
2019-02-07 13:44:05 +00:00
scrolled_sizer - > Add ( p - > sizer_params , 1 , wxEXPAND | wxLEFT , margin_5 ) ;
scrolled_sizer - > Add ( p - > object_info , 0 , wxEXPAND | wxTOP | wxLEFT , margin_5 ) ;
scrolled_sizer - > Add ( p - > sliced_info , 0 , wxEXPAND | wxTOP | wxLEFT , margin_5 ) ;
2018-09-17 10:15:11 +00:00
// Buttons underneath the scrolled area
2019-04-13 21:46:52 +00:00
auto init_btn = [ this ] ( wxButton * * btn , wxString label ) {
2019-04-16 12:06:09 +00:00
* btn = new wxButton ( this , wxID_ANY , label , wxDefaultPosition ,
2019-05-03 11:09:42 +00:00
wxDefaultSize , wxBU_EXACTFIT ) ;
2019-04-13 21:46:52 +00:00
( * btn ) - > SetFont ( wxGetApp ( ) . bold_font ( ) ) ;
} ;
init_btn ( & p - > btn_send_gcode , _ ( L ( " Send to printer " ) ) ) ;
p - > btn_send_gcode - > Hide ( ) ;
init_btn ( & p - > btn_export_gcode , _ ( L ( " Export G-code " ) ) + dots ) ;
init_btn ( & p - > btn_reslice , _ ( L ( " Slice now " ) ) ) ;
2018-12-04 09:28:05 +00:00
enable_buttons ( false ) ;
2018-09-17 10:15:11 +00:00
auto * btns_sizer = new wxBoxSizer ( wxVERTICAL ) ;
2019-02-07 13:44:05 +00:00
btns_sizer - > Add ( p - > btn_reslice , 0 , wxEXPAND | wxTOP , margin_5 ) ;
btns_sizer - > Add ( p - > btn_send_gcode , 0 , wxEXPAND | wxTOP , margin_5 ) ;
btns_sizer - > Add ( p - > btn_export_gcode , 0 , wxEXPAND | wxTOP , margin_5 ) ;
2018-09-17 10:15:11 +00:00
auto * sizer = new wxBoxSizer ( wxVERTICAL ) ;
2019-02-11 14:36:05 +00:00
sizer - > Add ( p - > scrolled , 1 , wxEXPAND ) ;
2019-02-07 13:44:05 +00:00
sizer - > Add ( btns_sizer , 0 , wxEXPAND | wxLEFT , margin_5 ) ;
2018-09-17 10:15:11 +00:00
SetSizer ( sizer ) ;
2018-10-04 09:12:55 +00:00
// Events
p - > btn_export_gcode - > Bind ( wxEVT_BUTTON , [ this ] ( wxCommandEvent & ) { p - > plater - > export_gcode ( ) ; } ) ;
2019-03-01 11:03:14 +00:00
p - > btn_reslice - > Bind ( wxEVT_BUTTON , [ this ] ( wxCommandEvent & )
{
const bool export_gcode_after_slicing = wxGetKeyState ( WXK_SHIFT ) ;
if ( export_gcode_after_slicing )
p - > plater - > export_gcode ( ) ;
2019-03-12 08:41:57 +00:00
else
p - > plater - > reslice ( ) ;
2019-04-09 15:15:14 +00:00
p - > plater - > select_view_3D ( " Preview " ) ;
2019-03-01 11:03:14 +00:00
} ) ;
2018-10-04 09:12:55 +00:00
p - > btn_send_gcode - > Bind ( wxEVT_BUTTON , [ this ] ( wxCommandEvent & ) { p - > plater - > send_gcode ( ) ; } ) ;
2018-09-17 10:15:11 +00:00
}
Sidebar : : ~ Sidebar ( ) { }
2018-10-10 11:53:45 +00:00
void Sidebar : : init_filament_combo ( PresetComboBox * * combo , const int extr_idx ) {
2019-03-13 12:13:18 +00:00
* combo = new PresetComboBox ( p - > presets_panel , Slic3r : : Preset : : TYPE_FILAMENT ) ;
2018-10-10 11:53:45 +00:00
// # copy icons from first choice
// $choice->SetItemBitmap($_, $choices->[0]->GetItemBitmap($_)) for 0..$#presets;
( * combo ) - > set_extruder_idx ( extr_idx ) ;
2019-03-18 14:10:40 +00:00
auto combo_and_btn_sizer = new wxBoxSizer ( wxHORIZONTAL ) ;
combo_and_btn_sizer - > Add ( * combo , 1 , wxEXPAND ) ;
combo_and_btn_sizer - > Add ( ( * combo ) - > edit_btn , 0 , wxLEFT | wxRIGHT , int ( 0.3 * wxGetApp ( ) . em_unit ( ) ) ) ;
2018-10-10 11:53:45 +00:00
auto /***/ sizer_filaments = this - > p - > sizer_filaments ;
2019-03-18 14:10:40 +00:00
sizer_filaments - > Add ( combo_and_btn_sizer , 1 , wxEXPAND | wxBOTTOM , 1 ) ;
2018-10-10 11:53:45 +00:00
}
void Sidebar : : remove_unused_filament_combos ( const int current_extruder_count )
{
if ( current_extruder_count > = p - > combos_filament . size ( ) )
return ;
auto sizer_filaments = this - > p - > sizer_filaments ;
while ( p - > combos_filament . size ( ) > current_extruder_count ) {
const int last = p - > combos_filament . size ( ) - 1 ;
sizer_filaments - > Remove ( last ) ;
( * p - > combos_filament [ last ] ) . Destroy ( ) ;
p - > combos_filament . pop_back ( ) ;
}
}
2019-04-10 07:56:32 +00:00
void Sidebar : : update_all_preset_comboboxes ( )
{
PresetBundle & preset_bundle = * wxGetApp ( ) . preset_bundle ;
const auto print_tech = preset_bundle . printers . get_edited_preset ( ) . printer_technology ( ) ;
// Update the print choosers to only contain the compatible presets, update the dirty flags.
if ( print_tech = = ptFFF )
preset_bundle . prints . update_platter_ui ( p - > combo_print ) ;
else {
preset_bundle . sla_prints . update_platter_ui ( p - > combo_sla_print ) ;
preset_bundle . sla_materials . update_platter_ui ( p - > combo_sla_material ) ;
}
// Update the printer choosers, update the dirty flags.
preset_bundle . printers . update_platter_ui ( p - > combo_printer ) ;
// Update the filament choosers to only contain the compatible presets, update the color preview,
// update the dirty flags.
if ( print_tech = = ptFFF ) {
for ( size_t i = 0 ; i < p - > combos_filament . size ( ) ; + + i )
2019-04-23 14:33:06 +00:00
preset_bundle . update_platter_filament_ui ( i , p - > combos_filament [ i ] ) ;
2019-04-10 07:56:32 +00:00
}
}
2018-09-17 10:15:11 +00:00
void Sidebar : : update_presets ( Preset : : Type preset_type )
{
2018-10-31 15:22:36 +00:00
PresetBundle & preset_bundle = * wxGetApp ( ) . preset_bundle ;
2019-02-22 08:38:56 +00:00
const auto print_tech = preset_bundle . printers . get_edited_preset ( ) . printer_technology ( ) ;
2018-10-31 15:22:36 +00:00
2018-09-17 10:15:11 +00:00
switch ( preset_type ) {
2019-01-15 14:54:20 +00:00
case Preset : : TYPE_FILAMENT :
{
2019-02-22 08:38:56 +00:00
const int extruder_cnt = print_tech ! = ptFFF ? 1 :
2019-01-15 14:54:20 +00:00
dynamic_cast < ConfigOptionFloats * > ( preset_bundle . printers . get_edited_preset ( ) . config . option ( " nozzle_diameter " ) ) - > values . size ( ) ;
const int filament_cnt = p - > combos_filament . size ( ) > extruder_cnt ? extruder_cnt : p - > combos_filament . size ( ) ;
if ( filament_cnt = = 1 ) {
2018-09-17 10:15:11 +00:00
// Single filament printer, synchronize the filament presets.
2019-01-15 14:54:20 +00:00
const std : : string & name = preset_bundle . filaments . get_selected_preset ( ) . name ;
preset_bundle . set_filament_preset ( 0 , name ) ;
2018-09-17 10:15:11 +00:00
}
2019-01-15 14:54:20 +00:00
for ( size_t i = 0 ; i < filament_cnt ; i + + ) {
2019-04-23 14:33:06 +00:00
preset_bundle . update_platter_filament_ui ( i , p - > combos_filament [ i ] ) ;
2018-09-17 10:15:11 +00:00
}
2018-10-03 14:27:02 +00:00
2018-09-17 10:15:11 +00:00
break ;
2019-01-15 14:54:20 +00:00
}
2018-09-17 10:15:11 +00:00
case Preset : : TYPE_PRINT :
2018-10-31 15:22:36 +00:00
preset_bundle . prints . update_platter_ui ( p - > combo_print ) ;
2018-09-17 10:15:11 +00:00
break ;
2018-11-16 16:36:23 +00:00
case Preset : : TYPE_SLA_PRINT :
preset_bundle . sla_prints . update_platter_ui ( p - > combo_sla_print ) ;
break ;
2018-09-17 10:15:11 +00:00
case Preset : : TYPE_SLA_MATERIAL :
2018-10-31 15:22:36 +00:00
preset_bundle . sla_materials . update_platter_ui ( p - > combo_sla_material ) ;
2018-09-17 10:15:11 +00:00
break ;
2018-10-31 15:22:36 +00:00
case Preset : : TYPE_PRINTER :
{
2019-04-10 07:56:32 +00:00
update_all_preset_comboboxes ( ) ;
2018-10-31 15:22:36 +00:00
p - > show_preset_comboboxes ( ) ;
break ;
}
2018-09-17 10:15:11 +00:00
default : break ;
}
// Synchronize config.ini with the current selections.
2018-10-03 14:27:02 +00:00
wxGetApp ( ) . preset_bundle - > export_selections ( * wxGetApp ( ) . app_config ) ;
2018-09-17 10:15:11 +00:00
}
2019-03-01 11:03:14 +00:00
void Sidebar : : update_mode_sizer ( ) const
2019-01-10 10:05:58 +00:00
{
2019-03-01 11:03:14 +00:00
p - > mode_sizer - > SetMode ( m_mode ) ;
}
void Sidebar : : update_reslice_btn_tooltip ( ) const
2019-01-10 10:05:58 +00:00
{
2019-03-26 13:00:53 +00:00
wxString tooltip = wxString ( " Slice " ) + " [ " + GUI : : shortkey_ctrl_prefix ( ) + " R] " ;
if ( m_mode ! = comSimple )
tooltip + = wxString ( " \n " ) + _ ( L ( " Hold Shift to Slice & Export G-code " ) ) ;
2019-03-01 11:03:14 +00:00
p - > btn_reslice - > SetToolTip ( tooltip ) ;
2019-01-10 10:05:58 +00:00
}
2019-04-24 23:45:00 +00:00
void Sidebar : : msw_rescale ( )
2019-04-13 21:46:52 +00:00
{
SetMinSize ( wxSize ( 40 * wxGetApp ( ) . em_unit ( ) , - 1 ) ) ;
2019-04-24 23:45:00 +00:00
p - > mode_sizer - > msw_rescale ( ) ;
2019-04-13 21:46:52 +00:00
2019-04-23 14:33:06 +00:00
// Rescale preset comboboxes in respect to the current em_unit ...
2019-04-13 21:46:52 +00:00
for ( PresetComboBox * combo : std : : vector < PresetComboBox * > { p - > combo_print ,
p - > combo_sla_print ,
p - > combo_sla_material ,
p - > combo_printer } )
2019-04-24 23:45:00 +00:00
combo - > msw_rescale ( ) ;
2019-04-13 21:46:52 +00:00
for ( PresetComboBox * combo : p - > combos_filament )
2019-04-24 23:45:00 +00:00
combo - > msw_rescale ( ) ;
2019-04-13 21:46:52 +00:00
2019-04-23 14:33:06 +00:00
// ... then refill them and set min size to correct layout of the sidebar
update_all_preset_comboboxes ( ) ;
2019-04-24 23:45:00 +00:00
p - > frequently_changed_parameters - > get_og ( true ) - > msw_rescale ( ) ;
p - > frequently_changed_parameters - > get_og ( false ) - > msw_rescale ( ) ;
2019-04-13 21:46:52 +00:00
2019-04-24 23:45:00 +00:00
p - > object_list - > msw_rescale ( ) ;
2019-04-29 13:27:59 +00:00
p - > object_manipulation - > msw_rescale ( ) ;
2019-04-24 23:45:00 +00:00
p - > object_settings - > msw_rescale ( ) ;
2019-04-13 21:46:52 +00:00
2019-04-24 23:45:00 +00:00
p - > object_info - > msw_rescale ( ) ;
2019-04-13 21:46:52 +00:00
p - > scrolled - > Layout ( ) ;
}
2018-10-04 14:43:10 +00:00
ObjectManipulation * Sidebar : : obj_manipul ( )
{
return p - > object_manipulation ;
}
2018-10-05 21:29:15 +00:00
ObjectList * Sidebar : : obj_list ( )
2018-10-03 13:14:52 +00:00
{
2018-10-05 21:29:15 +00:00
return p - > object_list ;
2018-10-03 13:14:52 +00:00
}
2018-11-09 17:39:07 +00:00
ObjectSettings * Sidebar : : obj_settings ( )
{
return p - > object_settings ;
}
wxScrolledWindow * Sidebar : : scrolled_panel ( )
{
return p - > scrolled ;
}
2019-03-13 12:13:18 +00:00
wxPanel * Sidebar : : presets_panel ( )
{
return p - > presets_panel ;
}
2019-01-15 08:31:53 +00:00
ConfigOptionsGroup * Sidebar : : og_freq_chng_params ( const bool is_fff )
2018-10-05 21:29:15 +00:00
{
2019-01-15 08:31:53 +00:00
return p - > frequently_changed_parameters - > get_og ( is_fff ) ;
2018-10-03 13:14:52 +00:00
}
wxButton * Sidebar : : get_wiping_dialog_button ( )
{
2018-10-04 14:43:10 +00:00
return p - > frequently_changed_parameters - > get_wiping_dialog_button ( ) ;
}
void Sidebar : : update_objects_list_extruder_column ( int extruders_count )
{
p - > object_list - > update_objects_list_extruder_column ( extruders_count ) ;
}
2018-11-13 11:19:56 +00:00
void Sidebar : : show_info_sizer ( )
2018-10-05 21:29:15 +00:00
{
2018-11-13 11:19:56 +00:00
if ( ! p - > plater - > is_single_full_object_selection ( ) | |
2019-01-10 10:05:58 +00:00
m_mode < comExpert | |
2018-11-14 15:24:36 +00:00
p - > plater - > model ( ) . objects . empty ( ) ) {
2018-11-01 11:33:56 +00:00
p - > object_info - > Show ( false ) ;
return ;
}
2018-11-09 17:39:07 +00:00
int obj_idx = p - > plater - > get_selected_object_idx ( ) ;
2018-11-14 15:24:36 +00:00
const ModelObject * model_object = p - > plater - > model ( ) . objects [ obj_idx ] ;
2018-11-13 14:24:05 +00:00
// hack to avoid crash when deleting the last object on the bed
if ( model_object - > volumes . empty ( ) )
{
p - > object_info - > Show ( false ) ;
return ;
}
2018-11-01 11:33:56 +00:00
const ModelInstance * model_instance = ! model_object - > instances . empty ( ) ? model_object - > instances . front ( ) : nullptr ;
2018-11-01 13:02:38 +00:00
2018-11-15 10:15:24 +00:00
auto size = model_object - > bounding_box ( ) . size ( ) ;
2018-11-01 11:33:56 +00:00
p - > object_info - > info_size - > SetLabel ( wxString : : Format ( " %.2f x %.2f x %.2f " , size ( 0 ) , size ( 1 ) , size ( 2 ) ) ) ;
p - > object_info - > info_materials - > SetLabel ( wxString : : Format ( " %d " , static_cast < int > ( model_object - > materials_count ( ) ) ) ) ;
2019-04-24 14:04:47 +00:00
const auto & stats = model_object - > get_object_stl_stats ( ) ; //model_object->volumes.front()->mesh.stl.stats;
2019-03-04 14:29:07 +00:00
p - > object_info - > info_volume - > SetLabel ( wxString : : Format ( " %.2f " , stats . volume ) ) ;
2018-11-01 11:33:56 +00:00
p - > object_info - > info_facets - > SetLabel ( wxString : : Format ( _ ( L ( " %d (%d shells) " ) ) , static_cast < int > ( model_object - > facets_count ( ) ) , stats . number_of_parts ) ) ;
int errors = stats . degenerate_facets + stats . edges_fixed + stats . facets_removed +
stats . facets_added + stats . facets_reversed + stats . backwards_edges ;
if ( errors > 0 ) {
wxString tooltip = wxString : : Format ( _ ( L ( " Auto-repaired (%d errors) " ) ) , errors ) ;
p - > object_info - > info_manifold - > SetLabel ( tooltip ) ;
2019-01-21 11:34:28 +00:00
tooltip + = " : \n " + wxString : : Format ( _ ( L ( " %d degenerate facets, %d edges fixed, %d facets removed, "
2018-11-01 11:33:56 +00:00
" %d facets added, %d facets reversed, %d backwards edges " ) ) ,
stats . degenerate_facets , stats . edges_fixed , stats . facets_removed ,
stats . facets_added , stats . facets_reversed , stats . backwards_edges ) ;
p - > object_info - > showing_manifold_warning_icon = true ;
p - > object_info - > info_manifold - > SetToolTip ( tooltip ) ;
p - > object_info - > manifold_warning_icon - > SetToolTip ( tooltip ) ;
}
else {
2019-05-04 00:07:07 +00:00
p - > object_info - > info_manifold - > SetLabel ( _ ( L ( " Yes " ) ) ) ;
2018-11-01 11:33:56 +00:00
p - > object_info - > showing_manifold_warning_icon = false ;
p - > object_info - > info_manifold - > SetToolTip ( " " ) ;
p - > object_info - > manifold_warning_icon - > SetToolTip ( " " ) ;
}
p - > object_info - > show_sizer ( true ) ;
2019-02-19 11:14:13 +00:00
if ( p - > plater - > printer_technology ( ) = = ptSLA ) {
2019-02-21 14:46:04 +00:00
for ( auto item : p - > object_info - > sla_hidden_items )
2019-02-19 11:14:13 +00:00
item - > Show ( false ) ;
}
2018-10-31 11:26:57 +00:00
}
void Sidebar : : show_sliced_info_sizer ( const bool show )
{
2018-11-13 11:19:56 +00:00
wxWindowUpdateLocker freeze_guard ( this ) ;
2018-11-01 11:33:56 +00:00
2018-10-31 11:26:57 +00:00
p - > sliced_info - > Show ( show ) ;
if ( show ) {
2019-02-12 15:34:42 +00:00
if ( p - > plater - > printer_technology ( ) = = ptSLA )
{
const SLAPrintStatistics & ps = p - > plater - > sla_print ( ) . print_statistics ( ) ;
2019-02-18 11:28:58 +00:00
wxString new_label = _ ( L ( " Used Material (ml) " ) ) + " : " ;
2019-02-13 14:35:41 +00:00
const bool is_supports = ps . support_used_material > 0.0 ;
if ( is_supports )
new_label + = wxString : : Format ( " \n - %s \n - %s " , _ ( L ( " object(s) " ) ) , _ ( L ( " supports and pad " ) ) ) ;
wxString info_text = is_supports ?
2019-02-18 11:28:58 +00:00
wxString : : Format ( " %.2f \n %.2f \n %.2f " , ( ps . objects_used_material + ps . support_used_material ) / 1000 ,
ps . objects_used_material / 1000 ,
ps . support_used_material / 1000 ) :
2019-02-18 12:18:47 +00:00
wxString : : Format ( " %.2f " , ( ps . objects_used_material + ps . support_used_material ) / 1000 ) ;
2019-02-13 14:35:41 +00:00
p - > sliced_info - > SetTextAndShow ( siMateril_unit , info_text , new_label ) ;
p - > sliced_info - > SetTextAndShow ( siCost , " N/A " /*wxString::Format("%.2f", ps.total_cost)*/ ) ;
2019-02-12 15:34:42 +00:00
p - > sliced_info - > SetTextAndShow ( siEstimatedTime , ps . estimated_print_time , _ ( L ( " Estimated printing time " ) ) + " : " ) ;
// Hide non-SLA sliced info parameters
p - > sliced_info - > SetTextAndShow ( siFilament_m , " N/A " ) ;
p - > sliced_info - > SetTextAndShow ( siFilament_mm3 , " N/A " ) ;
p - > sliced_info - > SetTextAndShow ( siFilament_g , " N/A " ) ;
p - > sliced_info - > SetTextAndShow ( siWTNumbetOfToolchanges , " N/A " ) ;
}
else
{
2019-02-21 14:46:04 +00:00
const PrintStatistics & ps = p - > plater - > fff_print ( ) . print_statistics ( ) ;
const bool is_wipe_tower = ps . total_wipe_tower_filament > 0 ;
wxString new_label = _ ( L ( " Used Filament (m) " ) ) ;
if ( is_wipe_tower )
new_label + = wxString : : Format ( " : \n - %s \n - %s " , _ ( L ( " objects " ) ) , _ ( L ( " wipe tower " ) ) ) ;
wxString info_text = is_wipe_tower ?
wxString : : Format ( " %.2f \n %.2f \n %.2f " , ps . total_used_filament / 1000 ,
( ps . total_used_filament - ps . total_wipe_tower_filament ) / 1000 ,
ps . total_wipe_tower_filament / 1000 ) :
wxString : : Format ( " %.2f " , ps . total_used_filament / 1000 ) ;
p - > sliced_info - > SetTextAndShow ( siFilament_m , info_text , new_label ) ;
p - > sliced_info - > SetTextAndShow ( siFilament_mm3 , wxString : : Format ( " %.2f " , ps . total_extruded_volume ) ) ;
p - > sliced_info - > SetTextAndShow ( siFilament_g , wxString : : Format ( " %.2f " , ps . total_weight ) ) ;
new_label = _ ( L ( " Cost " ) ) ;
if ( is_wipe_tower )
new_label + = wxString : : Format ( " : \n - %s \n - %s " , _ ( L ( " objects " ) ) , _ ( L ( " wipe tower " ) ) ) ;
info_text = is_wipe_tower ?
wxString : : Format ( " %.2f \n %.2f \n %.2f " , ps . total_cost ,
( ps . total_cost - ps . total_wipe_tower_cost ) ,
ps . total_wipe_tower_cost ) :
wxString : : Format ( " %.2f " , ps . total_cost ) ;
p - > sliced_info - > SetTextAndShow ( siCost , info_text , new_label ) ;
if ( ps . estimated_normal_print_time = = " N/A " & & ps . estimated_silent_print_time = = " N/A " )
p - > sliced_info - > SetTextAndShow ( siEstimatedTime , " N/A " ) ;
else {
new_label = _ ( L ( " Estimated printing time " ) ) + " : " ;
info_text = " " ;
if ( ps . estimated_normal_print_time ! = " N/A " ) {
new_label + = wxString : : Format ( " \n - %s " , _ ( L ( " normal mode " ) ) ) ;
info_text + = wxString : : Format ( " \n %s " , ps . estimated_normal_print_time ) ;
}
if ( ps . estimated_silent_print_time ! = " N/A " ) {
new_label + = wxString : : Format ( " \n - %s " , _ ( L ( " silent mode " ) ) ) ;
info_text + = wxString : : Format ( " \n %s " , ps . estimated_silent_print_time ) ;
}
p - > sliced_info - > SetTextAndShow ( siEstimatedTime , info_text , new_label ) ;
2018-11-20 09:33:54 +00:00
}
2018-10-31 11:26:57 +00:00
2019-02-21 14:46:04 +00:00
// if there is a wipe tower, insert number of toolchanges info into the array:
p - > sliced_info - > SetTextAndShow ( siWTNumbetOfToolchanges , is_wipe_tower ? wxString : : Format ( " %.d " , p - > plater - > fff_print ( ) . wipe_tower_data ( ) . number_of_toolchanges ) : " N/A " ) ;
2019-02-12 15:34:42 +00:00
2019-02-21 14:46:04 +00:00
// Hide non-FFF sliced info parameters
p - > sliced_info - > SetTextAndShow ( siMateril_unit , " N/A " ) ;
2019-02-12 15:34:42 +00:00
}
2018-10-31 11:26:57 +00:00
}
2018-11-13 11:19:56 +00:00
Layout ( ) ;
2018-11-15 10:15:24 +00:00
p - > scrolled - > Refresh ( ) ;
2018-10-05 21:29:15 +00:00
}
2018-10-08 17:14:55 +00:00
void Sidebar : : enable_buttons ( bool enable )
{
p - > btn_reslice - > Enable ( enable ) ;
p - > btn_export_gcode - > Enable ( enable ) ;
p - > btn_send_gcode - > Enable ( enable ) ;
}
2019-03-01 10:00:34 +00:00
void Sidebar : : show_reslice ( bool show ) const { p - > btn_reslice - > Show ( show ) ; }
void Sidebar : : show_export ( bool show ) const { p - > btn_export_gcode - > Show ( show ) ; }
void Sidebar : : show_send ( bool show ) const { p - > btn_send_gcode - > Show ( show ) ; }
2018-10-15 08:53:47 +00:00
2018-10-09 10:41:05 +00:00
bool Sidebar : : is_multifilament ( )
{
2018-11-01 14:58:14 +00:00
return p - > combos_filament . size ( ) > 1 ;
2018-10-09 10:41:05 +00:00
}
2018-10-10 11:53:45 +00:00
2019-03-01 11:03:14 +00:00
void Sidebar : : update_mode ( )
{
m_mode = wxGetApp ( ) . get_mode ( ) ;
update_reslice_btn_tooltip ( ) ;
update_mode_sizer ( ) ;
wxWindowUpdateLocker noUpdates ( this ) ;
p - > object_list - > get_sizer ( ) - > Show ( m_mode > comSimple ) ;
p - > object_list - > unselect_objects ( ) ;
p - > object_list - > update_selections ( ) ;
p - > object_list - > update_object_menu ( ) ;
Layout ( ) ;
}
2018-10-10 11:53:45 +00:00
std : : vector < PresetComboBox * > & Sidebar : : combos_filament ( )
{
return p - > combos_filament ;
}
2018-09-17 10:15:11 +00:00
// Plater::DropTarget
class PlaterDropTarget : public wxFileDropTarget
{
public :
2019-02-01 07:53:29 +00:00
PlaterDropTarget ( Plater * plater ) : plater ( plater ) { this - > SetDefaultAction ( wxDragCopy ) ; }
2018-09-17 10:15:11 +00:00
virtual bool OnDropFiles ( wxCoord x , wxCoord y , const wxArrayString & filenames ) ;
private :
Plater * plater ;
2018-10-08 17:14:55 +00:00
static const std : : regex pattern_drop ;
2018-09-17 10:15:11 +00:00
} ;
2018-10-22 09:52:13 +00:00
const std : : regex PlaterDropTarget : : pattern_drop ( " .*[.](stl|obj|amf|3mf|prusa) " , std : : regex : : icase ) ;
2018-10-08 17:14:55 +00:00
2018-09-17 10:15:11 +00:00
bool PlaterDropTarget : : OnDropFiles ( wxCoord x , wxCoord y , const wxArrayString & filenames )
{
2018-10-08 17:14:55 +00:00
std : : vector < fs : : path > paths ;
for ( const auto & filename : filenames ) {
2019-01-02 14:11:05 +00:00
fs : : path path ( into_path ( filename ) ) ;
2018-10-08 17:14:55 +00:00
if ( std : : regex_match ( path . string ( ) , pattern_drop ) ) {
paths . push_back ( std : : move ( path ) ) ;
} else {
return false ;
}
}
plater - > load_files ( paths ) ;
return true ;
2018-09-17 10:15:11 +00:00
}
// Plater / private
struct Plater : : priv
{
// PIMPL back pointer ("Q-Pointer")
Plater * q ;
MainFrame * main_frame ;
2018-10-17 10:17:25 +00:00
// Object popup menu
2019-04-24 23:45:00 +00:00
MenuWithSeparators object_menu ;
2018-12-07 16:50:48 +00:00
// Part popup menu
2019-04-24 23:45:00 +00:00
MenuWithSeparators part_menu ;
2018-12-07 16:50:48 +00:00
// SLA-Object popup menu
2019-04-24 23:45:00 +00:00
MenuWithSeparators sla_object_menu ;
2019-01-25 09:34:32 +00:00
2019-03-19 08:51:50 +00:00
// Removed/Prepended Items according to the view mode
std : : vector < wxMenuItem * > items_increase ;
std : : vector < wxMenuItem * > items_decrease ;
std : : vector < wxMenuItem * > items_set_number_of_copies ;
enum MenuIdentifier {
miObjectFFF = 0 ,
miObjectSLA
} ;
2018-09-17 10:15:11 +00:00
// Data
2018-12-05 14:22:03 +00:00
Slic3r : : DynamicPrintConfig * config ; // FIXME: leak?
2018-12-03 12:14:28 +00:00
Slic3r : : Print fff_print ;
2018-11-13 16:45:44 +00:00
Slic3r : : SLAPrint sla_print ;
Slic3r : : Model model ;
PrinterTechnology printer_technology = ptFFF ;
Slic3r : : GCodePreviewData gcode_preview_data ;
2018-09-17 10:15:11 +00:00
// GUI elements
2019-03-05 09:54:03 +00:00
wxSizer * panel_sizer { nullptr } ;
wxPanel * current_panel { nullptr } ;
2018-12-04 12:55:25 +00:00
std : : vector < wxPanel * > panels ;
2018-09-17 10:15:11 +00:00
Sidebar * sidebar ;
2019-02-19 14:15:27 +00:00
Bed3D bed ;
2019-03-06 14:46:19 +00:00
Camera camera ;
2018-12-04 12:55:25 +00:00
View3D * view3D ;
2018-12-17 09:55:14 +00:00
GLToolbar view_toolbar ;
2018-10-04 14:43:10 +00:00
Preview * preview ;
2018-11-15 14:27:39 +00:00
wxString project_filename ;
2018-10-17 09:12:38 +00:00
BackgroundSlicingProcess background_process ;
2019-04-17 12:56:00 +00:00
bool arranging ;
bool rotoptimizing ;
2018-11-23 11:47:32 +00:00
bool delayed_scene_refresh ;
2019-02-19 13:57:59 +00:00
std : : string delayed_error_message ;
2018-11-08 15:01:21 +00:00
2018-10-17 09:12:38 +00:00
wxTimer background_process_timer ;
2018-09-17 10:15:11 +00:00
2019-03-01 10:00:34 +00:00
std : : string label_btn_export ;
2019-03-12 08:41:57 +00:00
std : : string label_btn_send ;
2019-03-01 10:00:34 +00:00
2018-09-17 10:15:11 +00:00
static const std : : regex pattern_bundle ;
static const std : : regex pattern_3mf ;
static const std : : regex pattern_zip_amf ;
2019-01-03 11:04:14 +00:00
static const std : : regex pattern_any_amf ;
2019-01-18 15:01:43 +00:00
# if ENABLE_VOLUMES_CENTERING_FIXES
static const std : : regex pattern_prusa ;
# endif // ENABLE_VOLUMES_CENTERING_FIXES
2018-09-17 10:15:11 +00:00
priv ( Plater * q , MainFrame * main_frame ) ;
2018-11-21 12:52:46 +00:00
void update ( bool force_full_scene_refresh = false ) ;
2018-10-17 10:59:58 +00:00
void select_view ( const std : : string & direction ) ;
2018-12-04 12:55:25 +00:00
void select_view_3D ( const std : : string & name ) ;
2018-12-21 09:43:22 +00:00
void select_next_view_3D ( ) ;
2019-03-27 13:16:38 +00:00
void reset_all_gizmos ( ) ;
2018-09-17 10:15:11 +00:00
void update_ui_from_settings ( ) ;
ProgressStatusBar * statusbar ( ) ;
2018-10-01 14:48:08 +00:00
std : : string get_config ( const std : : string & key ) const ;
2018-10-03 14:18:23 +00:00
BoundingBoxf bed_shape_bb ( ) const ;
BoundingBox scaled_bed_shape_bb ( ) const ;
2018-11-16 08:26:41 +00:00
std : : vector < size_t > load_files ( const std : : vector < fs : : path > & input_files , bool load_model , bool load_config ) ;
2018-10-01 14:48:08 +00:00
std : : vector < size_t > load_model_objects ( const ModelObjectPtrs & model_objects ) ;
2019-04-04 09:31:26 +00:00
wxString get_export_file ( GUI : : FileType file_type ) ;
2018-10-04 09:12:55 +00:00
2019-03-19 12:30:21 +00:00
const Selection & get_selection ( ) const ;
Selection & get_selection ( ) ;
2018-10-17 07:30:07 +00:00
int get_selected_object_idx ( ) const ;
2018-12-06 13:49:14 +00:00
int get_selected_volume_idx ( ) const ;
2018-10-04 09:12:55 +00:00
void selection_changed ( ) ;
2018-10-08 17:14:55 +00:00
void object_list_changed ( ) ;
2018-10-04 09:12:55 +00:00
2018-11-21 14:28:35 +00:00
void select_all ( ) ;
2018-10-08 17:14:55 +00:00
void remove ( size_t obj_idx ) ;
2018-11-13 13:17:35 +00:00
void delete_object_from_model ( size_t obj_idx ) ;
2018-10-04 09:12:55 +00:00
void reset ( ) ;
2018-10-18 13:09:41 +00:00
void mirror ( Axis axis ) ;
2018-10-09 07:35:19 +00:00
void arrange ( ) ;
2018-11-22 15:04:21 +00:00
void sla_optimize_rotation ( ) ;
2018-10-09 07:35:19 +00:00
void split_object ( ) ;
2018-10-24 10:55:38 +00:00
void split_volume ( ) ;
2018-12-03 12:14:28 +00:00
bool background_processing_enabled ( ) const { return this - > get_config ( " background_processing " ) = = " 1 " ; }
void update_print_volume_state ( ) ;
2018-10-09 07:35:19 +00:00
void schedule_background_process ( ) ;
2018-11-13 16:45:44 +00:00
// Update background processing thread from the current config and Model.
enum UpdateBackgroundProcessReturnState {
// update_background_process() reports, that the Print / SLAPrint was updated in a way,
// that the background process was invalidated and it needs to be re-run.
UPDATE_BACKGROUND_PROCESS_RESTART = 1 ,
// update_background_process() reports, that the Print / SLAPrint was updated in a way,
2018-11-23 11:47:32 +00:00
// that a scene needs to be refreshed (you should call _3DScene::reload_scene(canvas3Dwidget, false))
2018-11-13 16:45:44 +00:00
UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE = 2 ,
// update_background_process() reports, that the Print / SLAPrint is invalid, and the error message
// was sent to the status line.
UPDATE_BACKGROUND_PROCESS_INVALID = 4 ,
2018-12-22 09:02:42 +00:00
// Restart even if the background processing is disabled.
UPDATE_BACKGROUND_PROCESS_FORCE_RESTART = 8 ,
// Restart for G-code (or SLA zip) export or upload.
UPDATE_BACKGROUND_PROCESS_FORCE_EXPORT = 16 ,
2018-11-13 16:45:44 +00:00
} ;
// returns bit mask of UpdateBackgroundProcessReturnState
2019-01-10 15:06:24 +00:00
unsigned int update_background_process ( bool force_validation = false ) ;
2018-12-22 09:02:42 +00:00
// Restart background processing thread based on a bitmask of UpdateBackgroundProcessReturnState.
bool restart_background_process ( unsigned int state ) ;
2019-02-03 09:41:14 +00:00
// returns bit mask of UpdateBackgroundProcessReturnState
unsigned int update_restart_background_process ( bool force_scene_update , bool force_preview_update ) ;
2018-12-11 09:33:11 +00:00
void export_gcode ( fs : : path output_path , PrintHostJob upload_job ) ;
2018-10-09 07:35:19 +00:00
void reload_from_disk ( ) ;
2019-01-30 15:27:07 +00:00
void fix_through_netfabb ( const int obj_idx , const int vol_idx = - 1 ) ;
2018-09-17 10:15:11 +00:00
2018-12-04 12:55:25 +00:00
void set_current_panel ( wxPanel * panel ) ;
2019-01-03 11:59:06 +00:00
2018-10-08 17:55:30 +00:00
void on_select_preset ( wxCommandEvent & ) ;
2018-11-20 12:22:26 +00:00
void on_slicing_update ( SlicingStatusEvent & ) ;
void on_slicing_completed ( wxCommandEvent & ) ;
2018-10-08 17:55:30 +00:00
void on_process_completed ( wxCommandEvent & ) ;
2018-09-17 10:15:11 +00:00
void on_layer_editing_toggled ( bool enable ) ;
2018-10-08 17:55:30 +00:00
2018-10-03 09:34:39 +00:00
void on_action_add ( SimpleEvent & ) ;
2018-10-24 10:55:38 +00:00
void on_action_split_objects ( SimpleEvent & ) ;
void on_action_split_volumes ( SimpleEvent & ) ;
2018-10-04 09:12:55 +00:00
void on_action_layersediting ( SimpleEvent & ) ;
2018-10-03 12:25:35 +00:00
2018-10-16 14:04:19 +00:00
void on_object_select ( SimpleEvent & ) ;
2018-10-08 17:55:30 +00:00
void on_right_click ( Vec2dEvent & ) ;
void on_wipetower_moved ( Vec3dEvent & ) ;
void on_update_geometry ( Vec3dsEvent < 2 > & ) ;
2018-11-23 11:47:32 +00:00
void on_3dcanvas_mouse_dragging_finished ( SimpleEvent & ) ;
2018-10-17 10:17:25 +00:00
2018-12-07 16:50:48 +00:00
void update_object_menu ( ) ;
2019-03-01 10:00:34 +00:00
void show_action_buttons ( const bool is_ready_to_slice ) const ;
2018-12-07 16:50:48 +00:00
2019-02-19 14:15:27 +00:00
// Set the bed shape to a single closed 2D polygon(array of two element arrays),
// triangulate the bed and store the triangles into m_bed.m_triangles,
// fills the m_bed.m_grid_lines and sets m_bed.m_origin.
// Sets m_bed.m_polygon to limit the object placement.
void set_bed_shape ( const Pointfs & shape ) ;
2019-03-14 12:54:05 +00:00
bool can_delete ( ) const ;
bool can_delete_all ( ) const ;
bool can_increase_instances ( ) const ;
bool can_decrease_instances ( ) const ;
bool can_split_to_objects ( ) const ;
bool can_split_to_volumes ( ) const ;
bool can_arrange ( ) const ;
bool can_layers_editing ( ) const ;
2019-04-24 14:04:47 +00:00
bool can_fix_through_netfabb ( ) const ;
2019-03-14 12:54:05 +00:00
2019-05-03 07:44:19 +00:00
void msw_rescale_object_menu ( ) ;
2018-10-17 10:17:25 +00:00
private :
bool init_object_menu ( ) ;
2018-12-07 16:50:48 +00:00
bool init_common_menu ( wxMenu * menu , const bool is_part = false ) ;
bool complit_init_object_menu ( ) ;
bool complit_init_sla_object_menu ( ) ;
bool complit_init_part_menu ( ) ;
2018-12-06 09:38:19 +00:00
void init_view_toolbar ( ) ;
2018-10-18 07:27:37 +00:00
2019-01-22 15:40:10 +00:00
bool can_set_instance_to_object ( ) const ;
2018-12-17 14:44:30 +00:00
bool can_split ( ) const ;
2018-10-18 07:27:37 +00:00
bool layers_height_allowed ( ) const ;
2018-10-18 13:09:41 +00:00
bool can_mirror ( ) const ;
2018-11-23 11:47:32 +00:00
2018-12-06 14:40:41 +00:00
void update_fff_scene ( ) ;
2018-11-23 11:47:32 +00:00
void update_sla_scene ( ) ;
2018-09-17 10:15:11 +00:00
} ;
2018-10-22 09:52:13 +00:00
const std : : regex Plater : : priv : : pattern_bundle ( " .*[.](amf|amf[.]xml|zip[.]amf|3mf|prusa) " , std : : regex : : icase ) ;
const std : : regex Plater : : priv : : pattern_3mf ( " .*3mf " , std : : regex : : icase ) ;
const std : : regex Plater : : priv : : pattern_zip_amf ( " .*[.]zip[.]amf " , std : : regex : : icase ) ;
2019-01-03 11:04:14 +00:00
const std : : regex Plater : : priv : : pattern_any_amf ( " .*[.](amf|amf[.]xml|zip[.]amf) " , std : : regex : : icase ) ;
2019-01-18 15:01:43 +00:00
# if ENABLE_VOLUMES_CENTERING_FIXES
const std : : regex Plater : : priv : : pattern_prusa ( " .*prusa " , std : : regex : : icase ) ;
# endif // ENABLE_VOLUMES_CENTERING_FIXES
2019-01-03 11:04:14 +00:00
2018-10-18 13:13:38 +00:00
Plater : : priv : : priv ( Plater * q , MainFrame * main_frame )
: q ( q )
, main_frame ( main_frame )
, config ( Slic3r : : DynamicPrintConfig : : new_from_defaults_keys ( {
2019-02-08 11:30:10 +00:00
" bed_shape " , " complete_objects " , " duplicate_distance " , " extruder_clearance_radius " , " skirts " , " skirt_distance " ,
2018-09-17 10:15:11 +00:00
" brim_width " , " variable_layer_height " , " serial_port " , " serial_speed " , " host_type " , " print_host " ,
" printhost_apikey " , " printhost_cafile " , " nozzle_diameter " , " single_extruder_multi_material " ,
" wipe_tower " , " wipe_tower_x " , " wipe_tower_y " , " wipe_tower_width " , " wipe_tower_rotation_angle " ,
2019-01-21 09:06:51 +00:00
" extruder_colour " , " filament_colour " , " max_print_height " , " printer_model " , " printer_technology " ,
2019-01-21 16:02:16 +00:00
// These values are necessary to construct SlicingParameters by the Canvas3D variable layer height editor.
" layer_height " , " first_layer_height " , " min_layer_height " , " max_layer_height " ,
" brim_width " , " perimeters " , " perimeter_extruder " , " fill_density " , " infill_extruder " , " top_solid_layers " , " bottom_solid_layers " , " solid_infill_extruder " ,
" support_material " , " support_material_extruder " , " support_material_interface_extruder " , " support_material_contact_distance " , " raft_layers "
2018-10-18 13:13:38 +00:00
} ) )
, sidebar ( new Sidebar ( q ) )
2018-11-23 11:47:32 +00:00
, delayed_scene_refresh ( false )
2018-11-15 14:27:39 +00:00
, project_filename ( wxEmptyString )
2019-02-26 11:56:13 +00:00
# if ENABLE_SVG_ICONS
, view_toolbar ( GLToolbar : : Radio , " View " )
# else
2018-12-17 09:55:14 +00:00
, view_toolbar ( GLToolbar : : Radio )
2019-02-26 11:56:13 +00:00
# endif // ENABLE_SVG_ICONS
2018-09-17 10:15:11 +00:00
{
2019-05-06 16:28:23 +00:00
this - > q - > SetFont ( Slic3r : : GUI : : wxGetApp ( ) . normal_font ( ) ) ;
2019-04-17 12:56:00 +00:00
arranging = false ;
rotoptimizing = false ;
2018-12-03 12:14:28 +00:00
background_process . set_fff_print ( & fff_print ) ;
2018-11-08 19:18:40 +00:00
background_process . set_sla_print ( & sla_print ) ;
2018-09-17 10:15:11 +00:00
background_process . set_gcode_preview_data ( & gcode_preview_data ) ;
2018-11-20 12:22:26 +00:00
background_process . set_slicing_completed_event ( EVT_SLICING_COMPLETED ) ;
2018-09-17 10:15:11 +00:00
background_process . set_finished_event ( EVT_PROCESS_COMPLETED ) ;
2018-11-08 19:18:40 +00:00
// Default printer technology for default config.
2018-11-13 16:45:44 +00:00
background_process . select_technology ( this - > printer_technology ) ;
2018-10-23 13:27:31 +00:00
// Register progress callback from the Print class to the Platter.
2018-11-13 10:53:54 +00:00
2018-11-20 15:27:30 +00:00
auto statuscb = [ this ] ( const Slic3r : : PrintBase : : SlicingStatus & status ) {
2018-11-20 12:22:26 +00:00
wxQueueEvent ( this - > q , new Slic3r : : SlicingStatusEvent ( EVT_SLICING_UPDATE , 0 , status ) ) ;
2018-11-13 10:53:54 +00:00
} ;
2018-12-03 12:14:28 +00:00
fff_print . set_status_callback ( statuscb ) ;
2018-11-13 10:53:54 +00:00
sla_print . set_status_callback ( statuscb ) ;
2018-11-20 12:22:26 +00:00
this - > q - > Bind ( EVT_SLICING_UPDATE , & priv : : on_slicing_update , this ) ;
2018-09-17 10:15:11 +00:00
2019-03-07 10:49:00 +00:00
view3D = new View3D ( q , bed , camera , view_toolbar , & model , config , & background_process ) ;
2019-04-02 11:47:49 +00:00
preview = new Preview ( q , bed , camera , view_toolbar , & model , config , & background_process , & gcode_preview_data , [ this ] ( ) { schedule_background_process ( ) ; } ) ;
2019-02-19 14:15:27 +00:00
2018-12-04 12:55:25 +00:00
panels . push_back ( view3D ) ;
panels . push_back ( preview ) ;
2018-09-17 10:15:11 +00:00
2018-10-23 13:27:31 +00:00
this - > background_process_timer . SetOwner ( this - > q , 0 ) ;
2018-12-22 09:02:42 +00:00
this - > q - > Bind ( wxEVT_TIMER , [ this ] ( wxTimerEvent & evt ) { this - > update_restart_background_process ( false , false ) ; } ) ;
2018-09-17 10:15:11 +00:00
update ( ) ;
auto * hsizer = new wxBoxSizer ( wxHORIZONTAL ) ;
2018-12-04 12:55:25 +00:00
panel_sizer = new wxBoxSizer ( wxHORIZONTAL ) ;
panel_sizer - > Add ( view3D , 1 , wxEXPAND | wxALL , 0 ) ;
panel_sizer - > Add ( preview , 1 , wxEXPAND | wxALL , 0 ) ;
hsizer - > Add ( panel_sizer , 1 , wxEXPAND | wxALL , 0 ) ;
2018-09-17 10:15:11 +00:00
hsizer - > Add ( sidebar , 0 , wxEXPAND | wxLEFT | wxRIGHT , 0 ) ;
q - > SetSizer ( hsizer ) ;
2018-10-17 10:17:25 +00:00
init_object_menu ( ) ;
2018-09-17 10:15:11 +00:00
// Events:
// Preset change event
sidebar - > Bind ( wxEVT_COMBOBOX , & priv : : on_select_preset , this ) ;
2018-11-01 11:33:56 +00:00
sidebar - > Bind ( EVT_OBJ_LIST_OBJECT_SELECT , [ this ] ( wxEvent & ) { priv : : selection_changed ( ) ; } ) ;
2018-12-04 10:14:39 +00:00
sidebar - > Bind ( EVT_SCHEDULE_BACKGROUND_PROCESS , [ this ] ( SimpleEvent & ) { this - > schedule_background_process ( ) ; } ) ;
2018-11-01 11:33:56 +00:00
2018-12-04 12:55:25 +00:00
wxGLCanvas * view3D_canvas = view3D - > get_wxglcanvas ( ) ;
// 3DScene events:
view3D_canvas - > Bind ( EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS , [ this ] ( SimpleEvent & ) { this - > schedule_background_process ( ) ; } ) ;
view3D_canvas - > Bind ( EVT_GLCANVAS_OBJECT_SELECT , & priv : : on_object_select , this ) ;
view3D_canvas - > Bind ( EVT_GLCANVAS_RIGHT_CLICK , & priv : : on_right_click , this ) ;
view3D_canvas - > Bind ( EVT_GLCANVAS_REMOVE_OBJECT , [ q ] ( SimpleEvent & ) { q - > remove_selected ( ) ; } ) ;
view3D_canvas - > Bind ( EVT_GLCANVAS_ARRANGE , [ this ] ( SimpleEvent & ) { arrange ( ) ; } ) ;
2019-02-03 13:06:13 +00:00
view3D_canvas - > Bind ( EVT_GLCANVAS_SELECT_ALL , [ this ] ( SimpleEvent & ) { this - > q - > select_all ( ) ; } ) ;
2018-12-19 13:01:13 +00:00
view3D_canvas - > Bind ( EVT_GLCANVAS_QUESTION_MARK , [ this ] ( SimpleEvent & ) { wxGetApp ( ) . keyboard_shortcuts ( ) ; } ) ;
2018-12-19 11:07:45 +00:00
view3D_canvas - > Bind ( EVT_GLCANVAS_INCREASE_INSTANCES , [ this ] ( Event < int > & evt )
{ if ( evt . data = = 1 ) this - > q - > increase_instances ( ) ; else if ( this - > can_decrease_instances ( ) ) this - > q - > decrease_instances ( ) ; } ) ;
2018-12-04 12:55:25 +00:00
view3D_canvas - > Bind ( EVT_GLCANVAS_INSTANCE_MOVED , [ this ] ( SimpleEvent & ) { update ( ) ; } ) ;
view3D_canvas - > Bind ( EVT_GLCANVAS_WIPETOWER_MOVED , & priv : : on_wipetower_moved , this ) ;
2019-01-03 10:24:03 +00:00
view3D_canvas - > Bind ( EVT_GLCANVAS_INSTANCE_ROTATED , [ this ] ( SimpleEvent & ) { update ( ) ; } ) ;
view3D_canvas - > Bind ( EVT_GLCANVAS_INSTANCE_SCALED , [ this ] ( SimpleEvent & ) { update ( ) ; } ) ;
2018-12-04 12:55:25 +00:00
view3D_canvas - > Bind ( EVT_GLCANVAS_ENABLE_ACTION_BUTTONS , [ this ] ( Event < bool > & evt ) { this - > sidebar - > enable_buttons ( evt . data ) ; } ) ;
view3D_canvas - > Bind ( EVT_GLCANVAS_UPDATE_GEOMETRY , & priv : : on_update_geometry , this ) ;
view3D_canvas - > Bind ( EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED , & priv : : on_3dcanvas_mouse_dragging_finished , this ) ;
2019-02-21 10:54:18 +00:00
view3D_canvas - > Bind ( EVT_GLCANVAS_TAB , [ this ] ( SimpleEvent & ) { select_next_view_3D ( ) ; } ) ;
2019-03-27 13:16:38 +00:00
view3D_canvas - > Bind ( EVT_GLCANVAS_RESETGIZMOS , [ this ] ( SimpleEvent & ) { reset_all_gizmos ( ) ; } ) ;
2018-12-04 12:55:25 +00:00
// 3DScene/Toolbar:
view3D_canvas - > Bind ( EVT_GLTOOLBAR_ADD , & priv : : on_action_add , this ) ;
view3D_canvas - > Bind ( EVT_GLTOOLBAR_DELETE , [ q ] ( SimpleEvent & ) { q - > remove_selected ( ) ; } ) ;
2019-05-02 11:52:13 +00:00
view3D_canvas - > Bind ( EVT_GLTOOLBAR_DELETE_ALL , [ q ] ( SimpleEvent & ) { q - > reset_with_confirm ( ) ; } ) ;
2018-12-04 12:55:25 +00:00
view3D_canvas - > Bind ( EVT_GLTOOLBAR_ARRANGE , [ this ] ( SimpleEvent & ) { arrange ( ) ; } ) ;
2019-04-11 11:20:34 +00:00
view3D_canvas - > Bind ( EVT_GLTOOLBAR_COPY , [ q ] ( SimpleEvent & ) { q - > copy_selection_to_clipboard ( ) ; } ) ;
view3D_canvas - > Bind ( EVT_GLTOOLBAR_PASTE , [ q ] ( SimpleEvent & ) { q - > paste_from_clipboard ( ) ; } ) ;
2018-12-04 12:55:25 +00:00
view3D_canvas - > Bind ( EVT_GLTOOLBAR_MORE , [ q ] ( SimpleEvent & ) { q - > increase_instances ( ) ; } ) ;
view3D_canvas - > Bind ( EVT_GLTOOLBAR_FEWER , [ q ] ( SimpleEvent & ) { q - > decrease_instances ( ) ; } ) ;
view3D_canvas - > Bind ( EVT_GLTOOLBAR_SPLIT_OBJECTS , & priv : : on_action_split_objects , this ) ;
view3D_canvas - > Bind ( EVT_GLTOOLBAR_SPLIT_VOLUMES , & priv : : on_action_split_volumes , this ) ;
view3D_canvas - > Bind ( EVT_GLTOOLBAR_LAYERSEDITING , & priv : : on_action_layersediting , this ) ;
2018-12-06 09:38:19 +00:00
view3D_canvas - > Bind ( EVT_GLCANVAS_INIT , [ this ] ( SimpleEvent & ) { init_view_toolbar ( ) ; } ) ;
2019-02-19 14:15:27 +00:00
view3D_canvas - > Bind ( EVT_GLCANVAS_UPDATE_BED_SHAPE , [ this ] ( SimpleEvent & ) { set_bed_shape ( config - > option < ConfigOptionPoints > ( " bed_shape " ) - > values ) ; } ) ;
2018-10-04 09:12:55 +00:00
2018-10-08 17:55:30 +00:00
// Preview events:
2018-12-22 09:02:42 +00:00
preview - > get_wxglcanvas ( ) - > Bind ( EVT_GLCANVAS_QUESTION_MARK , [ this ] ( SimpleEvent & ) { wxGetApp ( ) . keyboard_shortcuts ( ) ; } ) ;
2019-02-19 14:15:27 +00:00
preview - > get_wxglcanvas ( ) - > Bind ( EVT_GLCANVAS_UPDATE_BED_SHAPE , [ this ] ( SimpleEvent & ) { set_bed_shape ( config - > option < ConfigOptionPoints > ( " bed_shape " ) - > values ) ; } ) ;
2019-02-21 10:54:18 +00:00
preview - > get_wxglcanvas ( ) - > Bind ( EVT_GLCANVAS_TAB , [ this ] ( SimpleEvent & ) { select_next_view_3D ( ) ; } ) ;
2019-01-03 11:59:06 +00:00
2018-11-20 12:22:26 +00:00
q - > Bind ( EVT_SLICING_COMPLETED , & priv : : on_slicing_completed , this ) ;
2018-09-17 10:15:11 +00:00
q - > Bind ( EVT_PROCESS_COMPLETED , & priv : : on_process_completed , this ) ;
2018-12-06 09:38:19 +00:00
q - > Bind ( EVT_GLVIEWTOOLBAR_3D , [ q ] ( SimpleEvent & ) { q - > select_view_3D ( " 3D " ) ; } ) ;
q - > Bind ( EVT_GLVIEWTOOLBAR_PREVIEW , [ q ] ( SimpleEvent & ) { q - > select_view_3D ( " Preview " ) ; } ) ;
2018-09-17 10:15:11 +00:00
// Drop target:
q - > SetDropTarget ( new PlaterDropTarget ( q ) ) ; // if my understanding is right, wxWindow takes the owenership
update_ui_from_settings ( ) ;
q - > Layout ( ) ;
2018-12-20 11:51:42 +00:00
set_current_panel ( view3D ) ;
2018-09-17 10:15:11 +00:00
}
2018-11-21 12:52:46 +00:00
void Plater : : priv : : update ( bool force_full_scene_refresh )
2018-09-17 10:15:11 +00:00
{
2018-10-01 14:48:08 +00:00
wxWindowUpdateLocker freeze_guard ( q ) ;
2018-11-21 12:32:24 +00:00
if ( get_config ( " autocenter " ) = = " 1 " ) {
2018-10-01 14:48:08 +00:00
// auto *bed_shape_opt = config->opt<ConfigOptionPoints>("bed_shape");
// const auto bed_shape = Slic3r::Polygon::new_scale(bed_shape_opt->values);
// const BoundingBox bed_shape_bb = bed_shape.bounding_box();
2018-10-03 14:18:23 +00:00
const Vec2d & bed_center = bed_shape_bb ( ) . center ( ) ;
2018-10-01 14:48:08 +00:00
model . center_instances_around_point ( bed_center ) ;
}
2018-12-22 09:02:42 +00:00
unsigned int update_status = 0 ;
if ( this - > printer_technology = = ptSLA )
2018-11-13 16:45:44 +00:00
// Update the SLAPrint from the current Model, so that the reload_scene()
// pulls the correct data.
2019-01-10 15:06:24 +00:00
update_status = this - > update_background_process ( false ) ;
2018-12-22 09:02:42 +00:00
this - > view3D - > reload_scene ( false , force_full_scene_refresh ) ;
this - > preview - > reload_print ( ) ;
if ( this - > printer_technology = = ptSLA )
this - > restart_background_process ( update_status ) ;
else
this - > schedule_background_process ( ) ;
2018-09-17 10:15:11 +00:00
}
2018-12-04 12:55:25 +00:00
void Plater : : priv : : select_view ( const std : : string & direction )
{
if ( current_panel = = view3D )
view3D - > select_view ( direction ) ;
else if ( current_panel = = preview )
preview - > select_view ( direction ) ;
}
void Plater : : priv : : select_view_3D ( const std : : string & name )
{
if ( name = = " 3D " )
set_current_panel ( view3D ) ;
else if ( name = = " Preview " )
set_current_panel ( preview ) ;
2018-12-21 09:43:22 +00:00
}
void Plater : : priv : : select_next_view_3D ( )
{
if ( current_panel = = view3D )
set_current_panel ( preview ) ;
else if ( current_panel = = preview )
set_current_panel ( view3D ) ;
2018-12-04 12:55:25 +00:00
}
2018-10-17 10:59:58 +00:00
2019-03-27 13:16:38 +00:00
void Plater : : priv : : reset_all_gizmos ( )
{
view3D - > get_canvas3d ( ) - > reset_all_gizmos ( ) ;
}
2018-12-04 10:14:39 +00:00
// Called after the Preferences dialog is closed and the program settings are saved.
// Update the UI based on the current preferences.
2018-09-17 10:15:11 +00:00
void Plater : : priv : : update_ui_from_settings ( )
{
// TODO: (?)
// my ($self) = @_;
// if (defined($self->{btn_reslice}) && $self->{buttons_sizer}->IsShown($self->{btn_reslice}) != (! wxTheApp->{app_config}->get("background_processing"))) {
// $self->{buttons_sizer}->Show($self->{btn_reslice}, ! wxTheApp->{app_config}->get("background_processing"));
// $self->{buttons_sizer}->Layout;
// }
2019-01-24 12:16:46 +00:00
# if ENABLE_RETINA_GL
view3D - > get_canvas3d ( ) - > update_ui_from_settings ( ) ;
preview - > get_canvas3d ( ) - > update_ui_from_settings ( ) ;
# endif
2018-09-17 10:15:11 +00:00
}
2018-10-23 13:27:31 +00:00
ProgressStatusBar * Plater : : priv : : statusbar ( )
2018-09-17 10:15:11 +00:00
{
return main_frame - > m_statusbar ;
}
2018-10-01 14:48:08 +00:00
std : : string Plater : : priv : : get_config ( const std : : string & key ) const
{
return wxGetApp ( ) . app_config - > get ( key ) ;
}
2018-10-03 14:18:23 +00:00
BoundingBoxf Plater : : priv : : bed_shape_bb ( ) const
{
BoundingBox bb = scaled_bed_shape_bb ( ) ;
return BoundingBoxf ( unscale ( bb . min ) , unscale ( bb . max ) ) ;
}
BoundingBox Plater : : priv : : scaled_bed_shape_bb ( ) const
2018-10-01 14:48:08 +00:00
{
const auto * bed_shape_opt = config - > opt < ConfigOptionPoints > ( " bed_shape " ) ;
const auto bed_shape = Slic3r : : Polygon : : new_scale ( bed_shape_opt - > values ) ;
return bed_shape . bounding_box ( ) ;
}
2018-11-16 08:26:41 +00:00
std : : vector < size_t > Plater : : priv : : load_files ( const std : : vector < fs : : path > & input_files , bool load_model , bool load_config )
2018-09-17 10:15:11 +00:00
{
2018-10-04 09:12:55 +00:00
if ( input_files . empty ( ) ) { return std : : vector < size_t > ( ) ; }
2018-09-17 10:15:11 +00:00
auto * nozzle_dmrs = config - > opt < ConfigOptionFloats > ( " nozzle_diameter " ) ;
bool one_by_one = input_files . size ( ) = = 1 | | nozzle_dmrs - > values . size ( ) < = 1 ;
if ( ! one_by_one ) {
for ( const auto & path : input_files ) {
if ( std : : regex_match ( path . string ( ) , pattern_bundle ) ) {
one_by_one = true ;
break ;
}
}
}
2019-01-21 11:34:28 +00:00
const auto loading = _ ( L ( " Loading " ) ) + dots ;
2018-09-17 10:15:11 +00:00
wxProgressDialog dlg ( loading , loading ) ;
dlg . Pulse ( ) ;
2018-11-16 08:26:41 +00:00
auto * new_model = ( ! load_model | | one_by_one ) ? nullptr : new Slic3r : : Model ( ) ;
2018-10-01 14:48:08 +00:00
std : : vector < size_t > obj_idxs ;
2018-09-17 10:15:11 +00:00
for ( size_t i = 0 ; i < input_files . size ( ) ; i + + ) {
const auto & path = input_files [ i ] ;
const auto filename = path . filename ( ) ;
2019-01-02 14:11:05 +00:00
const auto dlg_info = wxString : : Format ( _ ( L ( " Processing input file %s \n " ) ) , from_path ( filename ) ) ;
2018-09-17 10:15:11 +00:00
dlg . Update ( 100 * i / input_files . size ( ) , dlg_info ) ;
const bool type_3mf = std : : regex_match ( path . string ( ) , pattern_3mf ) ;
const bool type_zip_amf = ! type_3mf & & std : : regex_match ( path . string ( ) , pattern_zip_amf ) ;
2019-01-03 11:04:14 +00:00
const bool type_any_amf = ! type_3mf & & std : : regex_match ( path . string ( ) , pattern_any_amf ) ;
2019-01-18 15:01:43 +00:00
# if ENABLE_VOLUMES_CENTERING_FIXES
const bool type_prusa = std : : regex_match ( path . string ( ) , pattern_prusa ) ;
# endif // ENABLE_VOLUMES_CENTERING_FIXES
2018-09-17 10:15:11 +00:00
Slic3r : : Model model ;
try {
if ( type_3mf | | type_zip_amf ) {
DynamicPrintConfig config ;
2018-11-06 18:09:54 +00:00
{
DynamicPrintConfig config_loaded ;
model = Slic3r : : Model : : read_from_archive ( path . string ( ) , & config_loaded , false ) ;
2018-11-16 08:26:41 +00:00
if ( load_config & & ! config_loaded . empty ( ) ) {
// Based on the printer technology field found in the loaded config, select the base for the config,
PrinterTechnology printer_technology = Preset : : printer_technology ( config_loaded ) ;
config . apply ( printer_technology = = ptFFF ?
2018-11-06 18:09:54 +00:00
static_cast < const ConfigBase & > ( FullPrintConfig : : defaults ( ) ) :
static_cast < const ConfigBase & > ( SLAFullPrintConfig : : defaults ( ) ) ) ;
// and place the loaded config over the base.
config + = std : : move ( config_loaded ) ;
}
}
2018-12-03 14:06:02 +00:00
2018-11-16 08:26:41 +00:00
if ( load_config )
{
if ( ! config . empty ( ) ) {
Preset : : normalize ( config ) ;
wxGetApp ( ) . preset_bundle - > load_config_model ( filename . string ( ) , std : : move ( config ) ) ;
wxGetApp ( ) . load_current_presets ( ) ;
}
wxGetApp ( ) . app_config - > update_config_dir ( path . parent_path ( ) . string ( ) ) ;
}
}
else {
2018-09-17 10:15:11 +00:00
model = Slic3r : : Model : : read_from_file ( path . string ( ) , nullptr , false ) ;
2018-10-19 09:02:50 +00:00
for ( auto obj : model . objects )
if ( obj - > name . empty ( ) )
obj - > name = fs : : path ( obj - > input_file ) . filename ( ) . string ( ) ;
2018-09-17 10:15:11 +00:00
}
2018-12-03 12:14:28 +00:00
} catch ( const std : : exception & e ) {
2018-09-17 10:15:11 +00:00
GUI : : show_error ( q , e . what ( ) ) ;
continue ;
}
2018-11-16 08:26:41 +00:00
if ( load_model )
{
// The model should now be initialized
2019-01-18 11:52:09 +00:00
# if ENABLE_VOLUMES_CENTERING_FIXES
2019-01-18 15:01:43 +00:00
if ( ! type_3mf & & ! type_any_amf & & ! type_prusa ) {
2019-01-18 11:52:09 +00:00
# endif // ENABLE_VOLUMES_CENTERING_FIXES
if ( model . looks_like_multipart_object ( ) ) {
2019-01-21 13:43:57 +00:00
wxMessageDialog dlg ( q , _ ( L (
2019-01-21 11:34:28 +00:00
" This file contains several objects positioned at multiple heights. "
" Instead of considering them as multiple objects, should I consider \n "
" this file as a single object having multiple parts? \n "
2019-01-21 13:43:57 +00:00
) ) , _ ( L ( " Multi-part object detected " ) ) , wxICON_WARNING | wxYES | wxNO ) ;
if ( dlg . ShowModal ( ) = = wxID_YES ) {
model . convert_multipart_object ( nozzle_dmrs - > values . size ( ) ) ;
}
2019-01-18 11:52:09 +00:00
}
# if ENABLE_VOLUMES_CENTERING_FIXES
2018-09-17 10:15:11 +00:00
}
2019-04-04 10:02:13 +00:00
else if ( ( wxGetApp ( ) . get_mode ( ) = = comSimple ) & & ( type_3mf | | type_any_amf ) )
{
bool advanced = false ;
for ( const ModelObject * model_object : model . objects )
{
// is there more than one instance ?
if ( model_object - > instances . size ( ) > 1 )
{
advanced = true ;
break ;
}
2019-04-15 07:22:11 +00:00
// is there any advanced config data ?
auto opt_keys = model_object - > config . keys ( ) ;
if ( ! opt_keys . empty ( ) & & ! ( ( opt_keys . size ( ) = = 1 ) & & ( opt_keys [ 0 ] = = " extruder " ) ) )
{
advanced = true ;
break ;
}
2019-04-04 10:02:13 +00:00
// is there any modifier ?
for ( const ModelVolume * model_volume : model_object - > volumes )
{
if ( ! model_volume - > is_model_part ( ) )
{
advanced = true ;
break ;
}
2019-04-15 07:22:11 +00:00
// is there any advanced config data ?
opt_keys = model_volume - > config . keys ( ) ;
if ( ! opt_keys . empty ( ) & & ! ( ( opt_keys . size ( ) = = 1 ) & & ( opt_keys [ 0 ] = = " extruder " ) ) )
{
advanced = true ;
break ;
}
2019-04-04 10:02:13 +00:00
}
if ( advanced )
break ;
}
if ( advanced )
{
2019-04-14 06:26:10 +00:00
wxMessageDialog dlg ( q , _ ( L ( " This file cannot be loaded in a simple mode. Do you want to switch to an advanced mode? \n " ) ) ,
2019-04-04 10:02:13 +00:00
_ ( L ( " Detected advanced data " ) ) , wxICON_WARNING | wxYES | wxNO ) ;
if ( dlg . ShowModal ( ) = = wxID_YES )
{
2019-04-14 06:26:10 +00:00
Slic3r : : GUI : : wxGetApp ( ) . save_mode ( comAdvanced ) ;
2019-04-04 10:02:13 +00:00
view3D - > set_as_dirty ( ) ;
}
else
return obj_idxs ;
}
}
2019-01-18 11:52:09 +00:00
# endif // ENABLE_VOLUMES_CENTERING_FIXES
2018-09-17 10:15:11 +00:00
2019-01-18 11:52:09 +00:00
# if !ENABLE_VOLUMES_CENTERING_FIXES
2019-01-03 11:04:14 +00:00
if ( type_3mf | | type_any_amf ) {
2019-01-18 11:52:09 +00:00
# endif // !ENABLE_VOLUMES_CENTERING_FIXES
2018-11-16 08:26:41 +00:00
for ( ModelObject * model_object : model . objects ) {
2019-03-22 08:47:40 +00:00
# if ENABLE_VOLUMES_CENTERING_FIXES
model_object - > center_around_origin ( false ) ;
# else
2018-11-16 08:26:41 +00:00
model_object - > center_around_origin ( ) ;
2019-03-22 08:47:40 +00:00
# endif // ENABLE_VOLUMES_CENTERING_FIXES
2018-11-16 08:26:41 +00:00
model_object - > ensure_on_bed ( ) ;
}
2019-01-18 11:52:09 +00:00
# if !ENABLE_VOLUMES_CENTERING_FIXES
2018-09-17 10:15:11 +00:00
}
2019-01-18 11:52:09 +00:00
# endif // !ENABLE_VOLUMES_CENTERING_FIXES
2018-09-17 10:15:11 +00:00
2018-12-10 12:39:56 +00:00
// check multi-part object adding for the SLA-printing
if ( printer_technology = = ptSLA )
{
for ( auto obj : model . objects )
if ( obj - > volumes . size ( ) > 1 ) {
Slic3r : : GUI : : show_error ( nullptr ,
wxString : : Format ( _ ( L ( " You can't to add the object(s) from %s because of one or some of them is(are) multi-part " ) ) ,
2019-01-02 14:11:05 +00:00
from_path ( filename ) ) ) ;
2019-04-04 10:02:13 +00:00
return obj_idxs ;
2018-12-10 12:39:56 +00:00
}
}
2018-11-16 08:26:41 +00:00
if ( one_by_one ) {
auto loaded_idxs = load_model_objects ( model . objects ) ;
obj_idxs . insert ( obj_idxs . end ( ) , loaded_idxs . begin ( ) , loaded_idxs . end ( ) ) ;
} else {
// This must be an .stl or .obj file, which may contain a maximum of one volume.
for ( const ModelObject * model_object : model . objects ) {
new_model - > add_object ( * model_object ) ;
}
2018-09-17 10:15:11 +00:00
}
}
}
if ( new_model ! = nullptr ) {
wxMessageDialog dlg ( q , _ ( L (
" Multiple objects were loaded for a multi-material printer. \n "
" Instead of considering them as multiple objects, should I consider \n "
" these files to represent a single object having multiple parts? \n "
) ) , _ ( L ( " Multi-part object detected " ) ) , wxICON_WARNING | wxYES | wxNO ) ;
if ( dlg . ShowModal ( ) = = wxID_YES ) {
new_model - > convert_multipart_object ( nozzle_dmrs - > values . size ( ) ) ;
}
2018-10-19 09:02:50 +00:00
auto loaded_idxs = load_model_objects ( new_model - > objects ) ;
2018-10-01 14:48:08 +00:00
obj_idxs . insert ( obj_idxs . end ( ) , loaded_idxs . begin ( ) , loaded_idxs . end ( ) ) ;
2018-09-17 10:15:11 +00:00
}
2018-11-16 08:26:41 +00:00
if ( load_model )
{
wxGetApp ( ) . app_config - > update_skein_dir ( input_files [ input_files . size ( ) - 1 ] . parent_path ( ) . string ( ) ) ;
// XXX: Plater.pm had @loaded_files, but didn't seem to fill them with the filenames...
statusbar ( ) - > set_status_text ( _ ( L ( " Loaded " ) ) ) ;
}
2018-12-03 14:06:02 +00:00
2019-01-03 08:12:50 +00:00
// automatic selection of added objects
if ( ! obj_idxs . empty ( ) & & ( view3D ! = nullptr ) )
{
2019-03-19 12:30:21 +00:00
Selection & selection = view3D - > get_canvas3d ( ) - > get_selection ( ) ;
2019-01-03 08:12:50 +00:00
selection . clear ( ) ;
for ( size_t idx : obj_idxs )
{
selection . add_object ( ( unsigned int ) idx , false ) ;
}
}
2018-10-01 14:48:08 +00:00
return obj_idxs ;
2018-09-17 10:15:11 +00:00
}
2019-01-28 09:56:02 +00:00
// #define AUTOPLACEMENT_ON_LOAD
2018-10-04 09:12:55 +00:00
std : : vector < size_t > Plater : : priv : : load_model_objects ( const ModelObjectPtrs & model_objects )
2018-09-17 10:15:11 +00:00
{
2018-10-03 14:18:23 +00:00
const BoundingBoxf bed_shape = bed_shape_bb ( ) ;
2018-12-19 08:54:15 +00:00
const Vec3d bed_size = Slic3r : : to_3d ( bed_shape . size ( ) . cast < double > ( ) , 1.0 ) - 2.0 * Vec3d : : Ones ( ) ;
2018-09-17 10:15:11 +00:00
2019-01-28 09:56:02 +00:00
# ifndef AUTOPLACEMENT_ON_LOAD
bool need_arrange = false ;
# endif /* AUTOPLACEMENT_ON_LOAD */
2018-09-17 10:15:11 +00:00
bool scaled_down = false ;
2018-10-01 14:48:08 +00:00
std : : vector < size_t > obj_idxs ;
2018-10-19 09:02:50 +00:00
unsigned int obj_count = model . objects . size ( ) ;
2018-09-17 10:15:11 +00:00
2019-01-28 09:56:02 +00:00
# ifdef AUTOPLACEMENT_ON_LOAD
2019-01-22 16:50:33 +00:00
ModelInstancePtrs new_instances ;
2019-01-28 09:56:02 +00:00
# endif /* AUTOPLACEMENT_ON_LOAD */
2018-10-01 14:48:08 +00:00
for ( ModelObject * model_object : model_objects ) {
2018-09-17 10:15:11 +00:00
auto * object = model . add_object ( * model_object ) ;
std : : string object_name = object - > name . empty ( ) ? fs : : path ( object - > input_file ) . filename ( ) . string ( ) : object - > name ;
2018-10-17 07:30:07 +00:00
obj_idxs . push_back ( obj_count + + ) ;
2018-09-17 10:15:11 +00:00
2018-10-04 09:12:55 +00:00
if ( model_object - > instances . empty ( ) ) {
2019-01-28 09:56:02 +00:00
# ifdef AUTOPLACEMENT_ON_LOAD
2019-01-22 16:50:33 +00:00
object - > center_around_origin ( ) ;
new_instances . emplace_back ( object - > add_instance ( ) ) ;
2019-01-28 09:56:02 +00:00
# else /* AUTOPLACEMENT_ON_LOAD */
2019-03-25 11:07:43 +00:00
// if object has no defined position(s) we need to rearrange everything after loading
need_arrange = true ;
2019-01-28 09:56:02 +00:00
// add a default instance and center object around origin
object - > center_around_origin ( ) ; // also aligns object to Z = 0
ModelInstance * instance = object - > add_instance ( ) ;
instance - > set_offset ( Slic3r : : to_3d ( bed_shape . center ( ) . cast < double > ( ) , - object - > origin_translation ( 2 ) ) ) ;
# endif /* AUTOPLACEMENT_ON_LOAD */
2018-09-17 10:15:11 +00:00
}
2018-10-01 14:48:08 +00:00
const Vec3d size = object - > bounding_box ( ) . size ( ) ;
const Vec3d ratio = size . cwiseQuotient ( bed_size ) ;
const double max_ratio = std : : max ( ratio ( 0 ) , ratio ( 1 ) ) ;
if ( max_ratio > 10000 ) {
// the size of the object is too big -> this could lead to overflow when moving to clipper coordinates,
// so scale down the mesh
2018-12-18 17:41:20 +00:00
double inv = 1. / max_ratio ;
2018-12-19 08:54:15 +00:00
object - > scale_mesh ( Vec3d ( inv , inv , inv ) ) ;
object - > origin_translation = Vec3d : : Zero ( ) ;
object - > center_around_origin ( ) ;
2018-10-01 14:48:08 +00:00
scaled_down = true ;
} else if ( max_ratio > 5 ) {
2019-01-25 12:30:01 +00:00
const Vec3d inverse = 1.0 / max_ratio * Vec3d : : Ones ( ) ;
for ( ModelInstance * instance : object - > instances ) {
2018-10-01 14:48:08 +00:00
instance - > set_scaling_factor ( inverse ) ;
}
2019-01-25 12:30:01 +00:00
scaled_down = true ;
2018-10-01 14:48:08 +00:00
}
2018-10-10 12:43:07 +00:00
2018-10-30 15:03:03 +00:00
object - > ensure_on_bed ( ) ;
2018-10-18 16:06:40 +00:00
// print.auto_assign_extruders(object);
// print.add_model_object(object);
2018-09-17 10:15:11 +00:00
}
2019-01-28 09:56:02 +00:00
# ifdef AUTOPLACEMENT_ON_LOAD
2019-01-23 12:12:44 +00:00
// FIXME distance should be a config value /////////////////////////////////
2019-01-22 16:50:33 +00:00
auto min_obj_distance = static_cast < coord_t > ( 6 / SCALING_FACTOR ) ;
const auto * bed_shape_opt = config - > opt < ConfigOptionPoints > ( " bed_shape " ) ;
assert ( bed_shape_opt ) ;
auto & bedpoints = bed_shape_opt - > values ;
Polyline bed ; bed . points . reserve ( bedpoints . size ( ) ) ;
for ( auto & v : bedpoints ) bed . append ( Point : : new_scale ( v ( 0 ) , v ( 1 ) ) ) ;
2019-01-23 12:12:44 +00:00
arr : : find_new_position ( model , new_instances , min_obj_distance , bed ) ;
2019-01-28 09:56:02 +00:00
# endif /* AUTOPLACEMENT_ON_LOAD */
2019-01-22 16:50:33 +00:00
2018-10-01 14:48:08 +00:00
if ( scaled_down ) {
GUI : : show_info ( q ,
_ ( L ( " Your object appears to be too large, so it was automatically scaled down to fit your print bed. " ) ) ,
_ ( L ( " Object too large? " ) ) ) ;
}
for ( const size_t idx : obj_idxs ) {
2018-10-08 14:27:38 +00:00
wxGetApp ( ) . obj_list ( ) - > add_object_to_list ( idx ) ;
2018-10-01 14:48:08 +00:00
}
update ( ) ;
2018-10-11 11:22:36 +00:00
object_list_changed ( ) ;
2018-10-17 09:12:38 +00:00
this - > schedule_background_process ( ) ;
2018-10-01 14:48:08 +00:00
return obj_idxs ;
2018-09-17 10:15:11 +00:00
}
2019-04-04 09:31:26 +00:00
wxString Plater : : priv : : get_export_file ( GUI : : FileType file_type )
2018-10-04 09:12:55 +00:00
{
wxString wildcard ;
switch ( file_type ) {
case FT_STL :
case FT_AMF :
case FT_3MF :
2018-10-19 14:52:41 +00:00
case FT_GCODE :
2018-12-06 16:32:49 +00:00
wildcard = file_wildcards ( file_type ) ;
2018-10-04 09:12:55 +00:00
break ;
default :
2018-12-06 16:32:49 +00:00
wildcard = file_wildcards ( FT_MODEL ) ;
2018-10-04 09:12:55 +00:00
break ;
}
2018-12-03 12:14:28 +00:00
// Update printbility state of each of the ModelInstances.
this - > update_print_volume_state ( ) ;
2019-04-04 12:00:31 +00:00
const Selection & selection = get_selection ( ) ;
int obj_idx = selection . get_object_idx ( ) ;
fs : : path output_file ;
// first try to get the file name from the current selection
if ( ( 0 < = obj_idx ) & & ( obj_idx < ( int ) this - > model . objects . size ( ) ) )
output_file = this - > model . objects [ obj_idx ] - > get_export_filename ( ) ;
if ( output_file . empty ( ) )
// Find the file name of the first printable object.
output_file = this - > model . propose_export_file_name_and_path ( ) ;
2018-10-04 09:12:55 +00:00
2019-04-04 09:31:26 +00:00
wxString dlg_title ;
2018-10-04 09:12:55 +00:00
switch ( file_type ) {
2019-04-04 09:31:26 +00:00
case FT_STL :
{
output_file . replace_extension ( " stl " ) ;
dlg_title = _ ( L ( " Export STL file: " ) ) ;
break ;
}
case FT_AMF :
{
// XXX: Problem on OS X with double extension?
output_file . replace_extension ( " zip.amf " ) ;
dlg_title = _ ( L ( " Export AMF file: " ) ) ;
break ;
}
case FT_3MF :
{
output_file . replace_extension ( " 3mf " ) ;
dlg_title = _ ( L ( " Save file as: " ) ) ;
break ;
}
2018-10-04 09:12:55 +00:00
default : break ;
}
2019-04-04 09:31:26 +00:00
wxFileDialog * dlg = new wxFileDialog ( q , dlg_title ,
from_path ( output_file . parent_path ( ) ) , from_path ( output_file . filename ( ) ) ,
wildcard , wxFD_SAVE | wxFD_OVERWRITE_PROMPT ) ;
2018-10-04 09:12:55 +00:00
if ( dlg - > ShowModal ( ) ! = wxID_OK ) {
2019-04-04 09:31:26 +00:00
return wxEmptyString ;
2018-10-04 09:12:55 +00:00
}
2019-04-04 09:31:26 +00:00
wxString out_path = dlg - > GetPath ( ) ;
fs : : path path ( into_path ( out_path ) ) ;
2018-10-04 09:12:55 +00:00
wxGetApp ( ) . app_config - > update_last_output_dir ( path . parent_path ( ) . string ( ) ) ;
2019-04-04 09:31:26 +00:00
return out_path ;
2018-10-04 09:12:55 +00:00
}
2019-03-19 12:30:21 +00:00
const Selection & Plater : : priv : : get_selection ( ) const
2018-10-17 07:30:07 +00:00
{
2018-12-04 12:55:25 +00:00
return view3D - > get_canvas3d ( ) - > get_selection ( ) ;
2018-10-17 07:30:07 +00:00
}
2019-03-19 12:30:21 +00:00
Selection & Plater : : priv : : get_selection ( )
2018-10-17 07:30:07 +00:00
{
2018-12-04 12:55:25 +00:00
return view3D - > get_canvas3d ( ) - > get_selection ( ) ;
2018-10-17 07:30:07 +00:00
}
int Plater : : priv : : get_selected_object_idx ( ) const
{
int idx = get_selection ( ) . get_object_idx ( ) ;
return ( ( 0 < = idx ) & & ( idx < 1000 ) ) ? idx : - 1 ;
}
2018-10-04 09:12:55 +00:00
2018-12-06 13:49:14 +00:00
int Plater : : priv : : get_selected_volume_idx ( ) const
{
auto & selection = get_selection ( ) ;
int idx = selection . get_object_idx ( ) ;
if ( ( 0 > idx ) | | ( idx > 1000 ) )
return - 1 ;
const GLVolume * v = selection . get_volume ( * selection . get_volume_idxs ( ) . begin ( ) ) ;
if ( model . objects [ idx ] - > volumes . size ( ) > 1 )
return v - > volume_idx ( ) ;
return - 1 ;
}
2018-10-04 09:12:55 +00:00
void Plater : : priv : : selection_changed ( )
{
2019-01-24 14:50:06 +00:00
// if the selection is not valid to allow for layer editing, we need to turn off the tool if it is running
bool enable_layer_editing = layers_height_allowed ( ) ;
2019-01-25 07:37:06 +00:00
if ( ! enable_layer_editing & & view3D - > is_layers_editing_enabled ( ) ) {
SimpleEvent evt ( EVT_GLTOOLBAR_LAYERSEDITING ) ;
on_action_layersediting ( evt ) ;
}
2019-01-24 14:50:06 +00:00
2018-12-04 12:55:25 +00:00
// forces a frame render to update the view (to avoid a missed update if, for example, the context menu appears)
view3D - > render ( ) ;
2018-10-04 09:12:55 +00:00
}
2018-10-08 17:14:55 +00:00
void Plater : : priv : : object_list_changed ( )
2018-10-04 09:12:55 +00:00
{
2018-10-23 13:27:31 +00:00
const bool export_in_progress = this - > background_process . is_export_scheduled ( ) ; // || ! send_gcode_file.empty());
2018-10-08 17:14:55 +00:00
// XXX: is this right?
2018-12-04 12:55:25 +00:00
const bool model_fits = view3D - > check_volumes_outside_state ( ) = = ModelInstance : : PVS_Inside ;
2018-10-08 17:14:55 +00:00
2018-10-18 13:09:41 +00:00
sidebar - > enable_buttons ( ! model . objects . empty ( ) & & ! export_in_progress & & model_fits ) ;
2018-10-04 09:12:55 +00:00
}
2018-11-21 14:28:35 +00:00
void Plater : : priv : : select_all ( )
{
2018-12-04 12:55:25 +00:00
view3D - > select_all ( ) ;
2018-12-03 12:29:07 +00:00
this - > sidebar - > obj_list ( ) - > update_selections ( ) ;
2018-11-21 14:28:35 +00:00
}
2018-10-08 17:14:55 +00:00
void Plater : : priv : : remove ( size_t obj_idx )
2018-10-04 09:12:55 +00:00
{
2018-10-08 17:14:55 +00:00
// Prevent toolpaths preview from rendering while we modify the Print object
preview - > set_enabled ( false ) ;
2018-12-04 12:55:25 +00:00
if ( view3D - > is_layers_editing_enabled ( ) )
view3D - > enable_layers_editing ( false ) ;
2018-10-22 13:18:56 +00:00
2018-10-08 17:14:55 +00:00
model . delete_object ( obj_idx ) ;
// Delete object from Sidebar list
2018-10-12 10:00:37 +00:00
sidebar - > obj_list ( ) - > delete_object_from_list ( obj_idx ) ;
2018-10-08 17:14:55 +00:00
object_list_changed ( ) ;
update ( ) ;
}
2018-11-13 13:17:35 +00:00
void Plater : : priv : : delete_object_from_model ( size_t obj_idx )
{
model . delete_object ( obj_idx ) ;
2018-11-14 10:22:13 +00:00
object_list_changed ( ) ;
update ( ) ;
2018-11-13 13:17:35 +00:00
}
2018-10-08 17:14:55 +00:00
void Plater : : priv : : reset ( )
{
2018-11-15 14:27:39 +00:00
project_filename . Clear ( ) ;
2018-10-04 09:12:55 +00:00
// Prevent toolpaths preview from rendering while we modify the Print object
preview - > set_enabled ( false ) ;
2018-12-04 12:55:25 +00:00
if ( view3D - > is_layers_editing_enabled ( ) )
view3D - > enable_layers_editing ( false ) ;
2018-10-22 13:18:56 +00:00
2018-11-08 13:23:17 +00:00
// Stop and reset the Print content.
this - > background_process . reset ( ) ;
2018-10-04 09:12:55 +00:00
model . clear_objects ( ) ;
// Delete all objects from list on c++ side
sidebar - > obj_list ( ) - > delete_all_objects_from_list ( ) ;
2018-10-08 17:14:55 +00:00
object_list_changed ( ) ;
2018-10-04 09:12:55 +00:00
update ( ) ;
2018-11-28 15:02:29 +00:00
2019-01-30 09:00:38 +00:00
// The hiding of the slicing results, if shown, is not taken care by the background process, so we do it here
this - > sidebar - > show_sliced_info_sizer ( false ) ;
2018-11-28 15:02:29 +00:00
auto & config = wxGetApp ( ) . preset_bundle - > project_config ;
config . option < ConfigOptionFloats > ( " colorprint_heights " ) - > values . clear ( ) ;
2018-10-04 09:12:55 +00:00
}
2018-10-18 13:09:41 +00:00
void Plater : : priv : : mirror ( Axis axis )
2018-10-09 07:35:19 +00:00
{
2018-12-04 12:55:25 +00:00
view3D - > mirror_selection ( axis ) ;
2018-10-09 07:35:19 +00:00
}
void Plater : : priv : : arrange ( )
{
2019-04-17 12:56:00 +00:00
if ( arranging ) { return ; }
arranging = true ;
Slic3r : : ScopeGuard arranging_guard ( [ this ] ( ) { arranging = false ; } ) ;
2018-11-12 13:52:52 +00:00
2019-02-03 13:06:13 +00:00
wxBusyCursor wait ;
2018-11-12 13:52:52 +00:00
this - > background_process . stop ( ) ;
2019-04-17 12:56:00 +00:00
2018-11-12 13:52:52 +00:00
unsigned count = 0 ;
for ( auto obj : model . objects ) count + = obj - > instances . size ( ) ;
auto prev_range = statusbar ( ) - > get_range ( ) ;
statusbar ( ) - > set_range ( count ) ;
auto statusfn = [ this , count ] ( unsigned st , const std : : string & msg ) {
/* // In case we would run the arrange asynchronously
wxCommandEvent event ( EVT_PROGRESS_BAR ) ;
event . SetInt ( st ) ;
event . SetString ( msg ) ;
wxQueueEvent ( this - > q , event . Clone ( ) ) ; */
statusbar ( ) - > set_progress ( count - st ) ;
statusbar ( ) - > set_status_text ( msg ) ;
2019-04-17 12:56:00 +00:00
// ok, this is dangerous, but we are protected by the flag
2018-11-21 10:07:08 +00:00
// 'arranging' and the arrange button is also disabled.
// This call is needed for the cancel button to work.
2018-11-12 13:52:52 +00:00
wxYieldIfNeeded ( ) ;
} ;
statusbar ( ) - > set_cancel_callback ( [ this , statusfn ] ( ) {
2019-04-17 12:56:00 +00:00
arranging = false ;
2018-11-12 13:52:52 +00:00
statusfn ( 0 , L ( " Arranging canceled " ) ) ;
} ) ;
static const std : : string arrangestr = L ( " Arranging " ) ;
// FIXME: I don't know how to obtain the minimum distance, it depends
// on printer technology. I guess the following should work but it crashes.
double dist = 6 ; //PrintConfig::min_object_distance(config);
2019-02-08 11:30:10 +00:00
if ( printer_technology = = ptFFF ) {
dist = PrintConfig : : min_object_distance ( config ) ;
}
2018-11-12 13:52:52 +00:00
2019-02-08 11:30:10 +00:00
auto min_obj_distance = coord_t ( dist / SCALING_FACTOR ) ;
2018-11-12 13:52:52 +00:00
const auto * bed_shape_opt = config - > opt < ConfigOptionPoints > ( " bed_shape " ) ;
assert ( bed_shape_opt ) ;
auto & bedpoints = bed_shape_opt - > values ;
Polyline bed ; bed . points . reserve ( bedpoints . size ( ) ) ;
for ( auto & v : bedpoints ) bed . append ( Point : : new_scale ( v ( 0 ) , v ( 1 ) ) ) ;
statusfn ( 0 , arrangestr ) ;
try {
arr : : BedShapeHint hint ;
// TODO: from Sasha from GUI or
hint . type = arr : : BedShapeType : : WHO_KNOWS ;
arr : : arrange ( model ,
min_obj_distance ,
bed ,
hint ,
false , // create many piles not just one pile
[ statusfn ] ( unsigned st ) { statusfn ( st , arrangestr ) ; } ,
2019-04-17 12:56:00 +00:00
[ this ] ( ) { return ! arranging ; } ) ;
2018-11-12 13:52:52 +00:00
} catch ( std : : exception & /*e*/ ) {
GUI : : show_error ( this - > q , L ( " Could not arrange model objects! "
" Some geometries may be invalid. " ) ) ;
}
statusfn ( 0 , L ( " Arranging done. " ) ) ;
statusbar ( ) - > set_range ( prev_range ) ;
statusbar ( ) - > set_cancel_callback ( ) ; // remove cancel button
2018-11-21 12:52:46 +00:00
// Do a full refresh of scene tree, including regenerating all the GLVolumes.
//FIXME The update function shall just reload the modified matrices.
update ( true ) ;
2018-10-09 07:35:19 +00:00
}
2018-11-22 15:04:21 +00:00
// This method will find an optimal orientation for the currently selected item
// Very similar in nature to the arrange method above...
void Plater : : priv : : sla_optimize_rotation ( ) {
// TODO: we should decide whether to allow arrange when the search is
// running we should probably disable explicit slicing and background
// processing
2019-04-17 12:56:00 +00:00
if ( rotoptimizing ) { return ; }
rotoptimizing = true ;
Slic3r : : ScopeGuard rotoptimizing_guard ( [ this ] ( ) { rotoptimizing = false ; } ) ;
2018-11-22 15:04:21 +00:00
int obj_idx = get_selected_object_idx ( ) ;
2019-04-17 12:56:00 +00:00
if ( obj_idx < 0 ) { return ; }
2019-04-04 14:03:23 +00:00
ModelObject * o = model . objects [ size_t ( obj_idx ) ] ;
2018-11-22 15:04:21 +00:00
background_process . stop ( ) ;
auto prev_range = statusbar ( ) - > get_range ( ) ;
statusbar ( ) - > set_range ( 100 ) ;
auto stfn = [ this ] ( unsigned st , const std : : string & msg ) {
2019-04-04 14:03:23 +00:00
statusbar ( ) - > set_progress ( int ( st ) ) ;
2018-11-22 15:04:21 +00:00
statusbar ( ) - > set_status_text ( msg ) ;
// could be problematic, but we need the cancel button.
wxYieldIfNeeded ( ) ;
} ;
statusbar ( ) - > set_cancel_callback ( [ this , stfn ] ( ) {
2019-04-17 12:56:00 +00:00
rotoptimizing = false ;
2018-11-22 15:04:21 +00:00
stfn ( 0 , L ( " Orientation search canceled " ) ) ;
} ) ;
auto r = sla : : find_best_rotation (
2018-11-27 10:09:25 +00:00
* o , .005f ,
2018-11-22 15:04:21 +00:00
[ stfn ] ( unsigned s ) { stfn ( s , L ( " Searching for optimal orientation " ) ) ; } ,
2019-04-17 12:56:00 +00:00
[ this ] ( ) { return ! rotoptimizing ; }
2018-11-22 15:04:21 +00:00
) ;
2019-04-04 14:03:23 +00:00
const auto * bed_shape_opt = config - > opt < ConfigOptionPoints > ( " bed_shape " ) ;
assert ( bed_shape_opt ) ;
auto & bedpoints = bed_shape_opt - > values ;
Polyline bed ; bed . points . reserve ( bedpoints . size ( ) ) ;
for ( auto & v : bedpoints ) bed . append ( Point : : new_scale ( v ( 0 ) , v ( 1 ) ) ) ;
double mindist = 6.0 ; // FIXME
double offs = mindist / 2.0 - EPSILON ;
2019-04-17 12:56:00 +00:00
if ( rotoptimizing ) // wasn't canceled
2019-04-04 14:03:23 +00:00
for ( ModelInstance * oi : o - > instances ) {
oi - > set_rotation ( { r [ X ] , r [ Y ] , r [ Z ] } ) ;
auto trchull = o - > convex_hull_2d ( oi - > get_transformation ( ) . get_matrix ( ) ) ;
namespace opt = libnest2d : : opt ;
opt : : StopCriteria stopcr ;
stopcr . relative_score_difference = 0.01 ;
stopcr . max_iterations = 10000 ;
stopcr . stop_score = 0.0 ;
opt : : GeneticOptimizer solver ( stopcr ) ;
Polygon pbed ( bed ) ;
auto bin = pbed . bounding_box ( ) ;
double binw = bin . size ( ) ( X ) * SCALING_FACTOR - offs ;
double binh = bin . size ( ) ( Y ) * SCALING_FACTOR - offs ;
auto result = solver . optimize_min ( [ & trchull , binw , binh ] ( double rot ) {
auto chull = trchull ;
chull . rotate ( rot ) ;
auto bb = chull . bounding_box ( ) ;
double bbw = bb . size ( ) ( X ) * SCALING_FACTOR ;
double bbh = bb . size ( ) ( Y ) * SCALING_FACTOR ;
auto wdiff = bbw - binw ;
auto hdiff = bbh - binh ;
double diff = 0 ;
if ( wdiff < 0 & & hdiff < 0 ) diff = wdiff + hdiff ;
if ( wdiff > 0 ) diff + = wdiff ;
if ( hdiff > 0 ) diff + = hdiff ;
return diff ;
} , opt : : initvals ( 0.0 ) , opt : : bound ( - PI / 2 , PI / 2 ) ) ;
double r = std : : get < 0 > ( result . optimum ) ;
Vec3d rt = oi - > get_rotation ( ) ; rt ( Z ) + = r ;
oi - > set_rotation ( rt ) ;
}
arr : : find_new_position ( model , o - > instances , coord_t ( mindist / SCALING_FACTOR ) , bed ) ;
2018-11-22 15:04:21 +00:00
2018-11-29 10:45:02 +00:00
// Correct the z offset of the object which was corrupted be the rotation
o - > ensure_on_bed ( ) ;
2018-11-22 15:04:21 +00:00
stfn ( 0 , L ( " Orientation found. " ) ) ;
statusbar ( ) - > set_range ( prev_range ) ;
statusbar ( ) - > set_cancel_callback ( ) ;
update ( true ) ;
}
2018-10-09 07:35:19 +00:00
void Plater : : priv : : split_object ( )
{
2018-10-19 13:27:19 +00:00
int obj_idx = get_selected_object_idx ( ) ;
if ( obj_idx = = - 1 )
return ;
// we clone model object because split_object() adds the split volumes
// into the same model object, thus causing duplicates when we call load_model_objects()
Model new_model = model ;
ModelObject * current_model_object = new_model . objects [ obj_idx ] ;
if ( current_model_object - > volumes . size ( ) > 1 )
{
Slic3r : : GUI : : warning_catcher ( q , _ ( L ( " The selected object can't be split because it contains more than one volume/material. " ) ) ) ;
return ;
}
2019-02-05 19:23:24 +00:00
wxBusyCursor wait ;
2018-10-19 13:27:19 +00:00
ModelObjectPtrs new_objects ;
current_model_object - > split ( & new_objects ) ;
if ( new_objects . size ( ) = = 1 )
Slic3r : : GUI : : warning_catcher ( q , _ ( L ( " The selected object couldn't be split because it contains only one part. " ) ) ) ;
else
{
2018-10-24 10:55:38 +00:00
unsigned int counter = 1 ;
2018-10-19 13:27:19 +00:00
for ( ModelObject * m : new_objects )
2018-10-24 10:55:38 +00:00
m - > name = current_model_object - > name + " _ " + std : : to_string ( counter + + ) ;
2018-10-19 13:27:19 +00:00
remove ( obj_idx ) ;
// load all model objects at once, otherwise the plate would be rearranged after each one
// causing original positions not to be kept
2018-10-31 10:24:56 +00:00
std : : vector < size_t > idxs = load_model_objects ( new_objects ) ;
// select newly added objects
for ( size_t idx : idxs )
{
get_selection ( ) . add_object ( ( unsigned int ) idx , false ) ;
}
2018-10-19 13:27:19 +00:00
}
2018-10-09 07:35:19 +00:00
}
2018-10-24 10:55:38 +00:00
void Plater : : priv : : split_volume ( )
{
2018-12-06 13:49:14 +00:00
wxGetApp ( ) . obj_list ( ) - > split ( ) ;
2018-10-24 10:55:38 +00:00
}
2018-10-09 07:35:19 +00:00
void Plater : : priv : : schedule_background_process ( )
{
2019-02-22 10:59:40 +00:00
delayed_error_message . clear ( ) ;
2018-10-17 09:12:38 +00:00
// Trigger the timer event after 0.5s
this - > background_process_timer . Start ( 500 , wxTIMER_ONE_SHOT ) ;
2019-01-21 16:02:16 +00:00
// Notify the Canvas3D that something has changed, so it may invalidate some of the layer editing stuff.
this - > view3D - > get_canvas3d ( ) - > set_config ( this - > config ) ;
2018-10-09 07:35:19 +00:00
}
2018-12-03 12:14:28 +00:00
void Plater : : priv : : update_print_volume_state ( )
{
BoundingBox bed_box_2D = get_extents ( Polygon : : new_scale ( this - > config - > opt < ConfigOptionPoints > ( " bed_shape " ) - > values ) ) ;
BoundingBoxf3 print_volume ( unscale ( bed_box_2D . min ( 0 ) , bed_box_2D . min ( 1 ) , 0.0 ) , unscale ( bed_box_2D . max ( 0 ) , bed_box_2D . max ( 1 ) , scale_ ( this - > config - > opt_float ( " max_print_height " ) ) ) ) ;
// Allow the objects to protrude below the print bed, only the part of the object above the print bed will be sliced.
print_volume . min ( 2 ) = - 1e10 ;
this - > q - > model ( ) . update_print_volume_state ( print_volume ) ;
}
2018-11-13 16:45:44 +00:00
// Update background processing thread from the current config and Model.
// Returns a bitmask of UpdateBackgroundProcessReturnState.
2019-01-10 15:06:24 +00:00
unsigned int Plater : : priv : : update_background_process ( bool force_validation )
2018-10-09 07:35:19 +00:00
{
2018-11-13 16:45:44 +00:00
// bitmap of enum UpdateBackgroundProcessReturnState
unsigned int return_state = 0 ;
2018-12-22 09:02:42 +00:00
// If the update_background_process() was not called by the timer, kill the timer,
// so the update_restart_background_process() will not be called again in vain.
2018-11-13 16:45:44 +00:00
this - > background_process_timer . Stop ( ) ;
2018-12-03 12:14:28 +00:00
// Update the "out of print bed" state of ModelInstances.
this - > update_print_volume_state ( ) ;
2019-02-19 13:57:59 +00:00
// The delayed error message is no more valid.
this - > delayed_error_message . clear ( ) ;
2018-10-17 09:12:38 +00:00
// Apply new config to the possibly running background task.
2018-12-22 09:02:42 +00:00
bool was_running = this - > background_process . running ( ) ;
2018-12-03 12:14:28 +00:00
Print : : ApplyStatus invalidated = this - > background_process . apply ( this - > q - > model ( ) , wxGetApp ( ) . preset_bundle - > full_config ( ) ) ;
2018-11-08 15:01:21 +00:00
2018-10-17 09:12:38 +00:00
// Just redraw the 3D canvas without reloading the scene to consume the update of the layer height profile.
2018-12-04 12:55:25 +00:00
if ( view3D - > is_layers_editing_enabled ( ) )
view3D - > get_wxglcanvas ( ) - > Refresh ( ) ;
2018-10-23 20:53:43 +00:00
if ( invalidated = = Print : : APPLY_STATUS_INVALIDATED ) {
// Some previously calculated data on the Print was invalidated.
// Hide the slicing results, as the current slicing status is no more valid.
2018-10-31 11:26:57 +00:00
this - > sidebar - > show_sliced_info_sizer ( false ) ;
2018-10-23 20:53:43 +00:00
// Reset preview canvases. If the print has been invalidated, the preview canvases will be cleared.
// Otherwise they will be just refreshed.
2019-04-09 08:41:42 +00:00
if ( this - > preview ! = nullptr )
// If the preview is not visible, the following line just invalidates the preview,
// but the G-code paths or SLA preview are calculated first once the preview is made visible.
this - > preview - > reload_print ( ) ;
// In FDM mode, we need to reload the 3D scene because of the wipe tower preview box.
// In SLA mode, we need to reload the 3D scene every time to show the support structures.
if ( this - > printer_technology = = ptSLA | | ( this - > printer_technology = = ptFFF & & this - > config - > opt_bool ( " wipe_tower " ) ) )
return_state | = UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE ;
2018-10-17 09:12:38 +00:00
}
2018-11-13 16:45:44 +00:00
2019-01-10 15:06:24 +00:00
if ( ( invalidated ! = Print : : APPLY_STATUS_UNCHANGED | | force_validation ) & & ! this - > background_process . empty ( ) ) {
// The state of the Print changed, and it is non-zero. Let's validate it and give the user feedback on errors.
2018-11-13 16:45:44 +00:00
std : : string err = this - > background_process . validate ( ) ;
if ( err . empty ( ) ) {
2018-12-22 09:02:42 +00:00
if ( invalidated ! = Print : : APPLY_STATUS_UNCHANGED & & this - > background_processing_enabled ( ) )
2018-11-13 16:45:44 +00:00
return_state | = UPDATE_BACKGROUND_PROCESS_RESTART ;
} else {
// The print is not valid.
2019-02-19 13:57:59 +00:00
// Only show the error message immediately, if the top level parent of this window is active.
auto p = dynamic_cast < wxWindow * > ( this - > q ) ;
while ( p - > GetParent ( ) )
p = p - > GetParent ( ) ;
auto * top_level_wnd = dynamic_cast < wxTopLevelWindow * > ( p ) ;
if ( top_level_wnd & & top_level_wnd - > IsActive ( ) ) {
// The error returned from the Print needs to be translated into the local language.
GUI : : show_error ( this - > q , _ ( err ) ) ;
} else {
// Show the error message once the main window gets activated.
this - > delayed_error_message = _ ( err ) ;
}
2018-11-13 16:45:44 +00:00
return_state | = UPDATE_BACKGROUND_PROCESS_INVALID ;
}
}
2018-12-22 09:02:42 +00:00
2019-01-10 15:06:24 +00:00
if ( invalidated ! = Print : : APPLY_STATUS_UNCHANGED & & was_running & & ! this - > background_process . running ( ) & &
2018-12-22 09:02:42 +00:00
( return_state & UPDATE_BACKGROUND_PROCESS_RESTART ) = = 0 ) {
// The background processing was killed and it will not be restarted.
wxCommandEvent evt ( EVT_PROCESS_COMPLETED ) ;
evt . SetInt ( - 1 ) ;
// Post the "canceled" callback message, so that it will be processed after any possible pending status bar update messages.
wxQueueEvent ( GUI : : wxGetApp ( ) . mainframe - > m_plater , evt . Clone ( ) ) ;
}
2019-03-01 10:00:34 +00:00
if ( ( return_state & UPDATE_BACKGROUND_PROCESS_INVALID ) ! = 0 )
{
2019-03-12 08:41:57 +00:00
// Validation of the background data failed.
2019-03-01 10:00:34 +00:00
const wxString invalid_str = _ ( L ( " Invalid data " ) ) ;
for ( auto btn : { ActionButtonType : : abReslice , ActionButtonType : : abSendGCode , ActionButtonType : : abExport } )
sidebar - > set_btn_label ( btn , invalid_str ) ;
}
else
{
2019-03-12 08:41:57 +00:00
// Background data is valid.
2019-03-01 10:00:34 +00:00
if ( ( return_state & UPDATE_BACKGROUND_PROCESS_RESTART ) ! = 0 | |
( return_state & UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE ) ! = 0 )
2019-05-04 00:07:07 +00:00
this - > statusbar ( ) - > set_status_text ( _ ( L ( " Ready to slice " ) ) ) ;
2019-03-01 10:00:34 +00:00
sidebar - > set_btn_label ( ActionButtonType : : abExport , _ ( label_btn_export ) ) ;
2019-03-12 08:41:57 +00:00
sidebar - > set_btn_label ( ActionButtonType : : abSendGCode , _ ( label_btn_send ) ) ;
2019-03-01 10:00:34 +00:00
const wxString slice_string = background_process . running ( ) & & wxGetApp ( ) . get_mode ( ) = = comSimple ?
_ ( L ( " Slicing " ) ) + dots : _ ( L ( " Slice now " ) ) ;
sidebar - > set_btn_label ( ActionButtonType : : abReslice , slice_string ) ;
if ( background_process . finished ( ) )
show_action_buttons ( false ) ;
2019-03-11 09:23:59 +00:00
else if ( ! background_process . empty ( ) & &
! background_process . running ( ) ) /* Do not update buttons if background process is running
* This condition is important for SLA mode especially ,
* when this function is called several times during calculations
* */
2019-03-01 10:00:34 +00:00
show_action_buttons ( true ) ;
}
2018-11-13 16:45:44 +00:00
return return_state ;
2018-10-09 07:35:19 +00:00
}
2018-12-22 09:02:42 +00:00
// Restart background processing thread based on a bitmask of UpdateBackgroundProcessReturnState.
bool Plater : : priv : : restart_background_process ( unsigned int state )
{
2019-04-17 12:56:00 +00:00
if ( arranging | | rotoptimizing ) {
// Avoid a race condition
return false ;
}
2018-12-22 09:02:42 +00:00
if ( ! this - > background_process . empty ( ) & &
( state & priv : : UPDATE_BACKGROUND_PROCESS_INVALID ) = = 0 & &
( ( ( state & UPDATE_BACKGROUND_PROCESS_FORCE_RESTART ) ! = 0 & & ! this - > background_process . finished ( ) ) | |
( state & UPDATE_BACKGROUND_PROCESS_FORCE_EXPORT ) ! = 0 | |
( state & UPDATE_BACKGROUND_PROCESS_RESTART ) ! = 0 ) ) {
// The print is valid and it can be started.
if ( this - > background_process . start ( ) ) {
this - > statusbar ( ) - > set_cancel_callback ( [ this ] ( ) {
2019-05-04 00:07:07 +00:00
this - > statusbar ( ) - > set_status_text ( _ ( L ( " Cancelling " ) ) ) ;
2018-12-22 09:02:42 +00:00
this - > background_process . stop ( ) ;
} ) ;
return true ;
}
}
return false ;
}
2018-12-11 09:33:11 +00:00
void Plater : : priv : : export_gcode ( fs : : path output_path , PrintHostJob upload_job )
{
wxCHECK_RET ( ! ( output_path . empty ( ) & & upload_job . empty ( ) ) , " export_gcode: output_path and upload_job empty " ) ;
if ( model . objects . empty ( ) )
return ;
if ( background_process . is_export_scheduled ( ) ) {
GUI : : show_error ( q , _ ( L ( " Another export job is currently running. " ) ) ) ;
return ;
}
// bitmask of UpdateBackgroundProcessReturnState
2019-01-10 15:06:24 +00:00
unsigned int state = update_background_process ( true ) ;
2018-12-11 09:33:11 +00:00
if ( state & priv : : UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE )
view3D - > reload_scene ( false ) ;
2019-01-03 11:59:06 +00:00
2018-12-11 09:33:11 +00:00
if ( ( state & priv : : UPDATE_BACKGROUND_PROCESS_INVALID ) ! = 0 )
return ;
if ( ! output_path . empty ( ) ) {
background_process . schedule_export ( output_path . string ( ) ) ;
} else {
background_process . schedule_upload ( std : : move ( upload_job ) ) ;
}
2019-02-25 09:21:12 +00:00
// If the SLA processing of just a single object's supports is running, restart slicing for the whole object.
this - > background_process . set_task ( PrintBase : : TaskParams ( ) ) ;
2018-12-22 09:02:42 +00:00
this - > restart_background_process ( priv : : UPDATE_BACKGROUND_PROCESS_FORCE_EXPORT ) ;
2018-12-11 09:33:11 +00:00
}
2019-02-03 09:41:14 +00:00
unsigned int Plater : : priv : : update_restart_background_process ( bool force_update_scene , bool force_update_preview )
2018-10-09 07:35:19 +00:00
{
2018-11-13 16:45:44 +00:00
// bitmask of UpdateBackgroundProcessReturnState
2019-01-10 15:06:24 +00:00
unsigned int state = this - > update_background_process ( false ) ;
2018-12-22 09:02:42 +00:00
if ( force_update_scene | | ( state & UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE ) ! = 0 )
2018-12-04 12:55:25 +00:00
view3D - > reload_scene ( false ) ;
2019-01-03 11:59:06 +00:00
2018-12-22 09:02:42 +00:00
if ( force_update_preview )
this - > preview - > reload_print ( ) ;
this - > restart_background_process ( state ) ;
2019-02-03 09:41:14 +00:00
return state ;
2018-10-09 07:35:19 +00:00
}
2018-12-06 14:40:41 +00:00
void Plater : : priv : : update_fff_scene ( )
{
if ( this - > preview ! = nullptr )
this - > preview - > reload_print ( ) ;
// In case this was MM print, wipe tower bounding box on 3D tab might need redrawing with exact depth:
view3D - > reload_scene ( true ) ;
}
2018-11-23 11:47:32 +00:00
void Plater : : priv : : update_sla_scene ( )
{
// Update the SLAPrint from the current Model, so that the reload_scene()
// pulls the correct data.
delayed_scene_refresh = false ;
2018-12-22 09:02:42 +00:00
this - > update_restart_background_process ( true , true ) ;
2018-11-23 11:47:32 +00:00
}
2018-10-09 07:35:19 +00:00
void Plater : : priv : : reload_from_disk ( )
{
2018-12-05 14:22:03 +00:00
const auto & selection = get_selection ( ) ;
const auto obj_orig_idx = selection . get_object_idx ( ) ;
if ( selection . is_wipe_tower ( ) | | obj_orig_idx = = - 1 ) { return ; }
2018-10-09 07:35:19 +00:00
2018-12-05 14:22:03 +00:00
auto * object_orig = model . objects [ obj_orig_idx ] ;
std : : vector < fs : : path > input_paths ( 1 , object_orig - > input_file ) ;
const auto new_idxs = load_files ( input_paths , true , false ) ;
for ( const auto idx : new_idxs ) {
ModelObject * object = model . objects [ idx ] ;
object - > clear_instances ( ) ;
for ( const ModelInstance * instance : object_orig - > instances ) {
object - > add_instance ( * instance ) ;
}
if ( object - > volumes . size ( ) = = object_orig - > volumes . size ( ) ) {
for ( size_t i = 0 ; i < object - > volumes . size ( ) ; i + + ) {
object - > volumes [ i ] - > config . apply ( object_orig - > volumes [ i ] - > config ) ;
}
}
2019-01-21 09:06:51 +00:00
// XXX: Restore more: layer_height_ranges, layer_height_profile (?)
2018-12-05 14:22:03 +00:00
}
remove ( obj_orig_idx ) ;
2018-10-09 07:35:19 +00:00
}
2019-01-30 15:27:07 +00:00
void Plater : : priv : : fix_through_netfabb ( const int obj_idx , const int vol_idx /* = -1*/ )
2018-10-09 07:35:19 +00:00
{
2018-11-07 12:40:24 +00:00
if ( obj_idx < 0 )
return ;
2019-02-03 21:14:34 +00:00
fix_model_by_win10_sdk_gui ( * model . objects [ obj_idx ] , vol_idx ) ;
this - > object_list_changed ( ) ;
this - > update ( ) ;
this - > schedule_background_process ( ) ;
2018-10-09 07:35:19 +00:00
}
2018-12-04 12:55:25 +00:00
void Plater : : priv : : set_current_panel ( wxPanel * panel )
{
if ( std : : find ( panels . begin ( ) , panels . end ( ) , panel ) = = panels . end ( ) )
return ;
2019-03-08 07:29:54 +00:00
# ifdef __WXMAC__
2019-03-07 14:44:25 +00:00
bool force_render = ( current_panel ! = nullptr ) ;
2019-03-08 07:29:54 +00:00
# endif // __WXMAC__
2019-03-07 14:44:25 +00:00
2018-12-04 12:55:25 +00:00
if ( current_panel = = panel )
return ;
current_panel = panel ;
2018-12-06 12:44:38 +00:00
// to reduce flickering when changing view, first set as visible the new current panel
2018-12-04 12:55:25 +00:00
for ( wxPanel * p : panels )
{
2018-12-06 12:44:38 +00:00
if ( p = = current_panel )
2019-03-07 14:44:25 +00:00
{
2019-03-08 07:29:54 +00:00
# ifdef __WXMAC__
// On Mac we need also to force a render to avoid flickering when changing view
2019-03-07 14:44:25 +00:00
if ( force_render )
{
if ( p = = view3D )
dynamic_cast < View3D * > ( p ) - > get_canvas3d ( ) - > render ( ) ;
else if ( p = = preview )
dynamic_cast < Preview * > ( p ) - > get_canvas3d ( ) - > render ( ) ;
}
2019-03-08 07:29:54 +00:00
# endif // __WXMAC__
2018-12-06 12:44:38 +00:00
p - > Show ( ) ;
2019-03-07 14:44:25 +00:00
}
2018-12-06 12:44:38 +00:00
}
// then set to invisible the other
for ( wxPanel * p : panels )
{
if ( p ! = current_panel )
p - > Hide ( ) ;
2018-12-04 12:55:25 +00:00
}
panel_sizer - > Layout ( ) ;
if ( current_panel = = view3D )
{
if ( view3D - > is_reload_delayed ( ) )
{
// Delayed loading of the 3D scene.
if ( this - > printer_technology = = ptSLA )
{
// Update the SLAPrint from the current Model, so that the reload_scene()
// pulls the correct data.
2018-12-22 09:02:42 +00:00
this - > update_restart_background_process ( true , false ) ;
} else
view3D - > reload_scene ( true ) ;
2018-12-04 12:55:25 +00:00
}
// sets the canvas as dirty to force a render at the 1st idle event (wxWidgets IsShownOnScreen() is buggy and cannot be used reliably)
view3D - > set_as_dirty ( ) ;
2018-12-21 09:43:22 +00:00
view_toolbar . select_item ( " 3D " ) ;
2018-12-04 12:55:25 +00:00
}
else if ( current_panel = = preview )
{
2018-12-11 16:49:31 +00:00
this - > q - > reslice ( ) ;
2019-02-28 14:27:03 +00:00
// keeps current gcode preview, if any
2019-03-18 13:07:55 +00:00
preview - > reload_print ( true ) ;
2018-12-04 12:55:25 +00:00
preview - > set_canvas_as_dirty ( ) ;
2018-12-21 09:43:22 +00:00
view_toolbar . select_item ( " Preview " ) ;
2018-12-04 12:55:25 +00:00
}
2018-12-21 10:39:37 +00:00
current_panel - > SetFocusFromKbd ( ) ;
2018-12-04 12:55:25 +00:00
}
2018-09-17 10:15:11 +00:00
void Plater : : priv : : on_select_preset ( wxCommandEvent & evt )
{
auto preset_type = static_cast < Preset : : Type > ( evt . GetInt ( ) ) ;
2018-10-10 11:53:45 +00:00
auto * combo = static_cast < PresetComboBox * > ( evt . GetEventObject ( ) ) ;
2018-09-17 10:15:11 +00:00
2018-10-10 11:53:45 +00:00
auto idx = combo - > get_extruder_idx ( ) ;
2018-10-09 10:41:05 +00:00
2018-10-15 09:39:48 +00:00
//! Because of The MSW and GTK version of wxBitmapComboBox derived from wxComboBox,
//! but the OSX version derived from wxOwnerDrawnCombo.
//! So, to get selected string we do
//! combo->GetString(combo->GetSelection())
//! instead of
2019-01-03 13:34:53 +00:00
//! combo->GetStringSelection().ToUTF8().data());
2018-10-15 09:39:48 +00:00
2019-03-13 12:13:18 +00:00
const std : : string & selected_string = combo - > GetString ( combo - > GetSelection ( ) ) . ToUTF8 ( ) . data ( ) ;
2018-10-15 09:39:48 +00:00
2018-09-17 10:15:11 +00:00
if ( preset_type = = Preset : : TYPE_FILAMENT ) {
2018-10-15 09:39:48 +00:00
wxGetApp ( ) . preset_bundle - > set_filament_preset ( idx , selected_string ) ;
2018-09-17 10:15:11 +00:00
}
// TODO: ?
2018-10-09 10:41:05 +00:00
if ( preset_type = = Preset : : TYPE_FILAMENT & & sidebar - > is_multifilament ( ) ) {
2018-10-10 11:53:45 +00:00
// Only update the platter UI for the 2nd and other filaments.
2019-04-23 14:33:06 +00:00
wxGetApp ( ) . preset_bundle - > update_platter_filament_ui ( idx , combo ) ;
2018-10-10 11:53:45 +00:00
}
else {
2019-03-13 12:13:18 +00:00
wxWindowUpdateLocker noUpdates ( sidebar - > presets_panel ( ) ) ;
wxGetApp ( ) . get_tab ( preset_type ) - > select_preset ( selected_string ) ;
2018-09-17 10:15:11 +00:00
}
2018-10-15 09:39:48 +00:00
// update plater with new config
2018-10-17 09:12:38 +00:00
wxGetApp ( ) . plater ( ) - > on_config_change ( wxGetApp ( ) . preset_bundle - > full_config ( ) ) ;
2018-11-29 14:00:23 +00:00
if ( preset_type = = Preset : : TYPE_PRINTER )
wxGetApp ( ) . obj_list ( ) - > update_settings_items ( ) ;
2018-09-17 10:15:11 +00:00
}
2018-11-20 12:22:26 +00:00
void Plater : : priv : : on_slicing_update ( SlicingStatusEvent & evt )
2018-10-09 07:35:19 +00:00
{
2019-03-14 14:11:27 +00:00
if ( evt . status . percent > = - 1 ) {
2019-04-17 12:56:00 +00:00
if ( arranging | | rotoptimizing ) {
// Avoid a race condition
return ;
}
2019-03-14 14:11:27 +00:00
this - > statusbar ( ) - > set_progress ( evt . status . percent ) ;
2019-05-04 00:07:07 +00:00
this - > statusbar ( ) - > set_status_text ( _ ( evt . status . text ) + wxString : : FromUTF8 ( " … " ) ) ;
2019-03-14 14:11:27 +00:00
}
2019-04-10 11:36:15 +00:00
if ( evt . status . flags & ( PrintBase : : SlicingStatus : : RELOAD_SCENE | | PrintBase : : SlicingStatus : : RELOAD_SLA_SUPPORT_POINTS ) ) {
2018-11-20 12:22:26 +00:00
switch ( this - > printer_technology ) {
case ptFFF :
2018-12-06 14:40:41 +00:00
this - > update_fff_scene ( ) ;
2018-11-20 12:22:26 +00:00
break ;
case ptSLA :
2019-04-10 11:36:15 +00:00
// If RELOAD_SLA_SUPPORT_POINTS, then the SLA gizmo is updated (reload_scene calls update_gizmos_data)
2018-12-04 12:55:25 +00:00
if ( view3D - > is_dragging ( ) )
2018-11-23 11:47:32 +00:00
delayed_scene_refresh = true ;
else
this - > update_sla_scene ( ) ;
2018-11-20 12:22:26 +00:00
break ;
}
2019-04-10 11:36:15 +00:00
} else if ( evt . status . flags & PrintBase : : SlicingStatus : : RELOAD_SLA_PREVIEW ) {
// Update the SLA preview. Only called if not RELOAD_SLA_SUPPORT_POINTS, as the block above will refresh the preview anyways.
2019-03-14 14:11:27 +00:00
this - > preview - > reload_print ( ) ;
}
2018-10-09 07:35:19 +00:00
}
2018-11-20 12:22:26 +00:00
void Plater : : priv : : on_slicing_completed ( wxCommandEvent & )
2018-09-17 10:15:11 +00:00
{
2018-11-20 12:22:26 +00:00
switch ( this - > printer_technology ) {
case ptFFF :
2018-12-06 14:40:41 +00:00
this - > update_fff_scene ( ) ;
2018-11-20 12:22:26 +00:00
break ;
case ptSLA :
2018-12-04 12:55:25 +00:00
if ( view3D - > is_dragging ( ) )
2018-11-23 11:47:32 +00:00
delayed_scene_refresh = true ;
else
this - > update_sla_scene ( ) ;
2018-11-20 12:22:26 +00:00
break ;
}
2018-09-17 10:15:11 +00:00
}
2018-10-23 13:27:31 +00:00
void Plater : : priv : : on_process_completed ( wxCommandEvent & evt )
2018-09-17 10:15:11 +00:00
{
2018-10-18 16:06:40 +00:00
// Stop the background task, wait until the thread goes into the "Idle" state.
// At this point of time the thread should be either finished or canceled,
// so the following call just confirms, that the produced data were consumed.
this - > background_process . stop ( ) ;
2018-10-23 13:27:31 +00:00
this - > statusbar ( ) - > reset_cancel_callback ( ) ;
this - > statusbar ( ) - > stop_busy ( ) ;
2019-03-11 08:48:24 +00:00
const bool canceled = evt . GetInt ( ) < 0 ;
const bool error = evt . GetInt ( ) = = 0 ;
const bool success = evt . GetInt ( ) > 0 ;
2018-10-23 13:27:31 +00:00
// Reset the "export G-code path" name, so that the automatic background processing will be enabled again.
this - > background_process . reset_export ( ) ;
2019-03-11 08:48:24 +00:00
if ( error ) {
2018-10-23 13:27:31 +00:00
wxString message = evt . GetString ( ) ;
if ( message . IsEmpty ( ) )
message = _ ( L ( " Export failed " ) ) ;
2019-03-11 08:48:24 +00:00
show_error ( q , message ) ;
2018-10-23 13:27:31 +00:00
this - > statusbar ( ) - > set_status_text ( message ) ;
2018-10-18 16:06:40 +00:00
}
2018-10-25 08:07:11 +00:00
if ( canceled )
2019-05-04 00:07:07 +00:00
this - > statusbar ( ) - > set_status_text ( _ ( L ( " Cancelled " ) ) ) ;
2018-10-18 16:06:40 +00:00
2018-10-31 11:26:57 +00:00
this - > sidebar - > show_sliced_info_sizer ( success ) ;
2018-10-18 16:06:40 +00:00
2018-12-04 10:14:39 +00:00
// This updates the "Slice now", "Export G-code", "Arrange" buttons status.
// Namely, it refreshes the "Out of print bed" property of all the ModelObjects, and it enables
// the "Slice now" and "Export G-code" buttons based on their "out of bed" status.
this - > object_list_changed ( ) ;
2018-10-18 16:06:40 +00:00
// refresh preview
2018-11-13 16:45:44 +00:00
switch ( this - > printer_technology ) {
case ptFFF :
2018-12-06 14:40:41 +00:00
this - > update_fff_scene ( ) ;
2018-11-13 16:45:44 +00:00
break ;
case ptSLA :
2018-12-04 12:55:25 +00:00
if ( view3D - > is_dragging ( ) )
2018-11-23 11:47:32 +00:00
delayed_scene_refresh = true ;
else
this - > update_sla_scene ( ) ;
2018-11-13 16:45:44 +00:00
break ;
2018-11-12 16:35:57 +00:00
}
2019-03-01 10:00:34 +00:00
2019-03-08 14:40:28 +00:00
if ( canceled ) {
if ( wxGetApp ( ) . get_mode ( ) = = comSimple )
sidebar - > set_btn_label ( ActionButtonType : : abReslice , " Slice now " ) ;
show_action_buttons ( true ) ;
}
else if ( wxGetApp ( ) . get_mode ( ) = = comSimple )
2019-03-01 10:00:34 +00:00
show_action_buttons ( false ) ;
2018-09-17 10:15:11 +00:00
}
void Plater : : priv : : on_layer_editing_toggled ( bool enable )
{
2018-12-04 12:55:25 +00:00
view3D - > enable_layers_editing ( enable ) ;
view3D - > set_as_dirty ( ) ;
2018-09-17 10:15:11 +00:00
}
2018-10-03 09:34:39 +00:00
void Plater : : priv : : on_action_add ( SimpleEvent & )
2018-09-17 10:15:11 +00:00
{
2018-10-17 10:17:25 +00:00
if ( q ! = nullptr )
2018-11-15 14:27:39 +00:00
q - > add_model ( ) ;
2018-09-17 10:15:11 +00:00
}
2018-10-24 10:55:38 +00:00
void Plater : : priv : : on_action_split_objects ( SimpleEvent & )
2018-10-04 09:12:55 +00:00
{
2018-10-19 13:27:19 +00:00
split_object ( ) ;
2018-10-04 09:12:55 +00:00
}
2018-10-24 10:55:38 +00:00
void Plater : : priv : : on_action_split_volumes ( SimpleEvent & )
{
split_volume ( ) ;
}
2018-10-04 09:12:55 +00:00
void Plater : : priv : : on_action_layersediting ( SimpleEvent & )
{
2019-03-14 12:54:05 +00:00
view3D - > enable_layers_editing ( ! view3D - > is_layers_editing_enabled ( ) ) ;
2018-10-04 09:12:55 +00:00
}
2018-10-16 14:04:19 +00:00
void Plater : : priv : : on_object_select ( SimpleEvent & evt )
{
wxGetApp ( ) . obj_list ( ) - > update_selections ( ) ;
2018-12-17 14:44:30 +00:00
selection_changed ( ) ;
2018-10-16 14:04:19 +00:00
}
2018-10-09 15:14:59 +00:00
2018-10-17 10:17:25 +00:00
void Plater : : priv : : on_right_click ( Vec2dEvent & evt )
2018-10-08 17:55:30 +00:00
{
2018-10-17 10:17:25 +00:00
int obj_idx = get_selected_object_idx ( ) ;
if ( obj_idx = = - 1 )
return ;
2018-12-07 16:50:48 +00:00
wxMenu * menu = printer_technology = = ptSLA ? & sla_object_menu :
2019-01-25 09:34:32 +00:00
get_selection ( ) . is_single_full_instance ( ) ? // show "Object menu" for each FullInstance instead of FullObject
2018-12-13 12:19:11 +00:00
& object_menu : & part_menu ;
2018-12-07 16:50:48 +00:00
sidebar - > obj_list ( ) - > append_menu_item_settings ( menu ) ;
2019-03-28 15:28:34 +00:00
if ( printer_technology ! = ptSLA )
sidebar - > obj_list ( ) - > append_menu_item_change_extruder ( menu ) ;
if ( menu ! = & part_menu )
{
/* Remove/Prepend "increase/decrease instances" menu items according to the view mode.
* Suppress to show those items for a Simple mode
*/
const MenuIdentifier id = printer_technology = = ptSLA ? miObjectSLA : miObjectFFF ;
if ( wxGetApp ( ) . get_mode ( ) = = comSimple ) {
if ( menu - > FindItem ( _ ( L ( " Increase copies " ) ) ) ! = wxNOT_FOUND )
{
/* Detach an items from the menu, but don't delete them
* so that they can be added back later
* ( after switching to the Advanced / Expert mode )
*/
menu - > Remove ( items_increase [ id ] ) ;
menu - > Remove ( items_decrease [ id ] ) ;
menu - > Remove ( items_set_number_of_copies [ id ] ) ;
}
2019-03-19 08:51:50 +00:00
}
2019-03-28 15:28:34 +00:00
else {
if ( menu - > FindItem ( _ ( L ( " Increase copies " ) ) ) = = wxNOT_FOUND )
{
// Prepend items to the menu, if those aren't not there
menu - > Prepend ( items_set_number_of_copies [ id ] ) ;
menu - > Prepend ( items_decrease [ id ] ) ;
menu - > Prepend ( items_increase [ id ] ) ;
}
2019-03-19 08:51:50 +00:00
}
}
2019-02-25 09:35:16 +00:00
if ( q ! = nullptr ) {
# ifdef __linux__
// For some reason on Linux the menu isn't displayed if position is specified
// (even though the position is sane).
q - > PopupMenu ( menu ) ;
# else
2018-12-07 16:50:48 +00:00
q - > PopupMenu ( menu , ( int ) evt . data . x ( ) , ( int ) evt . data . y ( ) ) ;
2019-02-25 09:35:16 +00:00
# endif
}
2018-10-08 17:55:30 +00:00
}
2018-10-09 15:14:59 +00:00
void Plater : : priv : : on_wipetower_moved ( Vec3dEvent & evt )
2018-10-08 17:55:30 +00:00
{
2018-10-09 15:14:59 +00:00
DynamicPrintConfig cfg ;
cfg . opt < ConfigOptionFloat > ( " wipe_tower_x " , true ) - > value = evt . data ( 0 ) ;
cfg . opt < ConfigOptionFloat > ( " wipe_tower_y " , true ) - > value = evt . data ( 1 ) ;
2018-11-19 12:17:14 +00:00
wxGetApp ( ) . get_tab ( Preset : : TYPE_PRINT ) - > load_config ( cfg ) ;
2018-10-08 17:55:30 +00:00
}
void Plater : : priv : : on_update_geometry ( Vec3dsEvent < 2 > & )
{
// TODO
}
2018-11-23 11:47:32 +00:00
// Update the scene from the background processing,
// if the update message was received during mouse manipulation.
void Plater : : priv : : on_3dcanvas_mouse_dragging_finished ( SimpleEvent & )
{
if ( this - > delayed_scene_refresh ) {
this - > delayed_scene_refresh = false ;
this - > update_sla_scene ( ) ;
}
}
2018-10-17 10:17:25 +00:00
bool Plater : : priv : : init_object_menu ( )
{
2019-03-19 08:51:50 +00:00
items_increase . reserve ( 2 ) ;
items_decrease . reserve ( 2 ) ;
items_set_number_of_copies . reserve ( 2 ) ;
2018-12-07 16:50:48 +00:00
init_common_menu ( & object_menu ) ;
complit_init_object_menu ( ) ;
init_common_menu ( & sla_object_menu ) ;
complit_init_sla_object_menu ( ) ;
init_common_menu ( & part_menu , true ) ;
complit_init_part_menu ( ) ;
return true ;
}
2019-05-03 07:44:19 +00:00
void Plater : : priv : : msw_rescale_object_menu ( )
{
for ( MenuWithSeparators * menu : { & object_menu , & sla_object_menu , & part_menu } )
msw_rescale_menu ( dynamic_cast < wxMenu * > ( menu ) ) ;
}
2018-12-07 16:50:48 +00:00
bool Plater : : priv : : init_common_menu ( wxMenu * menu , const bool is_part /* = false*/ )
{
2019-03-08 16:00:56 +00:00
wxMenuItem * item_delete = nullptr ;
if ( is_part ) {
item_delete = append_menu_item ( menu , wxID_ANY , _ ( L ( " Delete " ) ) + " \t Del " , _ ( L ( " Remove the selected object " ) ) ,
2019-04-12 10:08:52 +00:00
[ this ] ( wxCommandEvent & ) { q - > remove_selected ( ) ; } , " delete " ) ;
2019-04-04 13:13:43 +00:00
sidebar - > obj_list ( ) - > append_menu_item_export_stl ( menu ) ;
}
else {
2019-01-21 11:34:28 +00:00
wxMenuItem * item_increase = append_menu_item ( menu , wxID_ANY , _ ( L ( " Increase copies " ) ) + " \t + " , _ ( L ( " Place one more copy of the selected object " ) ) ,
2019-04-12 10:08:52 +00:00
[ this ] ( wxCommandEvent & ) { q - > increase_instances ( ) ; } , " add_copies " ) ;
2019-01-21 11:34:28 +00:00
wxMenuItem * item_decrease = append_menu_item ( menu , wxID_ANY , _ ( L ( " Decrease copies " ) ) + " \t - " , _ ( L ( " Remove one copy of the selected object " ) ) ,
2019-04-12 10:08:52 +00:00
[ this ] ( wxCommandEvent & ) { q - > decrease_instances ( ) ; } , " remove_copies " ) ;
2019-01-21 11:34:28 +00:00
wxMenuItem * item_set_number_of_copies = append_menu_item ( menu , wxID_ANY , _ ( L ( " Set number of copies " ) ) + dots , _ ( L ( " Change the number of copies of the selected object " ) ) ,
2019-04-12 10:08:52 +00:00
[ this ] ( wxCommandEvent & ) { q - > set_number_of_copies ( ) ; } , " number_of_copies " ) ;
2019-03-19 08:51:50 +00:00
items_increase . push_back ( item_increase ) ;
items_decrease . push_back ( item_decrease ) ;
items_set_number_of_copies . push_back ( item_set_number_of_copies ) ;
2019-03-08 16:00:56 +00:00
// Delete menu was moved to be after +/- instace to make it more difficult to be selected by mistake.
item_delete = append_menu_item ( menu , wxID_ANY , _ ( L ( " Delete " ) ) + " \t Del " , _ ( L ( " Remove the selected object " ) ) ,
2019-04-12 10:08:52 +00:00
[ this ] ( wxCommandEvent & ) { q - > remove_selected ( ) ; } , " delete " ) ;
2019-01-22 15:40:10 +00:00
menu - > AppendSeparator ( ) ;
2019-01-23 15:01:37 +00:00
wxMenuItem * item_instance_to_object = sidebar - > obj_list ( ) - > append_menu_item_instance_to_object ( menu ) ;
2019-01-22 15:40:10 +00:00
2018-12-07 16:50:48 +00:00
if ( q ! = nullptr )
{
q - > Bind ( wxEVT_UPDATE_UI , [ this ] ( wxUpdateUIEvent & evt ) { evt . Enable ( can_increase_instances ( ) ) ; } , item_increase - > GetId ( ) ) ;
q - > Bind ( wxEVT_UPDATE_UI , [ this ] ( wxUpdateUIEvent & evt ) { evt . Enable ( can_decrease_instances ( ) ) ; } , item_decrease - > GetId ( ) ) ;
q - > Bind ( wxEVT_UPDATE_UI , [ this ] ( wxUpdateUIEvent & evt ) { evt . Enable ( can_increase_instances ( ) ) ; } , item_set_number_of_copies - > GetId ( ) ) ;
2019-01-22 15:40:10 +00:00
q - > Bind ( wxEVT_UPDATE_UI , [ this ] ( wxUpdateUIEvent & evt ) { evt . Enable ( can_set_instance_to_object ( ) ) ; } , item_instance_to_object - > GetId ( ) ) ;
2018-12-07 16:50:48 +00:00
}
2018-12-07 17:20:22 +00:00
menu - > AppendSeparator ( ) ;
append_menu_item ( menu , wxID_ANY , _ ( L ( " Reload from Disk " ) ) , _ ( L ( " Reload the selected file from Disk " ) ) ,
[ this ] ( wxCommandEvent & ) { reload_from_disk ( ) ; } ) ;
2019-04-05 09:30:49 +00:00
append_menu_item ( menu , wxID_ANY , _ ( L ( " Export as STL " ) ) + dots , _ ( L ( " Export the selected object as STL file " ) ) ,
2019-05-02 11:46:39 +00:00
[ this ] ( wxCommandEvent & ) { q - > export_stl ( false , true ) ; } ) ;
2019-04-04 13:13:43 +00:00
menu - > AppendSeparator ( ) ;
2018-12-07 16:50:48 +00:00
}
2018-10-17 12:26:13 +00:00
2019-04-24 14:04:47 +00:00
wxMenuItem * item_fix_through_netfabb = sidebar - > obj_list ( ) - > append_menu_item_fix_through_netfabb ( menu ) ;
2019-01-30 15:27:07 +00:00
2018-10-18 12:42:21 +00:00
wxMenu * mirror_menu = new wxMenu ( ) ;
if ( mirror_menu = = nullptr )
return false ;
append_menu_item ( mirror_menu , wxID_ANY , _ ( L ( " Along X axis " ) ) , _ ( L ( " Mirror the selected object along the X axis " ) ) ,
2019-04-12 15:10:04 +00:00
[ this ] ( wxCommandEvent & ) { mirror ( X ) ; } , " mark_X " , menu ) ;
2018-10-18 12:42:21 +00:00
append_menu_item ( mirror_menu , wxID_ANY , _ ( L ( " Along Y axis " ) ) , _ ( L ( " Mirror the selected object along the Y axis " ) ) ,
2019-04-12 15:10:04 +00:00
[ this ] ( wxCommandEvent & ) { mirror ( Y ) ; } , " mark_Y " , menu ) ;
2018-10-18 12:42:21 +00:00
append_menu_item ( mirror_menu , wxID_ANY , _ ( L ( " Along Z axis " ) ) , _ ( L ( " Mirror the selected object along the Z axis " ) ) ,
2019-04-12 15:10:04 +00:00
[ this ] ( wxCommandEvent & ) { mirror ( Z ) ; } , " mark_Z " , menu ) ;
2018-10-18 12:42:21 +00:00
2018-12-07 16:50:48 +00:00
wxMenuItem * item_mirror = append_submenu ( menu , mirror_menu , wxID_ANY , _ ( L ( " Mirror " ) ) , _ ( L ( " Mirror the selected object " ) ) ) ;
2018-10-18 12:42:21 +00:00
2019-03-08 16:00:56 +00:00
// ui updates needs to be bound to the parent panel
2018-12-07 16:50:48 +00:00
if ( q ! = nullptr )
{
q - > Bind ( wxEVT_UPDATE_UI , [ this ] ( wxUpdateUIEvent & evt ) { evt . Enable ( can_mirror ( ) ) ; } , item_mirror - > GetId ( ) ) ;
2019-03-14 12:54:05 +00:00
q - > Bind ( wxEVT_UPDATE_UI , [ this ] ( wxUpdateUIEvent & evt ) { evt . Enable ( can_delete ( ) ) ; } , item_delete - > GetId ( ) ) ;
2019-04-25 14:19:50 +00:00
if ( item_fix_through_netfabb )
q - > Bind ( wxEVT_UPDATE_UI , [ this ] ( wxUpdateUIEvent & evt ) { evt . Enable ( can_fix_through_netfabb ( ) ) ; } , item_fix_through_netfabb - > GetId ( ) ) ;
2018-12-07 16:50:48 +00:00
}
return true ;
}
bool Plater : : priv : : complit_init_object_menu ( )
{
2018-10-24 10:55:38 +00:00
wxMenu * split_menu = new wxMenu ( ) ;
if ( split_menu = = nullptr )
return false ;
wxMenuItem * item_split_objects = append_menu_item ( split_menu , wxID_ANY , _ ( L ( " To objects " ) ) , _ ( L ( " Split the selected object into individual objects " ) ) ,
2019-04-12 15:10:04 +00:00
[ this ] ( wxCommandEvent & ) { split_object ( ) ; } , " split_object_SMALL " , & object_menu ) ;
2018-10-24 10:55:38 +00:00
wxMenuItem * item_split_volumes = append_menu_item ( split_menu , wxID_ANY , _ ( L ( " To parts " ) ) , _ ( L ( " Split the selected object into individual sub-parts " ) ) ,
2019-04-12 10:08:52 +00:00
[ this ] ( wxCommandEvent & ) { split_volume ( ) ; } , " split_parts_SMALL " , & object_menu ) ;
2018-10-24 10:55:38 +00:00
2019-04-08 07:37:23 +00:00
wxMenuItem * item_split = append_submenu ( & object_menu , split_menu , wxID_ANY , _ ( L ( " Split " ) ) , _ ( L ( " Split the selected object " ) ) /*, "shape_ungroup.png"*/ ) ;
2018-12-07 16:50:48 +00:00
object_menu . AppendSeparator ( ) ;
2018-11-22 15:04:21 +00:00
2019-01-25 09:34:32 +00:00
// "Add (volumes)" popupmenu will be added later in append_menu_items_add_volume()
2018-11-22 15:04:21 +00:00
2018-10-17 12:26:13 +00:00
// ui updates needs to be binded to the parent panel
if ( q ! = nullptr )
{
2019-01-22 15:40:10 +00:00
q - > Bind ( wxEVT_UPDATE_UI , [ this ] ( wxUpdateUIEvent & evt ) { evt . Enable ( can_split ( ) ) ; } , item_split - > GetId ( ) ) ;
q - > Bind ( wxEVT_UPDATE_UI , [ this ] ( wxUpdateUIEvent & evt ) { evt . Enable ( can_split ( ) ) ; } , item_split_objects - > GetId ( ) ) ;
2019-03-19 08:51:50 +00:00
q - > Bind ( wxEVT_UPDATE_UI , [ this ] ( wxUpdateUIEvent & evt ) { evt . Enable ( can_split ( ) & & wxGetApp ( ) . get_mode ( ) > comSimple ) ; } , item_split_volumes - > GetId ( ) ) ;
2018-10-17 12:26:13 +00:00
}
2018-12-07 16:50:48 +00:00
return true ;
}
bool Plater : : priv : : complit_init_sla_object_menu ( )
{
wxMenuItem * item_split = append_menu_item ( & sla_object_menu , wxID_ANY , _ ( L ( " Split " ) ) , _ ( L ( " Split the selected object into individual objects " ) ) ,
2019-04-12 15:10:04 +00:00
[ this ] ( wxCommandEvent & ) { split_object ( ) ; } , " split_object_SMALL " ) ;
2018-12-07 16:50:48 +00:00
2019-01-25 09:34:32 +00:00
sla_object_menu . AppendSeparator ( ) ;
2018-12-07 16:50:48 +00:00
// Add the automatic rotation sub-menu
append_menu_item ( & sla_object_menu , wxID_ANY , _ ( L ( " Optimize orientation " ) ) , _ ( L ( " Optimize the rotation of the object for better print results. " ) ) ,
[ this ] ( wxCommandEvent & ) { sla_optimize_rotation ( ) ; } ) ;
// ui updates needs to be binded to the parent panel
if ( q ! = nullptr )
{
2019-01-22 15:40:10 +00:00
q - > Bind ( wxEVT_UPDATE_UI , [ this ] ( wxUpdateUIEvent & evt ) { evt . Enable ( can_split ( ) ) ; } , item_split - > GetId ( ) ) ;
2018-12-07 16:50:48 +00:00
}
return true ;
}
bool Plater : : priv : : complit_init_part_menu ( )
{
wxMenuItem * item_split = append_menu_item ( & part_menu , wxID_ANY , _ ( L ( " Split " ) ) , _ ( L ( " Split the selected object into individual sub-parts " ) ) ,
2019-04-12 10:08:52 +00:00
[ this ] ( wxCommandEvent & ) { split_volume ( ) ; } , " split_parts_SMALL " ) ;
2018-12-07 16:50:48 +00:00
2019-01-25 09:34:32 +00:00
part_menu . AppendSeparator ( ) ;
2018-12-07 16:50:48 +00:00
auto obj_list = sidebar - > obj_list ( ) ;
obj_list - > append_menu_item_change_type ( & part_menu ) ;
// ui updates needs to be binded to the parent panel
if ( q ! = nullptr )
{
2019-01-22 15:40:10 +00:00
q - > Bind ( wxEVT_UPDATE_UI , [ this ] ( wxUpdateUIEvent & evt ) { evt . Enable ( can_split ( ) ) ; } , item_split - > GetId ( ) ) ;
2018-12-07 16:50:48 +00:00
}
2018-10-17 10:17:25 +00:00
return true ;
}
2018-10-08 17:55:30 +00:00
2018-12-06 09:38:19 +00:00
void Plater : : priv : : init_view_toolbar ( )
{
2019-02-26 08:56:23 +00:00
# if !ENABLE_SVG_ICONS
2018-12-17 09:55:14 +00:00
ItemsIconsTexture : : Metadata icons_data ;
icons_data . filename = " view_toolbar.png " ;
icons_data . icon_size = 64 ;
2019-02-26 08:56:23 +00:00
# endif // !ENABLE_SVG_ICONS
2018-12-17 09:55:14 +00:00
BackgroundTexture : : Metadata background_data ;
background_data . filename = " toolbar_background.png " ;
background_data . left = 16 ;
background_data . top = 16 ;
background_data . right = 16 ;
background_data . bottom = 16 ;
2019-02-26 08:56:23 +00:00
# if ENABLE_SVG_ICONS
if ( ! view_toolbar . init ( background_data ) )
# else
2018-12-17 09:55:14 +00:00
if ( ! view_toolbar . init ( icons_data , background_data ) )
2019-02-26 08:56:23 +00:00
# endif // ENABLE_SVG_ICONS
2018-12-17 09:55:14 +00:00
return ;
view_toolbar . set_layout_orientation ( GLToolbar : : Layout : : Bottom ) ;
view_toolbar . set_border ( 5.0f ) ;
view_toolbar . set_gap_size ( 1.0f ) ;
GLToolbarItem : : Data item ;
item . name = " 3D " ;
2019-02-26 08:56:23 +00:00
# if ENABLE_SVG_ICONS
2019-03-04 13:21:52 +00:00
item . icon_filename = " editor.svg " ;
2019-02-26 08:56:23 +00:00
# endif // ENABLE_SVG_ICONS
2019-02-03 10:10:25 +00:00
item . tooltip = GUI : : L_str ( " 3D editor view " ) + " [ " + GUI : : shortkey_ctrl_prefix ( ) + " 5] " ;
2018-12-17 09:55:14 +00:00
item . sprite_id = 0 ;
2019-03-14 12:54:05 +00:00
item . action_callback = [ this ] ( ) { if ( this - > q ! = nullptr ) wxPostEvent ( this - > q , SimpleEvent ( EVT_GLVIEWTOOLBAR_3D ) ) ; } ;
2018-12-17 09:55:14 +00:00
item . is_toggable = false ;
if ( ! view_toolbar . add_item ( item ) )
2018-12-06 09:38:19 +00:00
return ;
2018-12-17 09:55:14 +00:00
item . name = " Preview " ;
2019-02-26 08:56:23 +00:00
# if ENABLE_SVG_ICONS
2019-03-04 13:21:52 +00:00
item . icon_filename = " preview.svg " ;
2019-02-26 08:56:23 +00:00
# endif // ENABLE_SVG_ICONS
2019-02-03 10:10:25 +00:00
item . tooltip = GUI : : L_str ( " Preview " ) + " [ " + GUI : : shortkey_ctrl_prefix ( ) + " 6] " ;
2018-12-17 09:55:14 +00:00
item . sprite_id = 1 ;
2019-03-14 12:54:05 +00:00
item . action_callback = [ this ] ( ) { if ( this - > q ! = nullptr ) wxPostEvent ( this - > q , SimpleEvent ( EVT_GLVIEWTOOLBAR_PREVIEW ) ) ; } ;
2018-12-17 09:55:14 +00:00
item . is_toggable = false ;
if ( ! view_toolbar . add_item ( item ) )
return ;
view_toolbar . select_item ( " 3D " ) ;
view_toolbar . set_enabled ( true ) ;
2018-12-06 09:38:19 +00:00
}
2019-01-22 15:40:10 +00:00
bool Plater : : priv : : can_set_instance_to_object ( ) const
{
const int obj_idx = get_selected_object_idx ( ) ;
return ( 0 < = obj_idx ) & & ( obj_idx < ( int ) model . objects . size ( ) ) & & ( model . objects [ obj_idx ] - > instances . size ( ) > 1 ) ;
}
2018-12-17 14:44:30 +00:00
bool Plater : : priv : : can_split ( ) const
2018-10-18 07:27:37 +00:00
{
2018-12-17 14:44:30 +00:00
return sidebar - > obj_list ( ) - > is_splittable ( ) ;
2018-10-18 07:27:37 +00:00
}
bool Plater : : priv : : layers_height_allowed ( ) const
{
2019-04-05 07:51:58 +00:00
if ( printer_technology ! = ptFFF )
return false ;
2018-10-18 07:27:37 +00:00
int obj_idx = get_selected_object_idx ( ) ;
2018-12-04 12:55:25 +00:00
return ( 0 < = obj_idx ) & & ( obj_idx < ( int ) model . objects . size ( ) ) & & config - > opt_bool ( " variable_layer_height " ) & & view3D - > is_layers_editing_allowed ( ) ;
2018-10-18 07:27:37 +00:00
}
2018-10-18 13:09:41 +00:00
bool Plater : : priv : : can_mirror ( ) const
2019-01-22 15:40:10 +00:00
{
2018-10-18 13:09:41 +00:00
return get_selection ( ) . is_from_single_instance ( ) ;
2019-01-22 15:40:10 +00:00
}
2019-02-19 14:15:27 +00:00
void Plater : : priv : : set_bed_shape ( const Pointfs & shape )
2018-10-18 07:27:37 +00:00
{
2019-02-19 14:15:27 +00:00
bool new_shape = bed . set_shape ( shape ) ;
if ( new_shape )
{
if ( view3D ) view3D - > bed_shape_changed ( ) ;
if ( preview ) preview - > bed_shape_changed ( ) ;
}
2018-10-18 07:27:37 +00:00
}
2019-03-14 12:54:05 +00:00
bool Plater : : priv : : can_delete ( ) const
2018-10-24 10:55:38 +00:00
{
2019-04-10 10:16:17 +00:00
return ! get_selection ( ) . is_empty ( ) & & ! get_selection ( ) . is_wipe_tower ( ) ;
2018-10-24 10:55:38 +00:00
}
2019-03-14 12:54:05 +00:00
bool Plater : : priv : : can_delete_all ( ) const
2018-10-18 07:27:37 +00:00
{
2019-03-14 12:54:05 +00:00
return ! model . objects . empty ( ) ;
2018-10-18 07:27:37 +00:00
}
2019-04-24 14:04:47 +00:00
bool Plater : : priv : : can_fix_through_netfabb ( ) const
{
int obj_idx = get_selected_object_idx ( ) ;
if ( obj_idx < 0 )
return false ;
return model . objects [ obj_idx ] - > get_mesh_errors_count ( ) > 0 ;
}
2019-03-14 12:54:05 +00:00
bool Plater : : priv : : can_increase_instances ( ) const
2018-12-17 14:44:30 +00:00
{
2019-04-17 12:56:00 +00:00
if ( arranging | | rotoptimizing ) {
return false ;
}
2019-03-14 12:54:05 +00:00
int obj_idx = get_selected_object_idx ( ) ;
return ( 0 < = obj_idx ) & & ( obj_idx < ( int ) model . objects . size ( ) ) ;
2018-12-17 14:44:30 +00:00
}
2019-03-14 12:54:05 +00:00
bool Plater : : priv : : can_decrease_instances ( ) const
2018-10-18 07:27:37 +00:00
{
2019-04-17 12:56:00 +00:00
if ( arranging | | rotoptimizing ) {
return false ;
}
2018-10-22 13:18:56 +00:00
int obj_idx = get_selected_object_idx ( ) ;
2019-03-14 12:54:05 +00:00
return ( 0 < = obj_idx ) & & ( obj_idx < ( int ) model . objects . size ( ) ) & & ( model . objects [ obj_idx ] - > instances . size ( ) > 1 ) ;
2018-10-18 07:27:37 +00:00
}
2018-10-18 13:09:41 +00:00
2019-03-14 12:54:05 +00:00
bool Plater : : priv : : can_split_to_objects ( ) const
2018-10-18 13:09:41 +00:00
{
2019-03-14 12:54:05 +00:00
return can_split ( ) ;
2018-10-18 13:09:41 +00:00
}
2019-03-14 12:54:05 +00:00
bool Plater : : priv : : can_split_to_volumes ( ) const
2018-10-18 13:09:41 +00:00
{
2019-03-14 12:54:05 +00:00
return ( printer_technology ! = ptSLA ) & & can_split ( ) ;
2018-10-18 13:09:41 +00:00
}
2019-03-14 12:54:05 +00:00
bool Plater : : priv : : can_arrange ( ) const
2018-10-18 13:09:41 +00:00
{
2019-04-17 12:56:00 +00:00
return ! model . objects . empty ( ) & & ! arranging ;
2018-10-18 07:27:37 +00:00
}
2018-10-08 17:55:30 +00:00
2019-03-14 12:54:05 +00:00
bool Plater : : priv : : can_layers_editing ( ) const
2019-02-19 14:15:27 +00:00
{
2019-03-14 12:54:05 +00:00
return layers_height_allowed ( ) ;
2019-02-19 14:15:27 +00:00
}
2018-12-07 16:50:48 +00:00
void Plater : : priv : : update_object_menu ( )
{
2019-01-25 12:16:32 +00:00
sidebar - > obj_list ( ) - > append_menu_items_add_volume ( & object_menu ) ;
2018-12-07 16:50:48 +00:00
}
2019-03-01 10:00:34 +00:00
void Plater : : priv : : show_action_buttons ( const bool is_ready_to_slice ) const
{
wxWindowUpdateLocker noUpdater ( sidebar ) ;
const auto prin_host_opt = config - > option < ConfigOptionString > ( " print_host " ) ;
const bool send_gcode_shown = prin_host_opt ! = nullptr & & ! prin_host_opt - > value . empty ( ) ;
// when a background processing is ON, export_btn and/or send_btn are showing
if ( wxGetApp ( ) . app_config - > get ( " background_processing " ) = = " 1 " )
{
sidebar - > show_reslice ( false ) ;
sidebar - > show_export ( true ) ;
sidebar - > show_send ( send_gcode_shown ) ;
}
else
{
sidebar - > show_reslice ( is_ready_to_slice ) ;
sidebar - > show_export ( ! is_ready_to_slice ) ;
sidebar - > show_send ( send_gcode_shown & & ! is_ready_to_slice ) ;
}
2019-03-12 10:39:16 +00:00
sidebar - > Layout ( ) ;
2019-03-01 10:00:34 +00:00
}
void Sidebar : : set_btn_label ( const ActionButtonType btn_type , const wxString & label ) const
{
switch ( btn_type )
{
case ActionButtonType : : abReslice : p - > btn_reslice - > SetLabelText ( label ) ; break ;
case ActionButtonType : : abExport : p - > btn_export_gcode - > SetLabelText ( label ) ; break ;
case ActionButtonType : : abSendGCode : p - > btn_send_gcode - > SetLabelText ( label ) ; break ;
}
}
2018-09-17 10:15:11 +00:00
// Plater / Public
Plater : : Plater ( wxWindow * parent , MainFrame * main_frame )
: wxPanel ( parent ) , p ( new priv ( this , main_frame ) )
{
// Initialization performed in the private c-tor
}
Plater : : ~ Plater ( )
{
}
2018-12-03 12:14:28 +00:00
Sidebar & Plater : : sidebar ( ) { return * p - > sidebar ; }
Model & Plater : : model ( ) { return p - > model ; }
const Print & Plater : : fff_print ( ) const { return p - > fff_print ; }
Print & Plater : : fff_print ( ) { return p - > fff_print ; }
const SLAPrint & Plater : : sla_print ( ) const { return p - > sla_print ; }
SLAPrint & Plater : : sla_print ( ) { return p - > sla_print ; }
2018-09-17 10:15:11 +00:00
2018-11-15 14:27:39 +00:00
void Plater : : load_project ( )
{
wxString input_file ;
wxGetApp ( ) . load_project ( this , input_file ) ;
if ( input_file . empty ( ) )
return ;
p - > reset ( ) ;
p - > project_filename = input_file ;
std : : vector < fs : : path > input_paths ;
2019-01-02 14:11:05 +00:00
input_paths . push_back ( into_path ( input_file ) ) ;
2018-11-15 14:27:39 +00:00
load_files ( input_paths ) ;
}
void Plater : : add_model ( )
2018-10-17 10:17:25 +00:00
{
wxArrayString input_files ;
2018-11-15 14:27:39 +00:00
wxGetApp ( ) . import_model ( this , input_files ) ;
if ( input_files . empty ( ) )
return ;
2018-10-17 10:17:25 +00:00
std : : vector < fs : : path > input_paths ;
for ( const auto & file : input_files ) {
2019-01-02 14:11:05 +00:00
input_paths . push_back ( into_path ( file ) ) ;
2018-10-17 10:17:25 +00:00
}
2018-11-16 08:26:41 +00:00
load_files ( input_paths , true , false ) ;
2018-10-17 10:17:25 +00:00
}
2018-11-16 08:26:41 +00:00
void Plater : : extract_config_from_project ( )
{
wxString input_file ;
wxGetApp ( ) . load_project ( this , input_file ) ;
if ( input_file . empty ( ) )
return ;
std : : vector < fs : : path > input_paths ;
2019-01-02 14:11:05 +00:00
input_paths . push_back ( into_path ( input_file ) ) ;
2018-11-16 08:26:41 +00:00
load_files ( input_paths , false , true ) ;
}
void Plater : : load_files ( const std : : vector < fs : : path > & input_files , bool load_model , bool load_config ) { p - > load_files ( input_files , load_model , load_config ) ; }
2018-09-17 10:15:11 +00:00
2019-01-09 09:43:17 +00:00
// To be called when providing a list of files to the GUI slic3r on command line.
void Plater : : load_files ( const std : : vector < std : : string > & input_files , bool load_model , bool load_config )
{
std : : vector < fs : : path > paths ;
paths . reserve ( input_files . size ( ) ) ;
for ( const std : : string & path : input_files )
paths . emplace_back ( path ) ;
p - > load_files ( paths , load_model , load_config ) ;
}
2018-11-21 12:32:24 +00:00
void Plater : : update ( ) { p - > update ( ) ; }
2018-10-17 10:59:58 +00:00
2018-12-04 10:14:39 +00:00
void Plater : : update_ui_from_settings ( ) { p - > update_ui_from_settings ( ) ; }
2018-10-17 10:59:58 +00:00
void Plater : : select_view ( const std : : string & direction ) { p - > select_view ( direction ) ; }
2018-12-04 12:55:25 +00:00
void Plater : : select_view_3D ( const std : : string & name ) { p - > select_view_3D ( name ) ; }
2018-11-21 14:28:35 +00:00
void Plater : : select_all ( ) { p - > select_all ( ) ; }
2018-10-08 17:14:55 +00:00
void Plater : : remove ( size_t obj_idx ) { p - > remove ( obj_idx ) ; }
2018-11-22 10:31:53 +00:00
void Plater : : reset ( ) { p - > reset ( ) ; }
2019-05-02 11:52:13 +00:00
void Plater : : reset_with_confirm ( )
{
if ( wxMessageDialog ( ( wxWindow * ) this , _ ( L ( " All objects will be removed, continue ? " ) ) , _ ( L ( " Delete all " ) ) , wxYES_NO | wxYES_DEFAULT | wxCENTRE ) . ShowModal ( ) = = wxID_YES )
reset ( ) ;
}
2018-11-22 10:31:53 +00:00
2018-11-13 13:17:35 +00:00
void Plater : : delete_object_from_model ( size_t obj_idx ) { p - > delete_object_from_model ( obj_idx ) ; }
2018-10-04 09:12:55 +00:00
void Plater : : remove_selected ( )
{
2018-12-04 12:55:25 +00:00
this - > p - > view3D - > delete_selected ( ) ;
2018-10-04 09:12:55 +00:00
}
2018-10-18 13:09:41 +00:00
void Plater : : increase_instances ( size_t num )
2018-10-11 08:03:38 +00:00
{
2019-04-17 12:56:00 +00:00
if ( ! can_increase_instances ( ) ) { return ; }
2018-10-17 07:30:07 +00:00
int obj_idx = p - > get_selected_object_idx ( ) ;
ModelObject * model_object = p - > model . objects [ obj_idx ] ;
ModelInstance * model_instance = model_object - > instances . back ( ) ;
2018-10-11 08:03:38 +00:00
2018-11-07 12:40:24 +00:00
bool was_one_instance = model_object - > instances . size ( ) = = 1 ;
2019-04-12 13:31:33 +00:00
double offset_base = canvas3D ( ) - > get_size_proportional_to_max_bed_size ( 0.05 ) ;
double offset = offset_base ;
for ( size_t i = 0 ; i < num ; i + + , offset + = offset_base ) {
2018-10-11 08:03:38 +00:00
Vec3d offset_vec = model_instance - > get_offset ( ) + Vec3d ( offset , offset , 0.0 ) ;
2019-01-03 14:04:29 +00:00
model_object - > add_instance ( offset_vec , model_instance - > get_scaling_factor ( ) , model_instance - > get_rotation ( ) , model_instance - > get_mirror ( ) ) ;
2018-10-23 13:27:31 +00:00
// p->print.get_object(obj_idx)->add_copy(Slic3r::to_2d(offset_vec));
2018-10-11 08:03:38 +00:00
}
2018-11-07 12:40:24 +00:00
sidebar ( ) . obj_list ( ) - > increase_object_instances ( obj_idx , was_one_instance ? num + 1 : num ) ;
2018-10-11 08:03:38 +00:00
if ( p - > get_config ( " autocenter " ) = = " 1 " ) {
p - > arrange ( ) ;
} else {
p - > update ( ) ;
}
2018-10-23 07:19:41 +00:00
p - > get_selection ( ) . add_instance ( obj_idx , ( int ) model_object - > instances . size ( ) - 1 ) ;
2018-10-11 08:03:38 +00:00
p - > selection_changed ( ) ;
2018-10-17 09:12:38 +00:00
this - > p - > schedule_background_process ( ) ;
2018-10-11 08:03:38 +00:00
}
2018-10-18 13:09:41 +00:00
void Plater : : decrease_instances ( size_t num )
2018-10-11 08:03:38 +00:00
{
2019-04-17 12:56:00 +00:00
if ( ! can_decrease_instances ( ) ) { return ; }
2018-10-17 07:30:07 +00:00
int obj_idx = p - > get_selected_object_idx ( ) ;
ModelObject * model_object = p - > model . objects [ obj_idx ] ;
2018-10-11 08:03:38 +00:00
if ( model_object - > instances . size ( ) > num ) {
2018-11-08 13:23:17 +00:00
for ( size_t i = 0 ; i < num ; + + i )
2018-10-11 08:03:38 +00:00
model_object - > delete_last_instance ( ) ;
2018-10-18 09:41:29 +00:00
sidebar ( ) . obj_list ( ) - > decrease_object_instances ( obj_idx , num ) ;
2018-10-17 07:30:07 +00:00
}
else {
remove ( obj_idx ) ;
2018-10-11 08:03:38 +00:00
}
p - > update ( ) ;
2018-10-23 07:19:41 +00:00
if ( ! model_object - > instances . empty ( ) )
p - > get_selection ( ) . add_instance ( obj_idx , ( int ) model_object - > instances . size ( ) - 1 ) ;
2018-10-17 07:40:04 +00:00
p - > selection_changed ( ) ;
2018-10-23 13:27:31 +00:00
this - > p - > schedule_background_process ( ) ;
2018-10-11 08:03:38 +00:00
}
2018-10-25 19:13:45 +00:00
void Plater : : set_number_of_copies ( /*size_t num*/ )
2018-10-11 08:03:38 +00:00
{
2018-10-17 07:30:07 +00:00
int obj_idx = p - > get_selected_object_idx ( ) ;
if ( obj_idx = = - 1 )
return ;
ModelObject * model_object = p - > model . objects [ obj_idx ] ;
2018-10-11 08:03:38 +00:00
2018-10-25 19:13:45 +00:00
const auto num = wxGetNumberFromUser ( " " , _ ( " Enter the number of copies: " ) ,
_ ( " Copies of the selected object " ) , model_object - > instances . size ( ) , 0 , 1000 , this ) ;
if ( num < 0 )
return ;
2018-10-17 07:30:07 +00:00
int diff = ( int ) num - ( int ) model_object - > instances . size ( ) ;
2018-10-18 13:09:41 +00:00
if ( diff > 0 )
increase_instances ( diff ) ;
else if ( diff < 0 )
decrease_instances ( - diff ) ;
2018-10-11 08:03:38 +00:00
}
2018-10-04 09:12:55 +00:00
2018-11-21 14:47:41 +00:00
bool Plater : : is_selection_empty ( ) const
{
2019-04-10 10:16:17 +00:00
return p - > get_selection ( ) . is_empty ( ) | | p - > get_selection ( ) . is_wipe_tower ( ) ;
2018-11-21 14:47:41 +00:00
}
2018-11-26 09:56:07 +00:00
void Plater : : cut ( size_t obj_idx , size_t instance_idx , coordf_t z , bool keep_upper , bool keep_lower , bool rotate_lower )
2018-10-18 13:13:38 +00:00
{
wxCHECK_RET ( obj_idx < p - > model . objects . size ( ) , " obj_idx out of bounds " ) ;
auto * object = p - > model . objects [ obj_idx ] ;
wxCHECK_RET ( instance_idx < object - > instances . size ( ) , " instance_idx out of bounds " ) ;
2019-01-18 14:02:07 +00:00
if ( ! keep_upper & & ! keep_lower ) {
return ;
}
2019-02-05 19:23:24 +00:00
wxBusyCursor wait ;
2018-11-26 09:56:07 +00:00
const auto new_objects = object - > cut ( instance_idx , z , keep_upper , keep_lower , rotate_lower ) ;
2018-10-18 13:13:38 +00:00
remove ( obj_idx ) ;
p - > load_model_objects ( new_objects ) ;
}
2019-02-03 09:41:14 +00:00
void Plater : : export_gcode ( )
2018-10-04 09:12:55 +00:00
{
2018-10-23 13:27:31 +00:00
if ( p - > model . objects . empty ( ) )
return ;
2018-09-17 10:15:11 +00:00
2019-02-03 09:41:14 +00:00
// If possible, remove accents from accented latin characters.
// This function is useful for generating file names to be processed by legacy firmwares.
fs : : path default_output_file ;
try {
// Update the background processing, so that the placeholder parser will get the correct values for the ouput file template.
// Also if there is something wrong with the current configuration, a pop-up dialog will be shown and the export will not be performed.
unsigned int state = this - > p - > update_restart_background_process ( false , false ) ;
if ( state & priv : : UPDATE_BACKGROUND_PROCESS_INVALID )
return ;
default_output_file = this - > p - > background_process . current_print ( ) - > output_filepath ( " " ) ;
} catch ( const std : : exception & ex ) {
show_error ( this , ex . what ( ) ) ;
return ;
2018-09-17 10:15:11 +00:00
}
2019-02-03 09:41:14 +00:00
default_output_file = fs : : path ( Slic3r : : fold_utf8_to_ascii ( default_output_file . string ( ) ) ) ;
auto start_dir = wxGetApp ( ) . app_config - > get_last_output_dir ( default_output_file . parent_path ( ) . string ( ) ) ;
2018-09-17 10:15:11 +00:00
2019-03-01 09:09:20 +00:00
wxFileDialog dlg ( this , ( printer_technology ( ) = = ptFFF ) ? _ ( L ( " Save G-code file as: " ) ) : _ ( L ( " Save SL1 file as: " ) ) ,
2019-02-03 09:41:14 +00:00
start_dir ,
from_path ( default_output_file . filename ( ) ) ,
GUI : : file_wildcards ( ( printer_technology ( ) = = ptFFF ) ? FT_GCODE : FT_PNGZIP , default_output_file . extension ( ) . string ( ) ) ,
wxFD_SAVE | wxFD_OVERWRITE_PROMPT
) ;
fs : : path output_path ;
if ( dlg . ShowModal ( ) = = wxID_OK ) {
fs : : path path = into_path ( dlg . GetPath ( ) ) ;
wxGetApp ( ) . app_config - > update_last_output_dir ( path . parent_path ( ) . string ( ) ) ;
output_path = std : : move ( path ) ;
2018-10-23 13:27:31 +00:00
}
2019-02-03 09:41:14 +00:00
if ( ! output_path . empty ( ) )
p - > export_gcode ( std : : move ( output_path ) , PrintHostJob ( ) ) ;
2018-09-17 10:15:11 +00:00
}
2019-05-02 11:46:39 +00:00
void Plater : : export_stl ( bool extended , bool selection_only )
2018-10-04 09:12:55 +00:00
{
2018-10-17 07:30:07 +00:00
if ( p - > model . objects . empty ( ) ) { return ; }
2018-10-04 09:12:55 +00:00
2019-04-04 09:31:26 +00:00
wxString path = p - > get_export_file ( FT_STL ) ;
if ( path . empty ( ) ) { return ; }
2019-01-02 14:11:05 +00:00
const std : : string path_u8 = into_u8 ( path ) ;
2018-12-05 14:22:03 +00:00
2019-02-22 09:11:57 +00:00
wxBusyCursor wait ;
2018-12-05 14:22:03 +00:00
TriangleMesh mesh ;
if ( selection_only ) {
const auto & selection = p - > get_selection ( ) ;
if ( selection . is_wipe_tower ( ) ) { return ; }
const auto obj_idx = selection . get_object_idx ( ) ;
if ( obj_idx = = - 1 ) { return ; }
2019-04-04 13:13:43 +00:00
2019-04-05 08:08:34 +00:00
const ModelObject * model_object = p - > model . objects [ obj_idx ] ;
2019-04-04 13:13:43 +00:00
if ( selection . get_mode ( ) = = Selection : : Instance )
2019-04-05 09:30:49 +00:00
{
if ( selection . is_single_full_object ( ) )
mesh = model_object - > mesh ( ) ;
else
mesh = model_object - > full_raw_mesh ( ) ;
}
2019-04-04 13:13:43 +00:00
else
{
const GLVolume * volume = selection . get_volume ( * selection . get_volume_idxs ( ) . begin ( ) ) ;
2019-04-05 08:08:34 +00:00
mesh = model_object - > volumes [ volume - > volume_idx ( ) ] - > mesh ;
2019-04-04 13:13:43 +00:00
mesh . transform ( volume - > get_volume_transformation ( ) . get_matrix ( ) ) ;
2019-04-05 08:08:34 +00:00
mesh . translate ( - model_object - > origin_translation . cast < float > ( ) ) ;
2019-04-04 13:13:43 +00:00
}
}
2019-04-05 08:08:34 +00:00
else
2019-05-02 11:46:39 +00:00
{
2019-01-02 17:36:48 +00:00
mesh = p - > model . mesh ( ) ;
2018-12-05 14:22:03 +00:00
2019-05-02 11:46:39 +00:00
if ( extended & & ( p - > printer_technology = = ptSLA ) )
{
const PrintObjects & objects = p - > sla_print . objects ( ) ;
for ( const SLAPrintObject * object : objects )
{
const ModelObject * model_object = object - > model_object ( ) ;
Transform3d mesh_trafo_inv = object - > trafo ( ) . inverse ( ) ;
bool is_left_handed = object - > is_left_handed ( ) ;
TriangleMesh pad_mesh ;
bool has_pad_mesh = object - > has_mesh ( slaposBasePool ) ;
if ( has_pad_mesh )
{
pad_mesh = object - > get_mesh ( slaposBasePool ) ;
pad_mesh . transform ( mesh_trafo_inv ) ;
}
TriangleMesh supports_mesh ;
bool has_supports_mesh = object - > has_mesh ( slaposSupportTree ) ;
if ( has_supports_mesh )
{
supports_mesh = object - > get_mesh ( slaposSupportTree ) ;
supports_mesh . transform ( mesh_trafo_inv ) ;
}
const std : : vector < SLAPrintObject : : Instance > & obj_instances = object - > instances ( ) ;
for ( const SLAPrintObject : : Instance & obj_instance : obj_instances )
{
auto it = std : : find_if ( model_object - > instances . begin ( ) , model_object - > instances . end ( ) ,
[ & obj_instance ] ( const ModelInstance * mi ) { return mi - > id ( ) = = obj_instance . instance_id ; } ) ;
assert ( it ! = model_object - > instances . end ( ) ) ;
if ( it ! = model_object - > instances . end ( ) )
{
int instance_idx = it - model_object - > instances . begin ( ) ;
const Transform3d & inst_transform = object - > model_object ( ) - > instances [ instance_idx ] - > get_transformation ( ) . get_matrix ( ) ;
if ( has_pad_mesh )
{
TriangleMesh inst_pad_mesh = pad_mesh ;
inst_pad_mesh . transform ( inst_transform , is_left_handed ) ;
mesh . merge ( inst_pad_mesh ) ;
}
if ( has_supports_mesh )
{
TriangleMesh inst_supports_mesh = supports_mesh ;
inst_supports_mesh . transform ( inst_transform , is_left_handed ) ;
mesh . merge ( inst_supports_mesh ) ;
}
}
}
}
}
}
2019-01-02 14:11:05 +00:00
Slic3r : : store_stl ( path_u8 . c_str ( ) , & mesh , true ) ;
2018-10-04 09:12:55 +00:00
p - > statusbar ( ) - > set_status_text ( wxString : : Format ( _ ( L ( " STL file exported to %s " ) ) , path ) ) ;
}
void Plater : : export_amf ( )
{
2018-10-17 07:30:07 +00:00
if ( p - > model . objects . empty ( ) ) { return ; }
2018-10-08 17:55:30 +00:00
2019-04-04 09:31:26 +00:00
wxString path = p - > get_export_file ( FT_AMF ) ;
if ( path . empty ( ) ) { return ; }
2019-01-02 14:11:05 +00:00
const std : : string path_u8 = into_u8 ( path ) ;
2018-10-08 17:55:30 +00:00
2019-02-05 19:23:24 +00:00
wxBusyCursor wait ;
2019-04-04 09:31:26 +00:00
bool export_config = true ;
DynamicPrintConfig cfg = wxGetApp ( ) . preset_bundle - > full_config_secure ( ) ;
if ( Slic3r : : store_amf ( path_u8 . c_str ( ) , & p - > model , export_config ? & cfg : nullptr ) ) {
2018-10-08 17:55:30 +00:00
// Success
p - > statusbar ( ) - > set_status_text ( wxString : : Format ( _ ( L ( " AMF file exported to %s " ) ) , path ) ) ;
} else {
// Failure
p - > statusbar ( ) - > set_status_text ( wxString : : Format ( _ ( L ( " Error exporting AMF file %s " ) ) , path ) ) ;
}
2018-10-04 09:12:55 +00:00
}
2018-11-15 14:27:39 +00:00
void Plater : : export_3mf ( const boost : : filesystem : : path & output_path )
2018-10-04 09:12:55 +00:00
{
2018-10-17 07:30:07 +00:00
if ( p - > model . objects . empty ( ) ) { return ; }
2018-10-08 17:55:30 +00:00
2018-11-15 14:27:39 +00:00
wxString path ;
bool export_config = true ;
if ( output_path . empty ( ) )
{
2019-04-04 09:31:26 +00:00
path = p - > get_export_file ( FT_3MF ) ;
if ( path . empty ( ) ) { return ; }
2018-11-15 14:27:39 +00:00
}
else
2019-01-02 14:11:05 +00:00
path = from_path ( output_path ) ;
2018-10-08 17:55:30 +00:00
2018-11-15 14:27:39 +00:00
if ( ! path . Lower ( ) . EndsWith ( " .3mf " ) )
return ;
2018-10-08 17:55:30 +00:00
2018-12-06 13:47:53 +00:00
DynamicPrintConfig cfg = wxGetApp ( ) . preset_bundle - > full_config_secure ( ) ;
2019-01-02 14:11:05 +00:00
const std : : string path_u8 = into_u8 ( path ) ;
2019-02-05 19:23:24 +00:00
wxBusyCursor wait ;
2019-01-02 14:11:05 +00:00
if ( Slic3r : : store_3mf ( path_u8 . c_str ( ) , & p - > model , export_config ? & cfg : nullptr ) ) {
2018-10-08 17:55:30 +00:00
// Success
p - > statusbar ( ) - > set_status_text ( wxString : : Format ( _ ( L ( " 3MF file exported to %s " ) ) , path ) ) ;
} else {
// Failure
p - > statusbar ( ) - > set_status_text ( wxString : : Format ( _ ( L ( " Error exporting 3MF file %s " ) ) , path ) ) ;
}
2018-10-04 09:12:55 +00:00
}
2018-09-17 10:15:11 +00:00
void Plater : : reslice ( )
{
2018-11-13 16:45:44 +00:00
//FIXME Don't reslice if export of G-code or sending to OctoPrint is running.
// bitmask of UpdateBackgroundProcessReturnState
2019-01-10 15:06:24 +00:00
unsigned int state = this - > p - > update_background_process ( true ) ;
2018-11-13 16:45:44 +00:00
if ( state & priv : : UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE )
2018-12-04 12:55:25 +00:00
this - > p - > view3D - > reload_scene ( false ) ;
2019-02-25 09:21:12 +00:00
// If the SLA processing of just a single object's supports is running, restart slicing for the whole object.
this - > p - > background_process . set_task ( PrintBase : : TaskParams ( ) ) ;
2018-12-22 09:02:42 +00:00
// Only restarts if the state is valid.
this - > p - > restart_background_process ( state | priv : : UPDATE_BACKGROUND_PROCESS_FORCE_RESTART ) ;
2019-03-01 10:00:34 +00:00
if ( ( state & priv : : UPDATE_BACKGROUND_PROCESS_INVALID ) ! = 0 )
return ;
if ( p - > background_process . running ( ) )
{
if ( wxGetApp ( ) . get_mode ( ) = = comSimple )
p - > sidebar - > set_btn_label ( ActionButtonType : : abReslice , _ ( L ( " Slicing " ) ) + dots ) ;
else
{
p - > sidebar - > set_btn_label ( ActionButtonType : : abReslice , _ ( L ( " Slice now " ) ) ) ;
p - > show_action_buttons ( false ) ;
}
}
else if ( ! p - > background_process . empty ( ) & & ! p - > background_process . idle ( ) )
p - > show_action_buttons ( true ) ;
2018-09-17 10:15:11 +00:00
}
2019-02-21 10:40:56 +00:00
void Plater : : reslice_SLA_supports ( const ModelObject & object )
{
//FIXME Don't reslice if export of G-code or sending to OctoPrint is running.
// bitmask of UpdateBackgroundProcessReturnState
unsigned int state = this - > p - > update_background_process ( true ) ;
if ( state & priv : : UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE )
this - > p - > view3D - > reload_scene ( false ) ;
if ( this - > p - > background_process . empty ( ) | | ( state & priv : : UPDATE_BACKGROUND_PROCESS_INVALID ) )
// Nothing to do on empty input or invalid configuration.
return ;
// Limit calculation to the single object only.
PrintBase : : TaskParams task ;
task . single_model_object = object . id ( ) ;
// If the background processing is not enabled, calculate supports just for the single instance.
// Otherwise calculate everything, but start with the provided object.
if ( ! this - > p - > background_processing_enabled ( ) ) {
task . single_model_instance_only = true ;
task . to_object_step = slaposBasePool ;
}
this - > p - > background_process . set_task ( task ) ;
// and let the background processing start.
this - > p - > restart_background_process ( state | priv : : UPDATE_BACKGROUND_PROCESS_FORCE_RESTART ) ;
}
2018-10-04 09:12:55 +00:00
void Plater : : send_gcode ( )
{
2018-12-11 09:33:11 +00:00
if ( p - > model . objects . empty ( ) ) { return ; }
PrintHostJob upload_job ( p - > config ) ;
if ( upload_job . empty ( ) ) { return ; }
// Obtain default output path
fs : : path default_output_file ;
try {
2019-02-03 09:41:14 +00:00
// Update the background processing, so that the placeholder parser will get the correct values for the ouput file template.
// Also if there is something wrong with the current configuration, a pop-up dialog will be shown and the export will not be performed.
unsigned int state = this - > p - > update_restart_background_process ( false , false ) ;
if ( state & priv : : UPDATE_BACKGROUND_PROCESS_INVALID )
return ;
default_output_file = this - > p - > background_process . current_print ( ) - > output_filepath ( " " ) ;
2018-12-11 09:33:11 +00:00
} catch ( const std : : exception & ex ) {
show_error ( this , ex . what ( ) ) ;
return ;
}
default_output_file = fs : : path ( Slic3r : : fold_utf8_to_ascii ( default_output_file . string ( ) ) ) ;
2019-03-04 15:50:43 +00:00
PrintHostSendDialog dlg ( default_output_file , upload_job . printhost - > can_start_print ( ) ) ;
2018-12-11 09:33:11 +00:00
if ( dlg . ShowModal ( ) = = wxID_OK ) {
upload_job . upload_data . upload_path = dlg . filename ( ) ;
upload_job . upload_data . start_print = dlg . start_print ( ) ;
p - > export_gcode ( fs : : path ( ) , std : : move ( upload_job ) ) ;
}
2018-10-04 09:12:55 +00:00
}
2018-10-10 11:53:45 +00:00
void Plater : : on_extruders_change ( int num_extruders )
{
auto & choices = sidebar ( ) . combos_filament ( ) ;
2019-03-13 12:13:18 +00:00
if ( num_extruders = = choices . size ( ) )
return ;
2018-11-15 10:15:24 +00:00
wxWindowUpdateLocker noUpdates_scrolled_panel ( & sidebar ( ) /*.scrolled_panel()*/ ) ;
2018-11-09 17:39:07 +00:00
2018-10-10 11:53:45 +00:00
int i = choices . size ( ) ;
while ( i < num_extruders )
{
PresetComboBox * choice /*{ nullptr }*/ ;
sidebar ( ) . init_filament_combo ( & choice , i ) ;
choices . push_back ( choice ) ;
// initialize selection
2019-04-23 14:33:06 +00:00
wxGetApp ( ) . preset_bundle - > update_platter_filament_ui ( i , choice ) ;
2018-10-10 11:53:45 +00:00
+ + i ;
}
// remove unused choices if any
sidebar ( ) . remove_unused_filament_combos ( num_extruders ) ;
2018-11-15 10:15:24 +00:00
sidebar ( ) . Layout ( ) ;
sidebar ( ) . scrolled_panel ( ) - > Refresh ( ) ;
2018-10-10 11:53:45 +00:00
}
2018-10-17 09:12:38 +00:00
void Plater : : on_config_change ( const DynamicPrintConfig & config )
2018-10-10 11:53:45 +00:00
{
2018-10-15 08:53:47 +00:00
bool update_scheduled = false ;
2019-02-04 09:06:15 +00:00
bool bed_shape_changed = false ;
2018-10-17 09:12:38 +00:00
for ( auto opt_key : p - > config - > diff ( config ) ) {
p - > config - > set_key_value ( opt_key , config . option ( opt_key ) - > clone ( ) ) ;
2018-12-03 12:14:28 +00:00
if ( opt_key = = " printer_technology " )
this - > set_printer_technology ( config . opt_enum < PrinterTechnology > ( opt_key ) ) ;
2019-01-17 12:21:33 +00:00
else if ( opt_key = = " bed_shape " ) {
2019-02-04 09:06:15 +00:00
bed_shape_changed = true ;
2018-10-15 08:53:47 +00:00
update_scheduled = true ;
}
2018-12-06 14:40:41 +00:00
else if ( boost : : starts_with ( opt_key , " wipe_tower " ) | |
// opt_key == "filament_minimal_purge_on_wipe_tower" // ? #ys_FIXME
opt_key = = " single_extruder_multi_material " ) {
2018-10-15 08:53:47 +00:00
update_scheduled = true ;
}
else if ( opt_key = = " variable_layer_height " ) {
if ( p - > config - > opt_bool ( " variable_layer_height " ) ! = true ) {
2018-12-04 12:55:25 +00:00
p - > view3D - > enable_layers_editing ( false ) ;
p - > view3D - > set_as_dirty ( ) ;
2018-10-15 08:53:47 +00:00
}
2019-03-14 12:54:05 +00:00
}
2018-10-15 08:53:47 +00:00
else if ( opt_key = = " extruder_colour " ) {
update_scheduled = true ;
p - > preview - > set_number_extruders ( p - > config - > option < ConfigOptionStrings > ( opt_key ) - > values . size ( ) ) ;
} else if ( opt_key = = " max_print_height " ) {
update_scheduled = true ;
2019-01-17 12:21:33 +00:00
}
else if ( opt_key = = " printer_model " ) {
2018-10-15 08:53:47 +00:00
// update to force bed selection(for texturing)
2019-02-04 09:06:15 +00:00
bed_shape_changed = true ;
2018-10-15 08:53:47 +00:00
update_scheduled = true ;
2019-01-17 12:21:33 +00:00
}
2018-10-15 08:53:47 +00:00
}
2018-12-11 09:33:11 +00:00
{
const auto prin_host_opt = p - > config - > option < ConfigOptionString > ( " print_host " ) ;
p - > sidebar - > show_send ( prin_host_opt ! = nullptr & & ! prin_host_opt - > value . empty ( ) ) ;
}
2019-02-04 09:06:15 +00:00
if ( bed_shape_changed )
2019-02-19 14:15:27 +00:00
p - > set_bed_shape ( p - > config - > option < ConfigOptionPoints > ( " bed_shape " ) - > values ) ;
2019-02-04 09:06:15 +00:00
2018-10-15 08:53:47 +00:00
if ( update_scheduled )
update ( ) ;
2018-10-17 09:12:38 +00:00
if ( p - > main_frame - > is_loaded ( ) )
this - > p - > schedule_background_process ( ) ;
2018-10-10 11:53:45 +00:00
}
2019-02-19 13:57:59 +00:00
void Plater : : on_activate ( )
{
2019-02-19 14:54:43 +00:00
# ifdef __linux__
2019-02-19 13:57:59 +00:00
wxWindow * focus_window = wxWindow : : FindFocus ( ) ;
2019-02-19 14:54:43 +00:00
// Activating the main frame, and no window has keyboard focus.
// Set the keyboard focus to the visible Canvas3D.
if ( this - > p - > view3D - > IsShown ( ) & & ( ! focus_window | | focus_window = = this - > p - > view3D - > get_wxglcanvas ( ) ) )
this - > p - > view3D - > get_wxglcanvas ( ) - > SetFocus ( ) ;
else if ( this - > p - > preview - > IsShown ( ) & & ( ! focus_window | | focus_window = = this - > p - > view3D - > get_wxglcanvas ( ) ) )
this - > p - > preview - > get_wxglcanvas ( ) - > SetFocus ( ) ;
# endif
2019-02-19 13:57:59 +00:00
if ( ! this - > p - > delayed_error_message . empty ( ) ) {
std : : string msg = std : : move ( this - > p - > delayed_error_message ) ;
this - > p - > delayed_error_message . clear ( ) ;
GUI : : show_error ( this , msg ) ;
}
}
2018-11-15 14:27:39 +00:00
const wxString & Plater : : get_project_filename ( ) const
{
return p - > project_filename ;
}
bool Plater : : is_export_gcode_scheduled ( ) const
{
return p - > background_process . is_export_scheduled ( ) ;
}
2018-11-01 11:33:56 +00:00
int Plater : : get_selected_object_idx ( )
{
return p - > get_selected_object_idx ( ) ;
}
2018-11-13 14:24:05 +00:00
bool Plater : : is_single_full_object_selection ( ) const
2018-11-09 17:39:07 +00:00
{
return p - > get_selection ( ) . is_single_full_object ( ) ;
}
2018-11-23 11:47:32 +00:00
GLCanvas3D * Plater : : canvas3D ( )
2018-10-11 13:57:09 +00:00
{
2018-12-04 12:55:25 +00:00
return p - > view3D - > get_canvas3d ( ) ;
2018-10-11 13:57:09 +00:00
}
2018-11-12 16:35:57 +00:00
PrinterTechnology Plater : : printer_technology ( ) const
{
2018-11-13 16:45:44 +00:00
return p - > printer_technology ;
2018-11-12 16:35:57 +00:00
}
2018-12-03 12:14:28 +00:00
void Plater : : set_printer_technology ( PrinterTechnology printer_technology )
{
p - > printer_technology = printer_technology ;
if ( p - > background_process . select_technology ( printer_technology ) ) {
// Update the active presets.
}
//FIXME for SLA synchronize
//p->background_process.apply(Model)!
2019-03-01 10:00:34 +00:00
2019-03-12 08:41:57 +00:00
p - > label_btn_export = printer_technology = = ptFFF ? L ( " Export G-code " ) : L ( " Export " ) ;
p - > label_btn_send = printer_technology = = ptFFF ? L ( " Send G-code " ) : L ( " Send to printer " ) ;
2019-04-30 11:51:36 +00:00
if ( wxGetApp ( ) . mainframe )
wxGetApp ( ) . mainframe - > update_menubar ( ) ;
2018-12-03 12:14:28 +00:00
}
2018-10-31 14:41:27 +00:00
void Plater : : changed_object ( int obj_idx )
2018-10-08 14:27:38 +00:00
{
if ( obj_idx < 0 )
return ;
2019-04-21 23:51:10 +00:00
// recenter and re - align to Z = 0
auto model_object = p - > model . objects [ obj_idx ] ;
model_object - > ensure_on_bed ( ) ;
if ( this - > p - > printer_technology = = ptSLA ) {
// Update the SLAPrint from the current Model, so that the reload_scene()
// pulls the correct data, update the 3D scene.
this - > p - > update_restart_background_process ( true , false ) ;
2018-10-08 14:27:38 +00:00
}
2019-04-21 23:51:10 +00:00
else
p - > view3D - > reload_scene ( false ) ;
2018-10-08 14:27:38 +00:00
2018-11-07 14:29:13 +00:00
// update print
2018-12-03 12:14:28 +00:00
this - > p - > schedule_background_process ( ) ;
2018-10-08 14:27:38 +00:00
}
2019-04-15 13:40:40 +00:00
void Plater : : changed_objects ( const std : : vector < size_t > & object_idxs )
{
if ( object_idxs . empty ( ) )
return ;
2019-04-21 23:51:10 +00:00
for ( int obj_idx : object_idxs )
{
if ( obj_idx < p - > model . objects . size ( ) )
// recenter and re - align to Z = 0
p - > model . objects [ obj_idx ] - > ensure_on_bed ( ) ;
2019-04-15 13:40:40 +00:00
}
2019-04-21 23:51:10 +00:00
if ( this - > p - > printer_technology = = ptSLA ) {
// Update the SLAPrint from the current Model, so that the reload_scene()
// pulls the correct data, update the 3D scene.
this - > p - > update_restart_background_process ( true , false ) ;
}
else
p - > view3D - > reload_scene ( false ) ;
2019-04-15 13:40:40 +00:00
// update print
this - > p - > schedule_background_process ( ) ;
}
2019-04-12 16:29:47 +00:00
void Plater : : schedule_background_process ( )
{
this - > p - > schedule_background_process ( ) ;
}
2019-01-30 15:27:07 +00:00
void Plater : : fix_through_netfabb ( const int obj_idx , const int vol_idx /* = -1*/ ) { p - > fix_through_netfabb ( obj_idx , vol_idx ) ; }
2018-09-17 10:15:11 +00:00
2018-12-07 16:50:48 +00:00
void Plater : : update_object_menu ( ) { p - > update_object_menu ( ) ; }
2019-04-10 06:40:58 +00:00
void Plater : : copy_selection_to_clipboard ( )
{
p - > view3D - > get_canvas3d ( ) - > get_selection ( ) . copy_to_clipboard ( ) ;
}
void Plater : : paste_from_clipboard ( )
{
p - > view3D - > get_canvas3d ( ) - > get_selection ( ) . paste_from_clipboard ( ) ;
}
2019-04-12 06:41:59 +00:00
2019-04-11 12:21:08 +00:00
bool Plater : : can_paste_from_clipboard ( ) const
2019-04-10 06:40:58 +00:00
{
2019-04-11 12:21:08 +00:00
const Selection & selection = p - > view3D - > get_canvas3d ( ) - > get_selection ( ) ;
const Selection : : Clipboard & clipboard = selection . get_clipboard ( ) ;
Selection : : EMode mode = clipboard . get_mode ( ) ;
2019-04-12 06:49:24 +00:00
if ( clipboard . is_empty ( ) )
return false ;
if ( ( mode = = Selection : : Volume ) & & ! selection . is_from_single_instance ( ) )
return false ;
if ( ( mode = = Selection : : Instance ) & & ( selection . get_mode ( ) ! = Selection : : Instance ) )
return false ;
return true ;
2019-04-10 06:40:58 +00:00
}
2019-04-24 23:45:00 +00:00
void Plater : : msw_rescale ( )
2019-04-16 08:05:45 +00:00
{
2019-04-24 23:45:00 +00:00
p - > preview - > msw_rescale ( ) ;
2019-04-16 10:11:48 +00:00
2019-04-24 23:45:00 +00:00
p - > view3D - > get_canvas3d ( ) - > msw_rescale ( ) ;
2019-04-16 08:05:45 +00:00
2019-04-24 23:45:00 +00:00
p - > sidebar - > msw_rescale ( ) ;
2019-04-16 08:05:45 +00:00
2019-05-03 07:44:19 +00:00
p - > msw_rescale_object_menu ( ) ;
2019-04-16 08:05:45 +00:00
Layout ( ) ;
GetParent ( ) - > Layout ( ) ;
}
2019-03-14 12:54:05 +00:00
bool Plater : : can_delete ( ) const { return p - > can_delete ( ) ; }
bool Plater : : can_delete_all ( ) const { return p - > can_delete_all ( ) ; }
bool Plater : : can_increase_instances ( ) const { return p - > can_increase_instances ( ) ; }
bool Plater : : can_decrease_instances ( ) const { return p - > can_decrease_instances ( ) ; }
bool Plater : : can_split_to_objects ( ) const { return p - > can_split_to_objects ( ) ; }
bool Plater : : can_split_to_volumes ( ) const { return p - > can_split_to_volumes ( ) ; }
bool Plater : : can_arrange ( ) const { return p - > can_arrange ( ) ; }
bool Plater : : can_layers_editing ( ) const { return p - > can_layers_editing ( ) ; }
2019-04-11 11:20:34 +00:00
bool Plater : : can_copy ( ) const { return ! is_selection_empty ( ) ; }
2019-04-11 12:21:08 +00:00
bool Plater : : can_paste ( ) const { return can_paste_from_clipboard ( ) ; }
2019-03-14 12:54:05 +00:00
2018-09-17 10:15:11 +00:00
} } // namespace Slic3r::GUI