2020-07-30 14:16:56 +00:00
# include "UnsavedChangesDialog.hpp"
# include <cstddef>
# include <string>
2020-08-07 13:09:58 +00:00
# include <vector>
2020-07-30 14:16:56 +00:00
# include <boost/algorithm/string.hpp>
# include <boost/optional.hpp>
2020-12-04 23:02:23 +00:00
# include <boost/nowide/convert.hpp>
2020-07-30 14:16:56 +00:00
# include "libslic3r/PrintConfig.hpp"
# include "libslic3r/PresetBundle.hpp"
2020-10-17 12:04:05 +00:00
# include "format.hpp"
2020-07-30 14:16:56 +00:00
# include "GUI_App.hpp"
# include "Plater.hpp"
# include "Tab.hpp"
2020-08-10 17:07:45 +00:00
# include "ExtraRenderers.hpp"
# include "wxExtensions.hpp"
2020-10-19 12:17:45 +00:00
# include "SavePresetDialog.hpp"
2020-10-15 14:48:48 +00:00
# include "MainFrame.hpp"
2020-07-30 14:16:56 +00:00
2020-08-07 13:09:58 +00:00
//#define FTS_FUZZY_MATCH_IMPLEMENTATION
//#include "fts_fuzzy_match.h"
2020-07-30 14:16:56 +00:00
2020-08-05 17:25:04 +00:00
# include "BitmapCache.hpp"
2020-07-30 14:16:56 +00:00
using boost : : optional ;
2020-12-04 16:15:38 +00:00
# ifdef __linux__
2020-11-30 12:48:22 +00:00
# define wxLinux true
# else
# define wxLinux false
# endif
2020-07-30 14:16:56 +00:00
namespace Slic3r {
namespace GUI {
// ----------------------------------------------------------------------------
// ModelNode: a node inside UnsavedChangesModel
// ----------------------------------------------------------------------------
2020-08-05 17:25:04 +00:00
static const std : : map < Preset : : Type , std : : string > type_icon_names = {
{ Preset : : TYPE_PRINT , " cog " } ,
{ Preset : : TYPE_SLA_PRINT , " cog " } ,
{ Preset : : TYPE_FILAMENT , " spool " } ,
{ Preset : : TYPE_SLA_MATERIAL , " resin " } ,
2020-08-06 13:54:12 +00:00
{ Preset : : TYPE_PRINTER , " printer " } ,
2020-08-05 17:25:04 +00:00
} ;
2020-10-07 18:13:12 +00:00
static std : : string get_icon_name ( Preset : : Type type , PrinterTechnology pt ) {
return pt = = ptSLA & & type = = Preset : : TYPE_PRINTER ? " sla_printer " : type_icon_names . at ( type ) ;
}
2020-08-05 17:25:04 +00:00
static std : : string black = " #000000 " ;
static std : : string grey = " #808080 " ;
static std : : string orange = " #ed6b21 " ;
static void color_string ( wxString & str , const std : : string & color )
{
2020-08-10 09:24:31 +00:00
# if defined(SUPPORTS_MARKUP) && !defined(__APPLE__)
2020-08-05 17:25:04 +00:00
str = from_u8 ( ( boost : : format ( " <span color= \" %1% \" >%2%</span> " ) % color % into_u8 ( str ) ) . str ( ) ) ;
# endif
}
static void make_string_bold ( wxString & str )
{
2020-08-10 09:24:31 +00:00
# if defined(SUPPORTS_MARKUP) && !defined(__APPLE__)
2020-08-05 17:25:04 +00:00
str = from_u8 ( ( boost : : format ( " <b>%1%</b> " ) % into_u8 ( str ) ) . str ( ) ) ;
# endif
}
2020-07-30 14:16:56 +00:00
// preset(root) node
2020-10-07 18:13:12 +00:00
ModelNode : : ModelNode ( Preset : : Type preset_type , wxWindow * parent_win , const wxString & text , const std : : string & icon_name ) :
2020-08-12 11:36:26 +00:00
m_parent_win ( parent_win ) ,
2020-07-30 14:16:56 +00:00
m_parent ( nullptr ) ,
m_preset_type ( preset_type ) ,
2020-10-07 18:13:12 +00:00
m_icon_name ( icon_name ) ,
2020-07-30 14:16:56 +00:00
m_text ( text )
{
2020-08-12 11:36:26 +00:00
UpdateIcons ( ) ;
2020-07-30 14:16:56 +00:00
}
2020-10-07 18:13:12 +00:00
// category node
2020-07-30 14:16:56 +00:00
ModelNode : : ModelNode ( ModelNode * parent , const wxString & text , const std : : string & icon_name ) :
2020-08-12 11:36:26 +00:00
m_parent_win ( parent - > m_parent_win ) ,
2020-07-30 14:16:56 +00:00
m_parent ( parent ) ,
2020-08-12 11:36:26 +00:00
m_icon_name ( icon_name ) ,
2020-07-30 14:16:56 +00:00
m_text ( text )
{
2020-08-12 11:36:26 +00:00
UpdateIcons ( ) ;
2020-07-30 14:16:56 +00:00
}
2020-10-07 18:13:12 +00:00
// group node
2020-08-05 17:25:04 +00:00
ModelNode : : ModelNode ( ModelNode * parent , const wxString & text ) :
2020-08-12 11:36:26 +00:00
m_parent_win ( parent - > m_parent_win ) ,
2020-08-05 17:25:04 +00:00
m_parent ( parent ) ,
2020-10-07 18:13:12 +00:00
m_text ( text ) ,
m_icon_name ( " dot_small " )
2020-08-05 17:25:04 +00:00
{
2020-10-07 18:13:12 +00:00
UpdateIcons ( ) ;
2020-08-05 17:25:04 +00:00
}
2020-08-10 09:24:31 +00:00
# ifdef __linux__
2020-08-10 09:41:19 +00:00
wxIcon ModelNode : : get_bitmap ( const wxString & color )
2020-08-10 09:24:31 +00:00
# else
2020-08-05 17:25:04 +00:00
wxBitmap ModelNode : : get_bitmap ( const wxString & color )
2020-08-10 09:24:31 +00:00
# endif // __linux__
2020-08-05 17:25:04 +00:00
{
/* It's supposed that standard size of an icon is 48px*16px for 100% scaled display.
* So set sizes for solid_colored icons used for filament preset
* and scale them in respect to em_unit value
*/
const double em = em_unit ( m_parent_win ) ;
const int icon_width = lround ( 6.4 * em ) ;
const int icon_height = lround ( 1.6 * em ) ;
BitmapCache bmp_cache ;
unsigned char rgb [ 3 ] ;
BitmapCache : : parse_color ( into_u8 ( color ) , rgb ) ;
// there is no need to scale created solid bitmap
2020-08-10 17:07:45 +00:00
# ifndef __linux__
return bmp_cache . mksolid ( icon_width , icon_height , rgb , true ) ;
# else
2020-08-10 09:24:31 +00:00
wxIcon icon ;
2020-08-10 17:07:45 +00:00
icon . CopyFromBitmap ( bmp_cache . mksolid ( icon_width , icon_height , rgb , true ) ) ;
2020-08-10 09:24:31 +00:00
return icon ;
# endif // __linux__
2020-08-05 17:25:04 +00:00
}
// option node
ModelNode : : ModelNode ( ModelNode * parent , const wxString & text , const wxString & old_value , const wxString & new_value ) :
2020-07-30 14:16:56 +00:00
m_parent ( parent ) ,
2020-08-05 17:25:04 +00:00
m_old_color ( old_value . StartsWith ( " # " ) ? old_value : " " ) ,
m_new_color ( new_value . StartsWith ( " # " ) ? new_value : " " ) ,
m_container ( false ) ,
2020-07-30 14:16:56 +00:00
m_text ( text ) ,
2020-10-07 18:13:12 +00:00
m_icon_name ( " empty " ) ,
2020-08-05 17:25:04 +00:00
m_old_value ( old_value ) ,
m_new_value ( new_value )
{
// check if old/new_value is color
if ( m_old_color . IsEmpty ( ) ) {
if ( ! m_new_color . IsEmpty ( ) )
m_old_value = _L ( " Undef " ) ;
}
else {
m_old_color_bmp = get_bitmap ( m_old_color ) ;
m_old_value . Clear ( ) ;
}
if ( m_new_color . IsEmpty ( ) ) {
if ( ! m_old_color . IsEmpty ( ) )
m_new_value = _L ( " Undef " ) ;
}
else {
m_new_color_bmp = get_bitmap ( m_new_color ) ;
m_new_value . Clear ( ) ;
}
// "color" strings
color_string ( m_old_value , black ) ;
color_string ( m_new_value , orange ) ;
2020-10-07 18:13:12 +00:00
UpdateIcons ( ) ;
2020-08-05 17:25:04 +00:00
}
void ModelNode : : UpdateEnabling ( )
2020-07-30 14:16:56 +00:00
{
2020-08-05 17:25:04 +00:00
auto change_text_color = [ ] ( wxString & str , const std : : string & clr_from , const std : : string & clr_to )
{
2020-08-12 11:36:26 +00:00
# if defined(SUPPORTS_MARKUP) && !defined(__APPLE__)
2020-08-05 17:25:04 +00:00
std : : string old_val = into_u8 ( str ) ;
boost : : replace_all ( old_val , clr_from , clr_to ) ;
str = from_u8 ( old_val ) ;
2020-08-12 11:36:26 +00:00
# endif
2020-08-05 17:25:04 +00:00
} ;
if ( ! m_toggle ) {
change_text_color ( m_text , black , grey ) ;
change_text_color ( m_old_value , black , grey ) ;
change_text_color ( m_new_value , orange , grey ) ;
}
else {
change_text_color ( m_text , grey , black ) ;
change_text_color ( m_old_value , grey , black ) ;
change_text_color ( m_new_value , grey , orange ) ;
}
// update icons for the colors
2020-08-12 11:36:26 +00:00
UpdateIcons ( ) ;
}
void ModelNode : : UpdateIcons ( )
{
// update icons for the colors, if any exists
2020-08-05 17:25:04 +00:00
if ( ! m_old_color . IsEmpty ( ) )
2020-08-12 11:36:26 +00:00
m_old_color_bmp = get_bitmap ( m_toggle ? m_old_color : grey ) ;
2020-08-05 17:25:04 +00:00
if ( ! m_new_color . IsEmpty ( ) )
2020-08-12 11:36:26 +00:00
m_new_color_bmp = get_bitmap ( m_toggle ? m_new_color : grey ) ;
// update main icon, if any exists
if ( m_icon_name . empty ( ) )
return ;
# ifdef __linux__
m_icon . CopyFromBitmap ( create_scaled_bitmap ( m_icon_name , m_parent_win , 16 , ! m_toggle ) ) ;
# else
m_icon = create_scaled_bitmap ( m_icon_name , m_parent_win , 16 , ! m_toggle ) ;
# endif //__linux__
2020-07-30 14:16:56 +00:00
}
// ----------------------------------------------------------------------------
// UnsavedChangesModel
// ----------------------------------------------------------------------------
2020-08-05 17:25:04 +00:00
UnsavedChangesModel : : UnsavedChangesModel ( wxWindow * parent ) :
m_parent_win ( parent )
2020-07-30 14:16:56 +00:00
{
}
UnsavedChangesModel : : ~ UnsavedChangesModel ( )
{
2020-08-05 17:25:04 +00:00
for ( ModelNode * preset_node : m_preset_nodes )
delete preset_node ;
}
2020-10-07 18:13:12 +00:00
wxDataViewItem UnsavedChangesModel : : AddPreset ( Preset : : Type type , wxString preset_name , PrinterTechnology pt )
2020-08-05 17:25:04 +00:00
{
// "color" strings
color_string ( preset_name , black ) ;
make_string_bold ( preset_name ) ;
2020-10-07 18:13:12 +00:00
auto preset = new ModelNode ( type , m_parent_win , preset_name , get_icon_name ( type , pt ) ) ;
2020-08-05 17:25:04 +00:00
m_preset_nodes . emplace_back ( preset ) ;
wxDataViewItem child ( ( void * ) preset ) ;
wxDataViewItem parent ( nullptr ) ;
ItemAdded ( parent , child ) ;
return child ;
}
ModelNode * UnsavedChangesModel : : AddOption ( ModelNode * group_node , wxString option_name , wxString old_value , wxString new_value )
{
2020-10-16 10:20:51 +00:00
group_node - > Append ( std : : make_unique < ModelNode > ( group_node , option_name , old_value , new_value ) ) ;
ModelNode * option = group_node - > GetChildren ( ) . back ( ) . get ( ) ;
2020-08-07 13:09:58 +00:00
wxDataViewItem group_item = wxDataViewItem ( ( void * ) group_node ) ;
ItemAdded ( group_item , wxDataViewItem ( ( void * ) option ) ) ;
2020-08-05 17:25:04 +00:00
2020-08-07 13:09:58 +00:00
m_ctrl - > Expand ( group_item ) ;
2020-08-05 17:25:04 +00:00
return option ;
}
ModelNode * UnsavedChangesModel : : AddOptionWithGroup ( ModelNode * category_node , wxString group_name , wxString option_name , wxString old_value , wxString new_value )
{
2020-10-16 10:20:51 +00:00
category_node - > Append ( std : : make_unique < ModelNode > ( category_node , group_name ) ) ;
ModelNode * group_node = category_node - > GetChildren ( ) . back ( ) . get ( ) ;
2020-08-07 13:09:58 +00:00
ItemAdded ( wxDataViewItem ( ( void * ) category_node ) , wxDataViewItem ( ( void * ) group_node ) ) ;
2020-08-05 17:25:04 +00:00
return AddOption ( group_node , option_name , old_value , new_value ) ;
}
2020-10-07 18:13:12 +00:00
ModelNode * UnsavedChangesModel : : AddOptionWithGroupAndCategory ( ModelNode * preset_node , wxString category_name , wxString group_name ,
wxString option_name , wxString old_value , wxString new_value , const std : : string category_icon_name )
2020-08-05 17:25:04 +00:00
{
2020-10-16 10:20:51 +00:00
preset_node - > Append ( std : : make_unique < ModelNode > ( preset_node , category_name , category_icon_name ) ) ;
ModelNode * category_node = preset_node - > GetChildren ( ) . back ( ) . get ( ) ;
2020-08-05 17:25:04 +00:00
ItemAdded ( wxDataViewItem ( ( void * ) preset_node ) , wxDataViewItem ( ( void * ) category_node ) ) ;
return AddOptionWithGroup ( category_node , group_name , option_name , old_value , new_value ) ;
}
wxDataViewItem UnsavedChangesModel : : AddOption ( Preset : : Type type , wxString category_name , wxString group_name , wxString option_name ,
2020-10-07 18:13:12 +00:00
wxString old_value , wxString new_value , const std : : string category_icon_name )
2020-08-05 17:25:04 +00:00
{
// "color" strings
color_string ( category_name , black ) ;
color_string ( group_name , black ) ;
color_string ( option_name , black ) ;
// "make" strings bold
make_string_bold ( category_name ) ;
make_string_bold ( group_name ) ;
// add items
for ( ModelNode * preset : m_preset_nodes )
if ( preset - > type ( ) = = type )
{
2020-10-16 10:20:51 +00:00
for ( std : : unique_ptr < ModelNode > & category : preset - > GetChildren ( ) )
2020-08-05 17:25:04 +00:00
if ( category - > text ( ) = = category_name )
{
2020-10-16 10:20:51 +00:00
for ( std : : unique_ptr < ModelNode > & group : category - > GetChildren ( ) )
2020-08-05 17:25:04 +00:00
if ( group - > text ( ) = = group_name )
2020-10-16 10:20:51 +00:00
return wxDataViewItem ( ( void * ) AddOption ( group . get ( ) , option_name , old_value , new_value ) ) ;
2020-08-05 17:25:04 +00:00
2020-10-16 10:20:51 +00:00
return wxDataViewItem ( ( void * ) AddOptionWithGroup ( category . get ( ) , group_name , option_name , old_value , new_value ) ) ;
2020-08-05 17:25:04 +00:00
}
2020-10-07 18:13:12 +00:00
return wxDataViewItem ( ( void * ) AddOptionWithGroupAndCategory ( preset , category_name , group_name , option_name , old_value , new_value , category_icon_name ) ) ;
2020-08-05 17:25:04 +00:00
}
return wxDataViewItem ( nullptr ) ;
}
static void update_children ( ModelNode * parent )
{
if ( parent - > IsContainer ( ) ) {
bool toggle = parent - > IsToggled ( ) ;
2020-10-16 10:20:51 +00:00
for ( std : : unique_ptr < ModelNode > & child : parent - > GetChildren ( ) ) {
2020-08-05 17:25:04 +00:00
child - > Toggle ( toggle ) ;
child - > UpdateEnabling ( ) ;
2020-10-16 10:20:51 +00:00
update_children ( child . get ( ) ) ;
2020-08-05 17:25:04 +00:00
}
}
}
static void update_parents ( ModelNode * node )
{
ModelNode * parent = node - > GetParent ( ) ;
if ( parent ) {
bool toggle = false ;
2020-10-16 10:20:51 +00:00
for ( std : : unique_ptr < ModelNode > & child : parent - > GetChildren ( ) ) {
2020-08-05 17:25:04 +00:00
if ( child - > IsToggled ( ) ) {
toggle = true ;
break ;
}
}
parent - > Toggle ( toggle ) ;
parent - > UpdateEnabling ( ) ;
update_parents ( parent ) ;
}
}
void UnsavedChangesModel : : UpdateItemEnabling ( wxDataViewItem item )
{
assert ( item . IsOk ( ) ) ;
2020-11-26 12:45:30 +00:00
ModelNode * node = static_cast < ModelNode * > ( item . GetID ( ) ) ;
2020-08-05 17:25:04 +00:00
node - > UpdateEnabling ( ) ;
update_children ( node ) ;
update_parents ( node ) ;
2020-07-30 14:16:56 +00:00
}
2020-08-10 09:24:31 +00:00
bool UnsavedChangesModel : : IsEnabledItem ( const wxDataViewItem & item )
{
assert ( item . IsOk ( ) ) ;
2020-11-26 12:45:30 +00:00
ModelNode * node = static_cast < ModelNode * > ( item . GetID ( ) ) ;
2020-08-10 09:24:31 +00:00
return node - > IsToggled ( ) ;
}
2020-07-30 14:16:56 +00:00
void UnsavedChangesModel : : GetValue ( wxVariant & variant , const wxDataViewItem & item , unsigned int col ) const
{
2020-08-05 17:25:04 +00:00
assert ( item . IsOk ( ) ) ;
2020-07-30 14:16:56 +00:00
2020-11-26 12:45:30 +00:00
ModelNode * node = static_cast < ModelNode * > ( item . GetID ( ) ) ;
2020-07-30 14:16:56 +00:00
switch ( col )
{
case colToggle :
variant = node - > m_toggle ;
break ;
2020-08-10 07:45:32 +00:00
# ifdef __linux__
2020-08-10 09:24:31 +00:00
case colIconText :
2020-08-10 07:45:32 +00:00
variant < < wxDataViewIconText ( node - > m_text , node - > m_icon ) ;
2020-08-10 09:24:31 +00:00
break ;
case colOldValue :
variant < < wxDataViewIconText ( node - > m_old_value , node - > m_old_color_bmp ) ;
break ;
case colNewValue :
variant < < wxDataViewIconText ( node - > m_new_value , node - > m_new_color_bmp ) ;
break ;
2020-08-10 07:45:32 +00:00
# else
2020-08-10 09:24:31 +00:00
case colIconText :
2020-08-05 17:25:04 +00:00
variant < < DataViewBitmapText ( node - > m_text , node - > m_icon ) ;
2020-07-30 14:16:56 +00:00
break ;
case colOldValue :
2020-08-05 17:25:04 +00:00
variant < < DataViewBitmapText ( node - > m_old_value , node - > m_old_color_bmp ) ;
2020-07-30 14:16:56 +00:00
break ;
case colNewValue :
2020-08-05 17:25:04 +00:00
variant < < DataViewBitmapText ( node - > m_new_value , node - > m_new_color_bmp ) ;
2020-07-30 14:16:56 +00:00
break ;
2020-08-10 09:24:31 +00:00
# endif //__linux__
2020-07-30 14:16:56 +00:00
default :
wxLogError ( " UnsavedChangesModel::GetValue: wrong column %d " , col ) ;
}
}
bool UnsavedChangesModel : : SetValue ( const wxVariant & variant , const wxDataViewItem & item , unsigned int col )
{
assert ( item . IsOk ( ) ) ;
2020-11-26 12:45:30 +00:00
ModelNode * node = static_cast < ModelNode * > ( item . GetID ( ) ) ;
2020-07-30 14:16:56 +00:00
switch ( col )
{
2020-08-10 09:24:31 +00:00
case colToggle :
node - > m_toggle = variant . GetBool ( ) ;
return true ;
2020-08-10 07:45:32 +00:00
# ifdef __linux__
2020-08-10 09:24:31 +00:00
case colIconText : {
2020-08-10 07:45:32 +00:00
wxDataViewIconText data ;
2020-08-05 17:25:04 +00:00
data < < variant ;
2020-08-10 07:45:32 +00:00
node - > m_icon = data . GetIcon ( ) ;
2020-08-10 09:24:31 +00:00
node - > m_text = data . GetText ( ) ;
return true ; }
case colOldValue : {
wxDataViewIconText data ;
data < < variant ;
node - > m_old_color_bmp = data . GetIcon ( ) ;
node - > m_old_value = data . GetText ( ) ;
return true ; }
case colNewValue : {
wxDataViewIconText data ;
data < < variant ;
node - > m_new_color_bmp = data . GetIcon ( ) ;
node - > m_new_value = data . GetText ( ) ;
return true ; }
2020-08-10 07:45:32 +00:00
# else
2020-08-10 09:24:31 +00:00
case colIconText : {
DataViewBitmapText data ;
data < < variant ;
2020-08-10 07:45:32 +00:00
node - > m_icon = data . GetBitmap ( ) ;
2020-08-10 09:24:31 +00:00
node - > m_text = data . GetText ( ) ;
2020-08-05 17:25:04 +00:00
return true ; }
case colOldValue : {
DataViewBitmapText data ;
data < < variant ;
node - > m_old_color_bmp = data . GetBitmap ( ) ;
node - > m_old_value = data . GetText ( ) ;
return true ; }
case colNewValue : {
DataViewBitmapText data ;
data < < variant ;
node - > m_new_color_bmp = data . GetBitmap ( ) ;
node - > m_new_value = data . GetText ( ) ;
return true ; }
2020-08-10 09:24:31 +00:00
# endif //__linux__
2020-07-30 14:16:56 +00:00
default :
wxLogError ( " UnsavedChangesModel::SetValue: wrong column " ) ;
}
return false ;
}
bool UnsavedChangesModel : : IsEnabled ( const wxDataViewItem & item , unsigned int col ) const
{
assert ( item . IsOk ( ) ) ;
2020-08-05 17:25:04 +00:00
if ( col = = colToggle )
return true ;
2020-07-30 14:16:56 +00:00
// disable unchecked nodes
2020-11-26 12:45:30 +00:00
return ( static_cast < ModelNode * > ( item . GetID ( ) ) ) - > IsToggled ( ) ;
2020-07-30 14:16:56 +00:00
}
wxDataViewItem UnsavedChangesModel : : GetParent ( const wxDataViewItem & item ) const
{
// the invisible root node has no parent
if ( ! item . IsOk ( ) )
return wxDataViewItem ( nullptr ) ;
2020-11-26 12:45:30 +00:00
ModelNode * node = static_cast < ModelNode * > ( item . GetID ( ) ) ;
2020-07-30 14:16:56 +00:00
// "MyMusic" also has no parent
2020-08-05 17:25:04 +00:00
if ( node - > IsRoot ( ) )
2020-07-30 14:16:56 +00:00
return wxDataViewItem ( nullptr ) ;
return wxDataViewItem ( ( void * ) node - > GetParent ( ) ) ;
}
bool UnsavedChangesModel : : IsContainer ( const wxDataViewItem & item ) const
{
// the invisble root node can have children
if ( ! item . IsOk ( ) )
return true ;
2020-11-26 12:45:30 +00:00
ModelNode * node = static_cast < ModelNode * > ( item . GetID ( ) ) ;
2020-07-30 14:16:56 +00:00
return node - > IsContainer ( ) ;
}
unsigned int UnsavedChangesModel : : GetChildren ( const wxDataViewItem & parent , wxDataViewItemArray & array ) const
{
ModelNode * node = ( ModelNode * ) parent . GetID ( ) ;
if ( ! node ) {
2020-08-05 17:25:04 +00:00
for ( auto preset_node : m_preset_nodes )
array . Add ( wxDataViewItem ( ( void * ) preset_node ) ) ;
return m_preset_nodes . size ( ) ;
2020-07-30 14:16:56 +00:00
}
2020-10-16 10:20:51 +00:00
for ( std : : unique_ptr < ModelNode > & child : node - > GetChildren ( ) )
array . Add ( wxDataViewItem ( ( void * ) child . get ( ) ) ) ;
2020-07-30 14:16:56 +00:00
2020-10-16 10:20:51 +00:00
return node - > GetChildCount ( ) ;
2020-07-30 14:16:56 +00:00
}
wxString UnsavedChangesModel : : GetColumnType ( unsigned int col ) const
{
2020-08-05 17:25:04 +00:00
switch ( col )
{
case colToggle :
2020-07-30 14:16:56 +00:00
return " bool " ;
2020-08-05 17:25:04 +00:00
case colIconText :
case colOldValue :
case colNewValue :
default :
return " DataViewBitmapText " ; //"string";
}
2020-07-30 14:16:56 +00:00
}
2020-08-12 11:36:26 +00:00
static void rescale_children ( ModelNode * parent )
{
if ( parent - > IsContainer ( ) ) {
2020-10-16 10:20:51 +00:00
for ( std : : unique_ptr < ModelNode > & child : parent - > GetChildren ( ) ) {
2020-08-12 11:36:26 +00:00
child - > UpdateIcons ( ) ;
2020-10-16 10:20:51 +00:00
rescale_children ( child . get ( ) ) ;
2020-08-12 11:36:26 +00:00
}
}
}
void UnsavedChangesModel : : Rescale ( )
{
for ( ModelNode * node : m_preset_nodes ) {
node - > UpdateIcons ( ) ;
rescale_children ( node ) ;
}
}
2020-07-30 14:16:56 +00:00
//------------------------------------------
// UnsavedChangesDialog
//------------------------------------------
2020-08-14 16:17:16 +00:00
UnsavedChangesDialog : : UnsavedChangesDialog ( const wxString & header )
2020-11-26 12:45:30 +00:00
: DPIDialog ( static_cast < wxWindow * > ( wxGetApp ( ) . mainframe ) , wxID_ANY , _L ( " PrusaSlicer is closing: Unsaved Changes " ) , wxDefaultPosition , wxDefaultSize , wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER )
2020-08-14 16:17:16 +00:00
{
2020-10-15 14:48:48 +00:00
m_app_config_key = " default_action_on_close_application " ;
2020-08-14 16:17:16 +00:00
build ( Preset : : TYPE_INVALID , nullptr , " " , header ) ;
2020-10-15 14:48:48 +00:00
const std : : string & def_action = wxGetApp ( ) . app_config - > get ( m_app_config_key ) ;
if ( def_action = = " none " )
this - > CenterOnScreen ( ) ;
else {
m_exit_action = def_action = = ActSave ? Action : : Save : Action : : Discard ;
if ( m_exit_action = = Action : : Save )
save ( nullptr ) ;
}
2020-08-14 16:17:16 +00:00
}
2020-08-13 13:45:16 +00:00
UnsavedChangesDialog : : UnsavedChangesDialog ( Preset : : Type type , PresetCollection * dependent_presets , const std : : string & new_selected_preset )
2020-11-26 12:45:30 +00:00
: DPIDialog ( static_cast < wxWindow * > ( wxGetApp ( ) . mainframe ) , wxID_ANY , _L ( " Switching Presets: Unsaved Changes " ) , wxDefaultPosition , wxDefaultSize , wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER )
2020-08-14 16:17:16 +00:00
{
2020-10-15 14:48:48 +00:00
m_app_config_key = " default_action_on_select_preset " ;
2020-08-14 16:17:16 +00:00
build ( type , dependent_presets , new_selected_preset ) ;
2020-10-15 14:48:48 +00:00
const std : : string & def_action = wxGetApp ( ) . app_config - > get ( m_app_config_key ) ;
if ( def_action = = " none " ) {
2020-10-16 11:19:59 +00:00
if ( wxGetApp ( ) . mainframe - > is_dlg_layout ( ) & & wxGetApp ( ) . mainframe - > m_settings_dialog . HasFocus ( ) )
2020-10-15 14:48:48 +00:00
this - > SetPosition ( wxGetApp ( ) . mainframe - > m_settings_dialog . GetPosition ( ) ) ;
this - > CenterOnScreen ( ) ;
}
else {
m_exit_action = def_action = = ActTransfer ? Action : : Transfer :
def_action = = ActSave ? Action : : Save : Action : : Discard ;
const PresetCollection & printers = wxGetApp ( ) . preset_bundle - > printers ;
if ( m_exit_action = = Action : : Save | |
( m_exit_action = = Action : : Transfer & & dependent_presets & & ( type = = dependent_presets - > type ( ) ?
dependent_presets - > get_edited_preset ( ) . printer_technology ( ) ! = dependent_presets - > find_preset ( new_selected_preset ) - > printer_technology ( ) :
printers . get_edited_preset ( ) . printer_technology ( ) ! = printers . find_preset ( new_selected_preset ) - > printer_technology ( ) ) ) )
save ( dependent_presets ) ;
}
2020-08-14 16:17:16 +00:00
}
void UnsavedChangesDialog : : build ( Preset : : Type type , PresetCollection * dependent_presets , const std : : string & new_selected_preset , const wxString & header )
2020-07-30 14:16:56 +00:00
{
wxColour bgr_clr = wxSystemSettings : : GetColour ( wxSYS_COLOUR_WINDOW ) ;
SetBackgroundColour ( bgr_clr ) ;
2020-09-03 08:44:54 +00:00
# if ENABLE_WX_3_1_3_DPI_CHANGED_EVENT && defined(__WXMSW__)
2020-08-12 11:36:26 +00:00
// ys_FIXME! temporary workaround for correct font scaling
// Because of from wxWidgets 3.1.3 auto rescaling is implemented for the Fonts,
// From the very beginning set dialog font to the wxSYS_DEFAULT_GUI_FONT
this - > SetFont ( wxSystemSettings : : GetFont ( wxSYS_DEFAULT_GUI_FONT ) ) ;
# endif // ENABLE_WX_3_1_3_DPI_CHANGED_EVENT
2020-07-30 14:16:56 +00:00
int border = 10 ;
int em = em_unit ( ) ;
2020-08-13 13:45:16 +00:00
m_action_line = new wxStaticText ( this , wxID_ANY , " " ) ;
m_action_line - > SetFont ( wxSystemSettings : : GetFont ( wxSYS_DEFAULT_GUI_FONT ) . Bold ( ) ) ;
2020-10-15 14:48:48 +00:00
m_tree = new wxDataViewCtrl ( this , wxID_ANY , wxDefaultPosition , wxSize ( em * 60 , em * 30 ) , wxBORDER_SIMPLE | wxDV_VARIABLE_LINE_HEIGHT | wxDV_ROW_LINES ) ;
2020-08-05 17:25:04 +00:00
m_tree_model = new UnsavedChangesModel ( this ) ;
m_tree - > AssociateModel ( m_tree_model ) ;
m_tree_model - > SetAssociatedControl ( m_tree ) ;
2020-07-30 14:16:56 +00:00
2020-11-30 12:48:22 +00:00
m_tree - > AppendToggleColumn ( L " \u2714 " , UnsavedChangesModel : : colToggle , wxDATAVIEW_CELL_ACTIVATABLE , ( wxLinux ? 8 : 6 ) * em ) ;
2020-08-10 07:45:32 +00:00
2020-08-11 07:17:52 +00:00
auto append_bmp_text_column = [ this ] ( const wxString & label , unsigned model_column , int width , bool set_expander = false )
{
2020-08-10 07:45:32 +00:00
# ifdef __linux__
2020-08-11 07:17:52 +00:00
wxDataViewIconTextRenderer * rd = new wxDataViewIconTextRenderer ( ) ;
2020-08-10 07:45:32 +00:00
# ifdef SUPPORTS_MARKUP
2020-08-11 07:17:52 +00:00
rd - > EnableMarkup ( true ) ;
2020-08-10 07:45:32 +00:00
# endif
2020-08-11 07:17:52 +00:00
wxDataViewColumn * column = new wxDataViewColumn ( label , rd , model_column , width , wxALIGN_TOP , wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_CELL_INERT ) ;
2020-08-10 07:45:32 +00:00
# else
2020-10-18 11:44:15 +00:00
wxDataViewColumn * column = new wxDataViewColumn ( label , new BitmapTextRenderer ( true , wxDATAVIEW_CELL_INERT ) , model_column , width , wxALIGN_TOP , wxDATAVIEW_COL_RESIZABLE ) ;
2020-08-10 07:45:32 +00:00
# endif //__linux__
2020-08-11 07:17:52 +00:00
m_tree - > AppendColumn ( column ) ;
if ( set_expander )
m_tree - > SetExpanderColumn ( column ) ;
} ;
2020-08-05 17:25:04 +00:00
2020-10-15 14:48:48 +00:00
append_bmp_text_column ( " " , UnsavedChangesModel : : colIconText , 28 * em ) ;
append_bmp_text_column ( _L ( " Old Value " ) , UnsavedChangesModel : : colOldValue , 12 * em ) ;
append_bmp_text_column ( _L ( " New Value " ) , UnsavedChangesModel : : colNewValue , 12 * em ) ;
2020-08-07 13:09:58 +00:00
2020-08-05 17:25:04 +00:00
m_tree - > Bind ( wxEVT_DATAVIEW_ITEM_VALUE_CHANGED , & UnsavedChangesDialog : : item_value_changed , this ) ;
2020-08-10 17:07:45 +00:00
m_tree - > Bind ( wxEVT_DATAVIEW_ITEM_CONTEXT_MENU , & UnsavedChangesDialog : : context_menu , this ) ;
2020-08-05 17:25:04 +00:00
2020-08-11 07:17:52 +00:00
// Add Buttons
2020-10-15 14:48:48 +00:00
wxFont btn_font = this - > GetFont ( ) . Scaled ( 1.4f ) ;
wxBoxSizer * buttons = new wxBoxSizer ( wxHORIZONTAL ) ;
2020-08-10 09:24:31 +00:00
2020-10-15 14:48:48 +00:00
auto add_btn = [ this , buttons , btn_font , dependent_presets ] ( ScalableButton * * btn , int & btn_id , const std : : string & icon_name , Action close_act , const wxString & label , bool process_enable = true )
2020-08-13 13:45:16 +00:00
{
2020-10-15 14:48:48 +00:00
* btn = new ScalableButton ( this , btn_id = NewControlId ( ) , icon_name , label , wxDefaultSize , wxDefaultPosition , wxBORDER_DEFAULT , true , 24 ) ;
2020-07-30 14:16:56 +00:00
2020-10-15 14:48:48 +00:00
buttons - > Add ( * btn , 1 , wxLEFT , 5 ) ;
( * btn ) - > SetFont ( btn_font ) ;
( * btn ) - > Bind ( wxEVT_BUTTON , [ this , close_act , dependent_presets ] ( wxEvent & ) {
update_config ( close_act ) ;
2020-10-15 17:10:34 +00:00
if ( close_act = = Action : : Save & & ! save ( dependent_presets ) )
return ;
2020-10-15 14:48:48 +00:00
close ( close_act ) ;
} ) ;
2020-08-13 13:45:16 +00:00
if ( process_enable )
( * btn ) - > Bind ( wxEVT_UPDATE_UI , [ this ] ( wxUpdateUIEvent & evt ) { evt . Enable ( ! m_empty_selection ) ; } ) ;
( * btn ) - > Bind ( wxEVT_LEAVE_WINDOW , [ this ] ( wxMouseEvent & e ) { show_info_line ( Action : : Undef ) ; e . Skip ( ) ; } ) ;
} ;
2020-08-10 09:24:31 +00:00
2020-09-17 13:25:05 +00:00
const PresetCollection & printers = wxGetApp ( ) . preset_bundle - > printers ;
2020-10-15 14:48:48 +00:00
if ( dependent_presets & & ( type = = dependent_presets - > type ( ) ?
dependent_presets - > get_edited_preset ( ) . printer_technology ( ) = = dependent_presets - > find_preset ( new_selected_preset ) - > printer_technology ( ) :
printers . get_edited_preset ( ) . printer_technology ( ) = = printers . find_preset ( new_selected_preset ) - > printer_technology ( ) ) )
add_btn ( & m_transfer_btn , m_move_btn_id , " paste_menu " , Action : : Transfer , _L ( " Transfer " ) ) ;
2020-10-16 11:19:59 +00:00
add_btn ( & m_discard_btn , m_continue_btn_id , dependent_presets ? " switch_presets " : " exit " , Action : : Discard , _L ( " Discard " ) , false ) ;
2020-10-15 14:48:48 +00:00
add_btn ( & m_save_btn , m_save_btn_id , " save " , Action : : Save , _L ( " Save " ) ) ;
ScalableButton * cancel_btn = new ScalableButton ( this , wxID_CANCEL , " cross " , _L ( " Cancel " ) , wxDefaultSize , wxDefaultPosition , wxBORDER_DEFAULT , true , 24 ) ;
buttons - > Add ( cancel_btn , 1 , wxLEFT | wxRIGHT , 5 ) ;
cancel_btn - > SetFont ( btn_font ) ;
cancel_btn - > Bind ( wxEVT_BUTTON , [ this ] ( wxEvent & ) { this - > EndModal ( wxID_CANCEL ) ; } ) ;
2020-08-10 17:07:45 +00:00
m_info_line = new wxStaticText ( this , wxID_ANY , " " ) ;
2020-08-12 11:36:26 +00:00
m_info_line - > SetFont ( wxSystemSettings : : GetFont ( wxSYS_DEFAULT_GUI_FONT ) . Bold ( ) ) ;
m_info_line - > Hide ( ) ;
2020-07-30 14:16:56 +00:00
2020-10-15 14:48:48 +00:00
m_remember_choice = new wxCheckBox ( this , wxID_ANY , _L ( " Remember my choice " ) ) ;
m_remember_choice - > SetValue ( wxGetApp ( ) . app_config - > get ( m_app_config_key ) ! = " none " ) ;
2020-10-15 17:10:34 +00:00
m_remember_choice - > Bind ( wxEVT_CHECKBOX , [ type , this ] ( wxCommandEvent & evt )
2020-10-15 14:48:48 +00:00
{
if ( ! evt . IsChecked ( ) )
return ;
2020-10-17 12:04:05 +00:00
wxString preferences_item = type = = Preset : : TYPE_INVALID ? _L ( " Ask for unsaved changes when closing application " ) :
_L ( " Ask for unsaved changes when selecting new preset " ) ;
wxString msg =
_L ( " PrusaSlicer will remember your action. " ) + " \n \n " +
( type = = Preset : : TYPE_INVALID ?
_L ( " You will not be asked about the unsaved changes the next time you close PrusaSlicer. " ) :
_L ( " You will not be asked about the unsaved changes the next time you switch a preset. " ) ) + " \n \n " +
format_wxstr ( _L ( " Visit \" Preferences \" and check \" %1% \" \n to be asked about unsaved changes again. " ) , preferences_item ) ;
2020-10-15 14:48:48 +00:00
2020-10-17 12:04:05 +00:00
wxMessageDialog dialog ( nullptr , msg , _L ( " PrusaSlicer: Don't ask me again " ) , wxOK | wxCANCEL | wxICON_INFORMATION ) ;
2020-10-15 17:10:34 +00:00
if ( dialog . ShowModal ( ) = = wxID_CANCEL )
m_remember_choice - > SetValue ( false ) ;
2020-10-15 14:48:48 +00:00
} ) ;
2020-07-30 14:16:56 +00:00
wxBoxSizer * topSizer = new wxBoxSizer ( wxVERTICAL ) ;
2020-08-13 13:45:16 +00:00
topSizer - > Add ( m_action_line , 0 , wxEXPAND | wxLEFT | wxTOP | wxRIGHT , border ) ;
2020-08-11 07:17:52 +00:00
topSizer - > Add ( m_tree , 1 , wxEXPAND | wxLEFT | wxTOP | wxRIGHT , border ) ;
topSizer - > Add ( m_info_line , 0 , wxEXPAND | wxLEFT | wxTOP | wxRIGHT , 2 * border ) ;
2020-10-15 14:48:48 +00:00
topSizer - > Add ( buttons , 0 , wxEXPAND | wxLEFT | wxTOP | wxRIGHT , border ) ;
topSizer - > Add ( m_remember_choice , 0 , wxEXPAND | wxALL , border ) ;
2020-08-05 17:25:04 +00:00
2020-08-14 16:17:16 +00:00
update ( type , dependent_presets , new_selected_preset , header ) ;
2020-07-30 14:16:56 +00:00
SetSizer ( topSizer ) ;
topSizer - > SetSizeHints ( this ) ;
2020-08-11 07:17:52 +00:00
show_info_line ( Action : : Undef ) ;
2020-07-30 14:16:56 +00:00
}
2020-08-05 17:25:04 +00:00
void UnsavedChangesDialog : : item_value_changed ( wxDataViewEvent & event )
{
if ( event . GetColumn ( ) ! = UnsavedChangesModel : : colToggle )
return ;
wxDataViewItem item = event . GetItem ( ) ;
m_tree_model - > UpdateItemEnabling ( item ) ;
m_tree - > Refresh ( ) ;
2020-08-10 09:24:31 +00:00
// update an enabling of the "save/move" buttons
m_empty_selection = get_selected_options ( ) . empty ( ) ;
2020-08-05 17:25:04 +00:00
}
2020-08-10 17:07:45 +00:00
void UnsavedChangesDialog : : context_menu ( wxDataViewEvent & event )
{
if ( ! m_has_long_strings )
return ;
wxDataViewItem item = event . GetItem ( ) ;
if ( ! item )
{
wxPoint mouse_pos = wxGetMousePosition ( ) - m_tree - > GetScreenPosition ( ) ;
wxDataViewColumn * col = nullptr ;
m_tree - > HitTest ( mouse_pos , item , col ) ;
if ( ! item )
item = m_tree - > GetSelection ( ) ;
if ( ! item )
return ;
}
auto it = m_items_map . find ( item ) ;
if ( it = = m_items_map . end ( ) | | ! it - > second . is_long )
return ;
FullCompareDialog ( it - > second . opt_name , it - > second . old_val , it - > second . new_val ) . ShowModal ( ) ;
}
void UnsavedChangesDialog : : show_info_line ( Action action , std : : string preset_name )
{
if ( action = = Action : : Undef & & ! m_has_long_strings )
m_info_line - > Hide ( ) ;
else {
wxString text ;
if ( action = = Action : : Undef )
2020-10-17 12:04:05 +00:00
text = _L ( " Some fields are too long to fit. Right mouse click reveals the full text. " ) ;
2020-10-15 14:48:48 +00:00
else if ( action = = Action : : Discard )
2020-11-12 20:35:05 +00:00
text = _L ( " All settings changes will be discarded. " ) ;
2020-08-10 17:07:45 +00:00
else {
2020-09-02 07:06:42 +00:00
if ( preset_name . empty ( ) )
2020-11-05 21:17:49 +00:00
text = action = = Action : : Save ? _L ( " Save the selected options. " ) : _L ( " Transfer the selected settings to the newly selected preset. " ) ;
2020-09-02 07:06:42 +00:00
else
2020-10-17 12:04:05 +00:00
text = format_wxstr (
action = = Action : : Save ?
_L ( " Save the selected options to preset \" %1% \" . " ) :
_L ( " Transfer the selected options to the newly selected preset \" %1% \" . " ) ,
preset_name ) ;
//text += "\n" + _L("Unselected options will be reverted.");
2020-08-10 17:07:45 +00:00
}
m_info_line - > SetLabel ( text ) ;
m_info_line - > Show ( ) ;
}
Layout ( ) ;
Refresh ( ) ;
}
2020-10-15 14:48:48 +00:00
void UnsavedChangesDialog : : update_config ( Action action )
{
if ( ! m_remember_choice - > GetValue ( ) )
return ;
std : : string act = action = = Action : : Transfer ? ActTransfer :
action = = Action : : Discard ? ActDiscard : ActSave ;
wxGetApp ( ) . app_config - > set ( m_app_config_key , act ) ;
}
2020-08-05 17:25:04 +00:00
void UnsavedChangesDialog : : close ( Action action )
{
2020-08-10 17:07:45 +00:00
m_exit_action = action ;
2020-08-05 17:25:04 +00:00
this - > EndModal ( wxID_CLOSE ) ;
}
2020-10-15 17:10:34 +00:00
bool UnsavedChangesDialog : : save ( PresetCollection * dependent_presets )
2020-10-03 01:15:54 +00:00
{
names_and_types . clear ( ) ;
// save one preset
if ( dependent_presets ) {
const Preset & preset = dependent_presets - > get_edited_preset ( ) ;
std : : string name = preset . name ;
// for system/default/external presets we should take an edited name
if ( preset . is_system | | preset . is_default | | preset . is_external ) {
2020-11-05 19:50:49 +00:00
SavePresetDialog save_dlg ( this , preset . type ) ;
2020-10-15 14:48:48 +00:00
if ( save_dlg . ShowModal ( ) ! = wxID_OK ) {
m_exit_action = Action : : Discard ;
2020-10-15 17:10:34 +00:00
return false ;
2020-10-15 14:48:48 +00:00
}
2020-10-03 01:15:54 +00:00
name = save_dlg . get_name ( ) ;
}
names_and_types . emplace_back ( make_pair ( name , preset . type ) ) ;
}
// save all presets
else
{
std : : vector < Preset : : Type > types_for_save ;
PrinterTechnology printer_technology = wxGetApp ( ) . preset_bundle - > printers . get_edited_preset ( ) . printer_technology ( ) ;
for ( Tab * tab : wxGetApp ( ) . tabs_list )
if ( tab - > supports_printer_technology ( printer_technology ) & & tab - > current_preset_is_dirty ( ) ) {
const Preset & preset = tab - > get_presets ( ) - > get_edited_preset ( ) ;
if ( preset . is_system | | preset . is_default | | preset . is_external )
types_for_save . emplace_back ( preset . type ) ;
names_and_types . emplace_back ( make_pair ( preset . name , preset . type ) ) ;
}
if ( ! types_for_save . empty ( ) ) {
2020-11-05 19:50:49 +00:00
SavePresetDialog save_dlg ( this , types_for_save ) ;
2020-10-15 14:48:48 +00:00
if ( save_dlg . ShowModal ( ) ! = wxID_OK ) {
m_exit_action = Action : : Discard ;
2020-10-15 17:10:34 +00:00
return false ;
2020-10-15 14:48:48 +00:00
}
2020-10-03 01:15:54 +00:00
for ( std : : pair < std : : string , Preset : : Type > & nt : names_and_types ) {
const std : : string & name = save_dlg . get_name ( nt . second ) ;
if ( ! name . empty ( ) )
nt . first = name ;
}
}
}
2020-10-15 17:10:34 +00:00
return true ;
2020-10-03 01:15:54 +00:00
}
2020-08-05 17:25:04 +00:00
template < class T >
2020-08-07 13:09:58 +00:00
wxString get_string_from_enum ( const std : : string & opt_key , const DynamicPrintConfig & config , bool is_infill = false )
2020-08-05 17:25:04 +00:00
{
2020-08-07 13:09:58 +00:00
const ConfigOptionDef & def = config . def ( ) - > options . at ( opt_key ) ;
const std : : vector < std : : string > & names = def . enum_labels ; //ConfigOptionEnum<T>::get_enum_names();
2020-08-05 17:25:04 +00:00
T val = config . option < ConfigOptionEnum < T > > ( opt_key ) - > value ;
2020-08-07 13:09:58 +00:00
// Each infill doesn't use all list of infill declared in PrintConfig.hpp.
// So we should "convert" val to the correct one
if ( is_infill ) {
for ( auto key_val : * def . enum_keys_map )
if ( ( int ) key_val . second = = ( int ) val ) {
auto it = std : : find ( def . enum_values . begin ( ) , def . enum_values . end ( ) , key_val . first ) ;
if ( it = = def . enum_values . end ( ) )
return " " ;
return from_u8 ( _utf8 ( names [ it - def . enum_values . begin ( ) ] ) ) ;
}
return _L ( " Undef " ) ;
}
return from_u8 ( _utf8 ( names [ static_cast < int > ( val ) ] ) ) ;
2020-08-05 17:25:04 +00:00
}
2020-08-18 14:49:06 +00:00
static int get_id_from_opt_key ( std : : string opt_key )
2020-08-05 17:25:04 +00:00
{
2020-08-18 14:49:06 +00:00
int pos = opt_key . find ( " # " ) ;
if ( pos > 0 ) {
boost : : erase_head ( opt_key , pos + 1 ) ;
return atoi ( opt_key . c_str ( ) ) ;
}
return 0 ;
}
static std : : string get_pure_opt_key ( std : : string opt_key )
{
int pos = opt_key . find ( " # " ) ;
if ( pos > 0 )
boost : : erase_tail ( opt_key , opt_key . size ( ) - pos ) ;
return opt_key ;
}
static wxString get_string_value ( std : : string opt_key , const DynamicPrintConfig & config )
{
2020-08-19 13:35:58 +00:00
int opt_idx = get_id_from_opt_key ( opt_key ) ;
2020-08-18 14:49:06 +00:00
opt_key = get_pure_opt_key ( opt_key ) ;
if ( config . option ( opt_key ) - > is_nil ( ) )
return _L ( " N/A " ) ;
2020-08-05 17:25:04 +00:00
wxString out ;
2020-08-18 14:49:06 +00:00
const ConfigOptionDef * opt = config . def ( ) - > get ( opt_key ) ;
bool is_nullable = opt - > nullable ;
2020-08-05 17:25:04 +00:00
2020-08-18 14:49:06 +00:00
switch ( opt - > type ) {
2020-08-05 17:25:04 +00:00
case coInt :
return from_u8 ( ( boost : : format ( " %1% " ) % config . opt_int ( opt_key ) ) . str ( ) ) ;
case coInts : {
2020-08-18 14:49:06 +00:00
int val = is_nullable ?
config . opt < ConfigOptionIntsNullable > ( opt_key ) - > get_at ( opt_idx ) :
config . opt < ConfigOptionInts > ( opt_key ) - > get_at ( opt_idx ) ;
return from_u8 ( ( boost : : format ( " %1% " ) % val ) . str ( ) ) ;
2020-08-05 17:25:04 +00:00
}
case coBool :
return config . opt_bool ( opt_key ) ? " true " : " false " ;
case coBools : {
2020-08-18 14:49:06 +00:00
bool val = is_nullable ?
config . opt < ConfigOptionBoolsNullable > ( opt_key ) - > get_at ( opt_idx ) :
config . opt < ConfigOptionBools > ( opt_key ) - > get_at ( opt_idx ) ;
return val ? " true " : " false " ;
2020-08-05 17:25:04 +00:00
}
case coPercent :
return from_u8 ( ( boost : : format ( " %1%%% " ) % int ( config . optptr ( opt_key ) - > getFloat ( ) ) ) . str ( ) ) ;
case coPercents : {
2020-08-18 14:49:06 +00:00
double val = is_nullable ?
config . opt < ConfigOptionPercentsNullable > ( opt_key ) - > get_at ( opt_idx ) :
config . opt < ConfigOptionPercents > ( opt_key ) - > get_at ( opt_idx ) ;
return from_u8 ( ( boost : : format ( " %1%%% " ) % int ( val ) ) . str ( ) ) ;
2020-08-05 17:25:04 +00:00
}
case coFloat :
return double_to_string ( config . opt_float ( opt_key ) ) ;
case coFloats : {
2020-08-18 14:49:06 +00:00
double val = is_nullable ?
config . opt < ConfigOptionFloatsNullable > ( opt_key ) - > get_at ( opt_idx ) :
config . opt < ConfigOptionFloats > ( opt_key ) - > get_at ( opt_idx ) ;
return double_to_string ( val ) ;
2020-08-05 17:25:04 +00:00
}
case coString :
return from_u8 ( config . opt_string ( opt_key ) ) ;
case coStrings : {
const ConfigOptionStrings * strings = config . opt < ConfigOptionStrings > ( opt_key ) ;
if ( strings ) {
if ( opt_key = = " compatible_printers " | | opt_key = = " compatible_prints " ) {
if ( strings - > empty ( ) )
return _L ( " All " ) ;
for ( size_t id = 0 ; id < strings - > size ( ) ; id + + )
out + = from_u8 ( strings - > get_at ( id ) ) + " \n " ;
out . RemoveLast ( 1 ) ;
return out ;
}
if ( ! strings - > empty ( ) )
return from_u8 ( strings - > get_at ( opt_idx ) ) ;
}
break ;
}
case coFloatOrPercent : {
const ConfigOptionFloatOrPercent * opt = config . opt < ConfigOptionFloatOrPercent > ( opt_key ) ;
if ( opt )
out = double_to_string ( opt - > value ) + ( opt - > percent ? " % " : " " ) ;
return out ;
}
case coEnum : {
if ( opt_key = = " top_fill_pattern " | |
opt_key = = " bottom_fill_pattern " | |
opt_key = = " fill_pattern " )
2020-08-07 13:09:58 +00:00
return get_string_from_enum < InfillPattern > ( opt_key , config , true ) ;
2020-08-05 17:25:04 +00:00
if ( opt_key = = " gcode_flavor " )
return get_string_from_enum < GCodeFlavor > ( opt_key , config ) ;
2020-10-02 15:31:55 +00:00
if ( opt_key = = " machine_limits_usage " )
return get_string_from_enum < MachineLimitsUsage > ( opt_key , config ) ;
2020-08-05 17:25:04 +00:00
if ( opt_key = = " ironing_type " )
return get_string_from_enum < IroningType > ( opt_key , config ) ;
if ( opt_key = = " support_material_pattern " )
return get_string_from_enum < SupportMaterialPattern > ( opt_key , config ) ;
if ( opt_key = = " seam_position " )
return get_string_from_enum < SeamPosition > ( opt_key , config ) ;
if ( opt_key = = " display_orientation " )
return get_string_from_enum < SLADisplayOrientation > ( opt_key , config ) ;
if ( opt_key = = " support_pillar_connection_mode " )
return get_string_from_enum < SLAPillarConnectionMode > ( opt_key , config ) ;
break ;
}
case coPoints : {
if ( opt_key = = " bed_shape " ) {
2020-08-19 13:35:58 +00:00
BedShape shape ( * config . option < ConfigOptionPoints > ( opt_key ) ) ;
return shape . get_full_name_with_params ( ) ;
2020-08-05 17:25:04 +00:00
}
2020-12-07 15:14:40 +00:00
if ( opt_key = = " thumbnails " )
return get_thumbnails_string ( config . option < ConfigOptionPoints > ( opt_key ) - > values ) ;
2020-08-19 13:35:58 +00:00
Vec2d val = config . opt < ConfigOptionPoints > ( opt_key ) - > get_at ( opt_idx ) ;
return from_u8 ( ( boost : : format ( " [%1%] " ) % ConfigOptionPoint ( val ) . serialize ( ) ) . str ( ) ) ;
2020-08-05 17:25:04 +00:00
}
default :
break ;
}
return out ;
}
2020-08-10 17:07:45 +00:00
wxString UnsavedChangesDialog : : get_short_string ( wxString full_string )
{
int max_len = 30 ;
if ( full_string . IsEmpty ( ) | | full_string . StartsWith ( " # " ) | |
( full_string . Find ( " \n " ) = = wxNOT_FOUND & & full_string . Length ( ) < max_len ) )
return full_string ;
m_has_long_strings = true ;
int n_pos = full_string . Find ( " \n " ) ;
if ( n_pos ! = wxNOT_FOUND & & n_pos < max_len )
max_len = n_pos ;
full_string . Truncate ( max_len ) ;
return full_string + dots ;
}
2020-08-14 16:17:16 +00:00
void UnsavedChangesDialog : : update ( Preset : : Type type , PresetCollection * dependent_presets , const std : : string & new_selected_preset , const wxString & header )
2020-08-05 17:25:04 +00:00
{
2020-08-13 13:45:16 +00:00
PresetCollection * presets = dependent_presets ;
// activate buttons and labels
2020-08-14 16:17:16 +00:00
m_save_btn - > Bind ( wxEVT_ENTER_WINDOW , [ this , presets ] ( wxMouseEvent & e ) { show_info_line ( Action : : Save , presets ? presets - > get_selected_preset ( ) . name : " " ) ; e . Skip ( ) ; } ) ;
2020-10-15 14:48:48 +00:00
if ( m_transfer_btn ) {
2020-09-02 07:06:42 +00:00
bool is_empty_name = type ! = dependent_presets - > type ( ) ;
2020-10-15 14:48:48 +00:00
m_transfer_btn - > Bind ( wxEVT_ENTER_WINDOW , [ this , new_selected_preset , is_empty_name ] ( wxMouseEvent & e ) { show_info_line ( Action : : Transfer , is_empty_name ? " " : new_selected_preset ) ; e . Skip ( ) ; } ) ;
2020-09-02 07:06:42 +00:00
}
2020-10-15 14:48:48 +00:00
m_discard_btn - > Bind ( wxEVT_ENTER_WINDOW , [ this ] ( wxMouseEvent & e ) { show_info_line ( Action : : Discard ) ; e . Skip ( ) ; } ) ;
2020-08-13 13:45:16 +00:00
2020-08-14 16:17:16 +00:00
if ( type = = Preset : : TYPE_INVALID ) {
2020-10-17 12:04:05 +00:00
m_action_line - > SetLabel ( header + " \n " + _L ( " The following presets were modified: " ) ) ;
2020-08-13 13:45:16 +00:00
}
else {
2020-08-14 16:17:16 +00:00
wxString action_msg ;
if ( type = = dependent_presets - > type ( ) ) {
2020-10-17 12:04:05 +00:00
action_msg = format_wxstr ( _L ( " Preset \" %1% \" has the following unsaved changes: " ) , presets - > get_edited_preset ( ) . name ) ;
2020-08-14 16:17:16 +00:00
}
else {
2020-10-19 08:08:21 +00:00
action_msg = format_wxstr ( type = = Preset : : TYPE_PRINTER ?
2020-10-17 12:04:05 +00:00
_L ( " Preset \" %1% \" is not compatible with the new printer profile and it has the following unsaved changes: " ) :
_L ( " Preset \" %1% \" is not compatible with the new print profile and it has the following unsaved changes: " ) ,
presets - > get_edited_preset ( ) . name ) ;
2020-08-14 16:17:16 +00:00
}
2020-10-17 12:04:05 +00:00
m_action_line - > SetLabel ( action_msg ) ;
2020-08-13 13:45:16 +00:00
}
2020-08-05 17:25:04 +00:00
2020-08-14 16:17:16 +00:00
update_tree ( type , presets ) ;
}
2020-08-05 17:25:04 +00:00
2020-08-14 16:17:16 +00:00
void UnsavedChangesDialog : : update_tree ( Preset : : Type type , PresetCollection * presets_ )
{
2020-08-05 17:25:04 +00:00
Search : : OptionsSearcher & searcher = wxGetApp ( ) . sidebar ( ) . get_searcher ( ) ;
searcher . sort_options_by_opt_key ( ) ;
2020-08-14 16:17:16 +00:00
// list of the presets with unsaved changes
std : : vector < PresetCollection * > presets_list ;
if ( type = = Preset : : TYPE_INVALID )
{
PrinterTechnology printer_technology = wxGetApp ( ) . preset_bundle - > printers . get_edited_preset ( ) . printer_technology ( ) ;
for ( Tab * tab : wxGetApp ( ) . tabs_list )
if ( tab - > supports_printer_technology ( printer_technology ) & & tab - > current_preset_is_dirty ( ) )
presets_list . emplace_back ( tab - > get_presets ( ) ) ;
}
else
presets_list . emplace_back ( presets_ ) ;
// Display a dialog showing the dirty options in a human readable form.
for ( PresetCollection * presets : presets_list )
{
const DynamicPrintConfig & old_config = presets - > get_selected_preset ( ) . config ;
2020-10-07 18:13:12 +00:00
const PrinterTechnology & old_pt = presets - > get_selected_preset ( ) . printer_technology ( ) ;
2020-08-14 16:17:16 +00:00
const DynamicPrintConfig & new_config = presets - > get_edited_preset ( ) . config ;
type = presets - > type ( ) ;
2020-10-07 18:13:12 +00:00
const std : : map < wxString , std : : string > & category_icon_map = wxGetApp ( ) . get_tab ( type ) - > get_category_icon_map ( ) ;
m_tree_model - > AddPreset ( type , from_u8 ( presets - > get_edited_preset ( ) . name ) , old_pt ) ;
2020-08-14 16:17:16 +00:00
// Collect dirty options.
2020-08-18 14:49:06 +00:00
const bool deep_compare = ( type = = Preset : : TYPE_PRINTER | | type = = Preset : : TYPE_SLA_MATERIAL ) ;
auto dirty_options = presets - > current_dirty_options ( deep_compare ) ;
// process changes of extruders count
2020-10-07 18:13:12 +00:00
if ( type = = Preset : : TYPE_PRINTER & & old_pt = = ptFFF & &
2020-08-18 14:49:06 +00:00
old_config . opt < ConfigOptionStrings > ( " extruder_colour " ) - > values . size ( ) ! = new_config . opt < ConfigOptionStrings > ( " extruder_colour " ) - > values . size ( ) ) {
wxString local_label = _L ( " Extruders count " ) ;
wxString old_val = from_u8 ( ( boost : : format ( " %1% " ) % old_config . opt < ConfigOptionStrings > ( " extruder_colour " ) - > values . size ( ) ) . str ( ) ) ;
wxString new_val = from_u8 ( ( boost : : format ( " %1% " ) % new_config . opt < ConfigOptionStrings > ( " extruder_colour " ) - > values . size ( ) ) . str ( ) ) ;
ItemData item_data = { " extruders_count " , local_label , old_val , new_val , type } ;
2020-10-07 18:13:12 +00:00
m_items_map . emplace ( m_tree_model - > AddOption ( type , _L ( " General " ) , _L ( " Capabilities " ) , local_label , old_val , new_val , category_icon_map . at ( " General " ) ) , item_data ) ;
2020-08-18 14:49:06 +00:00
}
2020-09-17 13:25:05 +00:00
for ( const std : : string & opt_key : dirty_options ) {
2020-08-14 16:17:16 +00:00
const Search : : Option & option = searcher . get_option ( opt_key ) ;
2020-12-04 16:15:38 +00:00
if ( option . opt_key ! = boost : : nowide : : widen ( opt_key ) ) {
// When founded option isn't the correct one.
// It can be for dirty_options: "default_print_profile", "printer_model", "printer_settings_id",
// because of they don't exist in searcher
continue ;
}
2020-08-05 17:25:04 +00:00
2020-08-14 16:17:16 +00:00
ItemData item_data = { opt_key , option . label_local , get_string_value ( opt_key , old_config ) , get_string_value ( opt_key , new_config ) , type } ;
2020-08-10 17:07:45 +00:00
2020-08-14 16:17:16 +00:00
wxString old_val = get_short_string ( item_data . old_val ) ;
wxString new_val = get_short_string ( item_data . new_val ) ;
if ( old_val ! = item_data . old_val | | new_val ! = item_data . new_val )
item_data . is_long = true ;
2020-08-10 17:07:45 +00:00
2020-10-07 18:13:12 +00:00
m_items_map . emplace ( m_tree_model - > AddOption ( type , option . category_local , option . group_local , option . label_local , old_val , new_val , category_icon_map . at ( option . category ) ) , item_data ) ;
2020-08-14 16:17:16 +00:00
}
2020-08-05 17:25:04 +00:00
}
}
2020-08-14 16:17:16 +00:00
std : : vector < std : : string > UnsavedChangesDialog : : get_unselected_options ( Preset : : Type type )
2020-08-12 15:33:22 +00:00
{
std : : vector < std : : string > ret ;
2020-08-18 14:49:06 +00:00
for ( auto item : m_items_map ) {
if ( item . second . opt_key = = " extruders_count " )
continue ;
2020-08-14 16:17:16 +00:00
if ( item . second . type = = type & & ! m_tree_model - > IsEnabledItem ( item . first ) )
2020-08-18 14:49:06 +00:00
ret . emplace_back ( get_pure_opt_key ( item . second . opt_key ) ) ;
}
2020-08-12 15:33:22 +00:00
return ret ;
}
2020-08-05 17:25:04 +00:00
2020-08-10 09:24:31 +00:00
std : : vector < std : : string > UnsavedChangesDialog : : get_selected_options ( )
{
std : : vector < std : : string > ret ;
2020-08-18 14:49:06 +00:00
for ( auto item : m_items_map )
2020-08-10 09:24:31 +00:00
if ( m_tree_model - > IsEnabledItem ( item . first ) )
2020-08-18 14:49:06 +00:00
ret . emplace_back ( get_pure_opt_key ( item . second . opt_key ) ) ;
2020-08-10 09:24:31 +00:00
return ret ;
}
2020-07-30 14:16:56 +00:00
void UnsavedChangesDialog : : on_dpi_changed ( const wxRect & suggested_rect )
{
2020-08-12 11:36:26 +00:00
int em = em_unit ( ) ;
2020-07-30 14:16:56 +00:00
2020-08-05 17:25:04 +00:00
msw_buttons_rescale ( this , em , { wxID_CANCEL , m_save_btn_id , m_move_btn_id , m_continue_btn_id } ) ;
2020-10-15 14:48:48 +00:00
for ( auto btn : { m_save_btn , m_transfer_btn , m_discard_btn } )
if ( btn ) btn - > msw_rescale ( ) ;
2020-07-30 14:16:56 +00:00
2020-08-05 17:25:04 +00:00
const wxSize & size = wxSize ( 80 * em , 30 * em ) ;
2020-07-30 14:16:56 +00:00
SetMinSize ( size ) ;
2020-08-12 11:36:26 +00:00
m_tree - > GetColumn ( UnsavedChangesModel : : colToggle ) - > SetWidth ( 6 * em ) ;
m_tree - > GetColumn ( UnsavedChangesModel : : colIconText ) - > SetWidth ( 30 * em ) ;
m_tree - > GetColumn ( UnsavedChangesModel : : colOldValue ) - > SetWidth ( 20 * em ) ;
m_tree - > GetColumn ( UnsavedChangesModel : : colNewValue ) - > SetWidth ( 20 * em ) ;
m_tree_model - > Rescale ( ) ;
m_tree - > Refresh ( ) ;
2020-07-30 14:16:56 +00:00
Fit ( ) ;
Refresh ( ) ;
}
void UnsavedChangesDialog : : on_sys_color_changed ( )
{
2020-10-15 14:48:48 +00:00
for ( auto btn : { m_save_btn , m_transfer_btn , m_discard_btn } )
2020-08-12 11:36:26 +00:00
btn - > msw_rescale ( ) ;
2020-07-30 14:16:56 +00:00
// msw_rescale updates just icons, so use it
2020-08-12 11:36:26 +00:00
m_tree_model - > Rescale ( ) ;
m_tree - > Refresh ( ) ;
2020-07-30 14:16:56 +00:00
Refresh ( ) ;
}
2020-08-10 17:07:45 +00:00
//------------------------------------------
// FullCompareDialog
//------------------------------------------
FullCompareDialog : : FullCompareDialog ( const wxString & option_name , const wxString & old_value , const wxString & new_value )
: wxDialog ( nullptr , wxID_ANY , option_name , wxDefaultPosition , wxDefaultSize , wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER )
{
wxColour bgr_clr = wxSystemSettings : : GetColour ( wxSYS_COLOUR_WINDOW ) ;
SetBackgroundColour ( bgr_clr ) ;
int border = 10 ;
wxStaticBoxSizer * sizer = new wxStaticBoxSizer ( wxVERTICAL , this ) ;
wxFlexGridSizer * grid_sizer = new wxFlexGridSizer ( 2 , 2 , 1 , 0 ) ;
grid_sizer - > SetFlexibleDirection ( wxBOTH ) ;
grid_sizer - > AddGrowableCol ( 0 , 1 ) ;
grid_sizer - > AddGrowableCol ( 1 , 1 ) ;
grid_sizer - > AddGrowableRow ( 1 , 1 ) ;
auto add_header = [ grid_sizer , border , this ] ( wxString label ) {
wxStaticText * text = new wxStaticText ( this , wxID_ANY , label ) ;
2020-08-12 11:36:26 +00:00
text - > SetFont ( this - > GetFont ( ) . Bold ( ) ) ;
2020-08-10 17:07:45 +00:00
grid_sizer - > Add ( text , 0 , wxALL , border ) ;
} ;
auto add_value = [ grid_sizer , border , this ] ( wxString label , bool is_colored = false ) {
2020-08-11 08:37:08 +00:00
wxTextCtrl * text = new wxTextCtrl ( this , wxID_ANY , label , wxDefaultPosition , wxSize ( 300 , - 1 ) , wxTE_MULTILINE | wxTE_READONLY | wxBORDER_NONE | wxTE_RICH ) ;
2020-08-12 15:33:22 +00:00
text - > SetStyle ( 0 , label . Len ( ) , wxTextAttr ( is_colored ? wxColour ( orange ) : wxNullColour , wxNullColour , this - > GetFont ( ) ) ) ;
2020-08-10 17:07:45 +00:00
grid_sizer - > Add ( text , 1 , wxALL | wxEXPAND , border ) ;
} ;
add_header ( _L ( " Old value " ) ) ;
add_header ( _L ( " New value " ) ) ;
add_value ( old_value ) ;
add_value ( new_value , true ) ;
sizer - > Add ( grid_sizer , 1 , wxEXPAND ) ;
wxStdDialogButtonSizer * buttons = this - > CreateStdDialogButtonSizer ( wxOK ) ;
wxBoxSizer * topSizer = new wxBoxSizer ( wxVERTICAL ) ;
topSizer - > Add ( sizer , 1 , wxEXPAND | wxLEFT | wxTOP | wxRIGHT , border ) ;
topSizer - > Add ( buttons , 0 , wxEXPAND | wxALL , border ) ;
SetSizer ( topSizer ) ;
topSizer - > SetSizeHints ( this ) ;
}
2020-12-10 09:58:40 +00:00
2020-07-30 14:16:56 +00:00
}
} // namespace Slic3r::GUI