diff --git a/src/slic3r/GUI/BitmapCache.cpp b/src/slic3r/GUI/BitmapCache.cpp index 8d65ae90b..9668278bb 100644 --- a/src/slic3r/GUI/BitmapCache.cpp +++ b/src/slic3r/GUI/BitmapCache.cpp @@ -1,6 +1,7 @@ #include "BitmapCache.hpp" #include "libslic3r/Utils.hpp" +#include "../Utils/MacDarkMode.hpp" #include #if ! defined(WIN32) && ! defined(__APPLE__) @@ -20,6 +21,16 @@ namespace Slic3r { namespace GUI { +BitmapCache::BitmapCache() +{ +#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. + m_scale = mac_max_scaling_factor(); +#endif +} + void BitmapCache::clear() { for (std::pair &bitmap : m_map) @@ -49,7 +60,7 @@ static wxBitmap wxImage_to_wxBitmap_with_alpha(wxImage &&image, float scale = 1. #endif } -wxBitmap* BitmapCache::insert(const std::string &bitmap_key, size_t width, size_t height, float scale/* = 1.0f*/) +wxBitmap* BitmapCache::insert(const std::string &bitmap_key, size_t width, size_t height) { wxBitmap *bitmap = nullptr; auto it = m_map.find(bitmap_key); @@ -61,7 +72,7 @@ wxBitmap* BitmapCache::insert(const std::string &bitmap_key, size_t width, size_ // So, We need to let the Mac OS wxBitmap implementation // know that the image may already be scaled appropriately for Retina, // and thereby that it's not supposed to upscale it. - bitmap->CreateScaled(width, height, -1, scale); + bitmap->CreateScaled(width, height, -1, m_scale); #endif m_map[bitmap_key] = bitmap; } else { @@ -103,13 +114,18 @@ wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap &bmp return this->insert(bitmap_key, bmps, bmps + 3); } -wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap *begin, const wxBitmap *end, float scale/* = 1.0f*/) +wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap *begin, const wxBitmap *end) { size_t width = 0; size_t height = 0; for (const wxBitmap *bmp = begin; bmp != end; ++ bmp) { +#ifdef __APPLE__ + width += bmp->GetScaledWidth(); + height = std::max(height, bmp->GetScaledHeight()); +#else width += bmp->GetWidth(); height = std::max(height, bmp->GetHeight()); +#endif } #ifdef BROKEN_ALPHA @@ -166,13 +182,7 @@ wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap *beg #else -#ifdef __APPLE__ - // Note, for this moment width and height are scaled, so divide them by scale to avoid one more multiplication inside CreateScaled() - width *= 1.0 / scale; - height *= 1.0 / scale; -#endif - - wxBitmap *bitmap = this->insert(bitmap_key, width, height, scale); + wxBitmap *bitmap = this->insert(bitmap_key, width, height); wxMemoryDC memDC; memDC.SelectObject(*bitmap); memDC.SetBackground(*wxTRANSPARENT_BRUSH); @@ -181,8 +191,12 @@ wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap *beg for (const wxBitmap *bmp = begin; bmp != end; ++ bmp) { if (bmp->GetWidth() > 0) memDC.DrawBitmap(*bmp, x, 0, true); +#ifdef __APPLE__ // we should "move" with step equal to non-scaled width - x += bmp->GetWidth()/scale; + x += bmp->GetScaledWidth(); +#else + x += bmp->GetWidth(); +#endif } memDC.SelectObject(wxNullBitmap); return bitmap; @@ -190,7 +204,7 @@ wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap *beg #endif } -wxBitmap* BitmapCache::insert_raw_rgba(const std::string &bitmap_key, unsigned width, unsigned height, const unsigned char *raw_data, float scale /* = 1.0f */, const bool grayscale/* = false*/) +wxBitmap* BitmapCache::insert_raw_rgba(const std::string &bitmap_key, unsigned width, unsigned height, const unsigned char *raw_data, const bool grayscale/* = false*/) { wxImage image(width, height); image.InitAlpha(); @@ -207,7 +221,7 @@ wxBitmap* BitmapCache::insert_raw_rgba(const std::string &bitmap_key, unsigned w if (grayscale) image = image.ConvertToGreyscale(m_gs, m_gs, m_gs); - return this->insert(bitmap_key, wxImage_to_wxBitmap_with_alpha(std::move(image), scale)); + return this->insert(bitmap_key, wxImage_to_wxBitmap_with_alpha(std::move(image), m_scale)); } wxBitmap* BitmapCache::load_png(const std::string &bitmap_name, unsigned width, unsigned height, @@ -242,12 +256,12 @@ wxBitmap* BitmapCache::load_png(const std::string &bitmap_name, unsigned width, } wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned target_width, unsigned target_height, - float scale /* = 1.0f */, const bool grayscale/* = false*/, const bool dark_mode/* = false*/) + const bool grayscale/* = false*/, const bool dark_mode/* = false*/) { std::string bitmap_key = bitmap_name + ( target_height !=0 ? "-h" + std::to_string(target_height) : "-w" + std::to_string(target_width)) - + (scale != 1.0f ? "-s" + std::to_string(scale) : "") + + (m_scale != 1.0f ? "-s" + std::to_string(m_scale) : "") + (grayscale ? "-gs" : ""); /* For the Dark mode of any platform, we should draw icons in respect to OS background @@ -287,7 +301,7 @@ wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned target_ if (image == nullptr) return nullptr; - target_height != 0 ? target_height *= scale : target_width *= scale; + target_height != 0 ? target_height *= m_scale : target_width *= m_scale; float svg_scale = target_height != 0 ? (float)target_height / image->height : target_width != 0 ? @@ -312,11 +326,16 @@ wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned target_ ::nsvgDeleteRasterizer(rast); ::nsvgDelete(image); - return this->insert_raw_rgba(bitmap_key, width, height, data.data(), scale, grayscale); + return this->insert_raw_rgba(bitmap_key, width, height, data.data(), grayscale); } -wxBitmap BitmapCache::mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency) +//we make scaled solid bitmaps only for the cases, when its will be used with scaled SVG icon in one output bitmap +wxBitmap BitmapCache::mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency, bool suppress_scaling/* = false*/) { + double scale = suppress_scaling ? 1.0f : m_scale; + width *= scale; + height *= scale; + wxImage image(width, height); image.InitAlpha(); unsigned char* imgdata = image.GetData(); @@ -327,7 +346,7 @@ wxBitmap BitmapCache::mksolid(size_t width, size_t height, unsigned char r, unsi *imgdata ++ = b; *imgalpha ++ = transparency; } - return wxImage_to_wxBitmap_with_alpha(std::move(image)); + return wxImage_to_wxBitmap_with_alpha(std::move(image), scale); } } // namespace GUI diff --git a/src/slic3r/GUI/BitmapCache.hpp b/src/slic3r/GUI/BitmapCache.hpp index 49d45c66a..73e4a31dc 100644 --- a/src/slic3r/GUI/BitmapCache.hpp +++ b/src/slic3r/GUI/BitmapCache.hpp @@ -16,33 +16,35 @@ namespace Slic3r { namespace GUI { class BitmapCache { public: - BitmapCache() {} + BitmapCache(); ~BitmapCache() { clear(); } void clear(); + double scale() { return m_scale; } wxBitmap* find(const std::string &name) { auto it = m_map.find(name); return (it == m_map.end()) ? nullptr : it->second; } const wxBitmap* find(const std::string &name) const { return const_cast(this)->find(name); } - wxBitmap* insert(const std::string &name, size_t width, size_t height, float scale = 1.0f); + wxBitmap* insert(const std::string &name, size_t width, size_t height); wxBitmap* insert(const std::string &name, const wxBitmap &bmp); wxBitmap* insert(const std::string &name, const wxBitmap &bmp, const wxBitmap &bmp2); wxBitmap* insert(const std::string &name, const wxBitmap &bmp, const wxBitmap &bmp2, const wxBitmap &bmp3); - wxBitmap* insert(const std::string &name, const std::vector &bmps, float scale = 1.0f) { return this->insert(name, &bmps.front(), &bmps.front() + bmps.size(), scale); } - wxBitmap* insert(const std::string &name, const wxBitmap *begin, const wxBitmap *end, float scale = 1.0f); - wxBitmap* insert_raw_rgba(const std::string &bitmap_key, unsigned width, unsigned height, const unsigned char *raw_data, float scale = 1.0f, const bool grayscale = false); + wxBitmap* insert(const std::string &name, const std::vector &bmps) { return this->insert(name, &bmps.front(), &bmps.front() + bmps.size()); } + wxBitmap* insert(const std::string &name, const wxBitmap *begin, const wxBitmap *end); + wxBitmap* insert_raw_rgba(const std::string &bitmap_key, unsigned width, unsigned height, const unsigned char *raw_data, const bool grayscale = false); // Load png from resources/icons. bitmap_key is given without the .png suffix. Bitmap will be rescaled to provided height/width if nonzero. wxBitmap* load_png(const std::string &bitmap_key, unsigned width = 0, unsigned height = 0, const bool grayscale = false); // Load svg from resources/icons. bitmap_key is given without the .svg suffix. SVG will be rasterized to provided height/width. - wxBitmap* load_svg(const std::string &bitmap_key, unsigned width = 0, unsigned height = 0, float scale = 1.0f, const bool grayscale = false, const bool dark_mode = false); + wxBitmap* load_svg(const std::string &bitmap_key, unsigned width = 0, unsigned height = 0, const bool grayscale = false, const bool dark_mode = false); - static wxBitmap mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency); - static wxBitmap mksolid(size_t width, size_t height, const unsigned char rgb[3]) { return mksolid(width, height, rgb[0], rgb[1], rgb[2], wxALPHA_OPAQUE); } - static wxBitmap mkclear(size_t width, size_t height) { return mksolid(width, height, 0, 0, 0, wxALPHA_TRANSPARENT); } + /*static */wxBitmap mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency, bool suppress_scaling = false); + /*static */wxBitmap mksolid(size_t width, size_t height, const unsigned char rgb[3], bool suppress_scaling = false) { return mksolid(width, height, rgb[0], rgb[1], rgb[2], wxALPHA_OPAQUE); } + /*static */wxBitmap mkclear(size_t width, size_t height) { return mksolid(width, height, 0, 0, 0, wxALPHA_TRANSPARENT); } private: std::map m_map; - double m_gs = 0.2; // value, used for image.ConvertToGreyscale(m_gs, m_gs, m_gs) + double m_gs = 0.2; // value, used for image.ConvertToGreyscale(m_gs, m_gs, m_gs) + double m_scale = 1.0; // value, used for correct scaling of SVG icons on Retina display }; } // GUI diff --git a/src/slic3r/GUI/DoubleSlider.cpp b/src/slic3r/GUI/DoubleSlider.cpp index 47bdec1fb..4d29e13a7 100644 --- a/src/slic3r/GUI/DoubleSlider.cpp +++ b/src/slic3r/GUI/DoubleSlider.cpp @@ -52,28 +52,26 @@ Control::Control( wxWindow *parent, if (!is_osx) SetDoubleBuffered(true);// SetDoubleBuffered exists on Win and Linux/GTK, but is missing on OSX - const float scale_factor = get_svg_scale_factor(this); - m_bmp_thumb_higher = (style == wxSL_HORIZONTAL ? ScalableBitmap(this, "right_half_circle.png") : ScalableBitmap(this, "thumb_up")); m_bmp_thumb_lower = (style == wxSL_HORIZONTAL ? ScalableBitmap(this, "left_half_circle.png" ) : ScalableBitmap(this, "thumb_down")); - m_thumb_size = m_bmp_thumb_lower.bmp().GetSize()*(1.0/scale_factor); + m_thumb_size = m_bmp_thumb_lower.GetBmpSize(); m_bmp_add_tick_on = ScalableBitmap(this, "colorchange_add"); m_bmp_add_tick_off = ScalableBitmap(this, "colorchange_add_f"); m_bmp_del_tick_on = ScalableBitmap(this, "colorchange_del"); m_bmp_del_tick_off = ScalableBitmap(this, "colorchange_del_f"); - m_tick_icon_dim = int((float)m_bmp_add_tick_on.bmp().GetSize().x / scale_factor); + m_tick_icon_dim = m_bmp_add_tick_on.GetBmpWidth(); m_bmp_one_layer_lock_on = ScalableBitmap(this, "lock_closed"); m_bmp_one_layer_lock_off = ScalableBitmap(this, "lock_closed_f"); m_bmp_one_layer_unlock_on = ScalableBitmap(this, "lock_open"); m_bmp_one_layer_unlock_off = ScalableBitmap(this, "lock_open_f"); - m_lock_icon_dim = int((float)m_bmp_one_layer_lock_on.bmp().GetSize().x / scale_factor); + m_lock_icon_dim = m_bmp_one_layer_lock_on.GetBmpWidth(); m_bmp_revert = ScalableBitmap(this, "undo"); - m_revert_icon_dim = int((float)m_bmp_revert.bmp().GetSize().x / scale_factor); + m_revert_icon_dim = m_bmp_revert.GetBmpWidth(); m_bmp_cog = ScalableBitmap(this, "cog"); - m_cog_icon_dim = int((float)m_bmp_cog.bmp().GetSize().x / scale_factor); + m_cog_icon_dim = m_bmp_cog.GetBmpWidth(); m_selection = ssUndef; m_ticks.set_pause_print_msg(_utf8(L("Place bearings in slots and resume"))); @@ -554,9 +552,9 @@ void Control::draw_ticks(wxDC& dc) // Draw icon for "Pause print" or "Custom Gcode" if (tick.gcode != ColorChangeCode && tick.gcode != ToolChangeCode) - icon = create_scaled_bitmap(this, tick.gcode == PausePrintCode ? "pause_print" : "edit_gcode"); + icon = create_scaled_bitmap(tick.gcode == PausePrintCode ? "pause_print" : "edit_gcode"); else if (m_ticks.is_conflict_tick(tick, m_mode, m_only_extruder, m_values[tick.tick])) - icon = create_scaled_bitmap(this, "error_tick"); + icon = create_scaled_bitmap("error_tick"); if (!icon.IsNull()) { @@ -1028,7 +1026,7 @@ void Control::append_change_extruder_menu_item(wxMenu* menu, bool switch_current _(L("Change extruder (N/A)")); wxMenuItem* change_extruder_menu_item = menu->AppendSubMenu(change_extruder_menu, change_extruder_menu_name, _(L("Use another extruder"))); - change_extruder_menu_item->SetBitmap(create_scaled_bitmap(this, active_extruders[1] > 0 ? "edit_uni" : "change_extruder")); + change_extruder_menu_item->SetBitmap(create_scaled_bitmap(active_extruders[1] > 0 ? "edit_uni" : "change_extruder")); GUI::wxGetApp().plater()->Bind(wxEVT_UPDATE_UI, [this, change_extruder_menu_item](wxUpdateUIEvent& evt) { enable_menu_item(evt, [this]() {return m_mode == t_mode::MultiAsSingle; }, change_extruder_menu_item, this); }, @@ -1062,7 +1060,7 @@ void Control::append_add_color_change_menu_item(wxMenu* menu, bool switch_curren from_u8((boost::format(_utf8(L("Switch code to Color change (%1%) for:"))) % ColorChangeCode).str()) : from_u8((boost::format(_utf8(L("Add color change (%1%) for:"))) % ColorChangeCode).str()); wxMenuItem* add_color_change_menu_item = menu->AppendSubMenu(add_color_change_menu, menu_name, ""); - add_color_change_menu_item->SetBitmap(create_scaled_bitmap(this, "colorchange_add_m")); + add_color_change_menu_item->SetBitmap(create_scaled_bitmap("colorchange_add_m")); } } diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index babb8ed5c..33ddd475c 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -90,20 +90,20 @@ ObjectList::ObjectList(wxWindow* parent) : // see note in PresetBundle::load_compatible_bitmaps() // ptFFF - CATEGORY_ICON[L("Layers and Perimeters")] = create_scaled_bitmap(this, "layers"); - CATEGORY_ICON[L("Infill")] = create_scaled_bitmap(this, "infill"); - CATEGORY_ICON[L("Support material")] = create_scaled_bitmap(this, "support"); - CATEGORY_ICON[L("Speed")] = create_scaled_bitmap(this, "time"); - CATEGORY_ICON[L("Extruders")] = create_scaled_bitmap(this, "funnel"); - CATEGORY_ICON[L("Extrusion Width")] = create_scaled_bitmap(this, "funnel"); - CATEGORY_ICON[L("Wipe options")] = create_scaled_bitmap(this, "funnel"); -// CATEGORY_ICON[L("Skirt and brim")] = create_scaled_bitmap(this, "skirt+brim"); -// CATEGORY_ICON[L("Speed > Acceleration")] = create_scaled_bitmap(this, "time"); - CATEGORY_ICON[L("Advanced")] = create_scaled_bitmap(this, "wrench"); + CATEGORY_ICON[L("Layers and Perimeters")] = create_scaled_bitmap("layers"); + CATEGORY_ICON[L("Infill")] = create_scaled_bitmap("infill"); + CATEGORY_ICON[L("Support material")] = create_scaled_bitmap("support"); + CATEGORY_ICON[L("Speed")] = create_scaled_bitmap("time"); + CATEGORY_ICON[L("Extruders")] = create_scaled_bitmap("funnel"); + CATEGORY_ICON[L("Extrusion Width")] = create_scaled_bitmap("funnel"); + CATEGORY_ICON[L("Wipe options")] = create_scaled_bitmap("funnel"); +// CATEGORY_ICON[L("Skirt and brim")] = create_scaled_bitmap("skirt+brim"); +// CATEGORY_ICON[L("Speed > Acceleration")] = create_scaled_bitmap("time"); + CATEGORY_ICON[L("Advanced")] = create_scaled_bitmap("wrench"); // ptSLA - CATEGORY_ICON[L("Supports")] = create_scaled_bitmap(this, "support"/*"sla_supports"*/); - CATEGORY_ICON[L("Pad")] = create_scaled_bitmap(this, "pad"); - CATEGORY_ICON[L("Hollowing")] = create_scaled_bitmap(this, "hollowing"); + CATEGORY_ICON[L("Supports")] = create_scaled_bitmap("support"/*"sla_supports"*/); + CATEGORY_ICON[L("Pad")] = create_scaled_bitmap("pad"); + CATEGORY_ICON[L("Hollowing")] = create_scaled_bitmap("hollowing"); } // create control @@ -607,23 +607,20 @@ void ObjectList::msw_rescale_icons() // Update CATEGORY_ICON according to new scale { - // Note: `this` isn't passed to create_scaled_bitmap() here because of bugs in the widget, - // see note in PresetBundle::load_compatible_bitmaps() - // ptFFF - CATEGORY_ICON[L("Layers and Perimeters")] = create_scaled_bitmap(nullptr, "layers"); - CATEGORY_ICON[L("Infill")] = create_scaled_bitmap(nullptr, "infill"); - CATEGORY_ICON[L("Support material")] = create_scaled_bitmap(nullptr, "support"); - CATEGORY_ICON[L("Speed")] = create_scaled_bitmap(nullptr, "time"); - CATEGORY_ICON[L("Extruders")] = create_scaled_bitmap(nullptr, "funnel"); - CATEGORY_ICON[L("Extrusion Width")] = create_scaled_bitmap(nullptr, "funnel"); - CATEGORY_ICON[L("Wipe options")] = create_scaled_bitmap(nullptr, "funnel"); -// CATEGORY_ICON[L("Skirt and brim")] = create_scaled_bitmap(nullptr, "skirt+brim"); -// CATEGORY_ICON[L("Speed > Acceleration")] = create_scaled_bitmap(nullptr, "time"); - CATEGORY_ICON[L("Advanced")] = create_scaled_bitmap(nullptr, "wrench"); + CATEGORY_ICON[L("Layers and Perimeters")] = create_scaled_bitmap("layers"); + CATEGORY_ICON[L("Infill")] = create_scaled_bitmap("infill"); + CATEGORY_ICON[L("Support material")] = create_scaled_bitmap("support"); + CATEGORY_ICON[L("Speed")] = create_scaled_bitmap("time"); + CATEGORY_ICON[L("Extruders")] = create_scaled_bitmap("funnel"); + CATEGORY_ICON[L("Extrusion Width")] = create_scaled_bitmap("funnel"); + CATEGORY_ICON[L("Wipe options")] = create_scaled_bitmap("funnel"); +// CATEGORY_ICON[L("Skirt and brim")] = create_scaled_bitmap("skirt+brim"); +// CATEGORY_ICON[L("Speed > Acceleration")] = create_scaled_bitmap("time"); + CATEGORY_ICON[L("Advanced")] = create_scaled_bitmap("wrench"); // ptSLA - CATEGORY_ICON[L("Supports")] = create_scaled_bitmap(nullptr, "support"/*"sla_supports"*/); - CATEGORY_ICON[L("Pad")] = create_scaled_bitmap(nullptr, "pad"); + CATEGORY_ICON[L("Supports")] = create_scaled_bitmap("support"/*"sla_supports"*/); + CATEGORY_ICON[L("Pad")] = create_scaled_bitmap("pad"); } } diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 9929cf082..105c6faa5 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -68,7 +68,7 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S /* Load default preset bitmaps before a tabpanel initialization, * but after filling of an em_unit value */ - wxGetApp().preset_bundle->load_default_preset_bitmaps(this); + wxGetApp().preset_bundle->load_default_preset_bitmaps(); // initialize tabpanel and menubar init_tabpanel(); @@ -345,7 +345,7 @@ void MainFrame::on_dpi_changed(const wxRect &suggested_rect) /* Load default preset bitmaps before a tabpanel initialization, * but after filling of an em_unit value */ - wxGetApp().preset_bundle->load_default_preset_bitmaps(this); + wxGetApp().preset_bundle->load_default_preset_bitmaps(); // update Plater wxGetApp().plater()->msw_rescale(); @@ -733,7 +733,7 @@ void MainFrame::update_menubar() m_changeable_menu_items[miSend] ->SetItemLabel((is_fff ? _(L("S&end G-code")) : _(L("S&end to print"))) + dots + "\tCtrl+Shift+G"); m_changeable_menu_items[miMaterialTab] ->SetItemLabel((is_fff ? _(L("&Filament Settings Tab")) : _(L("Mate&rial Settings Tab"))) + "\tCtrl+3"); - m_changeable_menu_items[miMaterialTab] ->SetBitmap(create_scaled_bitmap(this, is_fff ? "spool": "resin")); + m_changeable_menu_items[miMaterialTab] ->SetBitmap(create_scaled_bitmap(is_fff ? "spool": "resin")); } // To perform the "Quck Slice", "Quick Slice and Save As", "Repeat last Quick Slice" and "Slice to SVG". diff --git a/src/slic3r/GUI/MsgDialog.cpp b/src/slic3r/GUI/MsgDialog.cpp index d1879e4ba..d4a82a03d 100644 --- a/src/slic3r/GUI/MsgDialog.cpp +++ b/src/slic3r/GUI/MsgDialog.cpp @@ -53,7 +53,7 @@ MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &he rightsizer->Add(btn_sizer, 0, wxALIGN_RIGHT); if (! bitmap.IsOk()) { - bitmap = create_scaled_bitmap(this, "PrusaSlicer_192px.png", 192); + bitmap = create_scaled_bitmap("PrusaSlicer_192px.png", this, 192); } logo = new wxStaticBitmap(this, wxID_ANY, wxNullBitmap); @@ -99,7 +99,7 @@ ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg) btn_ok->SetFocus(); btn_sizer->Add(btn_ok, 0, wxRIGHT, HORIZ_SPACING); - logo->SetBitmap(create_scaled_bitmap(this, "PrusaSlicer_192px_grayscale.png", 192)); + logo->SetBitmap(create_scaled_bitmap("PrusaSlicer_192px_grayscale.png", this, 192)); SetMaxSize(wxSize(-1, CONTENT_MAX_HEIGHT*wxGetApp().em_unit())); Fit(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index c93368673..8afd98d11 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -169,7 +169,7 @@ ObjectInfo::ObjectInfo(wxWindow *parent) : info_manifold_text->SetFont(wxGetApp().small_font()); info_manifold = new wxStaticText(parent, wxID_ANY, ""); info_manifold->SetFont(wxGetApp().small_font()); - manifold_warning_icon = new wxStaticBitmap(parent, wxID_ANY, create_scaled_bitmap(parent, "exclamation")); + manifold_warning_icon = new wxStaticBitmap(parent, wxID_ANY, create_scaled_bitmap("exclamation")); auto *sizer_manifold = new wxBoxSizer(wxHORIZONTAL); sizer_manifold->Add(info_manifold_text, 0); sizer_manifold->Add(manifold_warning_icon, 0, wxLEFT, 2); @@ -188,7 +188,7 @@ void ObjectInfo::show_sizer(bool show) void ObjectInfo::msw_rescale() { - manifold_warning_icon->SetBitmap(create_scaled_bitmap(nullptr, "exclamation")); + manifold_warning_icon->SetBitmap(create_scaled_bitmap("exclamation")); } enum SlicedInfoIdx @@ -258,7 +258,7 @@ void SlicedInfo::SetTextAndShow(SlicedInfoIdx idx, const wxString& text, const w } PresetComboBox::PresetComboBox(wxWindow *parent, Preset::Type preset_type) : -wxBitmapComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(15 * wxGetApp().em_unit(), -1), 0, nullptr, wxCB_READONLY), +PresetBitmapComboBox(parent, wxSize(15 * wxGetApp().em_unit(), -1)), preset_type(preset_type), last_selected(wxNOT_FOUND), m_em_unit(wxGetApp().em_unit()) diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 82fae44f0..568727abf 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -12,6 +12,7 @@ #include "3DScene.hpp" #include "GLTexture.hpp" +#include "wxExtensions.hpp" class wxButton; class ScalableButton; @@ -49,7 +50,7 @@ using t_optgroups = std::vector >; class Plater; enum class ActionButtonType : int; -class PresetComboBox : public wxBitmapComboBox +class PresetComboBox : public PresetBitmapComboBox { public: PresetComboBox(wxWindow *parent, Preset::Type preset_type); diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index d67abd13b..98fcf3f42 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -873,18 +873,14 @@ bool PresetCollection::delete_preset(const std::string& name) return true; } -void PresetCollection::load_bitmap_default(wxWindow *window, const std::string &file_name) +void PresetCollection::load_bitmap_default(const std::string &file_name) { - // XXX: See note in PresetBundle::load_compatible_bitmaps() - (void)window; - *m_bitmap_main_frame = create_scaled_bitmap(nullptr, file_name); + *m_bitmap_main_frame = create_scaled_bitmap(file_name); } -void PresetCollection::load_bitmap_add(wxWindow *window, const std::string &file_name) +void PresetCollection::load_bitmap_add(const std::string &file_name) { - // XXX: See note in PresetBundle::load_compatible_bitmaps() - (void)window; - *m_bitmap_add = create_scaled_bitmap(nullptr, file_name); + *m_bitmap_add = create_scaled_bitmap(file_name); } const Preset* PresetCollection::get_selected_preset_parent() const diff --git a/src/slic3r/GUI/Preset.hpp b/src/slic3r/GUI/Preset.hpp index c85933520..83970419c 100644 --- a/src/slic3r/GUI/Preset.hpp +++ b/src/slic3r/GUI/Preset.hpp @@ -313,10 +313,10 @@ public: bool delete_preset(const std::string& name); // Load default bitmap to be placed at the wxBitmapComboBox of a MainFrame. - void load_bitmap_default(wxWindow *window, const std::string &file_name); + void load_bitmap_default(const std::string &file_name); // Load "add new printer" bitmap to be placed at the wxBitmapComboBox of a MainFrame. - void load_bitmap_add(wxWindow *window, const std::string &file_name); + void load_bitmap_add(const std::string &file_name); // Compatible & incompatible marks, to be placed at the wxBitmapComboBox items. void set_bitmap_compatible (const wxBitmap *bmp) { m_bitmap_compatible = bmp; } diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp index 6c80a9eab..7bfbcd2e6 100644 --- a/src/slic3r/GUI/PresetBundle.cpp +++ b/src/slic3r/GUI/PresetBundle.cpp @@ -480,19 +480,12 @@ void PresetBundle::export_selections(AppConfig &config) config.set("presets", "printer", printers.get_selected_preset_name()); } -void PresetBundle::load_compatible_bitmaps(wxWindow *window) +void PresetBundle::load_compatible_bitmaps() { - // We don't actually pass the window pointer here and instead generate - // a low DPI bitmap, because the wxBitmapComboBox and wxDataViewCtrl don't support - // high DPI bitmaps very well, they compute their dimensions wrong. - // TODO: Update this when fixed in wxWidgets - // See also PresetCollection::load_bitmap_default() and PresetCollection::load_bitmap_add() - - (void)window; - *m_bitmapCompatible = create_scaled_bitmap(nullptr, "flag_green"); - *m_bitmapIncompatible = create_scaled_bitmap(nullptr, "flag_red"); - *m_bitmapLock = create_scaled_bitmap(nullptr, "lock_closed"); - *m_bitmapLockOpen = create_scaled_bitmap(nullptr, "lock_open"); + *m_bitmapCompatible = create_scaled_bitmap("flag_green"); + *m_bitmapIncompatible = create_scaled_bitmap("flag_red"); + *m_bitmapLock = create_scaled_bitmap("lock_closed"); + *m_bitmapLockOpen = create_scaled_bitmap("lock_open"); prints .set_bitmap_compatible(m_bitmapCompatible); filaments .set_bitmap_compatible(m_bitmapCompatible); @@ -1560,7 +1553,7 @@ bool PresetBundle::parse_color(const std::string &scolor, unsigned char *rgb_out return true; } -void PresetBundle::load_default_preset_bitmaps(wxWindow *window) +void PresetBundle::load_default_preset_bitmaps() { // Clear bitmap cache, before load new scaled default preset bitmaps m_bitmapCache->clear(); @@ -1570,13 +1563,13 @@ void PresetBundle::load_default_preset_bitmaps(wxWindow *window) this->sla_materials.clear_bitmap_cache(); this->printers.clear_bitmap_cache(); - this->prints.load_bitmap_default(window, "cog"); - this->sla_prints.load_bitmap_default(window, "cog"); - this->filaments.load_bitmap_default(window, "spool.png"); - this->sla_materials.load_bitmap_default(window, "resin"); - this->printers.load_bitmap_default(window, "printer"); - this->printers.load_bitmap_add(window, "add.png"); - this->load_compatible_bitmaps(window); + this->prints.load_bitmap_default("cog"); + this->sla_prints.load_bitmap_default("cog"); + this->filaments.load_bitmap_default("spool.png"); + this->sla_materials.load_bitmap_default("resin"); + this->printers.load_bitmap_default("printer"); + this->printers.load_bitmap_add("add.png"); + this->load_compatible_bitmaps(); } void PresetBundle::update_plater_filament_ui(unsigned int idx_extruder, GUI::PresetComboBox *ui) @@ -1623,7 +1616,12 @@ void PresetBundle::update_plater_filament_ui(unsigned int idx_extruder, GUI::Pre // To avoid asserts, each added bitmap to wxBitmapCombobox should be the same size, so // set a bitmap height to m_bitmapLock->GetHeight() - const int icon_height = m_bitmapLock->GetHeight();//2 * icon_unit; //16 * scale_f + 0.5f; + // Note, under OSX we should use a ScaledHeight because of Retina scale +#ifdef __APPLE__ + const int icon_height = m_bitmapLock->GetScaledHeight(); +#else + const int icon_height = m_bitmapLock->GetHeight(); +#endif wxString tooltip = ""; diff --git a/src/slic3r/GUI/PresetBundle.hpp b/src/slic3r/GUI/PresetBundle.hpp index 037c47c5f..bf64e0d34 100644 --- a/src/slic3r/GUI/PresetBundle.hpp +++ b/src/slic3r/GUI/PresetBundle.hpp @@ -131,7 +131,7 @@ public: static bool parse_color(const std::string &scolor, unsigned char *rgb_out); - void load_default_preset_bitmaps(wxWindow *window); + void load_default_preset_bitmaps(); // Set the is_visible flag for printer vendors, printer models and printer variants // based on the user configuration. @@ -160,7 +160,7 @@ private: // If it is not an external config, then the config will be stored into the user profile directory. void load_config_file_config(const std::string &name_or_path, bool is_external, DynamicPrintConfig &&config); void load_config_file_config_bundle(const std::string &path, const boost::property_tree::ptree &tree); - void load_compatible_bitmaps(wxWindow *window); + void load_compatible_bitmaps(); DynamicPrintConfig full_fff_config() const; DynamicPrintConfig full_sla_config() const; diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index a34a3e0b7..72e209167 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -114,7 +114,7 @@ void Tab::create_preset_tab() #endif //__WXOSX__ // preset chooser - m_presets_choice = new wxBitmapComboBox(panel, wxID_ANY, "", wxDefaultPosition, wxSize(35 * m_em_unit, -1), 0, 0, wxCB_READONLY); + m_presets_choice = new PresetBitmapComboBox(panel, wxSize(35 * m_em_unit, -1)); auto color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); @@ -1690,7 +1690,7 @@ void TabPrinter::build_printhost(ConfigOptionsGroup *optgroup) auto printhost_cafile_browse = [this, optgroup] (wxWindow* parent) { auto btn = new wxButton(parent, wxID_ANY, " " + _(L("Browse"))+" " +dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT); btn->SetFont(Slic3r::GUI::wxGetApp().normal_font()); - btn->SetBitmap(create_scaled_bitmap(this, "browse")); + btn->SetBitmap(create_scaled_bitmap("browse")); auto sizer = new wxBoxSizer(wxHORIZONTAL); sizer->Add(btn); diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index 4345f196c..cfa5ae56d 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -120,7 +120,7 @@ protected: Preset::Type m_type; std::string m_name; const wxString m_title; - wxBitmapComboBox* m_presets_choice; + PresetBitmapComboBox* m_presets_choice; ScalableButton* m_btn_save_preset; ScalableButton* m_btn_delete_preset; ScalableButton* m_btn_hide_incompatible_presets; diff --git a/src/slic3r/GUI/UpdateDialogs.cpp b/src/slic3r/GUI/UpdateDialogs.cpp index 00e7725ac..d5c69be0b 100644 --- a/src/slic3r/GUI/UpdateDialogs.cpp +++ b/src/slic3r/GUI/UpdateDialogs.cpp @@ -149,7 +149,7 @@ MsgDataIncompatible::MsgDataIncompatible(const std::unordered_mapSetBitmap(create_scaled_bitmap(this, "PrusaSlicer_192px_grayscale.png", 192)); + logo->SetBitmap(create_scaled_bitmap("PrusaSlicer_192px_grayscale.png", this, 192)); auto *text = new wxStaticText(this, wxID_ANY, wxString::Format(_(L( "This version of %s is not compatible with currently installed configuration bundles.\n" diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index a867ca0ec..e628c705a 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -41,7 +41,7 @@ void msw_rescale_menu(wxMenu* menu) 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); + const wxBitmap& item_icon = create_scaled_bitmap(it->second); if (item_icon.IsOk()) item->SetBitmap(item_icon); } @@ -108,7 +108,7 @@ wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const if (id == wxID_ANY) id = wxNewId(); - const wxBitmap& bmp = !icon.empty() ? create_scaled_bitmap(parent, icon) : wxNullBitmap; // FIXME: pass window ptr + const wxBitmap& bmp = !icon.empty() ? create_scaled_bitmap(icon) : wxNullBitmap; // FIXME: pass window ptr //#ifdef __WXMSW__ #ifndef __WXGTK__ if (bmp.IsOk()) @@ -126,7 +126,7 @@ wxMenuItem* append_submenu(wxMenu* menu, wxMenu* sub_menu, int id, const wxStrin wxMenuItem* item = new wxMenuItem(menu, id, string, description); if (!icon.empty()) { - item->SetBitmap(create_scaled_bitmap(parent, icon)); // FIXME: pass window ptr + item->SetBitmap(create_scaled_bitmap(icon)); // FIXME: pass window ptr //#ifdef __WXMSW__ #ifndef __WXGTK__ msw_menuitem_bitmaps[id] = icon; @@ -308,6 +308,94 @@ void wxCheckListBoxComboPopup::OnListBoxSelection(wxCommandEvent& evt) } +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 +} +} + + // *** wxDataViewTreeCtrlComboPopup *** const unsigned int wxDataViewTreeCtrlComboPopup::DefaultWidth = 270; @@ -407,32 +495,16 @@ int em_unit(wxWindow* win) return Slic3r::GUI::wxGetApp().em_unit(); } -float get_svg_scale_factor(wxWindow *win) -{ -#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 - (void)(win); - return 1.0f; -#endif -} - -// If an icon has horizontal orientation (width > height) call this function with is_horizontal = true -wxBitmap create_scaled_bitmap(wxWindow *win, const std::string& bmp_name_in, - const int px_cnt/* = 16*/, const bool grayscale/* = false*/) +// 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*/) { static Slic3r::GUI::BitmapCache cache; - const float scale_factor = get_svg_scale_factor(win); - unsigned int width = 0; unsigned int height = (unsigned int)(em_unit(win) * px_cnt * 0.1f + 0.5f); @@ -440,7 +512,7 @@ wxBitmap create_scaled_bitmap(wxWindow *win, const std::string& bmp_name_in, boost::replace_last(bmp_name, ".png", ""); // Try loading an SVG first, then PNG if SVG is not found: - wxBitmap *bmp = cache.load_svg(bmp_name, width, height, scale_factor, grayscale, Slic3r::GUI::wxGetApp().dark_mode()); + wxBitmap *bmp = cache.load_svg(bmp_name, width, height, grayscale, Slic3r::GUI::wxGetApp().dark_mode()); if (bmp == nullptr) { bmp = cache.load_png(bmp_name, width, height, grayscale); } @@ -482,7 +554,8 @@ std::vector get_extruder_color_icons(bool thin_icon/* = false*/) if (bitmap == nullptr) { // Paint the color icon. Slic3r::PresetBundle::parse_color(color, rgb); - bitmap = m_bitmap_cache->insert(bitmap_key, m_bitmap_cache->mksolid(icon_width, icon_height, rgb)); + // there is no neede to scale created solid bitmap + bitmap = m_bitmap_cache->insert(bitmap_key, m_bitmap_cache->mksolid(icon_width, icon_height, rgb, true)); } bmps.emplace_back(bitmap); } @@ -568,8 +641,7 @@ void ObjectDataViewModelNode::init_container() ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const ItemType type) : m_parent(parent), m_type(type), - m_extruder(wxEmptyString), - m_ctrl(parent->m_ctrl) + m_extruder(wxEmptyString) { if (type == itSettings) m_name = "Settings to modified"; @@ -584,7 +656,7 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent } else if (type == itLayerRoot) { - m_bmp = create_scaled_bitmap(m_ctrl, LAYER_ROOT_ICON); // FIXME: pass window ptr + m_bmp = create_scaled_bitmap(LAYER_ROOT_ICON); // FIXME: pass window ptr m_name = _(L("Layers")); } @@ -600,8 +672,7 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent m_type(itLayer), m_idx(idx), m_layer_range(layer_range), - m_extruder(extruder), - m_ctrl(parent->m_ctrl) + m_extruder(extruder) { const int children_cnt = parent->GetChildCount(); if (idx < 0) @@ -614,7 +685,7 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent } const std::string label_range = (boost::format(" %.2f-%.2f ") % layer_range.first % layer_range.second).str(); m_name = _(L("Range")) + label_range + "(" + _(L("mm")) + ")"; - m_bmp = create_scaled_bitmap(m_ctrl, LAYER_ICON); // FIXME: pass window ptr + m_bmp = create_scaled_bitmap(LAYER_ICON); // FIXME: pass window ptr set_action_and_extruder_icons(); init_container(); @@ -633,7 +704,7 @@ void ObjectDataViewModelNode::set_action_and_extruder_icons() { m_action_icon_name = m_type & itObject ? "advanced_plus" : m_type & (itVolume | itLayer) ? "cog" : /*m_type & itInstance*/ "set_separate_obj"; - m_action_icon = create_scaled_bitmap(m_ctrl, m_action_icon_name); // FIXME: pass window ptr + m_action_icon = create_scaled_bitmap(m_action_icon_name); // FIXME: pass window ptr if (m_type & itInstance) return; // don't set colored bitmap for Instance @@ -648,7 +719,7 @@ void ObjectDataViewModelNode::set_printable_icon(PrintIndicator printable) { m_printable = printable; m_printable_icon = m_printable == piUndef ? m_empty_bmp : - create_scaled_bitmap(m_ctrl, m_printable == piPrintable ? "eye_open.png" : "eye_closed.png"); + create_scaled_bitmap(m_printable == piPrintable ? "eye_open.png" : "eye_closed.png"); } void ObjectDataViewModelNode::update_settings_digest_bitmaps() @@ -666,7 +737,7 @@ void ObjectDataViewModelNode::update_settings_digest_bitmaps() 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, get_svg_scale_factor(m_ctrl)); + bmp = m_bitmap_cache->insert(scaled_bitmap_name, bmps); } m_bmp = *bmp; @@ -693,10 +764,10 @@ bool ObjectDataViewModelNode::update_settings_digest(const std::vectorm_bmp = *m_warning_bmp; @@ -1985,9 +2056,9 @@ void ObjectDataViewModel::Rescale() node->m_bmp = GetVolumeIcon(node->m_volume_type, node->m_bmp.GetWidth() != node->m_bmp.GetHeight()); break; case itLayerRoot: - node->m_bmp = create_scaled_bitmap(m_ctrl, LAYER_ROOT_ICON); + node->m_bmp = create_scaled_bitmap(LAYER_ROOT_ICON); case itLayer: - node->m_bmp = create_scaled_bitmap(m_ctrl, LAYER_ICON); + node->m_bmp = create_scaled_bitmap(LAYER_ICON); break; default: break; } @@ -2089,9 +2160,11 @@ bool BitmapTextRenderer::Render(wxRect rect, wxDC *dc, int state) const wxBitmap& icon = m_value.GetBitmap(); if (icon.IsOk()) { - float sf = (float)1.0 / get_svg_scale_factor(m_parent); - wxSize icon_sz = icon.GetSize() * sf; - +#ifdef __APPLE__ + wxSize icon_sz = icon.GetScaledSize(); +#else + wxSize icon_sz = icon.GetSize(); +#endif dc->DrawBitmap(icon, rect.x, rect.y + (rect.height - icon_sz.y) / 2); xoffset = icon_sz.x + 4; } @@ -2470,13 +2543,40 @@ ScalableBitmap::ScalableBitmap( wxWindow *parent, m_parent(parent), m_icon_name(icon_name), m_px_cnt(px_cnt) { - m_bmp = create_scaled_bitmap(parent, icon_name, px_cnt); + 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 } void ScalableBitmap::msw_rescale() { - m_bmp = create_scaled_bitmap(m_parent, m_icon_name, m_px_cnt); + m_bmp = create_scaled_bitmap(m_icon_name, m_parent, m_px_cnt); } // ---------------------------------------------------------------------------- @@ -2499,7 +2599,7 @@ ScalableButton::ScalableButton( wxWindow * parent, SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); #endif // __WXMSW__ - SetBitmap(create_scaled_bitmap(parent, icon_name)); + SetBitmap(create_scaled_bitmap(icon_name, parent)); if (size != wxDefaultSize) { @@ -2542,15 +2642,18 @@ void ScalableButton::SetBitmapDisabled_(const ScalableBitmap& bmp) int ScalableButton::GetBitmapHeight() { - const float scale_factor = get_svg_scale_factor(m_parent); - return int((float)GetBitmap().GetHeight() / scale_factor); +#ifdef __APPLE__ + return GetBitmap().GetScaledHeight(); +#else + return GetBitmap().GetHeight(); +#endif } void ScalableButton::msw_rescale() { - SetBitmap(create_scaled_bitmap(m_parent, m_current_icon_name, m_px_cnt)); + SetBitmap(create_scaled_bitmap(m_current_icon_name, m_parent, m_px_cnt)); if (!m_disabled_icon_name.empty()) - SetBitmapDisabled(create_scaled_bitmap(m_parent, m_disabled_icon_name, m_px_cnt)); + SetBitmapDisabled(create_scaled_bitmap(m_disabled_icon_name, m_parent, m_px_cnt)); if (m_width > 0 || m_height>0) { diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index 8cd144dc5..09afe3c0f 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -53,9 +53,8 @@ class wxBitmapComboBox; void edit_tooltip(wxString& tooltip); void msw_buttons_rescale(wxDialog* dlg, const int em_unit, const std::vector& btn_ids); int em_unit(wxWindow* win); -float get_svg_scale_factor(wxWindow* win); -wxBitmap create_scaled_bitmap(wxWindow *win, const std::string& bmp_name, +wxBitmap create_scaled_bitmap(const std::string& bmp_name, wxWindow *win = nullptr, const int px_cnt = 16, const bool grayscale = false); std::vector get_extruder_color_icons(bool thin_icon = false); @@ -102,6 +101,37 @@ public: void OnListBoxSelection(wxCommandEvent& evt); }; +namespace Slic3r { +namespace GUI { +// *** PresetBitmapComboBox *** + +// BitmapComboBox used to presets list on Sidebar and Tabs +class PresetBitmapComboBox: public wxBitmapComboBox +{ +public: + PresetBitmapComboBox(wxWindow* parent, const wxSize& size = wxDefaultSize); + ~PresetBitmapComboBox() {} + +#ifdef __APPLE__ +protected: + /* 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. + **/ + virtual bool OnAddBitmap(const wxBitmap& bitmap) override; + virtual void OnDrawItem(wxDC& dc, const wxRect& rect, int item, int flags) const override; +#endif +}; + +} +} + // *** wxDataViewTreeCtrlComboBox *** @@ -228,18 +258,13 @@ class ObjectDataViewModelNode std::string m_action_icon_name = ""; Slic3r::ModelVolumeType m_volume_type; - // pointer to control (is needed to create scaled bitmaps) - wxDataViewCtrl* m_ctrl{ nullptr }; - public: ObjectDataViewModelNode(const wxString& name, - const wxString& extruder, - wxDataViewCtrl* ctrl): + const wxString& extruder): m_parent(NULL), m_name(name), m_type(itObject), - m_extruder(extruder), - m_ctrl(ctrl) + m_extruder(extruder) { set_action_and_extruder_icons(); init_container(); @@ -254,8 +279,7 @@ public: m_name (sub_obj_name), m_type (itVolume), m_idx (idx), - m_extruder (extruder), - m_ctrl (parent->m_ctrl) + m_extruder (extruder) { m_bmp = bmp; set_action_and_extruder_icons(); @@ -734,6 +758,10 @@ public: ~ScalableBitmap() {} + wxSize GetBmpSize() const; + int GetBmpWidth() const; + int GetBmpHeight() const; + void msw_rescale(); const wxBitmap& bmp() const { return m_bmp; }