2018-02-02 11:38:35 +00:00
# include "wxExtensions.hpp"
2019-04-05 16:53:02 +00:00
# include <stdexcept>
2019-05-17 17:12:52 +00:00
# include <cmath>
2019-04-05 16:53:02 +00:00
2018-05-10 14:36:12 +00:00
# include <wx/sizer.h>
2018-11-26 13:41:58 +00:00
2019-04-04 07:20:11 +00:00
# include <boost/algorithm/string/replace.hpp>
2018-11-26 13:41:58 +00:00
# include "BitmapCache.hpp"
2019-01-07 18:17:10 +00:00
# include "GUI.hpp"
2018-10-05 21:29:15 +00:00
# include "GUI_App.hpp"
# include "GUI_ObjectList.hpp"
2019-02-11 13:14:35 +00:00
# include "I18N.hpp"
2019-04-17 19:35:53 +00:00
# include "GUI_Utils.hpp"
2019-05-17 17:12:52 +00:00
# include "../Utils/MacDarkMode.hpp"
2018-05-10 14:36:12 +00:00
2019-05-13 12:27:51 +00:00
# ifndef __WXGTK__ // msw_menuitem_bitmaps is used for MSW and OSX
2019-05-07 11:35:37 +00:00
static std : : map < int , std : : string > msw_menuitem_bitmaps ;
2019-05-13 12:27:51 +00:00
# ifdef __WXMSW__
2019-05-03 07:44:19 +00:00
void msw_rescale_menu ( wxMenu * menu )
{
2019-05-07 11:35:37 +00:00
struct update_icons {
static void run ( wxMenuItem * item ) {
const auto it = msw_menuitem_bitmaps . find ( item - > GetId ( ) ) ;
if ( it ! = msw_menuitem_bitmaps . end ( ) ) {
2020-01-31 15:50:11 +00:00
const wxBitmap & item_icon = create_scaled_bitmap ( it - > second ) ;
2019-05-07 11:35:37 +00:00
if ( item_icon . IsOk ( ) )
item - > SetBitmap ( item_icon ) ;
}
if ( item - > IsSubMenu ( ) )
for ( wxMenuItem * sub_item : item - > GetSubMenu ( ) - > GetMenuItems ( ) )
update_icons : : run ( sub_item ) ;
}
} ;
for ( wxMenuItem * item : menu - > GetMenuItems ( ) )
update_icons : : run ( item ) ;
2019-05-03 07:44:19 +00:00
}
2019-05-07 11:35:37 +00:00
# endif /* __WXMSW__ */
2019-05-13 12:27:51 +00:00
# endif /* no __WXGTK__ */
2019-12-18 14:54:01 +00:00
void enable_menu_item ( wxUpdateUIEvent & evt , std : : function < bool ( ) > const cb_condition , wxMenuItem * item , wxWindow * win )
2019-05-13 12:27:51 +00: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 ( ) )
{
2020-02-02 18:40:00 +00:00
const wxBitmap & item_icon = create_scaled_bitmap ( it - > second , win , 16 , ! enable ) ;
2019-05-13 15:57:31 +00:00
if ( item_icon . IsOk ( ) )
item - > SetBitmap ( item_icon ) ;
2019-05-13 12:27:51 +00:00
}
# endif // __WXOSX__
}
2019-05-03 07:44:19 +00:00
2018-10-17 10:17:25 +00:00
wxMenuItem * append_menu_item ( wxMenu * menu , int id , const wxString & string , const wxString & description ,
2019-05-13 12:27:51 +00:00
std : : function < void ( wxCommandEvent & event ) > cb , const wxBitmap & icon , wxEvtHandler * event_handler ,
std : : function < bool ( ) > const cb_condition , wxWindow * parent )
2018-10-17 10:17:25 +00:00
{
if ( id = = wxID_ANY )
id = wxNewId ( ) ;
2019-05-07 11:35:37 +00:00
auto * item = new wxMenuItem ( menu , id , string , description ) ;
if ( icon . IsOk ( ) ) {
2019-05-03 07:44:19 +00:00
item - > SetBitmap ( icon ) ;
}
2019-05-07 11:35:37 +00:00
menu - > Append ( item ) ;
2018-10-17 10:17:25 +00:00
2018-12-06 13:49:14 +00:00
# ifdef __WXMSW__
2018-12-07 16:50:48 +00:00
if ( event_handler ! = nullptr & & event_handler ! = menu )
2018-10-18 12:42:21 +00:00
event_handler - > Bind ( wxEVT_MENU , cb , id ) ;
else
2018-12-07 16:50:48 +00:00
# endif // __WXMSW__
2018-10-18 12:42:21 +00:00
menu - > Bind ( wxEVT_MENU , cb , id ) ;
2019-05-13 12:27:51 +00:00
if ( parent ) {
2019-12-18 14:54:01 +00:00
parent - > Bind ( wxEVT_UPDATE_UI , [ cb_condition , item , parent ] ( wxUpdateUIEvent & evt ) {
enable_menu_item ( evt , cb_condition , item , parent ) ; } , id ) ;
2019-05-13 12:27:51 +00:00
}
2018-10-18 12:42:21 +00:00
return item ;
}
2018-12-06 13:49:14 +00:00
wxMenuItem * append_menu_item ( wxMenu * menu , int id , const wxString & string , const wxString & description ,
2019-05-13 12:27:51 +00: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 13:49:14 +00:00
{
2019-05-03 07:44:19 +00:00
if ( id = = wxID_ANY )
id = wxNewId ( ) ;
2020-01-31 15:50:11 +00:00
const wxBitmap & bmp = ! icon . empty ( ) ? create_scaled_bitmap ( icon ) : wxNullBitmap ; // FIXME: pass window ptr
2019-05-13 12:27:51 +00:00
//#ifdef __WXMSW__
# ifndef __WXGTK__
2019-05-03 07:44:19 +00:00
if ( bmp . IsOk ( ) )
2019-05-07 11:35:37 +00:00
msw_menuitem_bitmaps [ id ] = icon ;
# endif /* __WXMSW__ */
2019-05-03 07:44:19 +00:00
2019-05-13 12:27:51 +00:00
return append_menu_item ( menu , id , string , description , cb , bmp , event_handler , cb_condition , parent ) ;
2018-12-06 13:49:14 +00:00
}
2019-05-13 12:27:51 +00: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 12:42:21 +00:00
{
if ( id = = wxID_ANY )
id = wxNewId ( ) ;
wxMenuItem * item = new wxMenuItem ( menu , id , string , description ) ;
2019-05-07 11:35:37 +00:00
if ( ! icon . empty ( ) ) {
2020-01-31 15:50:11 +00:00
item - > SetBitmap ( create_scaled_bitmap ( icon ) ) ; // FIXME: pass window ptr
2019-05-13 12:27:51 +00:00
//#ifdef __WXMSW__
# ifndef __WXGTK__
2019-05-07 11:35:37 +00:00
msw_menuitem_bitmaps [ id ] = icon ;
# endif /* __WXMSW__ */
}
2018-10-18 12:42:21 +00:00
item - > SetSubMenu ( sub_menu ) ;
menu - > Append ( item ) ;
2019-05-13 12:27:51 +00:00
if ( parent ) {
2019-12-18 14:54:01 +00:00
parent - > Bind ( wxEVT_UPDATE_UI , [ cb_condition , item , parent ] ( wxUpdateUIEvent & evt ) {
enable_menu_item ( evt , cb_condition , item , parent ) ; } , id ) ;
2019-05-13 12:27:51 +00:00
}
2018-10-17 10:17:25 +00:00
return item ;
}
2019-03-28 15:28:34 +00: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 08:12:13 +00:00
wxMenuItem * append_menu_check_item ( wxMenu * menu , int id , const wxString & string , const wxString & description ,
2020-02-04 13:42:26 +00:00
std : : function < void ( wxCommandEvent & event ) > cb , wxEvtHandler * event_handler ,
std : : function < bool ( ) > const enable_condition , std : : function < bool ( ) > const check_condition , wxWindow * parent )
2019-07-31 08:12:13 +00:00
{
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 ) ;
2020-02-04 13:42:26 +00:00
if ( parent )
parent - > Bind ( wxEVT_UPDATE_UI , [ enable_condition , check_condition ] ( wxUpdateUIEvent & evt )
{
evt . Enable ( enable_condition ( ) ) ;
evt . Check ( check_condition ( ) ) ;
} , id ) ;
2019-07-31 08:12:13 +00:00
return item ;
}
2018-02-20 13:25:40 +00:00
const unsigned int wxCheckListBoxComboPopup : : DefaultWidth = 200 ;
const unsigned int wxCheckListBoxComboPopup : : DefaultHeight = 200 ;
2018-02-20 13:44:00 +00:00
const unsigned int wxCheckListBoxComboPopup : : DefaultItemHeight = 18 ;
2018-02-02 11:38:35 +00:00
bool wxCheckListBoxComboPopup : : Create ( wxWindow * parent )
{
2018-02-06 11:43:25 +00:00
return wxCheckListBox : : Create ( parent , wxID_HIGHEST + 1 , wxPoint ( 0 , 0 ) ) ;
2018-02-02 11:38:35 +00: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 13:25:40 +00:00
// and sets height dinamically in dependence of contained items count
2018-02-02 11:38:35 +00:00
wxComboCtrl * cmb = GetComboCtrl ( ) ;
if ( cmb ! = nullptr )
{
wxSize size = GetComboCtrl ( ) - > GetSize ( ) ;
2018-02-20 13:25:40 +00:00
unsigned int count = GetCount ( ) ;
if ( count > 0 )
2018-02-20 13:44:00 +00:00
size . SetHeight ( count * DefaultItemHeight ) ;
2018-02-20 13:25:40 +00:00
else
size . SetHeight ( DefaultHeight ) ;
2018-02-02 11:38:35 +00:00
return size ;
}
else
2018-02-20 13:25:40 +00:00
return wxSize ( DefaultWidth , DefaultHeight ) ;
}
void wxCheckListBoxComboPopup : : OnKeyEvent ( wxKeyEvent & evt )
{
2018-02-22 07:59:47 +00: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 11:38:35 +00:00
}
void wxCheckListBoxComboPopup : : OnCheckListBox ( wxCommandEvent & evt )
{
// forwards the checklistbox event to the owner wxComboCtrl
2018-05-17 08:23:02 +00:00
if ( m_check_box_events_status = = OnCheckListBoxFunction : : FreeToProceed )
2018-02-02 11:38:35 +00:00
{
2018-05-17 08:23:02 +00:00
wxComboCtrl * cmb = GetComboCtrl ( ) ;
if ( cmb ! = nullptr ) {
wxCommandEvent event ( wxEVT_CHECKLISTBOX , cmb - > GetId ( ) ) ;
event . SetEventObject ( cmb ) ;
cmb - > ProcessWindowEvent ( event ) ;
}
2018-02-02 11:38:35 +00:00
}
2018-02-20 14:22:30 +00:00
evt . Skip ( ) ;
2018-05-17 08:23:02 +00: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 11:38:35 +00: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 08:23:02 +00:00
# ifndef _WIN32
if ( m_check_box_events_status = = OnCheckListBoxFunction : : RefuseToProceed )
# endif
Check ( ( unsigned int ) selId , ! IsChecked ( ( unsigned int ) selId ) ) ;
m_check_box_events_status = OnCheckListBoxFunction : : FreeToProceed ; // so the checkbox reacts to square-click the next time
2018-02-02 11:38:35 +00:00
2018-05-17 08:23:02 +00:00
SetSelection ( wxNOT_FOUND ) ;
2018-02-02 11:38:35 +00:00
wxCommandEvent event ( wxEVT_CHECKLISTBOX , GetId ( ) ) ;
event . SetInt ( selId ) ;
event . SetEventObject ( this ) ;
ProcessEvent ( event ) ;
}
}
2018-04-06 11:37:00 +00:00
2020-01-31 15:50:11 +00:00
namespace Slic3r {
namespace GUI {
// *** PresetBitmapComboBox ***
/* For PresetBitmapComboBox we use bitmaps that are created from images that are already scaled appropriately for Retina
* ( Contrary to the intuition , the ` scale ` argument for Bitmap ' s constructor doesn ' t mean
* " please scale this to such and such " but rather
* " the wxImage is already sized for backing scale such and such " . )
* Unfortunately , the constructor changes the size of wxBitmap too .
* Thus We need to use unscaled size value for bitmaps that we use
* to avoid scaled size of control items .
* For this purpose control drawing methods and
* control size calculation methods ( virtual ) are overridden .
* */
PresetBitmapComboBox : : PresetBitmapComboBox ( wxWindow * parent , const wxSize & size ) :
wxBitmapComboBox ( parent , wxID_ANY , wxEmptyString , wxDefaultPosition , size , 0 , nullptr , wxCB_READONLY )
{ }
# ifdef __APPLE__
bool PresetBitmapComboBox : : OnAddBitmap ( const wxBitmap & bitmap )
{
if ( bitmap . IsOk ( ) )
{
// we should use scaled! size values of bitmap
int width = ( int ) bitmap . GetScaledWidth ( ) ;
int height = ( int ) bitmap . GetScaledHeight ( ) ;
if ( m_usedImgSize . x < 0 )
{
// If size not yet determined, get it from this image.
m_usedImgSize . x = width ;
m_usedImgSize . y = height ;
// Adjust control size to vertically fit the bitmap
wxWindow * ctrl = GetControl ( ) ;
ctrl - > InvalidateBestSize ( ) ;
wxSize newSz = ctrl - > GetBestSize ( ) ;
wxSize sz = ctrl - > GetSize ( ) ;
if ( newSz . y > sz . y )
ctrl - > SetSize ( sz . x , newSz . y ) ;
else
DetermineIndent ( ) ;
}
wxCHECK_MSG ( width = = m_usedImgSize . x & & height = = m_usedImgSize . y ,
false ,
" you can only add images of same size " ) ;
return true ;
}
return false ;
}
void PresetBitmapComboBox : : OnDrawItem ( wxDC & dc ,
const wxRect & rect ,
int item ,
int flags ) const
{
const wxBitmap & bmp = * ( wxBitmap * ) m_bitmaps [ item ] ;
if ( bmp . IsOk ( ) )
{
// we should use scaled! size values of bitmap
wxCoord w = bmp . GetScaledWidth ( ) ;
wxCoord h = bmp . GetScaledHeight ( ) ;
const int imgSpacingLeft = 4 ;
// Draw the image centered
dc . DrawBitmap ( bmp ,
rect . x + ( m_usedImgSize . x - w ) / 2 + imgSpacingLeft ,
rect . y + ( rect . height - h ) / 2 ,
true ) ;
}
wxString text = GetString ( item ) ;
if ( ! text . empty ( ) )
dc . DrawText ( text ,
rect . x + m_imgAreaWidth + 1 ,
rect . y + ( rect . height - dc . GetCharHeight ( ) ) / 2 ) ;
}
# endif
}
}
2018-04-06 11:37:00 +00: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 14:50:17 +00:00
return wxDataViewTreeCtrl : : Create ( parent , wxID_ANY /*HIGHEST + 1*/ , wxPoint ( 0 , 0 ) , wxDefaultSize /*wxSize(270, -1)*/ , wxDV_NO_HEADER ) ;
2018-04-06 11:37:00 +00:00
}
2018-04-09 10:41:25 +00:00
/*
2018-04-06 11:37:00 +00: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 13:42:52 +00: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 11:37:00 +00:00
}
2018-04-09 10:41:25 +00:00
*/
2018-04-06 11:37:00 +00: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 16:32:20 +00:00
2019-04-26 08:52:38 +00: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 13:06:44 +00: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 19:35:53 +00: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 13:05:17 +00:00
if ( win )
{
2019-05-06 16:28:23 +00:00
wxTopLevelWindow * toplevel = Slic3r : : GUI : : find_toplevel_parent ( win ) ;
Slic3r : : GUI : : DPIDialog * dlg = dynamic_cast < Slic3r : : GUI : : DPIDialog * > ( toplevel ) ;
2019-04-17 19:35:53 +00:00
if ( dlg )
2019-04-18 13:05:17 +00:00
return dlg - > em_unit ( ) ;
2019-05-06 16:28:23 +00:00
Slic3r : : GUI : : DPIFrame * frame = dynamic_cast < Slic3r : : GUI : : DPIFrame * > ( toplevel ) ;
if ( frame )
return frame - > em_unit ( ) ;
2019-04-17 19:35:53 +00:00
}
return Slic3r : : GUI : : wxGetApp ( ) . em_unit ( ) ;
}
2018-07-04 06:54:30 +00:00
2020-02-10 19:05:20 +00:00
int mode_icon_px_size ( )
{
# ifdef __APPLE__
return 10 ;
# else
return 12 ;
# endif
}
2020-01-31 15:50:11 +00:00
// win is used to get a correct em_unit value
// It's important for bitmaps of dialogs.
// if win == nullptr, em_unit value of MainFrame will be used
wxBitmap create_scaled_bitmap ( const std : : string & bmp_name_in ,
wxWindow * win /* = nullptr*/ ,
const int px_cnt /* = 16*/ ,
const bool grayscale /* = false*/ )
2019-02-06 14:29:13 +00:00
{
2019-04-08 07:37:23 +00:00
static Slic3r : : GUI : : BitmapCache cache ;
2019-04-05 09:18:13 +00:00
2020-01-28 15:15:43 +00:00
unsigned int width = 0 ;
unsigned int height = ( unsigned int ) ( em_unit ( win ) * px_cnt * 0.1f + 0.5f ) ;
2019-04-08 07:37:23 +00:00
2020-01-02 12:41:49 +00:00
std : : string bmp_name = bmp_name_in ;
boost : : replace_last ( bmp_name , " .png " , " " ) ;
2019-12-18 14:54:01 +00:00
2019-04-05 16:53:02 +00:00
// Try loading an SVG first, then PNG if SVG is not found:
2020-01-31 15:50:11 +00:00
wxBitmap * bmp = cache . load_svg ( bmp_name , width , height , grayscale , Slic3r : : GUI : : wxGetApp ( ) . dark_mode ( ) ) ;
2019-04-09 12:18:03 +00:00
if ( bmp = = nullptr ) {
2019-05-13 15:57:31 +00:00
bmp = cache . load_png ( bmp_name , width , height , grayscale ) ;
2019-04-05 16:53:02 +00:00
}
2019-04-09 12:18:03 +00:00
if ( bmp = = nullptr ) {
2019-04-05 16:53:02 +00:00
// Neither SVG nor PNG has been found, raise error
throw std : : runtime_error ( " Could not load bitmap: " + bmp_name ) ;
}
2019-04-08 07:37:23 +00:00
2019-04-04 07:20:11 +00:00
return * bmp ;
2019-02-06 14:29:13 +00:00
}
2019-10-24 08:38:36 +00:00
std : : vector < wxBitmap * > get_extruder_color_icons ( bool thin_icon /* = false*/ )
2019-10-01 16:19:28 +00:00
{
2020-02-02 21:22:40 +00:00
static Slic3r : : GUI : : BitmapCache bmp_cache ;
2019-10-01 16:19:28 +00: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 09:05:59 +00:00
if ( colors . empty ( ) )
2019-10-07 10:36:16 +00:00
return bmps ;
2019-10-01 16:19:28 +00: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 ( ) ;
2020-02-17 10:26:40 +00:00
const int icon_width = lround ( ( thin_icon ? 1.6 : 3.2 ) * em ) ;
2019-10-01 16:19:28 +00:00
const int icon_height = lround ( 1.6 * em ) ;
for ( const std : : string & color : colors )
{
2019-10-24 08:38:36 +00:00
std : : string bitmap_key = color + " -h " + std : : to_string ( icon_height ) + " -w " + std : : to_string ( icon_width ) ;
2020-02-02 21:22:40 +00:00
wxBitmap * bitmap = bmp_cache . find ( bitmap_key ) ;
2019-10-01 16:19:28 +00:00
if ( bitmap = = nullptr ) {
// Paint the color icon.
2020-02-02 21:22:40 +00:00
Slic3r : : GUI : : BitmapCache : : parse_color ( color , rgb ) ;
2020-01-31 15:50:11 +00:00
// there is no neede to scale created solid bitmap
2020-02-02 21:22:40 +00:00
bitmap = bmp_cache . insert ( bitmap_key , bmp_cache . mksolid ( icon_width , icon_height , rgb , true ) ) ;
2019-10-01 16:19:28 +00:00
}
bmps . emplace_back ( bitmap ) ;
}
return bmps ;
}
2019-10-18 10:35:35 +00:00
void apply_extruder_selector ( wxBitmapComboBox * * ctrl ,
wxWindow * parent ,
const std : : string & first_item /* = ""*/ ,
wxPoint pos /* = wxDefaultPosition*/ ,
2019-10-24 08:38:36 +00:00
wxSize size /* = wxDefaultSize*/ ,
bool use_thin_icon /* = false*/ )
2019-10-18 10:35:35 +00:00
{
2019-10-24 08:38:36 +00:00
std : : vector < wxBitmap * > icons = get_extruder_color_icons ( use_thin_icon ) ;
2019-10-18 10:35:35 +00: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 15:44:17 +00:00
if ( first_item . empty ( ) )
( * ctrl ) - > Hide ( ) ; // to avoid unwanted rendering before layout (ExtruderSequenceDialog)
2019-10-18 10:35:35 +00:00
2019-11-08 10:24:57 +00: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 10:35:35 +00:00
int i = 0 ;
2019-10-24 08:38:36 +00:00
wxString str = _ ( L ( " Extruder " ) ) ;
2019-10-18 10:35:35 +00:00
for ( wxBitmap * bmp : icons ) {
if ( i = = 0 ) {
if ( ! first_item . empty ( ) )
( * ctrl ) - > Append ( _ ( first_item ) , * bmp ) ;
+ + i ;
}
2020-03-02 11:46:40 +00:00
( * ctrl ) - > Append ( use_full_item_name
2020-03-04 08:24:13 +00:00
? Slic3r : : GUI : : from_u8 ( ( boost : : format ( " %1% %2% " ) % str % i ) . str ( ) )
2020-03-02 11:46:40 +00:00
: wxString : : Format ( " %d " , i ) , * bmp ) ;
2019-10-18 10:35:35 +00:00
+ + i ;
}
( * ctrl ) - > SetSelection ( 0 ) ;
}
2018-08-28 13:51:53 +00:00
// ----------------------------------------------------------------------------
2019-04-24 23:45:00 +00:00
// LockButton
2018-08-28 13:51:53 +00:00
// ----------------------------------------------------------------------------
2019-04-24 23:45:00 +00: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 13:51:53 +00:00
{
2019-07-31 15:14:32 +00: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 13:51:53 +00:00
# ifdef __WXMSW__
SetBackgroundColour ( wxSystemSettings : : GetColour ( wxSYS_COLOUR_WINDOW ) ) ;
# endif // __WXMSW__
2019-07-31 15:14:32 +00:00
SetBitmap ( m_bmp_lock_open . bmp ( ) ) ;
SetBitmapDisabled ( m_bmp_lock_open . bmp ( ) ) ;
SetBitmapHover ( m_bmp_lock_closed_f . bmp ( ) ) ;
2018-08-28 13:51:53 +00:00
//button events
2019-07-31 15:14:32 +00:00
Bind ( wxEVT_BUTTON , & LockButton : : OnButton , this ) ;
2018-08-28 13:51:53 +00:00
}
2019-04-24 23:45:00 +00:00
void LockButton : : OnButton ( wxCommandEvent & event )
2018-08-28 13:51:53 +00:00
{
2019-06-20 10:56:23 +00:00
if ( m_disabled )
return ;
2018-08-28 13:51:53 +00:00
m_is_pushed = ! m_is_pushed ;
2019-07-31 15:14:32 +00:00
update_button_bitmaps ( ) ;
2018-08-28 13:51:53 +00:00
event . Skip ( ) ;
}
2019-04-24 23:45:00 +00:00
void LockButton : : SetLock ( bool lock )
2019-01-09 07:48:25 +00:00
{
m_is_pushed = lock ;
2019-07-31 15:14:32 +00:00
update_button_bitmaps ( ) ;
2019-01-09 07:48:25 +00:00
}
2019-04-24 23:45:00 +00:00
void LockButton : : msw_rescale ( )
2019-04-16 08:05:45 +00:00
{
2019-07-31 15:14:32 +00: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 13:10:36 +00:00
update_button_bitmaps ( ) ;
2019-04-16 08:05:45 +00:00
}
2019-07-31 15:14:32 +00:00
void LockButton : : update_button_bitmaps ( )
2018-08-28 13:51:53 +00:00
{
2019-07-31 15:14:32 +00: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 13:51:53 +00:00
Refresh ( ) ;
Update ( ) ;
}
2019-01-10 10:05:58 +00:00
// ----------------------------------------------------------------------------
2019-04-24 23:45:00 +00:00
// ModeButton
2019-01-10 10:05:58 +00:00
// ----------------------------------------------------------------------------
2019-04-24 23:45:00 +00: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 14:23:32 +00:00
ScalableButton ( parent , id , icon_name , mode , size , pos , wxBU_EXACTFIT )
2020-02-10 11:46:07 +00:00
{
Init ( mode ) ;
}
ModeButton : : ModeButton ( wxWindow * parent ,
const wxString & mode /* = wxEmptyString*/ ,
const std : : string & icon_name /* = ""*/ ,
int px_cnt /* = 16*/ ) :
ScalableButton ( parent , wxID_ANY , ScalableBitmap ( parent , icon_name , px_cnt ) , mode , wxBU_EXACTFIT )
{
Init ( mode ) ;
}
void ModeButton : : Init ( const wxString & mode )
2019-01-10 10:05:58 +00:00
{
2020-03-02 11:46:40 +00:00
std : : string mode_str = std : : string ( mode . ToUTF8 ( ) ) ;
2020-03-04 08:24:13 +00:00
m_tt_focused = Slic3r : : GUI : : from_u8 ( ( boost : : format ( _utf8 ( L ( " Switch to the %s mode " ) ) ) % mode_str ) . str ( ) ) ;
m_tt_selected = Slic3r : : GUI : : from_u8 ( ( boost : : format ( _utf8 ( L ( " Current mode is %s " ) ) ) % mode_str ) . str ( ) ) ;
2019-02-26 09:50:00 +00:00
2019-07-25 14:23:32 +00:00
SetBitmapMargins ( 3 , 0 ) ;
2019-01-10 10:05:58 +00:00
//button events
2019-04-24 23:45:00 +00:00
Bind ( wxEVT_BUTTON , & ModeButton : : OnButton , this ) ;
Bind ( wxEVT_ENTER_WINDOW , & ModeButton : : OnEnterBtn , this ) ;
Bind ( wxEVT_LEAVE_WINDOW , & ModeButton : : OnLeaveBtn , this ) ;
2019-01-10 10:05:58 +00:00
}
2019-04-24 23:45:00 +00:00
void ModeButton : : OnButton ( wxCommandEvent & event )
2019-01-10 10:05:58 +00:00
{
m_is_selected = true ;
focus_button ( m_is_selected ) ;
event . Skip ( ) ;
}
2019-04-24 23:45:00 +00:00
void ModeButton : : SetState ( const bool state )
2019-01-10 10:05:58 +00:00
{
m_is_selected = state ;
focus_button ( m_is_selected ) ;
2019-02-26 09:50:00 +00:00
SetToolTip ( state ? m_tt_selected : m_tt_focused ) ;
2019-01-10 10:05:58 +00:00
}
2019-04-24 23:45:00 +00:00
void ModeButton : : focus_button ( const bool focus )
2019-01-10 10:05:58 +00:00
{
2019-04-29 07:43:42 +00:00
const wxFont & new_font = focus ?
Slic3r : : GUI : : wxGetApp ( ) . bold_font ( ) :
Slic3r : : GUI : : wxGetApp ( ) . normal_font ( ) ;
2019-04-10 07:56:32 +00:00
2019-01-10 10:05:58 +00:00
SetFont ( new_font ) ;
2019-07-25 14:23:32 +00:00
SetForegroundColour ( wxSystemSettings : : GetColour ( focus ? wxSYS_COLOUR_BTNTEXT : wxSYS_COLOUR_BTNSHADOW ) ) ;
2019-01-10 10:05:58 +00:00
Refresh ( ) ;
Update ( ) ;
}
// ----------------------------------------------------------------------------
2019-04-24 23:45:00 +00:00
// ModeSizer
2019-01-10 10:05:58 +00:00
// ----------------------------------------------------------------------------
2019-07-25 14:23:32 +00:00
ModeSizer : : ModeSizer ( wxWindow * parent , int hgap /* = 0*/ ) :
2019-02-11 14:36:05 +00:00
wxFlexGridSizer ( 3 , 0 , hgap )
2019-01-10 10:05:58 +00:00
{
SetFlexibleDirection ( wxHORIZONTAL ) ;
2019-04-13 21:46:52 +00:00
std : : vector < std : : pair < wxString , std : : string > > buttons = {
2020-02-07 17:49:39 +00:00
{ _ ( L ( " Simple " ) ) , " mode_simple " } ,
{ _ ( L ( " Advanced " ) ) , " mode_advanced " } ,
{ _ ( L ( " Expert " ) ) , " mode_expert " } ,
2019-02-11 13:14:35 +00:00
} ;
2019-02-06 14:29:13 +00:00
2019-05-21 12:06:43 +00:00
auto modebtnfn = [ ] ( wxCommandEvent & event , int mode_id ) {
Slic3r : : GUI : : wxGetApp ( ) . save_mode ( mode_id ) ;
event . Skip ( ) ;
} ;
2019-04-24 23:45:00 +00:00
m_mode_btns . reserve ( 3 ) ;
2019-02-11 13:14:35 +00:00
for ( const auto & button : buttons ) {
2020-02-10 19:05:20 +00:00
m_mode_btns . push_back ( new ModeButton ( parent , button . first , button . second , mode_icon_px_size ( ) ) ) ;
2019-07-25 14:23:32 +00:00
2019-05-27 11:07:37 +00:00
m_mode_btns . back ( ) - > Bind ( wxEVT_BUTTON , std : : bind ( modebtnfn , std : : placeholders : : _1 , int ( m_mode_btns . size ( ) - 1 ) ) ) ;
2019-05-21 12:06:43 +00:00
Add ( m_mode_btns . back ( ) ) ;
2019-02-11 13:14:35 +00:00
}
2019-01-10 10:05:58 +00:00
}
2019-04-24 23:45:00 +00:00
void ModeSizer : : SetMode ( const int mode )
2019-01-10 10:05:58 +00:00
{
2019-05-21 12:06:43 +00:00
for ( size_t m = 0 ; m < m_mode_btns . size ( ) ; m + + )
m_mode_btns [ m ] - > SetState ( int ( m ) = = mode ) ;
2019-01-10 10:05:58 +00:00
}
2019-01-25 12:16:32 +00:00
2019-04-24 23:45:00 +00:00
void ModeSizer : : msw_rescale ( )
2019-04-13 21:46:52 +00:00
{
2019-05-21 12:06:43 +00:00
for ( size_t m = 0 ; m < m_mode_btns . size ( ) ; m + + )
2019-04-24 23:45:00 +00:00
m_mode_btns [ m ] - > msw_rescale ( ) ;
2019-04-13 21:46:52 +00:00
}
2019-01-25 12:16:32 +00:00
// ----------------------------------------------------------------------------
2019-04-24 23:45:00 +00:00
// MenuWithSeparators
2019-01-25 12:16:32 +00:00
// ----------------------------------------------------------------------------
2019-04-24 23:45:00 +00:00
void MenuWithSeparators : : DestroySeparators ( )
2019-01-25 12:16:32 +00: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-24 23:45:00 +00:00
void MenuWithSeparators : : SetFirstSeparator ( )
{
m_separator_frst = this - > AppendSeparator ( ) ;
}
void MenuWithSeparators : : SetSecondSeparator ( )
{
m_separator_scnd = this - > AppendSeparator ( ) ;
}
2019-01-25 12:16:32 +00:00
2019-04-13 21:46:52 +00:00
// ----------------------------------------------------------------------------
// PrusaBitmap
// ----------------------------------------------------------------------------
2019-04-24 23:45:00 +00:00
ScalableBitmap : : ScalableBitmap ( wxWindow * parent ,
const std : : string & icon_name /* = ""*/ ,
2020-01-28 15:15:43 +00:00
const int px_cnt /* = 16*/ ) :
2019-04-24 23:45:00 +00:00
m_parent ( parent ) , m_icon_name ( icon_name ) ,
2020-01-28 15:15:43 +00:00
m_px_cnt ( px_cnt )
2019-04-13 21:46:52 +00:00
{
2020-01-31 15:50:11 +00:00
m_bmp = create_scaled_bitmap ( icon_name , parent , px_cnt ) ;
}
wxSize ScalableBitmap : : GetBmpSize ( ) const
{
# ifdef __APPLE__
return m_bmp . GetScaledSize ( ) ;
# else
return m_bmp . GetSize ( ) ;
# endif
}
int ScalableBitmap : : GetBmpWidth ( ) const
{
# ifdef __APPLE__
return m_bmp . GetScaledWidth ( ) ;
# else
return m_bmp . GetWidth ( ) ;
# endif
}
int ScalableBitmap : : GetBmpHeight ( ) const
{
# ifdef __APPLE__
return m_bmp . GetScaledHeight ( ) ;
# else
return m_bmp . GetHeight ( ) ;
# endif
2019-04-13 21:46:52 +00:00
}
2019-04-24 23:45:00 +00:00
void ScalableBitmap : : msw_rescale ( )
2019-04-13 21:46:52 +00:00
{
2020-01-31 15:50:11 +00:00
m_bmp = create_scaled_bitmap ( m_icon_name , m_parent , m_px_cnt ) ;
2019-04-13 21:46:52 +00:00
}
// ----------------------------------------------------------------------------
// PrusaButton
// ----------------------------------------------------------------------------
2019-04-24 23:45:00 +00: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 21:46:52 +00: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 17:11:11 +00:00
2020-01-31 15:50:11 +00:00
SetBitmap ( create_scaled_bitmap ( icon_name , parent ) ) ;
2019-08-01 09:35:43 +00:00
if ( size ! = wxDefaultSize )
{
const int em = em_unit ( parent ) ;
m_width = size . x / em ;
m_height = size . y / em ;
}
2019-04-13 21:46:52 +00:00
}
2019-04-24 23:45:00 +00:00
ScalableButton : : ScalableButton ( wxWindow * parent ,
wxWindowID id ,
const ScalableBitmap & bitmap ,
const wxString & label /*= wxEmptyString*/ ,
long style /*= wxBU_EXACTFIT | wxNO_BORDER*/ ) :
2019-12-13 12:23:55 +00:00
m_parent ( parent ) ,
2019-04-13 21:46:52 +00:00
m_current_icon_name ( bitmap . name ( ) ) ,
2020-01-28 15:15:43 +00:00
m_px_cnt ( bitmap . px_cnt ( ) )
2019-04-13 21:46:52 +00: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 08:05:45 +00:00
SetBitmap ( bitmap . bmp ( ) ) ;
2019-04-13 21:46:52 +00:00
}
2019-04-24 23:45:00 +00:00
void ScalableButton : : SetBitmap_ ( const ScalableBitmap & bmp )
2019-04-13 21:46:52 +00:00
{
SetBitmap ( bmp . bmp ( ) ) ;
m_current_icon_name = bmp . name ( ) ;
}
2019-08-01 09:35:43 +00:00
void ScalableButton : : SetBitmapDisabled_ ( const ScalableBitmap & bmp )
{
SetBitmapDisabled ( bmp . bmp ( ) ) ;
m_disabled_icon_name = bmp . name ( ) ;
}
2019-12-13 16:56:04 +00:00
int ScalableButton : : GetBitmapHeight ( )
{
2020-01-31 15:50:11 +00:00
# ifdef __APPLE__
return GetBitmap ( ) . GetScaledHeight ( ) ;
# else
return GetBitmap ( ) . GetHeight ( ) ;
# endif
2019-12-13 16:56:04 +00:00
}
2019-04-24 23:45:00 +00:00
void ScalableButton : : msw_rescale ( )
2019-04-13 21:46:52 +00:00
{
2020-01-31 15:50:11 +00:00
SetBitmap ( create_scaled_bitmap ( m_current_icon_name , m_parent , m_px_cnt ) ) ;
2019-08-01 09:35:43 +00:00
if ( ! m_disabled_icon_name . empty ( ) )
2020-01-31 15:50:11 +00:00
SetBitmapDisabled ( create_scaled_bitmap ( m_disabled_icon_name , m_parent , m_px_cnt ) ) ;
2019-04-13 21:46:52 +00:00
2019-08-01 09:35:43 +00: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 21:46:52 +00:00
}
2018-08-29 09:21:22 +00:00
2018-08-28 13:51:53 +00:00
2018-08-29 09:21:22 +00:00