diff --git a/src/slic3r/GUI/BitmapCache.cpp b/src/slic3r/GUI/BitmapCache.cpp index 7322a88d1..b80ac1726 100644 --- a/src/slic3r/GUI/BitmapCache.cpp +++ b/src/slic3r/GUI/BitmapCache.cpp @@ -49,12 +49,20 @@ 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) +wxBitmap* BitmapCache::insert(const std::string &bitmap_key, size_t width, size_t height, float scale/* = 1.0f*/) { wxBitmap *bitmap = nullptr; auto it = m_map.find(bitmap_key); if (it == m_map.end()) { bitmap = new wxBitmap(width, height); +#ifdef __APPLE__ + // Contrary to intuition, the `scale` argument isn't "please scale this to such and such" + // but rather "the wxImage is sized for backing scale such and such". + // 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. + return bitmap->CreateScaled(width, height, scale); +#endif m_map[bitmap_key] = bitmap; } else { bitmap = it->second; @@ -95,7 +103,7 @@ 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) +wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap *begin, const wxBitmap *end, float scale/* = 1.0f*/) { size_t width = 0; size_t height = 0; @@ -158,6 +166,12 @@ 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); wxMemoryDC memDC; memDC.SelectObject(*bitmap); @@ -167,7 +181,8 @@ 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); - x += bmp->GetWidth(); + // we should "move" with step equal to non-scaled width + x += bmp->GetWidth()/scale; } memDC.SelectObject(wxNullBitmap); return bitmap; diff --git a/src/slic3r/GUI/BitmapCache.hpp b/src/slic3r/GUI/BitmapCache.hpp index 041e7d892..49d45c66a 100644 --- a/src/slic3r/GUI/BitmapCache.hpp +++ b/src/slic3r/GUI/BitmapCache.hpp @@ -23,12 +23,12 @@ public: 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); + wxBitmap* insert(const std::string &name, size_t width, size_t height, float scale = 1.0f); 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) { return this->insert(name, &bmps.front(), &bmps.front() + bmps.size()); } - wxBitmap* insert(const std::string &name, const wxBitmap *begin, const wxBitmap *end); + 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); // Load png from resources/icons. bitmap_key is given without the .png suffix. Bitmap will be rescaled to provided height/width if nonzero. diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 8e2bc1d97..b710d2cd7 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -66,7 +66,7 @@ void enable_menu_item(wxUpdateUIEvent& evt, std::function const cb_condi const auto it = msw_menuitem_bitmaps.find(item->GetId()); if (it != msw_menuitem_bitmaps.end()) { - const wxBitmap& item_icon = create_scaled_bitmap(win, it->second, 16, false, !enable); + const wxBitmap& item_icon = create_scaled_bitmap(win, it->second, 16, !enable); if (item_icon.IsOk()) item->SetBitmap(item_icon); } @@ -420,41 +420,25 @@ float get_svg_scale_factor(wxWindow *win) } 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 is_horizontal /* = false*/, const bool grayscale/* = false*/) + const int px_cnt/* = 16*/, const bool grayscale/* = false*/) { static Slic3r::GUI::BitmapCache cache; -#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. + const float scale_factor = get_svg_scale_factor(win); - 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; -#else - (void)(win); - const float scale_factor = 1.0f; -#endif - - unsigned int height, width = height = 0; - unsigned int& scale_base = is_horizontal ? width : height; - - scale_base = (unsigned int)(em_unit(win) * px_cnt * 0.1f + 0.5f); + unsigned int width = 0; + unsigned int height = (unsigned int)(em_unit(win) * px_cnt * 0.1f + 0.5f); std::string bmp_name = bmp_name_in; boost::replace_last(bmp_name, ".png", ""); -// std::string bmp_name = icon_name_respected_to_mode(bmp_name_in); - // 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()); if (bmp == nullptr) { @@ -682,7 +666,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); + bmp = m_bitmap_cache->insert(scaled_bitmap_name, bmps, get_svg_scale_factor(m_ctrl)); } m_bmp = *bmp; @@ -2470,18 +2454,17 @@ void MenuWithSeparators::SetSecondSeparator() // ---------------------------------------------------------------------------- ScalableBitmap::ScalableBitmap( wxWindow *parent, const std::string& icon_name/* = ""*/, - const int px_cnt/* = 16*/, - const bool is_horizontal/* = false*/): + const int px_cnt/* = 16*/): m_parent(parent), m_icon_name(icon_name), - m_px_cnt(px_cnt), m_is_horizontal(is_horizontal) + m_px_cnt(px_cnt) { - m_bmp = create_scaled_bitmap(parent, icon_name, px_cnt, is_horizontal); + m_bmp = create_scaled_bitmap(parent, icon_name, px_cnt); } void ScalableBitmap::msw_rescale() { - m_bmp = create_scaled_bitmap(m_parent, m_icon_name, m_px_cnt, m_is_horizontal); + m_bmp = create_scaled_bitmap(m_parent, m_icon_name, m_px_cnt); } // ---------------------------------------------------------------------------- @@ -2522,8 +2505,7 @@ ScalableButton::ScalableButton( wxWindow * parent, long style /*= wxBU_EXACTFIT | wxNO_BORDER*/) : m_parent(parent), m_current_icon_name(bitmap.name()), - m_px_cnt(bitmap.px_cnt()), - m_is_horizontal(bitmap.is_horizontal()) + m_px_cnt(bitmap.px_cnt()) { Create(parent, id, label, wxDefaultPosition, wxDefaultSize, style); #ifdef __WXMSW__ @@ -2554,9 +2536,9 @@ int ScalableButton::GetBitmapHeight() void ScalableButton::msw_rescale() { - SetBitmap(create_scaled_bitmap(m_parent, m_current_icon_name, m_px_cnt, m_is_horizontal)); + SetBitmap(create_scaled_bitmap(m_parent, m_current_icon_name, m_px_cnt)); if (!m_disabled_icon_name.empty()) - SetBitmapDisabled(create_scaled_bitmap(m_parent, m_disabled_icon_name, m_px_cnt, m_is_horizontal)); + SetBitmapDisabled(create_scaled_bitmap(m_parent, m_disabled_icon_name, 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 1ee42dc29..c3d26c8be 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -56,7 +56,7 @@ int em_unit(wxWindow* win); float get_svg_scale_factor(wxWindow* win); wxBitmap create_scaled_bitmap(wxWindow *win, const std::string& bmp_name, - const int px_cnt = 16, const bool is_horizontal = false, const bool grayscale = false); + const int px_cnt = 16, const bool grayscale = false); std::vector get_extruder_color_icons(bool thin_icon = false); void apply_extruder_selector(wxBitmapComboBox** ctrl, @@ -729,8 +729,7 @@ public: ScalableBitmap() {}; ScalableBitmap( wxWindow *parent, const std::string& icon_name = "", - const int px_cnt = 16, - const bool is_horizontal = false); + const int px_cnt = 16); ~ScalableBitmap() {} @@ -741,14 +740,12 @@ public: const std::string& name() const{ return m_icon_name; } int px_cnt()const {return m_px_cnt;} - bool is_horizontal()const {return m_is_horizontal;} private: wxWindow* m_parent{ nullptr }; wxBitmap m_bmp = wxBitmap(); std::string m_icon_name = ""; int m_px_cnt {16}; - bool m_is_horizontal {false}; }; @@ -832,7 +829,6 @@ private: // bitmap dimensions int m_px_cnt{ 16 }; - bool m_is_horizontal{ false }; };