2018-02-02 12:38:35 +01:00
#include "wxExtensions.hpp"
2019-04-05 18:53:02 +02:00
#include <stdexcept>
2019-05-17 19:12:52 +02:00
#include <cmath>
2019-04-05 18:53:02 +02:00
2018-11-26 14:41:58 +01:00
#include "libslic3r/Utils.hpp"
#include "libslic3r/Model.hpp"
2020-01-15 15:35:56 +01:00
#include "libslic3r/Print.hpp"
2018-05-10 16:36:12 +02:00
#include <wx/sizer.h>
2019-09-30 14:03:50 +02:00
#include <wx/bmpcbox.h>
2018-05-10 16:36:12 +02:00
#include <wx/statline.h>
2018-08-21 02:03:10 +02:00
#include <wx/dcclient.h>
2018-08-21 17:47:05 +02:00
#include <wx/numformatter.h>
2019-11-07 16:36:24 +01:00
#include <wx/colordlg.h>
2018-11-26 14:41:58 +01:00
2019-04-04 09:20:11 +02:00
#include <boost/algorithm/string/replace.hpp>
2018-11-26 14:41:58 +01:00
#include "BitmapCache.hpp"
2019-01-07 19:17:10 +01:00
#include "GUI.hpp"
2018-10-05 23:29:15 +02:00
#include "GUI_App.hpp"
#include "GUI_ObjectList.hpp"
2019-01-10 17:24:23 +01:00
#include "libslic3r/GCode/PreviewData.hpp"
2019-02-11 14:14:35 +01:00
#include "I18N.hpp"
2019-04-17 21:35:53 +02:00
#include "GUI_Utils.hpp"
2019-09-30 14:03:50 +02:00
#include "PresetBundle.hpp"
2019-10-18 12:35:35 +02:00
#include "ExtruderSequenceDialog.hpp"
2019-05-17 19:12:52 +02:00
#include "../Utils/MacDarkMode.hpp"
2018-05-10 16:36:12 +02:00
2019-01-07 19:17:10 +01:00
using Slic3r :: GUI :: from_u8 ;
2019-11-27 14:44:33 +01:00
using Slic3r :: GUI :: into_u8 ;
2019-01-07 19:17:10 +01:00
2018-11-12 13:47:24 +01:00
wxDEFINE_EVENT ( wxCUSTOMEVT_LAST_VOLUME_IS_DELETED , wxCommandEvent );
2018-11-07 14:44:47 +01:00
2019-05-13 14:27:51 +02:00
#ifndef __WXGTK__ // msw_menuitem_bitmaps is used for MSW and OSX
2019-05-07 13:35:37 +02:00
static std :: map < int , std :: string > msw_menuitem_bitmaps ;
2019-05-13 14:27:51 +02:00
#ifdef __WXMSW__
2019-05-03 09:44:19 +02:00
void msw_rescale_menu ( wxMenu * menu )
{
2019-05-07 13:35:37 +02:00
struct update_icons {
static void run ( wxMenuItem * item ) {
const auto it = msw_menuitem_bitmaps . find ( item -> GetId ());
if ( it != msw_menuitem_bitmaps . end ()) {
const wxBitmap & item_icon = create_scaled_bitmap ( nullptr , it -> second );
if ( item_icon . IsOk ())
item -> SetBitmap ( item_icon );
}
if ( item -> IsSubMenu ())
for ( wxMenuItem * sub_item : item -> GetSubMenu () -> GetMenuItems ())
update_icons :: run ( sub_item );
}
};
2019-05-03 09:44:19 +02:00
2019-05-07 13:35:37 +02:00
for ( wxMenuItem * item : menu -> GetMenuItems ())
update_icons :: run ( item );
2019-05-03 09:44:19 +02:00
}
2019-05-07 13:35:37 +02:00
#endif /* __WXMSW__ */
2019-05-13 14:27:51 +02:00
#endif /* no __WXGTK__ */
2019-12-18 15:54:01 +01:00
void enable_menu_item ( wxUpdateUIEvent & evt , std :: function < bool () > const cb_condition , wxMenuItem * item , wxWindow * win )
2019-05-13 14:27:51 +02:00
{
const bool enable = cb_condition ();
evt . Enable ( enable );
#ifdef __WXOSX__
const auto it = msw_menuitem_bitmaps . find ( item -> GetId ());
if ( it != msw_menuitem_bitmaps . end ())
{
2019-12-18 15:54:01 +01:00
const wxBitmap & item_icon = create_scaled_bitmap ( win , it -> second , 16 , false , ! enable );
2019-05-13 17:57:31 +02:00
if ( item_icon . IsOk ())
item -> SetBitmap ( item_icon );
2019-05-13 14:27:51 +02:00
}
#endif // __WXOSX__
}
2019-05-03 09:44:19 +02:00
2018-10-17 12:17:25 +02:00
wxMenuItem * append_menu_item ( wxMenu * menu , int id , const wxString & string , const wxString & description ,
2019-05-13 14:27:51 +02:00
std :: function < void ( wxCommandEvent & event ) > cb , const wxBitmap & icon , wxEvtHandler * event_handler ,
std :: function < bool () > const cb_condition , wxWindow * parent )
2018-10-17 12:17:25 +02:00
{
if ( id == wxID_ANY )
id = wxNewId ();
2019-05-07 13:35:37 +02:00
auto * item = new wxMenuItem ( menu , id , string , description );
if ( icon . IsOk ()) {
2019-05-03 09:44:19 +02:00
item -> SetBitmap ( icon );
}
2019-05-07 13:35:37 +02:00
menu -> Append ( item );
2018-10-17 12:17:25 +02:00
2018-12-06 14:49:14 +01:00
#ifdef __WXMSW__
2018-12-07 17:50:48 +01:00
if ( event_handler != nullptr && event_handler != menu )
2018-10-18 14:42:21 +02:00
event_handler -> Bind ( wxEVT_MENU , cb , id );
else
2018-12-07 17:50:48 +01:00
#endif // __WXMSW__
2018-10-18 14:42:21 +02:00
menu -> Bind ( wxEVT_MENU , cb , id );
2019-05-13 14:27:51 +02:00
if ( parent ) {
2019-12-18 15:54:01 +01:00
parent -> Bind ( wxEVT_UPDATE_UI , [ cb_condition , item , parent ]( wxUpdateUIEvent & evt ) {
enable_menu_item ( evt , cb_condition , item , parent ); }, id );
2019-05-13 14:27:51 +02:00
}
2018-10-18 14:42:21 +02:00
return item ;
}
2018-12-06 14:49:14 +01:00
wxMenuItem * append_menu_item ( wxMenu * menu , int id , const wxString & string , const wxString & description ,
2019-05-13 14:27:51 +02:00
std :: function < void ( wxCommandEvent & event ) > cb , const std :: string & icon , wxEvtHandler * event_handler ,
std :: function < bool () > const cb_condition , wxWindow * parent )
2018-12-06 14:49:14 +01:00
{
2019-05-03 09:44:19 +02:00
if ( id == wxID_ANY )
id = wxNewId ();
2019-12-18 15:54:01 +01:00
const wxBitmap & bmp = ! icon . empty () ? create_scaled_bitmap ( parent , icon ) : wxNullBitmap ; // FIXME: pass window ptr
2019-05-13 14:27:51 +02:00
//#ifdef __WXMSW__
#ifndef __WXGTK__
2019-05-03 09:44:19 +02:00
if ( bmp . IsOk ())
2019-05-07 13:35:37 +02:00
msw_menuitem_bitmaps [ id ] = icon ;
#endif /* __WXMSW__ */
2019-05-03 09:44:19 +02:00
2019-05-13 14:27:51 +02:00
return append_menu_item ( menu , id , string , description , cb , bmp , event_handler , cb_condition , parent );
2018-12-06 14:49:14 +01:00
}
2019-05-13 14:27:51 +02:00
wxMenuItem * append_submenu ( wxMenu * menu , wxMenu * sub_menu , int id , const wxString & string , const wxString & description , const std :: string & icon ,
std :: function < bool () > const cb_condition , wxWindow * parent )
2018-10-18 14:42:21 +02:00
{
if ( id == wxID_ANY )
id = wxNewId ();
wxMenuItem * item = new wxMenuItem ( menu , id , string , description );
2019-05-07 13:35:37 +02:00
if ( ! icon . empty ()) {
2019-12-18 15:54:01 +01:00
item -> SetBitmap ( create_scaled_bitmap ( parent , icon )); // FIXME: pass window ptr
2019-05-13 14:27:51 +02:00
//#ifdef __WXMSW__
#ifndef __WXGTK__
2019-05-07 13:35:37 +02:00
msw_menuitem_bitmaps [ id ] = icon ;
#endif /* __WXMSW__ */
}
2018-10-18 14:42:21 +02:00
item -> SetSubMenu ( sub_menu );
menu -> Append ( item );
2019-05-13 14:27:51 +02:00
if ( parent ) {
2019-12-18 15:54:01 +01:00
parent -> Bind ( wxEVT_UPDATE_UI , [ cb_condition , item , parent ]( wxUpdateUIEvent & evt ) {
enable_menu_item ( evt , cb_condition , item , parent ); }, id );
2019-05-13 14:27:51 +02:00
}
2018-10-17 12:17:25 +02:00
return item ;
}
2019-03-28 16:28:34 +01:00
wxMenuItem * append_menu_radio_item ( wxMenu * menu , int id , const wxString & string , const wxString & description ,
std :: function < void ( wxCommandEvent & event ) > cb , wxEvtHandler * event_handler )
{
if ( id == wxID_ANY )
id = wxNewId ();
wxMenuItem * item = menu -> AppendRadioItem ( id , string , description );
#ifdef __WXMSW__
if ( event_handler != nullptr && event_handler != menu )
event_handler -> Bind ( wxEVT_MENU , cb , id );
else
#endif // __WXMSW__
menu -> Bind ( wxEVT_MENU , cb , id );
return item ;
}
2019-07-31 10:12:13 +02:00
wxMenuItem * append_menu_check_item ( wxMenu * menu , int id , const wxString & string , const wxString & description ,
std :: function < void ( wxCommandEvent & event ) > cb , wxEvtHandler * event_handler )
{
if ( id == wxID_ANY )
id = wxNewId ();
wxMenuItem * item = menu -> AppendCheckItem ( id , string , description );
#ifdef __WXMSW__
if ( event_handler != nullptr && event_handler != menu )
event_handler -> Bind ( wxEVT_MENU , cb , id );
else
#endif // __WXMSW__
menu -> Bind ( wxEVT_MENU , cb , id );
return item ;
}
2018-02-20 14:25:40 +01:00
const unsigned int wxCheckListBoxComboPopup :: DefaultWidth = 200 ;
const unsigned int wxCheckListBoxComboPopup :: DefaultHeight = 200 ;
2018-02-20 14:44:00 +01:00
const unsigned int wxCheckListBoxComboPopup :: DefaultItemHeight = 18 ;
2018-02-02 12:38:35 +01:00
bool wxCheckListBoxComboPopup :: Create ( wxWindow * parent )
{
2018-02-06 12:43:25 +01:00
return wxCheckListBox :: Create ( parent , wxID_HIGHEST + 1 , wxPoint ( 0 , 0 ));
2018-02-02 12:38:35 +01:00
}
wxWindow * wxCheckListBoxComboPopup :: GetControl ()
{
return this ;
}
void wxCheckListBoxComboPopup :: SetStringValue ( const wxString & value )
{
m_text = value ;
}
wxString wxCheckListBoxComboPopup :: GetStringValue () const
{
return m_text ;
}
wxSize wxCheckListBoxComboPopup :: GetAdjustedSize ( int minWidth , int prefHeight , int maxHeight )
{
// matches owner wxComboCtrl's width
2018-02-20 14:25:40 +01:00
// and sets height dinamically in dependence of contained items count
2018-02-02 12:38:35 +01:00
wxComboCtrl * cmb = GetComboCtrl ();
if ( cmb != nullptr )
{
wxSize size = GetComboCtrl () -> GetSize ();
2018-02-20 14:25:40 +01:00
unsigned int count = GetCount ();
if ( count > 0 )
2018-02-20 14:44:00 +01:00
size . SetHeight ( count * DefaultItemHeight );
2018-02-20 14:25:40 +01:00
else
size . SetHeight ( DefaultHeight );
2018-02-02 12:38:35 +01:00
return size ;
}
else
2018-02-20 14:25:40 +01:00
return wxSize ( DefaultWidth , DefaultHeight );
}
void wxCheckListBoxComboPopup :: OnKeyEvent ( wxKeyEvent & evt )
{
2018-02-22 08:59:47 +01:00
// filters out all the keys which are not working properly
switch ( evt . GetKeyCode ())
{
case WXK_LEFT :
case WXK_UP :
case WXK_RIGHT :
case WXK_DOWN :
case WXK_PAGEUP :
case WXK_PAGEDOWN :
case WXK_END :
case WXK_HOME :
case WXK_NUMPAD_LEFT :
case WXK_NUMPAD_UP :
case WXK_NUMPAD_RIGHT :
case WXK_NUMPAD_DOWN :
case WXK_NUMPAD_PAGEUP :
case WXK_NUMPAD_PAGEDOWN :
case WXK_NUMPAD_END :
case WXK_NUMPAD_HOME :
{
break ;
}
default :
{
evt . Skip ();
break ;
}
}
2018-02-02 12:38:35 +01:00
}
void wxCheckListBoxComboPopup :: OnCheckListBox ( wxCommandEvent & evt )
{
// forwards the checklistbox event to the owner wxComboCtrl
2018-05-17 10:23:02 +02:00
if ( m_check_box_events_status == OnCheckListBoxFunction :: FreeToProceed )
2018-02-02 12:38:35 +01:00
{
2018-05-17 10:23:02 +02:00
wxComboCtrl * cmb = GetComboCtrl ();
if ( cmb != nullptr ) {
wxCommandEvent event ( wxEVT_CHECKLISTBOX , cmb -> GetId ());
event . SetEventObject ( cmb );
cmb -> ProcessWindowEvent ( event );
}
2018-02-02 12:38:35 +01:00
}
2018-02-20 15:22:30 +01:00
evt . Skip ();
2018-05-17 10:23:02 +02:00
#ifndef _WIN32 // events are sent differently on OSX+Linux vs Win (more description in header file)
if ( m_check_box_events_status == OnCheckListBoxFunction :: RefuseToProceed )
// this happens if the event was resent by OnListBoxSelection - next call to OnListBoxSelection is due to user clicking the text, so the function should
// explicitly change the state on the checkbox
m_check_box_events_status = OnCheckListBoxFunction :: WasRefusedLastTime ;
else
// if the user clicked the checkbox square, this event was sent before OnListBoxSelection was called, so we don't want it to resend it
m_check_box_events_status = OnCheckListBoxFunction :: RefuseToProceed ;
#endif
2018-02-02 12:38:35 +01:00
}
void wxCheckListBoxComboPopup :: OnListBoxSelection ( wxCommandEvent & evt )
{
// transforms list box item selection event into checklistbox item toggle event
int selId = GetSelection ();
if ( selId != wxNOT_FOUND )
{
2018-05-17 10:23:02 +02:00
#ifndef _WIN32
if ( m_check_box_events_status == OnCheckListBoxFunction :: RefuseToProceed )
#endif
Check (( unsigned int ) selId , ! IsChecked (( unsigned int ) selId ));
2018-02-02 12:38:35 +01:00
2018-05-17 10:23:02 +02:00
m_check_box_events_status = OnCheckListBoxFunction :: FreeToProceed ; // so the checkbox reacts to square-click the next time
SetSelection ( wxNOT_FOUND );
2018-02-02 12:38:35 +01:00
wxCommandEvent event ( wxEVT_CHECKLISTBOX , GetId ());
event . SetInt ( selId );
event . SetEventObject ( this );
ProcessEvent ( event );
}
}
2018-04-06 13:37:00 +02:00
// *** wxDataViewTreeCtrlComboPopup ***
const unsigned int wxDataViewTreeCtrlComboPopup :: DefaultWidth = 270 ;
const unsigned int wxDataViewTreeCtrlComboPopup :: DefaultHeight = 200 ;
const unsigned int wxDataViewTreeCtrlComboPopup :: DefaultItemHeight = 22 ;
bool wxDataViewTreeCtrlComboPopup :: Create ( wxWindow * parent )
{
2018-04-09 16:50:17 +02:00
return wxDataViewTreeCtrl :: Create ( parent , wxID_ANY /*HIGHEST + 1*/ , wxPoint ( 0 , 0 ), wxDefaultSize /*wxSize(270, -1)*/ , wxDV_NO_HEADER );
2018-04-06 13:37:00 +02:00
}
2018-04-09 12:41:25 +02:00
/*
2018-04-06 13:37:00 +02:00
wxSize wxDataViewTreeCtrlComboPopup::GetAdjustedSize(int minWidth, int prefHeight, int maxHeight)
{
// matches owner wxComboCtrl's width
// and sets height dinamically in dependence of contained items count
2018-04-06 15:42:52 +02:00
wxComboCtrl* cmb = GetComboCtrl();
if (cmb != nullptr)
{
wxSize size = GetComboCtrl()->GetSize();
if (m_cnt_open_items > 0)
size.SetHeight(m_cnt_open_items * DefaultItemHeight);
else
size.SetHeight(DefaultHeight);
return size;
}
else
return wxSize(DefaultWidth, DefaultHeight);
2018-04-06 13:37:00 +02:00
}
2018-04-09 12:41:25 +02:00
*/
2018-04-06 13:37:00 +02:00
void wxDataViewTreeCtrlComboPopup :: OnKeyEvent ( wxKeyEvent & evt )
{
// filters out all the keys which are not working properly
if ( evt . GetKeyCode () == WXK_UP )
{
return ;
}
else if ( evt . GetKeyCode () == WXK_DOWN )
{
return ;
}
else
{
evt . Skip ();
return ;
}
}
void wxDataViewTreeCtrlComboPopup :: OnDataViewTreeCtrlSelection ( wxCommandEvent & evt )
{
wxComboCtrl * cmb = GetComboCtrl ();
auto selected = GetItemText ( GetSelection ());
cmb -> SetText ( selected );
}
2018-05-04 18:32:20 +02:00
2019-04-26 10:52:38 +02:00
// edit tooltip : change Slic3r to SLIC3R_APP_KEY
// Temporary workaround for localization
void edit_tooltip ( wxString & tooltip )
{
tooltip . Replace ( "Slic3r" , SLIC3R_APP_KEY , true );
}
2019-04-25 15:06:44 +02:00
/* Function for rescale of buttons in Dialog under MSW if dpi is changed.
* btn_ids - vector of buttons identifiers
*/
void msw_buttons_rescale ( wxDialog * dlg , const int em_unit , const std :: vector < int >& btn_ids )
{
const wxSize & btn_size = wxSize ( - 1 , int ( 2.5f * em_unit + 0.5f ));
for ( int btn_id : btn_ids ) {
// There is a case [FirmwareDialog], when we have wxControl instead of wxButton
// so let casting everything to the wxControl
wxControl * btn = static_cast < wxControl *> ( dlg -> FindWindowById ( btn_id , dlg ));
if ( btn )
btn -> SetMinSize ( btn_size );
}
}
2019-04-17 21:35:53 +02:00
/* Function for getting of em_unit value from correct parent.
* In most of cases it is m_em_unit value from GUI_App,
* but for DPIDialogs it's its own value.
* This value will be used to correct rescale after moving between
* Displays with different HDPI */
int em_unit ( wxWindow * win )
{
2019-04-18 15:05:17 +02:00
if ( win )
{
2019-05-06 18:28:23 +02:00
wxTopLevelWindow * toplevel = Slic3r :: GUI :: find_toplevel_parent ( win );
Slic3r :: GUI :: DPIDialog * dlg = dynamic_cast < Slic3r :: GUI :: DPIDialog *> ( toplevel );
2019-04-17 21:35:53 +02:00
if ( dlg )
2019-04-18 15:05:17 +02:00
return dlg -> em_unit ();
2019-05-06 18:28:23 +02:00
Slic3r :: GUI :: DPIFrame * frame = dynamic_cast < Slic3r :: GUI :: DPIFrame *> ( toplevel );
if ( frame )
return frame -> em_unit ();
2019-04-17 21:35:53 +02:00
}
return Slic3r :: GUI :: wxGetApp (). em_unit ();
}
2019-04-08 09:37:23 +02:00
2020-01-23 15:07:31 +01:00
float get_svg_scale_factor ( wxWindow * win )
2019-11-08 14:52:11 +01:00
{
#ifdef __APPLE__
// Note: win->GetContentScaleFactor() is not used anymore here because it tends to
// return bogus results quite often (such as 1.0 on Retina or even 0.0).
// We're using the max scaling factor across all screens because it's very likely to be good enough.
static float max_scaling_factor = NAN ;
if ( std :: isnan ( max_scaling_factor )) {
max_scaling_factor = Slic3r :: GUI :: mac_max_scaling_factor ();
}
return win != nullptr ? max_scaling_factor : 1.0f ;
#else
return 1.0f ;
#endif
}
2019-04-08 09:37:23 +02:00
// If an icon has horizontal orientation (width > height) call this function with is_horizontal = true
2019-05-13 17:57:31 +02:00
wxBitmap create_scaled_bitmap ( wxWindow * win , const std :: string & bmp_name_in ,
const int px_cnt /* = 16*/ , const bool is_horizontal /* = false*/ , const bool grayscale /* = false*/ )
2019-04-08 09:37:23 +02:00
{
static Slic3r :: GUI :: BitmapCache cache ;
2019-04-09 17:39:04 +02:00
#ifdef __APPLE__
2019-05-17 19:12:52 +02:00
// Note: win->GetContentScaleFactor() is not used anymore here because it tends to
// return bogus results quite often (such as 1.0 on Retina or even 0.0).
// We're using the max scaling factor across all screens because it's very likely to be good enough.
static float max_scaling_factor = NAN ;
if ( std :: isnan ( max_scaling_factor )) {
max_scaling_factor = Slic3r :: GUI :: mac_max_scaling_factor ();
}
const float scale_factor = win != nullptr ? max_scaling_factor : 1.0f ;
2019-04-09 17:39:04 +02:00
#else
( void )( win );
const float scale_factor = 1.0f ;
#endif
2019-04-05 18:53:02 +02:00
2019-04-08 09:37:23 +02:00
unsigned int height , width = height = 0 ;
unsigned int & scale_base = is_horizontal ? width : height ;
2019-04-05 18:53:02 +02:00
2019-04-17 21:35:53 +02:00
scale_base = ( unsigned int )( em_unit ( win ) * px_cnt * 0.1f + 0.5f );
2019-04-08 09:37:23 +02:00
2020-01-02 13:41:49 +01:00
std :: string bmp_name = bmp_name_in ;
boost :: replace_last ( bmp_name , ".png" , "" );
2019-12-18 15:54:01 +01:00
2020-01-02 13:41:49 +01:00
// std::string bmp_name = icon_name_respected_to_mode(bmp_name_in);
2019-04-05 18:53:02 +02:00
// Try loading an SVG first, then PNG if SVG is not found:
2020-01-02 13:41:49 +01:00
wxBitmap * bmp = cache . load_svg ( bmp_name , width , height , scale_factor , grayscale , Slic3r :: GUI :: wxGetApp (). dark_mode ());
2019-04-09 14:18:03 +02:00
if ( bmp == nullptr ) {
2019-05-13 17:57:31 +02:00
bmp = cache . load_png ( bmp_name , width , height , grayscale );
2019-04-05 18:53:02 +02:00
}
2019-04-09 14:18:03 +02:00
if ( bmp == nullptr ) {
2019-04-05 18:53:02 +02:00
// Neither SVG nor PNG has been found, raise error
throw std :: runtime_error ( "Could not load bitmap: " + bmp_name );
}
2019-04-08 09:37:23 +02:00
return * bmp ;
}
2019-10-01 18:19:28 +02:00
Slic3r :: GUI :: BitmapCache * m_bitmap_cache = nullptr ;
2019-10-24 10:38:36 +02:00
std :: vector < wxBitmap *> get_extruder_color_icons ( bool thin_icon /* = false*/ )
2019-10-01 18:19:28 +02:00
{
// Create the bitmap with color bars.
std :: vector < wxBitmap *> bmps ;
std :: vector < std :: string > colors = Slic3r :: GUI :: wxGetApp (). plater () -> get_extruder_colors_from_plater_config ();
2019-10-08 11:05:59 +02:00
if ( colors . empty ())
2019-10-07 12:36:16 +02:00
return bmps ;
2019-10-01 18:19:28 +02:00
unsigned char rgb [ 3 ];
/* It's supposed that standard size of an icon is 36px*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 = Slic3r :: GUI :: wxGetApp (). em_unit ();
2019-10-24 10:38:36 +02:00
const int icon_width = lround (( thin_icon ? 1 : 3.2 ) * em );
2019-10-01 18:19:28 +02:00
const int icon_height = lround ( 1.6 * em );
for ( const std :: string & color : colors )
{
2019-10-24 10:38:36 +02:00
std :: string bitmap_key = color + "-h" + std :: to_string ( icon_height ) + "-w" + std :: to_string ( icon_width );
wxBitmap * bitmap = m_bitmap_cache -> find ( bitmap_key );
2019-10-01 18:19:28 +02:00
if ( bitmap == nullptr ) {
// Paint the color icon.
Slic3r :: PresetBundle :: parse_color ( color , rgb );
2019-10-24 10:38:36 +02:00
bitmap = m_bitmap_cache -> insert ( bitmap_key , m_bitmap_cache -> mksolid ( icon_width , icon_height , rgb ));
2019-10-01 18:19:28 +02:00
}
bmps . emplace_back ( bitmap );
}
return bmps ;
}
2019-10-24 10:38:36 +02:00
static wxBitmap get_extruder_color_icon ( size_t extruder_idx , bool thin_icon = false )
2019-10-01 18:19:28 +02:00
{
// Create the bitmap with color bars.
2019-10-24 10:38:36 +02:00
std :: vector < wxBitmap *> bmps = get_extruder_color_icons ( thin_icon );
2019-10-07 12:36:16 +02:00
if ( bmps . empty ())
return wxNullBitmap ;
2019-10-01 18:19:28 +02:00
return * bmps [ extruder_idx >= bmps . size () ? 0 : extruder_idx ];
}
2019-10-18 12:35:35 +02:00
void apply_extruder_selector ( wxBitmapComboBox ** ctrl ,
wxWindow * parent ,
const std :: string & first_item /* = ""*/ ,
wxPoint pos /* = wxDefaultPosition*/ ,
2019-10-24 10:38:36 +02:00
wxSize size /* = wxDefaultSize*/ ,
bool use_thin_icon /* = false*/ )
2019-10-18 12:35:35 +02:00
{
2019-10-24 10:38:36 +02:00
std :: vector < wxBitmap *> icons = get_extruder_color_icons ( use_thin_icon );
2019-10-18 12:35:35 +02:00
if ( !* ctrl )
* ctrl = new wxBitmapComboBox ( parent , wxID_ANY , wxEmptyString , pos , size ,
0 , nullptr , wxCB_READONLY );
else
{
( * ctrl ) -> SetPosition ( pos );
( * ctrl ) -> SetMinSize ( size );
( * ctrl ) -> SetSize ( size );
( * ctrl ) -> Clear ();
}
2019-11-15 16:44:17 +01:00
if ( first_item . empty ())
( * ctrl ) -> Hide (); // to avoid unwanted rendering before layout (ExtruderSequenceDialog)
2019-10-18 12:35:35 +02:00
2019-11-08 11:24:57 +01:00
if ( icons . empty () && ! first_item . empty ()) {
( * ctrl ) -> Append ( _ ( first_item ), wxNullBitmap );
return ;
}
// For ObjectList we use short extruder name (just a number)
const bool use_full_item_name = dynamic_cast < Slic3r :: GUI :: ObjectList *> ( parent ) == nullptr ;
2019-10-18 12:35:35 +02:00
int i = 0 ;
2019-10-24 10:38:36 +02:00
wxString str = _ ( L ( "Extruder" ));
2019-10-18 12:35:35 +02:00
for ( wxBitmap * bmp : icons ) {
if ( i == 0 ) {
if ( ! first_item . empty ())
( * ctrl ) -> Append ( _ ( first_item ), * bmp );
++ i ;
}
2019-11-08 11:24:57 +01:00
( * ctrl ) -> Append ( use_full_item_name ? wxString :: Format ( "%s %d" , str , i ) : std :: to_string ( i ), * bmp );
2019-10-18 12:35:35 +02:00
++ i ;
}
( * ctrl ) -> SetSelection ( 0 );
}
2018-07-04 08:54:30 +02:00
// *****************************************************************************
// ----------------------------------------------------------------------------
2019-04-25 01:45:00 +02:00
// ObjectDataViewModelNode
2018-07-04 08:54:30 +02:00
// ----------------------------------------------------------------------------
2019-04-25 01:45:00 +02:00
2019-08-01 14:58:04 +02:00
void ObjectDataViewModelNode :: init_container ()
{
#ifdef __WXGTK__
// it's necessary on GTK because of control have to know if this item will be container
// in another case you couldn't to add subitem for this item
// it will be produce "segmentation fault"
m_container = true ;
#endif //__WXGTK__
}
2019-09-17 13:41:44 +02:00
#define LAYER_ROOT_ICON "edit_layers_all"
#define LAYER_ICON "edit_layers_some"
2019-05-04 02:07:07 +02:00
ObjectDataViewModelNode :: ObjectDataViewModelNode ( ObjectDataViewModelNode * parent , const ItemType type ) :
m_parent ( parent ),
m_type ( type ),
2020-01-27 16:30:09 +01:00
m_extruder ( wxEmptyString ),
m_ctrl ( parent -> m_ctrl )
2019-05-04 02:07:07 +02:00
{
2019-05-27 13:07:37 +02:00
if ( type == itSettings )
2019-05-04 02:07:07 +02:00
m_name = "Settings to modified" ;
2019-05-27 13:07:37 +02:00
else if ( type == itInstanceRoot )
2019-05-04 02:07:07 +02:00
m_name = _ ( L ( "Instances" ));
2019-05-27 13:07:37 +02:00
else if ( type == itInstance )
{
2019-05-04 02:07:07 +02:00
m_idx = parent -> GetChildCount ();
2019-05-09 18:18:21 +02:00
m_name = wxString :: Format ( _ ( L ( "Instance %d" )), m_idx + 1 );
2019-05-04 02:07:07 +02:00
2019-10-01 18:19:28 +02:00
set_action_and_extruder_icons ();
2019-05-04 02:07:07 +02:00
}
2019-05-27 13:07:37 +02:00
else if ( type == itLayerRoot )
{
2020-01-27 16:30:09 +01:00
m_bmp = create_scaled_bitmap ( m_ctrl , LAYER_ROOT_ICON ); // FIXME: pass window ptr
2019-05-27 13:07:37 +02:00
m_name = _ ( L ( "Layers" ));
}
2019-05-30 14:41:16 +02:00
if ( type & ( itInstanceRoot | itLayerRoot ))
2019-08-01 14:58:04 +02:00
init_container ();
2019-05-04 02:07:07 +02:00
}
2019-05-30 14:41:16 +02:00
ObjectDataViewModelNode :: ObjectDataViewModelNode ( ObjectDataViewModelNode * parent ,
2019-06-06 14:14:29 +02:00
const t_layer_height_range & layer_range ,
2019-05-31 15:29:09 +02:00
const int idx /*= -1 */ ,
const wxString & extruder ) :
2019-05-30 14:41:16 +02:00
m_parent ( parent ),
m_type ( itLayer ),
m_idx ( idx ),
2019-06-06 14:14:29 +02:00
m_layer_range ( layer_range ),
2020-01-27 16:30:09 +01:00
m_extruder ( extruder ),
m_ctrl ( parent -> m_ctrl )
2019-05-30 14:41:16 +02:00
{
2019-05-31 15:29:09 +02:00
const int children_cnt = parent -> GetChildCount ();
if ( idx < 0 )
m_idx = children_cnt ;
else
{
// update indexes for another Laeyr Nodes
for ( int i = m_idx ; i < children_cnt ; i ++ )
parent -> GetNthChild ( i ) -> SetIdx ( i + 1 );
}
2019-06-06 14:14:29 +02:00
const std :: string label_range = ( boost :: format ( " %.2f-%.2f " ) % layer_range . first % layer_range . second ). str ();
2019-05-30 16:53:17 +02:00
m_name = _ ( L ( "Range" )) + label_range + "(" + _ ( L ( "mm" )) + ")" ;
2020-01-27 16:30:09 +01:00
m_bmp = create_scaled_bitmap ( m_ctrl , LAYER_ICON ); // FIXME: pass window ptr
2019-05-30 14:41:16 +02:00
2019-10-01 18:19:28 +02:00
set_action_and_extruder_icons ();
2019-08-01 14:58:04 +02:00
init_container ();
2019-05-30 14:41:16 +02:00
}
2019-07-31 16:36:56 +02:00
#ifndef NDEBUG
bool ObjectDataViewModelNode :: valid ()
{
// Verify that the object was not deleted yet.
assert ( m_idx >= - 1 );
return m_idx >= - 1 ;
}
#endif /* NDEBUG */
2019-10-01 18:19:28 +02:00
void ObjectDataViewModelNode :: set_action_and_extruder_icons ()
2019-04-16 10:05:45 +02:00
{
2019-05-27 13:07:37 +02:00
m_action_icon_name = m_type & itObject ? "advanced_plus" :
m_type & ( itVolume | itLayer ) ? "cog" : /*m_type & itInstance*/ "set_separate_obj" ;
2020-01-27 16:30:09 +01:00
m_action_icon = create_scaled_bitmap ( m_ctrl , m_action_icon_name ); // FIXME: pass window ptr
2019-10-01 18:19:28 +02:00
2019-10-09 12:36:13 +02:00
if ( m_type & itInstance )
return ; // don't set colored bitmap for Instance
2019-10-01 18:19:28 +02:00
// set extruder bitmap
int extruder_idx = atoi ( m_extruder . c_str ());
if ( extruder_idx > 0 ) -- extruder_idx ;
m_extruder_bmp = get_extruder_color_icon ( extruder_idx );
2019-04-16 10:05:45 +02:00
}
2018-07-04 08:54:30 +02:00
2019-08-01 14:58:04 +02:00
void ObjectDataViewModelNode :: set_printable_icon ( PrintIndicator printable )
{
m_printable = printable ;
m_printable_icon = m_printable == piUndef ? m_empty_bmp :
2020-01-27 16:30:09 +01:00
create_scaled_bitmap ( m_ctrl , m_printable == piPrintable ? "eye_open.png" : "eye_closed.png" );
2019-08-01 14:58:04 +02:00
}
2019-04-25 01:45:00 +02:00
void ObjectDataViewModelNode :: update_settings_digest_bitmaps ()
2019-04-16 10:05:45 +02:00
{
m_bmp = m_empty_bmp ;
std :: map < std :: string , wxBitmap >& categories_icon = Slic3r :: GUI :: wxGetApp (). obj_list () -> CATEGORY_ICON ;
std :: string scaled_bitmap_name = m_name . ToUTF8 (). data ();
scaled_bitmap_name += "-em" + std :: to_string ( Slic3r :: GUI :: wxGetApp (). em_unit ());
wxBitmap * bmp = m_bitmap_cache -> find ( scaled_bitmap_name );
if ( bmp == nullptr ) {
std :: vector < wxBitmap > bmps ;
for ( auto & cat : m_opt_categories )
bmps . emplace_back ( categories_icon . find ( cat ) == categories_icon . end () ?
wxNullBitmap : categories_icon . at ( cat ));
bmp = m_bitmap_cache -> insert ( scaled_bitmap_name , bmps );
}
m_bmp = * bmp ;
}
2019-04-25 01:45:00 +02:00
bool ObjectDataViewModelNode :: update_settings_digest ( const std :: vector < std :: string >& categories )
2018-09-17 15:12:13 +02:00
{
2018-10-16 11:08:37 +02:00
if ( m_type != itSettings || m_opt_categories == categories )
2018-09-17 15:12:13 +02:00
return false ;
m_opt_categories = categories ;
m_name = wxEmptyString ;
for ( auto & cat : m_opt_categories )
2019-05-04 02:07:07 +02:00
m_name += _ ( cat ) + "; " ;
2018-11-23 11:54:06 +01:00
if ( ! m_name . IsEmpty ())
m_name . erase ( m_name . Length () - 2 , 2 ); // Delete last "; "
2019-04-16 10:05:45 +02:00
update_settings_digest_bitmaps ();
2018-09-17 15:12:13 +02:00
return true ;
}
2019-04-25 01:45:00 +02:00
void ObjectDataViewModelNode :: msw_rescale ()
2019-04-16 10:05:45 +02:00
{
if ( ! m_action_icon_name . empty ())
2020-01-27 16:30:09 +01:00
m_action_icon = create_scaled_bitmap ( m_ctrl , m_action_icon_name );
2019-04-16 10:05:45 +02:00
2019-09-17 13:41:44 +02:00
if ( m_printable != piUndef )
2020-01-27 16:30:09 +01:00
m_printable_icon = create_scaled_bitmap ( m_ctrl , m_printable == piPrintable ? "eye_open.png" : "eye_closed.png" );
2019-09-17 13:41:44 +02:00
2019-04-16 10:05:45 +02:00
if ( ! m_opt_categories . empty ())
update_settings_digest_bitmaps ();
}
2019-07-22 10:28:25 +02:00
bool ObjectDataViewModelNode :: SetValue ( const wxVariant & variant , unsigned col )
{
switch ( col )
{
2019-08-01 14:58:04 +02:00
case colPrint :
m_printable_icon << variant ;
return true ;
case colName : {
2019-07-22 10:28:25 +02:00
DataViewBitmapText data ;
data << variant ;
m_bmp = data . GetBitmap ();
m_name = data . GetText ();
return true ; }
2019-08-01 14:58:04 +02:00
case colExtruder : {
2019-10-01 18:19:28 +02:00
DataViewBitmapText data ;
data << variant ;
m_extruder_bmp = data . GetBitmap ();
m_extruder = data . GetText () == "0" ? _ ( L ( "default" )) : data . GetText ();
2019-07-22 10:28:25 +02:00
return true ; }
2019-08-01 14:58:04 +02:00
case colEditing :
2019-07-22 10:28:25 +02:00
m_action_icon << variant ;
return true ;
default :
printf ( "MyObjectTreeModel::SetValue: wrong column" );
}
return false ;
}
2019-05-09 18:18:21 +02:00
void ObjectDataViewModelNode :: SetIdx ( const int & idx )
{
m_idx = idx ;
// update name if this node is instance
if ( m_type == itInstance )
m_name = wxString :: Format ( _ ( L ( "Instance %d" )), m_idx + 1 );
}
2018-05-04 18:32:20 +02:00
// *****************************************************************************
// ----------------------------------------------------------------------------
2019-04-25 01:45:00 +02:00
// ObjectDataViewModel
2018-05-04 18:32:20 +02:00
// ----------------------------------------------------------------------------
2019-05-27 16:13:24 +02:00
static int get_root_idx ( ObjectDataViewModelNode * parent_node , const ItemType root_type )
{
// because of istance_root and layers_root are at the end of the list, so
// start locking from the end
for ( int root_idx = parent_node -> GetChildCount () - 1 ; root_idx >= 0 ; root_idx -- )
{
// if there is SettingsItem or VolumeItem, then RootItems don't exist in current ObjectItem
if ( parent_node -> GetNthChild ( root_idx ) -> GetType () & ( itSettings | itVolume ))
break ;
if ( parent_node -> GetNthChild ( root_idx ) -> GetType () & root_type )
return root_idx ;
}
return - 1 ;
}
2019-04-25 01:45:00 +02:00
ObjectDataViewModel :: ObjectDataViewModel ()
2018-09-17 15:12:13 +02:00
{
m_bitmap_cache = new Slic3r :: GUI :: BitmapCache ;
}
2019-04-25 01:45:00 +02:00
ObjectDataViewModel ::~ ObjectDataViewModel ()
2018-09-17 15:12:13 +02:00
{
for ( auto object : m_objects )
delete object ;
delete m_bitmap_cache ;
m_bitmap_cache = nullptr ;
}
2019-04-29 15:27:59 +02:00
wxDataViewItem ObjectDataViewModel :: Add ( const wxString & name ,
const int extruder ,
const bool has_errors /* = false*/ )
2018-05-04 18:32:20 +02:00
{
2019-05-10 12:54:20 +02:00
const wxString extruder_str = extruder == 0 ? _ ( L ( "default" )) : wxString :: Format ( "%d" , extruder );
2020-01-27 16:30:09 +01:00
auto root = new ObjectDataViewModelNode ( name , extruder_str , m_ctrl );
2019-04-29 15:27:59 +02:00
// Add error icon if detected auto-repaire
if ( has_errors )
root -> m_bmp = * m_warning_bmp ;
2019-09-24 16:01:01 +02:00
m_objects . push_back ( root );
2018-05-29 22:45:35 +02:00
// notify control
wxDataViewItem child (( void * ) root );
wxDataViewItem parent (( void * ) NULL );
2019-04-29 15:27:59 +02:00
2018-05-29 22:45:35 +02:00
ItemAdded ( parent , child );
2018-05-30 17:52:28 +02:00
return child ;
2018-05-29 22:45:35 +02:00
}
2018-05-04 18:32:20 +02:00
2019-04-25 01:45:00 +02:00
wxDataViewItem ObjectDataViewModel :: AddVolumeChild ( const wxDataViewItem & parent_item ,
const wxString & name ,
const Slic3r :: ModelVolumeType volume_type ,
2019-04-29 15:27:59 +02:00
const bool has_errors /* = false*/ ,
2019-04-25 01:45:00 +02:00
const int extruder /* = 0*/ ,
const bool create_frst_child /* = true*/ )
2018-05-29 22:45:35 +02:00
{
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * root = ( ObjectDataViewModelNode * ) parent_item . GetID ();
2018-05-30 17:52:28 +02:00
if ( ! root ) return wxDataViewItem ( 0 );
2018-05-04 18:32:20 +02:00
2019-05-10 12:54:20 +02:00
wxString extruder_str = extruder == 0 ? _ ( L ( "default" )) : wxString :: Format ( "%d" , extruder );
2018-08-15 13:59:33 +02:00
2019-05-27 16:13:24 +02:00
// get insertion position according to the existed Layers and/or Instances Items
int insert_position = get_root_idx ( root , itLayerRoot );
if ( insert_position < 0 )
insert_position = get_root_idx ( root , itInstanceRoot );
2018-11-06 11:39:38 +01:00
2019-04-29 15:27:59 +02:00
const bool obj_errors = root -> m_bmp . IsOk ();
2018-10-18 10:40:26 +02:00
if ( create_frst_child && root -> m_volumes_cnt == 0 )
2019-04-10 09:27:42 +02:00
{
2019-04-29 15:27:59 +02:00
const Slic3r :: ModelVolumeType type = Slic3r :: ModelVolumeType :: MODEL_PART ;
const auto node = new ObjectDataViewModelNode ( root , root -> m_name , GetVolumeIcon ( type , obj_errors ), extruder_str , 0 );
node -> m_volume_type = type ;
2018-11-06 11:39:38 +01:00
insert_position < 0 ? root -> Append ( node ) : root -> Insert ( node , insert_position );
2018-05-30 00:36:44 +02:00
// notify control
2018-09-17 15:12:13 +02:00
const wxDataViewItem child (( void * ) node );
2018-05-30 00:36:44 +02:00
ItemAdded ( parent_item , child );
2018-10-18 10:40:26 +02:00
root -> m_volumes_cnt ++ ;
2019-05-27 16:13:24 +02:00
if ( insert_position >= 0 ) insert_position ++ ;
2018-05-30 00:36:44 +02:00
}
2019-04-29 15:27:59 +02:00
const auto node = new ObjectDataViewModelNode ( root , name , GetVolumeIcon ( volume_type , has_errors ), extruder_str , root -> m_volumes_cnt );
2018-11-06 11:39:38 +01:00
insert_position < 0 ? root -> Append ( node ) : root -> Insert ( node , insert_position );
2019-04-29 15:27:59 +02:00
// if part with errors is added, but object wasn't marked, then mark it
if ( ! obj_errors && has_errors )
root -> SetBitmap ( * m_warning_bmp );
2018-05-29 22:45:35 +02:00
// notify control
2019-09-24 16:01:01 +02:00
const wxDataViewItem child (( void * ) node );
2018-10-18 10:40:26 +02:00
ItemAdded ( parent_item , child );
root -> m_volumes_cnt ++ ;
2019-04-16 10:05:45 +02:00
node -> m_volume_type = volume_type ;
2018-05-30 17:52:28 +02:00
return child ;
2018-05-29 22:45:35 +02:00
}
2018-05-10 16:36:12 +02:00
2019-04-25 01:45:00 +02:00
wxDataViewItem ObjectDataViewModel :: AddSettingsChild ( const wxDataViewItem & parent_item )
2018-09-17 15:12:13 +02:00
{
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * root = ( ObjectDataViewModelNode * ) parent_item . GetID ();
2018-09-17 15:12:13 +02:00
if ( ! root ) return wxDataViewItem ( 0 );
2019-04-25 01:45:00 +02:00
const auto node = new ObjectDataViewModelNode ( root , itSettings );
2018-09-17 15:12:13 +02:00
root -> Insert ( node , 0 );
// notify control
const wxDataViewItem child (( void * ) node );
ItemAdded ( parent_item , child );
return child ;
}
2019-05-27 13:07:37 +02:00
/* return values:
* true => root_node is created and added to the parent_root
* false => root node alredy exists
*/
static bool append_root_node ( ObjectDataViewModelNode * parent_node ,
ObjectDataViewModelNode ** root_node ,
const ItemType root_type )
{
const int inst_root_id = get_root_idx ( parent_node , root_type );
* root_node = inst_root_id < 0 ?
new ObjectDataViewModelNode ( parent_node , root_type ) :
parent_node -> GetNthChild ( inst_root_id );
if ( inst_root_id < 0 ) {
if (( root_type & itInstanceRoot ) ||
2019-09-03 10:27:16 +02:00
( ( root_type & itLayerRoot ) && get_root_idx ( parent_node , itInstanceRoot ) < 0 ) )
2019-05-27 13:07:37 +02:00
parent_node -> Append ( * root_node );
else if ( root_type & itLayerRoot )
2019-05-30 14:41:16 +02:00
parent_node -> Insert ( * root_node , static_cast < unsigned int > ( get_root_idx ( parent_node , itInstanceRoot )));
2019-05-27 13:07:37 +02:00
return true ;
}
return false ;
}
2019-08-01 14:58:04 +02:00
wxDataViewItem ObjectDataViewModel :: AddRoot ( const wxDataViewItem & parent_item , ItemType root_type )
2018-10-18 10:40:26 +02:00
{
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * parent_node = ( ObjectDataViewModelNode * ) parent_item . GetID ();
2018-10-18 10:40:26 +02:00
if ( ! parent_node ) return wxDataViewItem ( 0 );
2019-05-27 13:07:37 +02:00
// get InstanceRoot node
2019-08-01 14:58:04 +02:00
ObjectDataViewModelNode * root_node { nullptr };
const bool appended = append_root_node ( parent_node , & root_node , root_type );
if ( ! root_node ) return wxDataViewItem ( 0 );
2018-10-18 10:40:26 +02:00
2019-08-01 14:58:04 +02:00
const wxDataViewItem root_item (( void * ) root_node );
2018-10-18 10:40:26 +02:00
2019-05-27 13:07:37 +02:00
if ( appended )
2019-08-01 14:58:04 +02:00
ItemAdded ( parent_item , root_item ); // notify control
return root_item ;
}
wxDataViewItem ObjectDataViewModel :: AddInstanceRoot ( const wxDataViewItem & parent_item )
{
return AddRoot ( parent_item , itInstanceRoot );
}
wxDataViewItem ObjectDataViewModel :: AddInstanceChild ( const wxDataViewItem & parent_item , size_t num )
{
2019-09-02 10:03:07 +02:00
std :: vector < bool > print_indicator ( num , true );
// if InstanceRoot item isn't created for this moment
if ( ! GetInstanceRootItem ( parent_item ). IsOk ())
// use object's printable state to first instance
print_indicator [ 0 ] = IsPrintable ( parent_item );
2019-08-01 14:58:04 +02:00
return wxDataViewItem (( void * ) AddInstanceChild ( parent_item , print_indicator ));
}
wxDataViewItem ObjectDataViewModel :: AddInstanceChild ( const wxDataViewItem & parent_item ,
const std :: vector < bool >& print_indicator )
{
const wxDataViewItem inst_root_item = AddInstanceRoot ( parent_item );
if ( ! inst_root_item ) return wxDataViewItem ( 0 );
ObjectDataViewModelNode * inst_root_node = ( ObjectDataViewModelNode * ) inst_root_item . GetID ();
2018-10-18 10:40:26 +02:00
// Add instance nodes
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * instance_node = nullptr ;
2018-10-18 10:40:26 +02:00
size_t counter = 0 ;
2019-08-01 14:58:04 +02:00
while ( counter < print_indicator . size ()) {
2019-04-25 01:45:00 +02:00
instance_node = new ObjectDataViewModelNode ( inst_root_node , itInstance );
2019-08-13 18:15:12 +02:00
2019-08-30 09:35:34 +02:00
instance_node -> set_printable_icon ( print_indicator [ counter ] ? piPrintable : piUnprintable );
2019-08-05 08:44:55 +02:00
2018-10-18 10:40:26 +02:00
inst_root_node -> Append ( instance_node );
// notify control
const wxDataViewItem instance_item (( void * ) instance_node );
ItemAdded ( inst_root_item , instance_item );
++ counter ;
}
2019-08-07 14:11:41 +02:00
// update object_node printable property
UpdateObjectPrintable ( parent_item );
2018-10-18 10:40:26 +02:00
return wxDataViewItem (( void * ) instance_node );
}
2019-08-07 14:11:41 +02:00
void ObjectDataViewModel :: UpdateObjectPrintable ( wxDataViewItem parent_item )
{
const wxDataViewItem inst_root_item = GetInstanceRootItem ( parent_item );
if ( ! inst_root_item )
return ;
ObjectDataViewModelNode * inst_root_node = ( ObjectDataViewModelNode * ) inst_root_item . GetID ();
const size_t child_cnt = inst_root_node -> GetChildren (). Count ();
PrintIndicator obj_pi = piUnprintable ;
for ( size_t i = 0 ; i < child_cnt ; i ++ )
if ( inst_root_node -> GetNthChild ( i ) -> IsPrintable () & piPrintable ) {
obj_pi = piPrintable ;
break ;
}
// and set printable state for object_node to piUndef
ObjectDataViewModelNode * obj_node = ( ObjectDataViewModelNode * ) parent_item . GetID ();
obj_node -> set_printable_icon ( obj_pi );
ItemChanged ( parent_item );
}
// update printable property for all instances from object
void ObjectDataViewModel :: UpdateInstancesPrintable ( wxDataViewItem parent_item )
{
const wxDataViewItem inst_root_item = GetInstanceRootItem ( parent_item );
if ( ! inst_root_item )
return ;
ObjectDataViewModelNode * obj_node = ( ObjectDataViewModelNode * ) parent_item . GetID ();
const PrintIndicator obj_pi = obj_node -> IsPrintable ();
ObjectDataViewModelNode * inst_root_node = ( ObjectDataViewModelNode * ) inst_root_item . GetID ();
const size_t child_cnt = inst_root_node -> GetChildren (). Count ();
for ( size_t i = 0 ; i < child_cnt ; i ++ )
{
ObjectDataViewModelNode * inst_node = inst_root_node -> GetNthChild ( i );
// and set printable state for object_node to piUndef
inst_node -> set_printable_icon ( obj_pi );
ItemChanged ( wxDataViewItem (( void * ) inst_node ));
}
}
bool ObjectDataViewModel :: IsPrintable ( const wxDataViewItem & item ) const
{
ObjectDataViewModelNode * node = ( ObjectDataViewModelNode * ) item . GetID ();
if ( ! node )
return false ;
return node -> IsPrintable () == piPrintable ;
}
2019-05-27 13:07:37 +02:00
wxDataViewItem ObjectDataViewModel :: AddLayersRoot ( const wxDataViewItem & parent_item )
{
2019-08-01 14:58:04 +02:00
return AddRoot ( parent_item , itLayerRoot );
2019-05-27 13:07:37 +02:00
}
2019-05-31 15:29:09 +02:00
wxDataViewItem ObjectDataViewModel :: AddLayersChild ( const wxDataViewItem & parent_item ,
2019-06-07 11:32:46 +02:00
const t_layer_height_range & layer_range ,
const int extruder /* = 0*/ ,
2019-05-31 15:29:09 +02:00
const int index /* = -1*/ )
2019-05-27 13:07:37 +02:00
{
ObjectDataViewModelNode * parent_node = ( ObjectDataViewModelNode * ) parent_item . GetID ();
if ( ! parent_node ) return wxDataViewItem ( 0 );
2019-06-07 11:32:46 +02:00
wxString extruder_str = extruder == 0 ? _ ( L ( "default" )) : wxString :: Format ( "%d" , extruder );
2019-05-27 13:07:37 +02:00
// get LayerRoot node
2019-05-27 16:13:24 +02:00
ObjectDataViewModelNode * layer_root_node ;
2019-05-30 14:41:16 +02:00
wxDataViewItem layer_root_item ;
2019-05-27 16:13:24 +02:00
2019-05-30 14:41:16 +02:00
if ( parent_node -> GetType () & itLayerRoot ) {
2019-05-27 16:13:24 +02:00
layer_root_node = parent_node ;
2019-05-30 14:41:16 +02:00
layer_root_item = parent_item ;
}
2019-05-27 16:13:24 +02:00
else {
const int root_idx = get_root_idx ( parent_node , itLayerRoot );
if ( root_idx < 0 ) return wxDataViewItem ( 0 );
layer_root_node = parent_node -> GetNthChild ( root_idx );
2019-05-30 14:41:16 +02:00
layer_root_item = wxDataViewItem (( void * ) layer_root_node );
2019-05-27 16:13:24 +02:00
}
2019-05-27 13:07:37 +02:00
// Add layer node
2019-06-07 11:32:46 +02:00
ObjectDataViewModelNode * layer_node = new ObjectDataViewModelNode ( layer_root_node , layer_range , index , extruder_str );
2019-05-31 15:29:09 +02:00
if ( index < 0 )
layer_root_node -> Append ( layer_node );
else
layer_root_node -> Insert ( layer_node , index );
2019-05-27 13:07:37 +02:00
// notify control
2019-05-30 14:41:16 +02:00
const wxDataViewItem layer_item (( void * ) layer_node );
ItemAdded ( layer_root_item , layer_item );
2019-05-27 13:07:37 +02:00
2019-05-30 14:41:16 +02:00
return layer_item ;
2019-05-27 13:07:37 +02:00
}
2019-04-25 01:45:00 +02:00
wxDataViewItem ObjectDataViewModel :: Delete ( const wxDataViewItem & item )
2018-05-29 22:45:35 +02:00
{
2018-05-30 17:52:28 +02:00
auto ret_item = wxDataViewItem ( 0 );
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * node = ( ObjectDataViewModelNode * ) item . GetID ();
2018-05-29 22:45:35 +02:00
if ( ! node ) // happens if item.IsOk()==false
2018-05-30 17:52:28 +02:00
return ret_item ;
2018-05-29 22:45:35 +02:00
2018-05-30 00:36:44 +02:00
auto node_parent = node -> GetParent ();
wxDataViewItem parent ( node_parent );
2018-05-29 22:45:35 +02:00
// first remove the node from the parent's array of children;
// NOTE: MyObjectTreeModelNodePtrArray is only an array of _pointers_
// thus removing the node from it doesn't result in freeing it
2018-10-31 12:56:08 +01:00
if ( node_parent ) {
2019-05-27 16:13:24 +02:00
if ( node -> m_type & ( itInstanceRoot | itLayerRoot ))
2018-11-12 13:47:24 +01:00
{
2019-07-15 17:09:06 +02:00
// node can be deleted by the Delete, let's check its type while we safely can
bool is_instance_root = ( node -> m_type & itInstanceRoot );
2019-09-06 17:46:55 +02:00
for ( int i = int ( node -> GetChildCount () - 1 ); i >= ( is_instance_root ? 1 : 0 ); i -- )
2018-11-12 13:47:24 +01:00
Delete ( wxDataViewItem ( node -> GetNthChild ( i )));
2019-07-15 17:09:06 +02:00
2018-11-12 13:47:24 +01:00
return parent ;
}
2018-05-30 17:52:28 +02:00
auto id = node_parent -> GetChildren (). Index ( node );
2018-10-16 11:08:37 +02:00
auto idx = node -> GetIdx ();
2018-11-02 23:27:31 +01:00
2018-11-12 13:47:24 +01:00
2019-05-27 16:13:24 +02:00
if ( node -> m_type & ( itVolume | itLayer )) {
2018-11-02 23:27:31 +01:00
node_parent -> m_volumes_cnt -- ;
2018-11-12 13:47:24 +01:00
DeleteSettings ( item );
}
node_parent -> GetChildren (). Remove ( node );
2018-11-02 23:27:31 +01:00
2018-10-31 12:56:08 +01:00
if ( id > 0 ) {
2019-10-29 10:40:34 +01:00
if ( size_t ( id ) == node_parent -> GetChildCount ()) id -- ;
2018-05-30 17:52:28 +02:00
ret_item = wxDataViewItem ( node_parent -> GetChildren (). Item ( id ));
}
2018-06-18 15:26:09 +02:00
2018-10-16 11:08:37 +02:00
//update idx value for remaining child-nodes
2018-06-18 15:26:09 +02:00
auto children = node_parent -> GetChildren ();
2018-10-16 11:08:37 +02:00
for ( size_t i = 0 ; i < node_parent -> GetChildCount () && idx >= 0 ; i ++ )
2018-06-18 15:26:09 +02:00
{
2018-10-16 11:08:37 +02:00
auto cur_idx = children [ i ] -> GetIdx ();
if ( cur_idx > idx )
children [ i ] -> SetIdx ( cur_idx - 1 );
2018-06-18 15:26:09 +02:00
}
2018-10-18 10:40:26 +02:00
// if there is last instance item, delete both of it and instance root item
if ( node_parent -> GetChildCount () == 1 && node_parent -> GetNthChild ( 0 ) -> m_type == itInstance )
{
delete node ;
ItemDeleted ( parent , item );
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * last_instance_node = node_parent -> GetNthChild ( 0 );
2019-08-05 08:44:55 +02:00
PrintIndicator last_instance_printable = last_instance_node -> IsPrintable ();
2018-10-18 10:40:26 +02:00
node_parent -> GetChildren (). Remove ( last_instance_node );
delete last_instance_node ;
ItemDeleted ( parent , wxDataViewItem ( last_instance_node ));
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * obj_node = node_parent -> GetParent ();
2019-08-05 08:44:55 +02:00
obj_node -> set_printable_icon ( last_instance_printable );
2018-10-18 10:40:26 +02:00
obj_node -> GetChildren (). Remove ( node_parent );
delete node_parent ;
ret_item = wxDataViewItem ( obj_node );
2019-05-27 16:13:24 +02:00
#ifndef __WXGTK__
if ( obj_node -> GetChildCount () == 0 )
obj_node -> m_container = false ;
#endif //__WXGTK__
ItemDeleted ( ret_item , wxDataViewItem ( node_parent ));
return ret_item ;
}
2019-08-07 14:11:41 +02:00
if ( node -> m_type & itInstance )
UpdateObjectPrintable ( wxDataViewItem ( node_parent -> GetParent ()));
2019-05-27 16:13:24 +02:00
// if there was last layer item, delete this one and layers root item
if ( node_parent -> GetChildCount () == 0 && node_parent -> m_type == itLayerRoot )
{
ObjectDataViewModelNode * obj_node = node_parent -> GetParent ();
obj_node -> GetChildren (). Remove ( node_parent );
delete node_parent ;
ret_item = wxDataViewItem ( obj_node );
2018-10-18 10:40:26 +02:00
#ifndef __WXGTK__
if ( obj_node -> GetChildCount () == 0 )
obj_node -> m_container = false ;
#endif //__WXGTK__
2018-11-12 13:47:24 +01:00
ItemDeleted ( ret_item , wxDataViewItem ( node_parent ));
2018-10-18 10:40:26 +02:00
return ret_item ;
}
2018-11-12 13:47:24 +01:00
// if there is last volume item after deleting, delete this last volume too
2019-05-27 16:13:24 +02:00
if ( node_parent -> GetChildCount () <= 3 ) // 3??? #ys_FIXME
2018-11-12 13:47:24 +01:00
{
int vol_cnt = 0 ;
int vol_idx = 0 ;
2019-09-06 17:46:55 +02:00
for ( size_t i = 0 ; i < node_parent -> GetChildCount (); ++ i ) {
2018-11-12 13:47:24 +01:00
if ( node_parent -> GetNthChild ( i ) -> GetType () == itVolume ) {
vol_idx = i ;
vol_cnt ++ ;
}
if ( vol_cnt > 1 )
break ;
}
if ( vol_cnt == 1 ) {
delete node ;
ItemDeleted ( parent , item );
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * last_child_node = node_parent -> GetNthChild ( vol_idx );
2018-11-12 13:47:24 +01:00
DeleteSettings ( wxDataViewItem ( last_child_node ));
node_parent -> GetChildren (). Remove ( last_child_node );
2018-11-12 16:03:29 +01:00
node_parent -> m_volumes_cnt = 0 ;
2018-11-12 13:47:24 +01:00
delete last_child_node ;
#ifndef __WXGTK__
if ( node_parent -> GetChildCount () == 0 )
node_parent -> m_container = false ;
#endif //__WXGTK__
ItemDeleted ( parent , wxDataViewItem ( last_child_node ));
wxCommandEvent event ( wxCUSTOMEVT_LAST_VOLUME_IS_DELETED );
auto it = find ( m_objects . begin (), m_objects . end (), node_parent );
event . SetInt ( it == m_objects . end () ? - 1 : it - m_objects . begin ());
wxPostEvent ( m_ctrl , event );
ret_item = parent ;
return ret_item ;
}
}
2018-05-30 17:52:28 +02:00
}
2018-05-30 00:36:44 +02:00
else
{
2018-05-30 17:52:28 +02:00
auto it = find ( m_objects . begin (), m_objects . end (), node );
2019-09-06 17:46:55 +02:00
size_t id = it - m_objects . begin ();
2018-05-30 00:36:44 +02:00
if ( it != m_objects . end ())
2018-11-12 13:47:24 +01:00
{
// Delete all sub-items
int i = m_objects [ id ] -> GetChildCount () - 1 ;
while ( i >= 0 ) {
Delete ( wxDataViewItem ( m_objects [ id ] -> GetNthChild ( i )));
i = m_objects [ id ] -> GetChildCount () - 1 ;
}
2018-05-30 00:36:44 +02:00
m_objects . erase ( it );
2018-11-12 13:47:24 +01:00
}
2018-10-31 12:56:08 +01:00
if ( id > 0 ) {
2018-05-30 17:52:28 +02:00
if ( id == m_objects . size ()) id -- ;
ret_item = wxDataViewItem ( m_objects [ id ]);
}
2018-05-30 00:36:44 +02:00
}
2018-05-29 22:45:35 +02:00
// free the node
delete node ;
2018-05-30 00:36:44 +02:00
// set m_containet to FALSE if parent has no child
2018-09-17 15:12:13 +02:00
if ( node_parent ) {
2018-07-31 15:31:12 +02:00
#ifndef __WXGTK__
2018-09-17 15:12:13 +02:00
if ( node_parent -> GetChildCount () == 0 )
node_parent -> m_container = false ;
2018-07-31 15:31:12 +02:00
#endif //__WXGTK__
2018-05-30 17:52:28 +02:00
ret_item = parent ;
}
2018-05-30 00:36:44 +02:00
2018-05-29 22:45:35 +02:00
// notify control
ItemDeleted ( parent , item );
2018-05-30 17:52:28 +02:00
return ret_item ;
2018-05-04 18:32:20 +02:00
}
2019-04-25 01:45:00 +02:00
wxDataViewItem ObjectDataViewModel :: DeleteLastInstance ( const wxDataViewItem & parent_item , size_t num )
2018-10-18 10:40:26 +02:00
{
auto ret_item = wxDataViewItem ( 0 );
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * parent_node = ( ObjectDataViewModelNode * ) parent_item . GetID ();
2018-10-18 10:40:26 +02:00
if ( ! parent_node ) return ret_item ;
2019-05-27 13:07:37 +02:00
const int inst_root_id = get_root_idx ( parent_node , itInstanceRoot );
2018-10-18 10:40:26 +02:00
if ( inst_root_id < 0 ) return ret_item ;
wxDataViewItemArray items ;
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * inst_root_node = parent_node -> GetNthChild ( inst_root_id );
2018-10-18 10:40:26 +02:00
const wxDataViewItem inst_root_item (( void * ) inst_root_node );
const int inst_cnt = inst_root_node -> GetChildCount ();
const bool delete_inst_root_item = inst_cnt - num < 2 ? true : false ;
2019-08-05 08:44:55 +02:00
PrintIndicator last_inst_printable = piUndef ;
2018-10-18 10:40:26 +02:00
int stop = delete_inst_root_item ? 0 : inst_cnt - num ;
for ( int i = inst_cnt - 1 ; i >= stop ; -- i ) {
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * last_instance_node = inst_root_node -> GetNthChild ( i );
2019-08-05 08:44:55 +02:00
if ( i == 0 ) last_inst_printable = last_instance_node -> IsPrintable ();
2018-10-18 10:40:26 +02:00
inst_root_node -> GetChildren (). Remove ( last_instance_node );
delete last_instance_node ;
ItemDeleted ( inst_root_item , wxDataViewItem ( last_instance_node ));
}
if ( delete_inst_root_item ) {
ret_item = parent_item ;
parent_node -> GetChildren (). Remove ( inst_root_node );
2019-08-05 08:44:55 +02:00
parent_node -> set_printable_icon ( last_inst_printable );
2018-10-18 10:40:26 +02:00
ItemDeleted ( parent_item , inst_root_item );
2019-08-05 08:44:55 +02:00
ItemChanged ( parent_item );
2018-10-18 10:40:26 +02:00
#ifndef __WXGTK__
if ( parent_node -> GetChildCount () == 0 )
parent_node -> m_container = false ;
#endif //__WXGTK__
}
2019-08-07 14:11:41 +02:00
// update object_node printable property
UpdateObjectPrintable ( parent_item );
2018-10-18 10:40:26 +02:00
return ret_item ;
}
2019-04-25 01:45:00 +02:00
void ObjectDataViewModel :: DeleteAll ()
2018-06-04 15:59:55 +02:00
{
while ( ! m_objects . empty ())
{
auto object = m_objects . back ();
// object->RemoveAllChildren();
Delete ( wxDataViewItem ( object ));
}
}
2019-04-25 01:45:00 +02:00
void ObjectDataViewModel :: DeleteChildren ( wxDataViewItem & parent )
2018-07-31 15:31:12 +02:00
{
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * root = ( ObjectDataViewModelNode * ) parent . GetID ();
2018-07-31 15:31:12 +02:00
if ( ! root ) // happens if item.IsOk()==false
return ;
// first remove the node from the parent's array of children;
// NOTE: MyObjectTreeModelNodePtrArray is only an array of _pointers_
// thus removing the node from it doesn't result in freeing it
auto & children = root -> GetChildren ();
for ( int id = root -> GetChildCount () - 1 ; id >= 0 ; -- id )
{
auto node = children [ id ];
auto item = wxDataViewItem ( node );
children . RemoveAt ( id );
2018-11-02 23:27:31 +01:00
if ( node -> m_type == itVolume )
root -> m_volumes_cnt -- ;
2018-07-31 15:31:12 +02:00
// free the node
delete node ;
// notify control
ItemDeleted ( parent , item );
}
// set m_containet to FALSE if parent has no child
#ifndef __WXGTK__
root -> m_container = false ;
#endif //__WXGTK__
}
2019-04-25 01:45:00 +02:00
void ObjectDataViewModel :: DeleteVolumeChildren ( wxDataViewItem & parent )
2018-11-06 09:06:26 +01:00
{
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * root = ( ObjectDataViewModelNode * ) parent . GetID ();
2018-11-06 09:06:26 +01:00
if ( ! root ) // happens if item.IsOk()==false
return ;
// first remove the node from the parent's array of children;
// NOTE: MyObjectTreeModelNodePtrArray is only an array of _pointers_
// thus removing the node from it doesn't result in freeing it
auto & children = root -> GetChildren ();
for ( int id = root -> GetChildCount () - 1 ; id >= 0 ; -- id )
{
auto node = children [ id ];
if ( node -> m_type != itVolume )
continue ;
auto item = wxDataViewItem ( node );
2018-11-12 13:47:24 +01:00
DeleteSettings ( item );
2018-11-06 09:06:26 +01:00
children . RemoveAt ( id );
// free the node
delete node ;
// notify control
ItemDeleted ( parent , item );
}
2018-11-12 13:47:24 +01:00
root -> m_volumes_cnt = 0 ;
2018-11-06 09:06:26 +01:00
// set m_containet to FALSE if parent has no child
#ifndef __WXGTK__
root -> m_container = false ;
#endif //__WXGTK__
}
2019-04-25 01:45:00 +02:00
void ObjectDataViewModel :: DeleteSettings ( const wxDataViewItem & parent )
2018-11-12 13:47:24 +01:00
{
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * node = ( ObjectDataViewModelNode * ) parent . GetID ();
2018-11-12 13:47:24 +01:00
if ( ! node ) return ;
// if volume has a "settings"item, than delete it before volume deleting
if ( node -> GetChildCount () > 0 && node -> GetNthChild ( 0 ) -> GetType () == itSettings ) {
auto settings_node = node -> GetNthChild ( 0 );
auto settings_item = wxDataViewItem ( settings_node );
node -> GetChildren (). RemoveAt ( 0 );
delete settings_node ;
ItemDeleted ( parent , settings_item );
}
}
2019-04-25 01:45:00 +02:00
wxDataViewItem ObjectDataViewModel :: GetItemById ( int obj_idx )
2018-06-04 15:59:55 +02:00
{
2019-09-06 17:46:55 +02:00
if ( size_t ( obj_idx ) >= m_objects . size ())
2018-06-04 15:59:55 +02:00
{
printf ( "Error! Out of objects range. \n " );
return wxDataViewItem ( 0 );
}
return wxDataViewItem ( m_objects [ obj_idx ]);
}
2019-04-25 01:45:00 +02:00
wxDataViewItem ObjectDataViewModel :: GetItemByVolumeId ( int obj_idx , int volume_idx )
2018-09-17 15:12:13 +02:00
{
2019-09-06 17:46:55 +02:00
if ( size_t ( obj_idx ) >= m_objects . size ()) {
2018-09-17 15:12:13 +02:00
printf ( "Error! Out of objects range. \n " );
return wxDataViewItem ( 0 );
}
auto parent = m_objects [ obj_idx ];
2018-10-12 12:00:37 +02:00
if ( parent -> GetChildCount () == 0 ||
2018-10-16 11:08:37 +02:00
( parent -> GetChildCount () == 1 && parent -> GetNthChild ( 0 ) -> GetType () & itSettings )) {
2018-10-11 15:57:09 +02:00
if ( volume_idx == 0 )
return GetItemById ( obj_idx );
2018-09-17 15:12:13 +02:00
printf ( "Error! Object has no one volume. \n " );
return wxDataViewItem ( 0 );
}
for ( size_t i = 0 ; i < parent -> GetChildCount (); i ++ )
2018-11-09 18:39:07 +01:00
if ( parent -> GetNthChild ( i ) -> m_idx == volume_idx && parent -> GetNthChild ( i ) -> GetType () & itVolume )
2018-09-17 15:12:13 +02:00
return wxDataViewItem ( parent -> GetNthChild ( i ));
return wxDataViewItem ( 0 );
}
2019-05-31 10:54:52 +02:00
wxDataViewItem ObjectDataViewModel :: GetItemById ( const int obj_idx , const int sub_obj_idx , const ItemType parent_type )
2018-11-05 13:53:30 +01:00
{
2019-09-06 17:46:55 +02:00
if ( size_t ( obj_idx ) >= m_objects . size ()) {
2018-11-05 13:53:30 +01:00
printf ( "Error! Out of objects range. \n " );
return wxDataViewItem ( 0 );
}
2019-05-31 10:54:52 +02:00
auto item = GetItemByType ( wxDataViewItem ( m_objects [ obj_idx ]), parent_type );
if ( ! item )
2018-11-05 13:53:30 +01:00
return wxDataViewItem ( 0 );
2019-06-06 14:14:29 +02:00
auto parent = ( ObjectDataViewModelNode * ) item . GetID ();
2018-11-05 13:53:30 +01:00
for ( size_t i = 0 ; i < parent -> GetChildCount (); i ++ )
2019-05-31 10:54:52 +02:00
if ( parent -> GetNthChild ( i ) -> m_idx == sub_obj_idx )
2018-11-05 13:53:30 +01:00
return wxDataViewItem ( parent -> GetNthChild ( i ));
return wxDataViewItem ( 0 );
}
2019-05-31 10:54:52 +02:00
wxDataViewItem ObjectDataViewModel :: GetItemByInstanceId ( int obj_idx , int inst_idx )
{
return GetItemById ( obj_idx , inst_idx , itInstanceRoot );
}
wxDataViewItem ObjectDataViewModel :: GetItemByLayerId ( int obj_idx , int layer_idx )
{
return GetItemById ( obj_idx , layer_idx , itLayerRoot );
}
2019-06-06 14:14:29 +02:00
wxDataViewItem ObjectDataViewModel :: GetItemByLayerRange ( const int obj_idx , const t_layer_height_range & layer_range )
{
2019-09-06 17:46:55 +02:00
if ( size_t ( obj_idx ) >= m_objects . size ()) {
2019-06-06 14:14:29 +02:00
printf ( "Error! Out of objects range. \n " );
return wxDataViewItem ( 0 );
}
auto item = GetItemByType ( wxDataViewItem ( m_objects [ obj_idx ]), itLayerRoot );
if ( ! item )
return wxDataViewItem ( 0 );
auto parent = ( ObjectDataViewModelNode * ) item . GetID ();
for ( size_t i = 0 ; i < parent -> GetChildCount (); i ++ )
if ( parent -> GetNthChild ( i ) -> m_layer_range == layer_range )
return wxDataViewItem ( parent -> GetNthChild ( i ));
return wxDataViewItem ( 0 );
}
int ObjectDataViewModel :: GetItemIdByLayerRange ( const int obj_idx , const t_layer_height_range & layer_range )
{
wxDataViewItem item = GetItemByLayerRange ( obj_idx , layer_range );
if ( ! item )
return - 1 ;
return GetLayerIdByItem ( item );
}
2019-04-25 01:45:00 +02:00
int ObjectDataViewModel :: GetIdByItem ( const wxDataViewItem & item ) const
2018-06-07 00:55:09 +02:00
{
2019-06-10 15:22:09 +02:00
if ( ! item . IsOk ())
return - 1 ;
2018-06-07 00:55:09 +02:00
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * node = ( ObjectDataViewModelNode * ) item . GetID ();
2018-06-07 00:55:09 +02:00
auto it = find ( m_objects . begin (), m_objects . end (), node );
if ( it == m_objects . end ())
return - 1 ;
return it - m_objects . begin ();
}
2019-04-25 01:45:00 +02:00
int ObjectDataViewModel :: GetIdByItemAndType ( const wxDataViewItem & item , const ItemType type ) const
2018-06-18 14:20:29 +02:00
{
wxASSERT ( item . IsOk ());
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * node = ( ObjectDataViewModelNode * ) item . GetID ();
2018-10-18 10:40:26 +02:00
if ( ! node || node -> m_type != type )
2018-06-18 14:20:29 +02:00
return - 1 ;
2018-10-16 11:08:37 +02:00
return node -> GetIdx ();
2018-06-18 14:20:29 +02:00
}
2019-04-25 01:45:00 +02:00
int ObjectDataViewModel :: GetObjectIdByItem ( const wxDataViewItem & item ) const
2018-12-12 08:40:10 +01:00
{
return GetIdByItem ( GetTopParent ( item ));
}
2019-04-25 01:45:00 +02:00
int ObjectDataViewModel :: GetVolumeIdByItem ( const wxDataViewItem & item ) const
2018-10-18 10:40:26 +02:00
{
return GetIdByItemAndType ( item , itVolume );
}
2019-04-25 01:45:00 +02:00
int ObjectDataViewModel :: GetInstanceIdByItem ( const wxDataViewItem & item ) const
2018-10-18 10:40:26 +02:00
{
return GetIdByItemAndType ( item , itInstance );
}
2019-05-30 14:41:16 +02:00
int ObjectDataViewModel :: GetLayerIdByItem ( const wxDataViewItem & item ) const
{
return GetIdByItemAndType ( item , itLayer );
}
2019-06-06 14:14:29 +02:00
t_layer_height_range ObjectDataViewModel :: GetLayerRangeByItem ( const wxDataViewItem & item ) const
{
wxASSERT ( item . IsOk ());
ObjectDataViewModelNode * node = ( ObjectDataViewModelNode * ) item . GetID ();
if ( ! node || node -> m_type != itLayer )
return { 0.0f , 0.0f };
return node -> GetLayerRange ();
}
2019-10-01 18:19:28 +02:00
bool ObjectDataViewModel :: UpdateColumValues ( unsigned col )
{
switch ( col )
{
case colPrint :
case colName :
case colEditing :
return true ;
case colExtruder :
{
wxDataViewItemArray items ;
GetAllChildren ( wxDataViewItem ( nullptr ), items );
if ( items . IsEmpty ()) return false ;
for ( auto item : items )
UpdateExtruderBitmap ( item );
return true ;
}
default :
printf ( "MyObjectTreeModel::SetValue: wrong column" );
}
return false ;
}
void ObjectDataViewModel :: UpdateExtruderBitmap ( wxDataViewItem item )
{
wxString extruder = GetExtruder ( item );
if ( extruder . IsEmpty ())
return ;
// set extruder bitmap
int extruder_idx = atoi ( extruder . c_str ());
if ( extruder_idx > 0 ) -- extruder_idx ;
const DataViewBitmapText extruder_val ( extruder , get_extruder_color_icon ( extruder_idx ));
wxVariant value ;
value << extruder_val ;
SetValue ( value , item , colExtruder );
}
2019-04-25 01:45:00 +02:00
void ObjectDataViewModel :: GetItemInfo ( const wxDataViewItem & item , ItemType & type , int & obj_idx , int & idx )
2018-10-12 12:00:37 +02:00
{
wxASSERT ( item . IsOk ());
2018-10-16 11:08:37 +02:00
type = itUndef ;
2018-10-12 12:00:37 +02:00
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * node = ( ObjectDataViewModelNode * ) item . GetID ();
2019-09-03 10:27:16 +02:00
if ( ! node ||
node -> GetIdx () <- 1 ||
( node -> GetIdx () == - 1 &&
! ( node -> GetType () & ( itObject | itSettings | itInstanceRoot | itLayerRoot /* | itLayer*/ ))
)
)
2018-10-18 10:40:26 +02:00
return ;
2018-10-16 11:08:37 +02:00
idx = node -> GetIdx ();
2018-10-18 10:40:26 +02:00
type = node -> GetType ();
2018-10-12 12:00:37 +02:00
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * parent_node = node -> GetParent ();
2018-10-12 12:00:37 +02:00
if ( ! parent_node ) return ;
2019-06-06 14:14:29 +02:00
// get top parent (Object) node
while ( parent_node -> m_type != itObject )
parent_node = parent_node -> GetParent ();
2018-10-12 12:00:37 +02:00
auto it = find ( m_objects . begin (), m_objects . end (), parent_node );
if ( it != m_objects . end ())
obj_idx = it - m_objects . begin ();
2018-10-18 10:40:26 +02:00
else
type = itUndef ;
2018-10-12 12:00:37 +02:00
}
2019-04-25 01:45:00 +02:00
int ObjectDataViewModel :: GetRowByItem ( const wxDataViewItem & item ) const
2018-12-17 12:46:36 +01:00
{
if ( m_objects . empty ())
return - 1 ;
int row_num = 0 ;
2019-09-06 17:46:55 +02:00
for ( size_t i = 0 ; i < m_objects . size (); i ++ )
2018-12-17 12:46:36 +01:00
{
row_num ++ ;
if ( item == wxDataViewItem ( m_objects [ i ]))
return row_num ;
2019-09-06 17:46:55 +02:00
for ( size_t j = 0 ; j < m_objects [ i ] -> GetChildCount (); j ++ )
2018-12-17 12:46:36 +01:00
{
row_num ++ ;
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * cur_node = m_objects [ i ] -> GetNthChild ( j );
2018-12-17 12:46:36 +01:00
if ( item == wxDataViewItem ( cur_node ))
return row_num ;
if ( cur_node -> m_type == itVolume && cur_node -> GetChildCount () == 1 )
row_num ++ ;
if ( cur_node -> m_type == itInstanceRoot )
{
row_num ++ ;
2019-09-06 17:46:55 +02:00
for ( size_t t = 0 ; t < cur_node -> GetChildCount (); t ++ )
2018-12-17 12:46:36 +01:00
{
row_num ++ ;
if ( item == wxDataViewItem ( cur_node -> GetNthChild ( t )))
return row_num ;
}
}
}
}
return - 1 ;
}
2019-08-02 17:53:12 +02:00
bool ObjectDataViewModel :: InvalidItem ( const wxDataViewItem & item )
{
if ( ! item )
return true ;
ObjectDataViewModelNode * node = ( ObjectDataViewModelNode * ) item . GetID ();
if ( ! node || node -> invalid ())
return true ;
return false ;
}
2019-04-25 01:45:00 +02:00
wxString ObjectDataViewModel :: GetName ( const wxDataViewItem & item ) const
2018-05-04 18:32:20 +02:00
{
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * node = ( ObjectDataViewModelNode * ) item . GetID ();
2018-05-04 18:32:20 +02:00
if ( ! node ) // happens if item.IsOk()==false
return wxEmptyString ;
return node -> m_name ;
}
2019-04-25 01:45:00 +02:00
wxBitmap & ObjectDataViewModel :: GetBitmap ( const wxDataViewItem & item ) const
2018-09-17 15:12:13 +02:00
{
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * node = ( ObjectDataViewModelNode * ) item . GetID ();
2018-09-17 15:12:13 +02:00
return node -> m_bmp ;
}
2019-10-01 18:19:28 +02:00
wxString ObjectDataViewModel :: GetExtruder ( const wxDataViewItem & item ) const
{
ObjectDataViewModelNode * node = ( ObjectDataViewModelNode * ) item . GetID ();
if ( ! node ) // happens if item.IsOk()==false
return wxEmptyString ;
return node -> m_extruder ;
}
int ObjectDataViewModel :: GetExtruderNumber ( const wxDataViewItem & item ) const
{
ObjectDataViewModelNode * node = ( ObjectDataViewModelNode * ) item . GetID ();
if ( ! node ) // happens if item.IsOk()==false
return 0 ;
return atoi ( node -> m_extruder . c_str ());
}
2019-04-25 01:45:00 +02:00
void ObjectDataViewModel :: GetValue ( wxVariant & variant , const wxDataViewItem & item , unsigned int col ) const
2018-05-04 18:32:20 +02:00
{
wxASSERT ( item . IsOk ());
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * node = ( ObjectDataViewModelNode * ) item . GetID ();
2018-05-04 18:32:20 +02:00
switch ( col )
{
2019-08-01 14:58:04 +02:00
case colPrint :
variant << node -> m_printable_icon ;
break ;
case colName :
2019-04-25 01:45:00 +02:00
variant << DataViewBitmapText ( node -> m_name , node -> m_bmp );
2018-05-04 18:32:20 +02:00
break ;
2019-08-01 14:58:04 +02:00
case colExtruder :
2019-10-01 18:19:28 +02:00
variant << DataViewBitmapText ( node -> m_extruder , node -> m_extruder_bmp );
2018-07-04 08:54:30 +02:00
break ;
2019-08-01 14:58:04 +02:00
case colEditing :
2018-07-04 08:54:30 +02:00
variant << node -> m_action_icon ;
break ;
2018-05-04 18:32:20 +02:00
default :
2018-06-04 15:59:55 +02:00
;
2018-05-04 18:32:20 +02:00
}
}
2019-04-25 01:45:00 +02:00
bool ObjectDataViewModel :: SetValue ( const wxVariant & variant , const wxDataViewItem & item , unsigned int col )
2018-05-04 18:32:20 +02:00
{
wxASSERT ( item . IsOk ());
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * node = ( ObjectDataViewModelNode * ) item . GetID ();
2018-06-05 13:17:24 +02:00
return node -> SetValue ( variant , col );
2018-05-04 18:32:20 +02:00
}
2019-04-25 01:45:00 +02:00
bool ObjectDataViewModel :: SetValue ( const wxVariant & variant , const int item_idx , unsigned int col )
2018-06-05 10:41:20 +02:00
{
2019-09-06 17:46:55 +02:00
if ( size_t ( item_idx ) >= m_objects . size ())
2018-06-05 10:41:20 +02:00
return false ;
return m_objects [ item_idx ] -> SetValue ( variant , col );
}
2018-06-19 12:24:16 +02:00
2019-10-01 18:19:28 +02:00
void ObjectDataViewModel :: SetExtruder ( const wxString & extruder , wxDataViewItem item )
{
DataViewBitmapText extruder_val ;
extruder_val . SetText ( extruder );
// set extruder bitmap
int extruder_idx = atoi ( extruder . c_str ());
if ( extruder_idx > 0 ) -- extruder_idx ;
extruder_val . SetBitmap ( get_extruder_color_icon ( extruder_idx ));
wxVariant value ;
value << extruder_val ;
SetValue ( value , item , colExtruder );
}
2019-04-25 01:45:00 +02:00
wxDataViewItem ObjectDataViewModel :: ReorganizeChildren ( const int current_volume_id ,
const int new_volume_id ,
const wxDataViewItem & parent )
2018-08-13 14:15:43 +02:00
{
auto ret_item = wxDataViewItem ( 0 );
if ( current_volume_id == new_volume_id )
return ret_item ;
wxASSERT ( parent . IsOk ());
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * node_parent = ( ObjectDataViewModelNode * ) parent . GetID ();
2018-08-13 14:15:43 +02:00
if ( ! node_parent ) // happens if item.IsOk()==false
return ret_item ;
2018-10-16 11:08:37 +02:00
const size_t shift = node_parent -> GetChildren (). Item ( 0 ) -> m_type == itSettings ? 1 : 0 ;
2018-09-17 15:12:13 +02:00
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * deleted_node = node_parent -> GetNthChild ( current_volume_id + shift );
2018-08-13 14:15:43 +02:00
node_parent -> GetChildren (). Remove ( deleted_node );
ItemDeleted ( parent , wxDataViewItem ( deleted_node ));
2018-09-17 15:12:13 +02:00
node_parent -> Insert ( deleted_node , new_volume_id + shift );
2018-08-13 14:15:43 +02:00
ItemAdded ( parent , wxDataViewItem ( deleted_node ));
2018-10-16 11:08:37 +02:00
const auto settings_item = GetSettingsItem ( wxDataViewItem ( deleted_node ));
2018-09-17 15:12:13 +02:00
if ( settings_item )
ItemAdded ( wxDataViewItem ( deleted_node ), settings_item );
2018-08-13 14:15:43 +02:00
//update volume_id value for child-nodes
auto children = node_parent -> GetChildren ();
int id_frst = current_volume_id < new_volume_id ? current_volume_id : new_volume_id ;
int id_last = current_volume_id > new_volume_id ? current_volume_id : new_volume_id ;
for ( int id = id_frst ; id <= id_last ; ++ id )
2018-10-16 11:08:37 +02:00
children [ id + shift ] -> SetIdx ( id );
2018-08-13 14:15:43 +02:00
2018-09-17 15:12:13 +02:00
return wxDataViewItem ( node_parent -> GetNthChild ( new_volume_id + shift ));
2018-08-13 14:15:43 +02:00
}
2019-04-25 01:45:00 +02:00
bool ObjectDataViewModel :: IsEnabled ( const wxDataViewItem & item , unsigned int col ) const
2018-09-17 15:12:13 +02:00
{
wxASSERT ( item . IsOk ());
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * node = ( ObjectDataViewModelNode * ) item . GetID ();
2018-09-17 15:12:13 +02:00
2018-12-04 18:14:02 +01:00
// disable extruder selection for the non "itObject|itVolume" item
2019-08-01 14:58:04 +02:00
return ! ( col == colExtruder && node -> m_extruder . IsEmpty ());
2018-09-17 15:12:13 +02:00
}
2018-05-04 18:32:20 +02:00
2019-04-25 01:45:00 +02:00
wxDataViewItem ObjectDataViewModel :: GetParent ( const wxDataViewItem & item ) const
2018-05-04 18:32:20 +02:00
{
// the invisible root node has no parent
if ( ! item . IsOk ())
return wxDataViewItem ( 0 );
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * node = ( ObjectDataViewModelNode * ) item . GetID ();
2019-07-31 16:36:56 +02:00
assert ( node != nullptr && node -> valid ());
2018-05-04 18:32:20 +02:00
2018-05-29 22:45:35 +02:00
// objects nodes has no parent too
2018-10-18 10:40:26 +02:00
if ( node -> m_type == itObject )
2018-05-04 18:32:20 +02:00
return wxDataViewItem ( 0 );
return wxDataViewItem (( void * ) node -> GetParent ());
}
2019-04-25 01:45:00 +02:00
wxDataViewItem ObjectDataViewModel :: GetTopParent ( const wxDataViewItem & item ) const
2018-10-18 10:40:26 +02:00
{
// the invisible root node has no parent
if ( ! item . IsOk ())
return wxDataViewItem ( 0 );
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * node = ( ObjectDataViewModelNode * ) item . GetID ();
2018-10-18 10:40:26 +02:00
if ( node -> m_type == itObject )
return item ;
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * parent_node = node -> GetParent ();
2018-10-18 10:40:26 +02:00
while ( parent_node -> m_type != itObject )
2019-06-06 14:14:29 +02:00
parent_node = parent_node -> GetParent ();
2018-10-18 10:40:26 +02:00
return wxDataViewItem (( void * ) parent_node );
}
2019-04-25 01:45:00 +02:00
bool ObjectDataViewModel :: IsContainer ( const wxDataViewItem & item ) const
2018-05-04 18:32:20 +02:00
{
2018-05-30 00:36:44 +02:00
// the invisible root node can have children
2018-05-04 18:32:20 +02:00
if ( ! item . IsOk ())
return true ;
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * node = ( ObjectDataViewModelNode * ) item . GetID ();
2018-05-04 18:32:20 +02:00
return node -> IsContainer ();
}
2019-04-25 01:45:00 +02:00
unsigned int ObjectDataViewModel :: GetChildren ( const wxDataViewItem & parent , wxDataViewItemArray & array ) const
2018-05-04 18:32:20 +02:00
{
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * node = ( ObjectDataViewModelNode * ) parent . GetID ();
2018-05-04 18:32:20 +02:00
if ( ! node )
{
2018-05-09 14:36:20 +02:00
for ( auto object : m_objects )
array . Add ( wxDataViewItem (( void * ) object ));
2018-05-04 18:32:20 +02:00
return m_objects . size ();
}
if ( node -> GetChildCount () == 0 )
{
return 0 ;
}
unsigned int count = node -> GetChildren (). GetCount ();
for ( unsigned int pos = 0 ; pos < count ; pos ++ )
{
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * child = node -> GetChildren (). Item ( pos );
2018-05-04 18:32:20 +02:00
array . Add ( wxDataViewItem (( void * ) child ));
}
return count ;
}
2018-07-30 12:17:32 +02:00
2019-04-25 01:45:00 +02:00
void ObjectDataViewModel :: GetAllChildren ( const wxDataViewItem & parent , wxDataViewItemArray & array ) const
2019-03-29 14:36:09 +01:00
{
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * node = ( ObjectDataViewModelNode * ) parent . GetID ();
2019-03-29 14:36:09 +01:00
if ( ! node ) {
for ( auto object : m_objects )
array . Add ( wxDataViewItem (( void * ) object ));
}
else if ( node -> GetChildCount () == 0 )
return ;
else {
const size_t count = node -> GetChildren (). GetCount ();
for ( size_t pos = 0 ; pos < count ; pos ++ ) {
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * child = node -> GetChildren (). Item ( pos );
2019-03-29 14:36:09 +01:00
array . Add ( wxDataViewItem (( void * ) child ));
}
}
wxDataViewItemArray new_array = array ;
for ( const auto item : new_array )
{
wxDataViewItemArray children ;
GetAllChildren ( item , children );
WX_APPEND_ARRAY ( array , children );
}
}
2019-04-25 01:45:00 +02:00
ItemType ObjectDataViewModel :: GetItemType ( const wxDataViewItem & item ) const
2018-10-16 11:08:37 +02:00
{
if ( ! item . IsOk ())
return itUndef ;
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * node = ( ObjectDataViewModelNode * ) item . GetID ();
2019-07-23 17:09:19 +02:00
return node -> m_type < 0 ? itUndef : node -> m_type ;
2018-10-16 11:08:37 +02:00
}
2019-04-25 01:45:00 +02:00
wxDataViewItem ObjectDataViewModel :: GetItemByType ( const wxDataViewItem & parent_item , ItemType type ) const
2018-09-17 15:12:13 +02:00
{
2018-11-05 13:53:30 +01:00
if ( ! parent_item . IsOk ())
2018-09-17 15:12:13 +02:00
return wxDataViewItem ( 0 );
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * node = ( ObjectDataViewModelNode * ) parent_item . GetID ();
2018-09-17 15:12:13 +02:00
if ( node -> GetChildCount () == 0 )
return wxDataViewItem ( 0 );
2019-09-06 17:46:55 +02:00
for ( size_t i = 0 ; i < node -> GetChildCount (); i ++ ) {
2018-11-05 13:53:30 +01:00
if ( node -> GetNthChild ( i ) -> m_type == type )
return wxDataViewItem (( void * ) node -> GetNthChild ( i ));
}
2018-09-17 15:12:13 +02:00
return wxDataViewItem ( 0 );
}
2019-04-25 01:45:00 +02:00
wxDataViewItem ObjectDataViewModel :: GetSettingsItem ( const wxDataViewItem & item ) const
2018-11-05 13:53:30 +01:00
{
return GetItemByType ( item , itSettings );
}
2019-04-25 01:45:00 +02:00
wxDataViewItem ObjectDataViewModel :: GetInstanceRootItem ( const wxDataViewItem & item ) const
2018-11-05 13:53:30 +01:00
{
return GetItemByType ( item , itInstanceRoot );
}
2019-05-31 10:54:52 +02:00
wxDataViewItem ObjectDataViewModel :: GetLayerRootItem ( const wxDataViewItem & item ) const
{
return GetItemByType ( item , itLayerRoot );
}
2019-04-25 01:45:00 +02:00
bool ObjectDataViewModel :: IsSettingsItem ( const wxDataViewItem & item ) const
2018-09-17 15:12:13 +02:00
{
if ( ! item . IsOk ())
return false ;
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * node = ( ObjectDataViewModelNode * ) item . GetID ();
2018-10-16 11:08:37 +02:00
return node -> m_type == itSettings ;
2018-09-17 15:12:13 +02:00
}
2019-04-25 01:45:00 +02:00
void ObjectDataViewModel :: UpdateSettingsDigest ( const wxDataViewItem & item ,
2018-09-17 15:12:13 +02:00
const std :: vector < std :: string >& categories )
{
if ( ! item . IsOk ()) return ;
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * node = ( ObjectDataViewModelNode * ) item . GetID ();
2018-09-17 15:12:13 +02:00
if ( ! node -> update_settings_digest ( categories ))
return ;
ItemChanged ( item );
}
2019-04-25 01:45:00 +02:00
void ObjectDataViewModel :: SetVolumeType ( const wxDataViewItem & item , const Slic3r :: ModelVolumeType type )
2018-11-02 23:27:31 +01:00
{
if ( ! item . IsOk () || GetItemType ( item ) != itVolume )
return ;
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * node = ( ObjectDataViewModelNode * ) item . GetID ();
2019-02-22 12:12:10 +01:00
node -> SetBitmap ( * m_volume_bmps [ int ( type )]);
2018-11-02 23:27:31 +01:00
ItemChanged ( item );
}
2019-08-05 08:44:55 +02:00
wxDataViewItem ObjectDataViewModel :: SetPrintableState (
2019-08-05 10:05:28 +02:00
PrintIndicator printable ,
2019-08-05 08:44:55 +02:00
int obj_idx ,
int subobj_idx /* = -1*/ ,
ItemType subobj_type /* = itInstance*/ )
{
wxDataViewItem item = wxDataViewItem ( 0 );
if ( subobj_idx < 0 )
item = GetItemById ( obj_idx );
else
item = subobj_type & itInstance ? GetItemByInstanceId ( obj_idx , subobj_idx ) :
GetItemByVolumeId ( obj_idx , subobj_idx );
ObjectDataViewModelNode * node = ( ObjectDataViewModelNode * ) item . GetID ();
if ( ! node )
return wxDataViewItem ( 0 );
node -> set_printable_icon ( printable );
2019-08-05 10:05:28 +02:00
ItemChanged ( item );
2019-08-05 08:44:55 +02:00
2019-08-07 14:11:41 +02:00
if ( subobj_idx >= 0 )
UpdateObjectPrintable ( GetItemById ( obj_idx ));
2019-08-05 08:44:55 +02:00
return item ;
}
2019-08-07 14:11:41 +02:00
wxDataViewItem ObjectDataViewModel :: SetObjectPrintableState (
PrintIndicator printable ,
wxDataViewItem obj_item )
{
ObjectDataViewModelNode * node = ( ObjectDataViewModelNode * ) obj_item . GetID ();
if ( ! node )
return wxDataViewItem ( 0 );
node -> set_printable_icon ( printable );
ItemChanged ( obj_item );
UpdateInstancesPrintable ( obj_item );
return obj_item ;
}
2019-04-25 01:45:00 +02:00
void ObjectDataViewModel :: Rescale ()
2019-04-16 10:05:45 +02:00
{
wxDataViewItemArray all_items ;
GetAllChildren ( wxDataViewItem ( 0 ), all_items );
for ( wxDataViewItem item : all_items )
{
if ( ! item . IsOk ())
continue ;
2019-04-25 01:45:00 +02:00
ObjectDataViewModelNode * node = ( ObjectDataViewModelNode * ) item . GetID ();
node -> msw_rescale ();
2019-04-16 10:05:45 +02:00
2019-09-17 13:41:44 +02:00
switch ( node -> m_type )
{
case itObject :
if ( node -> m_bmp . IsOk ()) node -> m_bmp = * m_warning_bmp ;
break ;
case itVolume :
2019-04-29 15:27:59 +02:00
node -> m_bmp = GetVolumeIcon ( node -> m_volume_type , node -> m_bmp . GetWidth () != node -> m_bmp . GetHeight ());
2019-09-17 13:41:44 +02:00
break ;
case itLayerRoot :
2020-01-27 16:30:09 +01:00
node -> m_bmp = create_scaled_bitmap ( m_ctrl , LAYER_ROOT_ICON );
2019-09-17 13:41:44 +02:00
case itLayer :
2020-01-27 16:30:09 +01:00
node -> m_bmp = create_scaled_bitmap ( m_ctrl , LAYER_ICON );
2019-09-17 13:41:44 +02:00
break ;
default : break ;
}
2019-04-16 10:05:45 +02:00
ItemChanged ( item );
}
}
2019-04-29 15:27:59 +02:00
wxBitmap ObjectDataViewModel :: GetVolumeIcon ( const Slic3r :: ModelVolumeType vol_type , const bool is_marked /* = false*/ )
{
if ( ! is_marked )
return * m_volume_bmps [ static_cast < int > ( vol_type )];
std :: string scaled_bitmap_name = "warning" + std :: to_string ( static_cast < int > ( vol_type ));
scaled_bitmap_name += "-em" + std :: to_string ( Slic3r :: GUI :: wxGetApp (). em_unit ());
wxBitmap * bmp = m_bitmap_cache -> find ( scaled_bitmap_name );
if ( bmp == nullptr ) {
std :: vector < wxBitmap > bmps ;
bmps . emplace_back ( * m_warning_bmp );
bmps . emplace_back ( * m_volume_bmps [ static_cast < int > ( vol_type )]);
bmp = m_bitmap_cache -> insert ( scaled_bitmap_name , bmps );
}
return * bmp ;
}
void ObjectDataViewModel :: DeleteWarningIcon ( const wxDataViewItem & item , const bool unmark_object /* = false*/ )
{
if ( ! item . IsOk ())
return ;
ObjectDataViewModelNode * node = ( ObjectDataViewModelNode * ) item . GetID ();
if ( ! node -> GetBitmap (). IsOk () || ! ( node -> GetType () & ( itVolume | itObject )))
return ;
if ( node -> GetType () & itVolume ) {
node -> SetBitmap ( * m_volume_bmps [ static_cast < int > ( node -> volume_type ())]);
return ;
}
node -> SetBitmap ( wxNullBitmap );
if ( unmark_object )
{
wxDataViewItemArray children ;
GetChildren ( item , children );
for ( const wxDataViewItem & child : children )
DeleteWarningIcon ( child );
}
}
2018-10-15 13:25:22 +02:00
//-----------------------------------------------------------------------------
2019-09-30 14:03:50 +02:00
// DataViewBitmapText
2018-10-15 13:25:22 +02:00
//-----------------------------------------------------------------------------
2019-04-25 01:45:00 +02:00
wxIMPLEMENT_DYNAMIC_CLASS ( DataViewBitmapText , wxObject )
2018-10-15 13:25:22 +02:00
2019-04-25 01:45:00 +02:00
IMPLEMENT_VARIANT_OBJECT ( DataViewBitmapText )
2018-10-15 13:25:22 +02:00
2018-09-17 15:12:13 +02:00
// ---------------------------------------------------------
2019-04-25 01:45:00 +02:00
// BitmapTextRenderer
2018-09-17 15:12:13 +02:00
// ---------------------------------------------------------
2018-12-17 08:37:50 +01:00
#if ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
2019-04-25 01:45:00 +02:00
BitmapTextRenderer :: BitmapTextRenderer ( wxDataViewCellMode mode /*= wxDATAVIEW_CELL_EDITABLE*/ ,
2018-12-17 08:37:50 +01:00
int align /*= wxDVR_DEFAULT_ALIGNMENT*/ ) :
wxDataViewRenderer ( wxT ( "PrusaDataViewBitmapText" ), mode , align )
{
SetMode ( mode );
SetAlignment ( align );
}
#endif // ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
2019-04-25 01:45:00 +02:00
bool BitmapTextRenderer :: SetValue ( const wxVariant & value )
2018-09-17 15:12:13 +02:00
{
m_value << value ;
return true ;
}
2019-04-25 01:45:00 +02:00
bool BitmapTextRenderer :: GetValue ( wxVariant & WXUNUSED ( value )) const
2018-09-17 15:12:13 +02:00
{
return false ;
}
2018-12-17 08:37:50 +01:00
#if ENABLE_NONCUSTOM_DATA_VIEW_RENDERING && wxUSE_ACCESSIBILITY
2019-04-25 01:45:00 +02:00
wxString BitmapTextRenderer :: GetAccessibleDescription () const
2018-12-14 16:07:28 +01:00
{
return m_value . GetText ();
}
2018-12-17 08:37:50 +01:00
#endif // wxUSE_ACCESSIBILITY && ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
2018-12-14 16:07:28 +01:00
2019-04-25 01:45:00 +02:00
bool BitmapTextRenderer :: Render ( wxRect rect , wxDC * dc , int state )
2018-09-17 15:12:13 +02:00
{
int xoffset = 0 ;
const wxBitmap & icon = m_value . GetBitmap ();
if ( icon . IsOk ())
{
2020-01-27 16:30:09 +01:00
float sf = ( float ) 1.0 / get_svg_scale_factor ( m_parent );
wxSize icon_sz = icon . GetSize () * sf ;
dc -> DrawBitmap ( icon , rect . x , rect . y + ( rect . height - icon_sz . y ) / 2 );
xoffset = icon_sz . x + 4 ;
2018-09-17 15:12:13 +02:00
}
RenderText ( m_value . GetText (), xoffset , rect , dc , state );
return true ;
}
2019-04-25 01:45:00 +02:00
wxSize BitmapTextRenderer :: GetSize () const
2018-09-17 15:12:13 +02:00
{
if ( ! m_value . GetText (). empty ())
{
wxSize size = GetTextExtent ( m_value . GetText ());
if ( m_value . GetBitmap (). IsOk ())
size . x += m_value . GetBitmap (). GetWidth () + 4 ;
return size ;
}
return wxSize ( 80 , 20 );
}
2018-08-29 11:21:22 +02:00
2019-04-25 01:45:00 +02:00
wxWindow * BitmapTextRenderer :: CreateEditorCtrl ( wxWindow * parent , wxRect labelRect , const wxVariant & value )
2018-12-12 13:18:38 +01:00
{
wxDataViewCtrl * const dv_ctrl = GetOwner () -> GetOwner ();
2019-04-25 01:45:00 +02:00
ObjectDataViewModel * const model = dynamic_cast < ObjectDataViewModel *> ( dv_ctrl -> GetModel ());
2018-12-12 13:18:38 +01:00
if ( ! ( model -> GetItemType ( dv_ctrl -> GetSelection ()) & ( itVolume | itObject )) )
return nullptr ;
2019-04-25 01:45:00 +02:00
DataViewBitmapText data ;
2018-12-12 13:18:38 +01:00
data << value ;
2018-12-14 16:07:28 +01:00
2018-12-12 14:35:18 +01:00
m_was_unusable_symbol = false ;
2018-12-12 13:18:38 +01:00
wxPoint position = labelRect . GetPosition ();
2018-12-14 16:07:28 +01:00
if ( data . GetBitmap (). IsOk ()) {
const int bmp_width = data . GetBitmap (). GetWidth ();
2018-12-12 13:18:38 +01:00
position . x += bmp_width ;
labelRect . SetWidth ( labelRect . GetWidth () - bmp_width );
}
wxTextCtrl * text_editor = new wxTextCtrl ( parent , wxID_ANY , data . GetText (),
position , labelRect . GetSize (), wxTE_PROCESS_ENTER );
text_editor -> SetInsertionPointEnd ();
2018-12-14 16:07:28 +01:00
text_editor -> SelectAll ();
2018-12-12 13:18:38 +01:00
return text_editor ;
}
2019-04-25 01:45:00 +02:00
bool BitmapTextRenderer :: GetValueFromEditorCtrl ( wxWindow * ctrl , wxVariant & value )
2018-12-12 13:18:38 +01:00
{
wxTextCtrl * text_editor = wxDynamicCast ( ctrl , wxTextCtrl );
2018-12-12 14:35:18 +01:00
if ( ! text_editor || text_editor -> GetValue (). IsEmpty ())
2018-12-12 13:18:38 +01:00
return false ;
2018-12-12 14:35:18 +01:00
std :: string chosen_name = Slic3r :: normalize_utf8_nfc ( text_editor -> GetValue (). ToUTF8 ());
const char * unusable_symbols = "<>:/ \\ |?* \" " ;
for ( size_t i = 0 ; i < std :: strlen ( unusable_symbols ); i ++ ) {
if ( chosen_name . find_first_of ( unusable_symbols [ i ]) != std :: string :: npos ) {
m_was_unusable_symbol = true ;
return false ;
}
}
2018-12-14 16:07:28 +01:00
// The icon can't be edited so get its old value and reuse it.
wxVariant valueOld ;
2019-08-01 14:58:04 +02:00
GetView () -> GetModel () -> GetValue ( valueOld , m_item , colName );
2018-12-14 16:07:28 +01:00
2019-04-25 01:45:00 +02:00
DataViewBitmapText bmpText ;
2018-12-14 16:07:28 +01:00
bmpText << valueOld ;
// But replace the text with the value entered by user.
bmpText . SetText ( text_editor -> GetValue ());
value << bmpText ;
2018-12-12 13:18:38 +01:00
return true ;
}
2019-09-30 14:03:50 +02:00
// ----------------------------------------------------------------------------
2019-10-01 18:19:28 +02:00
// BitmapChoiceRenderer
2019-09-30 14:03:50 +02:00
// ----------------------------------------------------------------------------
2019-10-01 18:19:28 +02:00
bool BitmapChoiceRenderer :: SetValue ( const wxVariant & value )
2019-09-30 14:03:50 +02:00
{
m_value << value ;
return true ;
}
2019-10-01 18:19:28 +02:00
bool BitmapChoiceRenderer :: GetValue ( wxVariant & value ) const
2019-09-30 14:03:50 +02:00
{
value << m_value ;
return true ;
}
2019-10-01 18:19:28 +02:00
bool BitmapChoiceRenderer :: Render ( wxRect rect , wxDC * dc , int state )
2019-09-30 14:03:50 +02:00
{
int xoffset = 0 ;
const wxBitmap & icon = m_value . GetBitmap ();
if ( icon . IsOk ())
{
dc -> DrawBitmap ( icon , rect . x , rect . y + ( rect . height - icon . GetHeight ()) / 2 );
xoffset = icon . GetWidth () + 4 ;
}
2019-10-01 18:19:28 +02:00
if ( rect . height == 0 )
rect . height = icon . GetHeight ();
2019-09-30 14:03:50 +02:00
RenderText ( m_value . GetText (), xoffset , rect , dc , state );
return true ;
}
2019-10-01 18:19:28 +02:00
wxSize BitmapChoiceRenderer :: GetSize () const
2019-09-30 14:03:50 +02:00
{
2019-10-01 18:19:28 +02:00
wxSize sz = GetTextExtent ( m_value . GetText ());
2019-09-30 14:03:50 +02:00
2019-10-01 18:19:28 +02:00
if ( m_value . GetBitmap (). IsOk ())
sz . x += m_value . GetBitmap (). GetWidth () + 4 ;
2019-09-30 14:03:50 +02:00
return sz ;
}
2019-10-01 18:19:28 +02:00
wxWindow * BitmapChoiceRenderer :: CreateEditorCtrl ( wxWindow * parent , wxRect labelRect , const wxVariant & value )
2019-09-30 14:03:50 +02:00
{
wxDataViewCtrl * const dv_ctrl = GetOwner () -> GetOwner ();
ObjectDataViewModel * const model = dynamic_cast < ObjectDataViewModel *> ( dv_ctrl -> GetModel ());
2019-10-09 12:36:13 +02:00
if ( ! ( model -> GetItemType ( dv_ctrl -> GetSelection ()) & ( itVolume | itLayer | itObject )))
2019-09-30 14:03:50 +02:00
return nullptr ;
2019-10-01 18:19:28 +02:00
std :: vector < wxBitmap *> icons = get_extruder_color_icons ();
if ( icons . empty ())
return nullptr ;
2019-09-30 14:03:50 +02:00
DataViewBitmapText data ;
data << value ;
2019-10-01 18:19:28 +02:00
auto c_editor = new wxBitmapComboBox ( parent , wxID_ANY , wxEmptyString ,
2019-09-30 14:03:50 +02:00
labelRect . GetTopLeft (), wxSize ( labelRect . GetWidth (), - 1 ),
0 , nullptr , wxCB_READONLY );
2019-10-01 18:19:28 +02:00
int i = 0 ;
for ( wxBitmap * bmp : icons ) {
if ( i == 0 ) {
c_editor -> Append ( _ ( L ( "default" )), * bmp );
++ i ;
}
c_editor -> Append ( wxString :: Format ( "%d" , i ), * bmp );
++ i ;
}
c_editor -> SetSelection ( atoi ( data . GetText (). c_str ()));
// to avoid event propagation to other sidebar items
2019-10-10 11:03:55 +02:00
c_editor -> Bind ( wxEVT_COMBOBOX , [ this ]( wxCommandEvent & evt ) {
evt . StopPropagation ();
// FinishEditing grabs new selection and triggers config update. We better call
// it explicitly, automatic update on KILL_FOCUS didn't work on Linux.
this -> FinishEditing ();
});
2019-10-01 18:19:28 +02:00
2019-09-30 14:03:50 +02:00
return c_editor ;
}
2019-10-01 18:19:28 +02:00
bool BitmapChoiceRenderer :: GetValueFromEditorCtrl ( wxWindow * ctrl , wxVariant & value )
2019-09-30 14:03:50 +02:00
{
wxBitmapComboBox * c = ( wxBitmapComboBox * ) ctrl ;
int selection = c -> GetSelection ();
if ( selection < 0 )
return false ;
DataViewBitmapText bmpText ;
bmpText . SetText ( c -> GetString ( selection ));
bmpText . SetBitmap ( c -> GetItemBitmap ( selection ));
value << bmpText ;
return true ;
}
2018-08-28 15:51:53 +02:00
// ----------------------------------------------------------------------------
2019-04-25 01:45:00 +02:00
// LockButton
2018-08-28 15:51:53 +02:00
// ----------------------------------------------------------------------------
2019-04-25 01:45:00 +02:00
LockButton :: LockButton ( wxWindow * parent ,
wxWindowID id ,
const wxPoint & pos /*= wxDefaultPosition*/ ,
const wxSize & size /*= wxDefaultSize*/ ) :
wxButton ( parent , id , wxEmptyString , pos , size , wxBU_EXACTFIT | wxNO_BORDER )
2018-08-28 15:51:53 +02:00
{
2019-07-31 17:14:32 +02:00
m_bmp_lock_closed = ScalableBitmap ( this , "lock_closed" );
m_bmp_lock_closed_f = ScalableBitmap ( this , "lock_closed_f" );
m_bmp_lock_open = ScalableBitmap ( this , "lock_open" );
m_bmp_lock_open_f = ScalableBitmap ( this , "lock_open_f" );
2018-08-28 15:51:53 +02:00
#ifdef __WXMSW__
SetBackgroundColour ( wxSystemSettings :: GetColour ( wxSYS_COLOUR_WINDOW ));
#endif // __WXMSW__
2019-07-31 17:14:32 +02:00
SetBitmap ( m_bmp_lock_open . bmp ());
SetBitmapDisabled ( m_bmp_lock_open . bmp ());
SetBitmapHover ( m_bmp_lock_closed_f . bmp ());
2018-08-28 15:51:53 +02:00
//button events
2019-07-31 17:14:32 +02:00
Bind ( wxEVT_BUTTON , & LockButton :: OnButton , this );
2018-08-28 15:51:53 +02:00
}
2019-04-25 01:45:00 +02:00
void LockButton :: OnButton ( wxCommandEvent & event )
2018-08-28 15:51:53 +02:00
{
2019-06-20 12:56:23 +02:00
if ( m_disabled )
return ;
2018-08-28 15:51:53 +02:00
m_is_pushed = ! m_is_pushed ;
2019-07-31 17:14:32 +02:00
update_button_bitmaps ();
2018-08-28 15:51:53 +02:00
event . Skip ();
}
2019-04-25 01:45:00 +02:00
void LockButton :: SetLock ( bool lock )
2019-01-09 08:48:25 +01:00
{
m_is_pushed = lock ;
2019-07-31 17:14:32 +02:00
update_button_bitmaps ();
2019-01-09 08:48:25 +01:00
}
2019-04-25 01:45:00 +02:00
void LockButton :: msw_rescale ()
2019-04-16 10:05:45 +02:00
{
2019-07-31 17:14:32 +02:00
m_bmp_lock_closed . msw_rescale ();
m_bmp_lock_closed_f . msw_rescale ();
m_bmp_lock_open . msw_rescale ();
m_bmp_lock_open_f . msw_rescale ();
2019-09-18 15:10:36 +02:00
update_button_bitmaps ();
2019-04-16 10:05:45 +02:00
}
2019-07-31 17:14:32 +02:00
void LockButton :: update_button_bitmaps ()
2018-08-28 15:51:53 +02:00
{
2019-07-31 17:14:32 +02:00
SetBitmap ( m_is_pushed ? m_bmp_lock_closed . bmp () : m_bmp_lock_open . bmp ());
SetBitmapHover ( m_is_pushed ? m_bmp_lock_closed_f . bmp () : m_bmp_lock_open_f . bmp ());
2018-08-28 15:51:53 +02:00
Refresh ();
Update ();
}
2019-01-10 11:05:58 +01:00
// ----------------------------------------------------------------------------
2019-04-25 01:45:00 +02:00
// ModeButton
2019-01-10 11:05:58 +01:00
// ----------------------------------------------------------------------------
2019-04-25 01:45:00 +02:00
ModeButton :: ModeButton ( wxWindow * parent ,
wxWindowID id ,
const std :: string & icon_name /* = ""*/ ,
const wxString & mode /* = wxEmptyString*/ ,
const wxSize & size /* = wxDefaultSize*/ ,
const wxPoint & pos /* = wxDefaultPosition*/ ) :
2019-07-25 16:23:32 +02:00
ScalableButton ( parent , id , icon_name , mode , size , pos , wxBU_EXACTFIT )
2019-01-10 11:05:58 +01:00
{
2019-02-26 10:50:00 +01:00
m_tt_focused = wxString :: Format ( _ ( L ( "Switch to the %s mode" )), mode );
m_tt_selected = wxString :: Format ( _ ( L ( "Current mode is %s" )), mode );
2019-07-25 16:23:32 +02:00
SetBitmapMargins ( 3 , 0 );
2019-01-10 11:05:58 +01:00
//button events
2019-04-25 01:45:00 +02:00
Bind ( wxEVT_BUTTON , & ModeButton :: OnButton , this );
Bind ( wxEVT_ENTER_WINDOW , & ModeButton :: OnEnterBtn , this );
Bind ( wxEVT_LEAVE_WINDOW , & ModeButton :: OnLeaveBtn , this );
2019-01-10 11:05:58 +01:00
}
2019-04-25 01:45:00 +02:00
void ModeButton :: OnButton ( wxCommandEvent & event )
2019-01-10 11:05:58 +01:00
{
m_is_selected = true ;
focus_button ( m_is_selected );
event . Skip ();
}
2019-04-25 01:45:00 +02:00
void ModeButton :: SetState ( const bool state )
2019-01-10 11:05:58 +01:00
{
m_is_selected = state ;
focus_button ( m_is_selected );
2019-02-26 10:50:00 +01:00
SetToolTip ( state ? m_tt_selected : m_tt_focused );
2019-01-10 11:05:58 +01:00
}
2019-04-25 01:45:00 +02:00
void ModeButton :: focus_button ( const bool focus )
2019-01-10 11:05:58 +01:00
{
2019-04-29 09:43:42 +02:00
const wxFont & new_font = focus ?
Slic3r :: GUI :: wxGetApp (). bold_font () :
Slic3r :: GUI :: wxGetApp (). normal_font ();
2019-04-10 09:56:32 +02:00
2019-01-10 11:05:58 +01:00
SetFont ( new_font );
2019-07-25 16:23:32 +02:00
SetForegroundColour ( wxSystemSettings :: GetColour ( focus ? wxSYS_COLOUR_BTNTEXT : wxSYS_COLOUR_BTNSHADOW ));
2019-01-10 11:05:58 +01:00
Refresh ();
Update ();
}
// ----------------------------------------------------------------------------
2019-04-25 01:45:00 +02:00
// ModeSizer
2019-01-10 11:05:58 +01:00
// ----------------------------------------------------------------------------
2019-07-25 16:23:32 +02:00
ModeSizer :: ModeSizer ( wxWindow * parent , int hgap /* = 0*/ ) :
2019-02-11 15:36:05 +01:00
wxFlexGridSizer ( 3 , 0 , hgap )
2019-01-10 11:05:58 +01:00
{
SetFlexibleDirection ( wxHORIZONTAL );
2019-04-13 23:46:52 +02:00
std :: vector < std :: pair < wxString , std :: string >> buttons = {
2019-04-25 01:45:00 +02:00
{ _ ( L ( "Simple" )), "mode_simple_sq.png" },
2019-05-13 12:13:28 +02:00
{ _ ( L ( "Advanced" )), "mode_advanced_sq.png" },
2019-04-25 01:45:00 +02:00
{ _ ( L ( "Expert" )), "mode_expert_sq.png" }
2019-02-11 14:14:35 +01:00
};
2019-02-06 15:29:13 +01:00
2019-05-21 14:06:43 +02:00
auto modebtnfn = []( wxCommandEvent & event , int mode_id ) {
Slic3r :: GUI :: wxGetApp (). save_mode ( mode_id );
event . Skip ();
};
2019-04-25 01:45:00 +02:00
m_mode_btns . reserve ( 3 );
2019-02-11 14:14:35 +01:00
for ( const auto & button : buttons ) {
2019-07-25 16:23:32 +02:00
m_mode_btns . push_back ( new ModeButton ( parent , wxID_ANY , button . second , button . first ));
2019-05-27 13:07:37 +02:00
m_mode_btns . back () -> Bind ( wxEVT_BUTTON , std :: bind ( modebtnfn , std :: placeholders :: _1 , int ( m_mode_btns . size () - 1 )));
2019-05-21 14:06:43 +02:00
Add ( m_mode_btns . back ());
2019-02-11 14:14:35 +01:00
}
2019-01-10 11:05:58 +01:00
}
2019-04-25 01:45:00 +02:00
void ModeSizer :: SetMode ( const int mode )
2019-01-10 11:05:58 +01:00
{
2019-05-21 14:06:43 +02:00
for ( size_t m = 0 ; m < m_mode_btns . size (); m ++ )
m_mode_btns [ m ] -> SetState ( int ( m ) == mode );
2019-01-10 11:05:58 +01:00
}
2019-01-25 13:16:32 +01:00
2019-04-25 01:45:00 +02:00
void ModeSizer :: msw_rescale ()
2019-04-13 23:46:52 +02:00
{
2019-05-21 14:06:43 +02:00
for ( size_t m = 0 ; m < m_mode_btns . size (); m ++ )
2019-04-25 01:45:00 +02:00
m_mode_btns [ m ] -> msw_rescale ();
2019-04-13 23:46:52 +02:00
}
2019-01-25 13:16:32 +01:00
// ----------------------------------------------------------------------------
2019-04-25 01:45:00 +02:00
// MenuWithSeparators
2019-01-25 13:16:32 +01:00
// ----------------------------------------------------------------------------
2019-04-25 01:45:00 +02:00
void MenuWithSeparators :: DestroySeparators ()
2019-01-25 13:16:32 +01:00
{
if ( m_separator_frst ) {
Destroy ( m_separator_frst );
m_separator_frst = nullptr ;
}
if ( m_separator_scnd ) {
Destroy ( m_separator_scnd );
m_separator_scnd = nullptr ;
}
}
2019-04-25 01:45:00 +02:00
void MenuWithSeparators :: SetFirstSeparator ()
{
m_separator_frst = this -> AppendSeparator ();
}
void MenuWithSeparators :: SetSecondSeparator ()
{
m_separator_scnd = this -> AppendSeparator ();
}
2019-01-25 13:16:32 +01:00
2019-04-13 23:46:52 +02:00
// ----------------------------------------------------------------------------
// PrusaBitmap
// ----------------------------------------------------------------------------
2019-04-25 01:45:00 +02:00
ScalableBitmap :: ScalableBitmap ( wxWindow * parent ,
const std :: string & icon_name /* = ""*/ ,
const int px_cnt /* = 16*/ ,
const bool is_horizontal /* = false*/ ) :
m_parent ( parent ), m_icon_name ( icon_name ),
m_px_cnt ( px_cnt ), m_is_horizontal ( is_horizontal )
2019-04-13 23:46:52 +02:00
{
2019-04-16 10:05:45 +02:00
m_bmp = create_scaled_bitmap ( parent , icon_name , px_cnt , is_horizontal );
2019-04-13 23:46:52 +02:00
}
2019-04-25 01:45:00 +02:00
void ScalableBitmap :: msw_rescale ()
2019-04-13 23:46:52 +02:00
{
2019-04-16 10:05:45 +02:00
m_bmp = create_scaled_bitmap ( m_parent , m_icon_name , m_px_cnt , m_is_horizontal );
2019-04-13 23:46:52 +02:00
}
// ----------------------------------------------------------------------------
// PrusaButton
// ----------------------------------------------------------------------------
2019-04-25 01:45:00 +02:00
ScalableButton :: ScalableButton ( wxWindow * parent ,
wxWindowID id ,
const std :: string & icon_name /*= ""*/ ,
const wxString & label /* = wxEmptyString*/ ,
const wxSize & size /* = wxDefaultSize*/ ,
const wxPoint & pos /* = wxDefaultPosition*/ ,
long style /*= wxBU_EXACTFIT | wxNO_BORDER*/ ) :
2019-04-13 23:46:52 +02:00
m_current_icon_name ( icon_name ),
m_parent ( parent )
{
Create ( parent , id , label , pos , size , style );
#ifdef __WXMSW__
if ( style & wxNO_BORDER )
SetBackgroundColour ( wxSystemSettings :: GetColour ( wxSYS_COLOUR_WINDOW ));
#endif // __WXMSW__
2019-05-17 19:11:11 +02:00
SetBitmap ( create_scaled_bitmap ( parent , icon_name ));
2019-08-01 11:35:43 +02:00
if ( size != wxDefaultSize )
{
const int em = em_unit ( parent );
m_width = size . x / em ;
m_height = size . y / em ;
}
2019-04-13 23:46:52 +02:00
}
2019-04-25 01:45:00 +02:00
ScalableButton :: ScalableButton ( wxWindow * parent ,
wxWindowID id ,
const ScalableBitmap & bitmap ,
const wxString & label /*= wxEmptyString*/ ,
long style /*= wxBU_EXACTFIT | wxNO_BORDER*/ ) :
2019-12-13 13:23:55 +01:00
m_parent ( parent ),
2019-04-13 23:46:52 +02:00
m_current_icon_name ( bitmap . name ()),
2019-12-13 13:23:55 +01:00
m_px_cnt ( bitmap . px_cnt ()),
m_is_horizontal ( bitmap . is_horizontal ())
2019-04-13 23:46:52 +02:00
{
Create ( parent , id , label , wxDefaultPosition , wxDefaultSize , style );
#ifdef __WXMSW__
if ( style & wxNO_BORDER )
SetBackgroundColour ( wxSystemSettings :: GetColour ( wxSYS_COLOUR_WINDOW ));
#endif // __WXMSW__
2019-04-16 10:05:45 +02:00
SetBitmap ( bitmap . bmp ());
2019-04-13 23:46:52 +02:00
}
2019-04-25 01:45:00 +02:00
void ScalableButton :: SetBitmap_ ( const ScalableBitmap & bmp )
2019-04-13 23:46:52 +02:00
{
SetBitmap ( bmp . bmp ());
m_current_icon_name = bmp . name ();
}
2019-08-01 11:35:43 +02:00
void ScalableButton :: SetBitmapDisabled_ ( const ScalableBitmap & bmp )
{
SetBitmapDisabled ( bmp . bmp ());
m_disabled_icon_name = bmp . name ();
}
2019-12-13 17:56:04 +01:00
int ScalableButton :: GetBitmapHeight ()
{
const float scale_factor = get_svg_scale_factor ( m_parent );
return int (( float ) GetBitmap (). GetHeight () / scale_factor );
}
2019-04-25 01:45:00 +02:00
void ScalableButton :: msw_rescale ()
2019-04-13 23:46:52 +02:00
{
2019-12-13 13:23:55 +01:00
SetBitmap ( create_scaled_bitmap ( m_parent , m_current_icon_name , m_px_cnt , m_is_horizontal ));
2019-08-01 11:35:43 +02:00
if ( ! m_disabled_icon_name . empty ())
2019-12-13 13:23:55 +01:00
SetBitmapDisabled ( create_scaled_bitmap ( m_parent , m_disabled_icon_name , m_px_cnt , m_is_horizontal ));
2019-04-13 23:46:52 +02:00
2019-08-01 11:35:43 +02:00
if ( m_width > 0 || m_height > 0 )
{
const int em = em_unit ( m_parent );
wxSize size ( m_width * em , m_height * em );
SetMinSize ( size );
}
2019-04-13 23:46:52 +02:00
}
2018-08-29 11:21:22 +02:00
2018-08-28 15:51:53 +02:00
2018-08-29 11:21:22 +02:00