Code refactoring:

- PresetCombpBoxes are extracted to the separate file.
- All preset icons are moved to the PresetComboBox from Preset and PresetBundle
- First "steps" to add physical printers to the printers list on the sidebar.
This commit is contained in:
YuSanka 2020-06-16 12:57:49 +02:00
parent f23a275fbb
commit 43e6e4f18c
15 changed files with 1304 additions and 1041 deletions

View file

@ -80,6 +80,8 @@ set(SLIC3R_GUI_SOURCES
GUI/MainFrame.cpp
GUI/MainFrame.hpp
GUI/Plater.cpp
GUI/PresetComboBoxes.hpp
GUI/PresetComboBoxes.cpp
GUI/Plater.hpp
GUI/GUI_ObjectList.cpp
GUI/GUI_ObjectList.hpp

View file

@ -88,9 +88,6 @@ ObjectList::ObjectList(wxWindow* parent) :
{
// Fill CATEGORY_ICON
{
// 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("layers");
CATEGORY_ICON[L("Infill")] = create_scaled_bitmap("infill");

View file

@ -74,11 +74,6 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
SLIC3R_VERSION +
_(L(" - Remember to check for updates at http://github.com/prusa3d/PrusaSlicer/releases")));
/* Load default preset bitmaps before a tabpanel initialization,
* but after filling of an em_unit value
*/
wxGetApp().preset_bundle->load_default_preset_bitmaps();
// initialize tabpanel and menubar
init_tabpanel();
init_menubar();
@ -540,11 +535,6 @@ void MainFrame::on_dpi_changed(const wxRect &suggested_rect)
wxGetApp().update_fonts();
this->SetFont(this->normal_font());
/* Load default preset bitmaps before a tabpanel initialization,
* but after filling of an em_unit value
*/
wxGetApp().preset_bundle->load_default_preset_bitmaps();
// update Plater
wxGetApp().plater()->msw_rescale();
@ -586,8 +576,6 @@ void MainFrame::on_sys_color_changed()
// update label colors in respect to the system mode
wxGetApp().init_label_colours();
wxGetApp().preset_bundle->load_default_preset_bitmaps();
// update Plater
wxGetApp().plater()->sys_color_changed();

View file

@ -24,7 +24,6 @@
#include <wx/dnd.h>
#include <wx/progdlg.h>
#include <wx/wupdlock.h>
#include <wx/colordlg.h>
#include <wx/numdlg.h>
#include <wx/debug.h>
#include <wx/busyinfo.h>
@ -77,6 +76,7 @@
#include "../Utils/UndoRedo.hpp"
#include "RemovableDriveManager.hpp"
#include "InstanceCheck.hpp"
#include "PresetComboBoxes.hpp"
#ifdef __APPLE__
#include "Gizmos/GLGizmosManager.hpp"
@ -253,153 +253,6 @@ void SlicedInfo::SetTextAndShow(SlicedInfoIdx idx, const wxString& text, const w
info_vec[idx].second->Show(show);
}
PresetComboBox::PresetComboBox(wxWindow *parent, Preset::Type preset_type) :
PresetBitmapComboBox(parent, wxSize(15 * wxGetApp().em_unit(), -1)),
preset_type(preset_type),
last_selected(wxNOT_FOUND),
m_em_unit(wxGetApp().em_unit())
{
SetFont(wxGetApp().normal_font());
#ifdef _WIN32
// Workaround for ignoring CBN_EDITCHANGE events, which are processed after the content of the combo box changes, so that
// the index of the item inside CBN_EDITCHANGE may no more be valid.
EnableTextChangedEvents(false);
#endif /* _WIN32 */
Bind(wxEVT_COMBOBOX, [this](wxCommandEvent &evt) {
auto selected_item = evt.GetSelection();
auto marker = reinterpret_cast<Marker>(this->GetClientData(selected_item));
if (marker >= LABEL_ITEM_MARKER && marker < LABEL_ITEM_MAX) {
this->SetSelection(this->last_selected);
evt.StopPropagation();
if (marker >= LABEL_ITEM_WIZARD_PRINTERS) {
ConfigWizard::StartPage sp = ConfigWizard::SP_WELCOME;
switch (marker) {
case LABEL_ITEM_WIZARD_PRINTERS: sp = ConfigWizard::SP_PRINTERS; break;
case LABEL_ITEM_WIZARD_FILAMENTS: sp = ConfigWizard::SP_FILAMENTS; break;
case LABEL_ITEM_WIZARD_MATERIALS: sp = ConfigWizard::SP_MATERIALS; break;
}
wxTheApp->CallAfter([sp]() { wxGetApp().run_wizard(ConfigWizard::RR_USER, sp); });
}
} else if ( this->last_selected != selected_item ||
wxGetApp().get_tab(this->preset_type)->get_presets()->current_is_dirty() ) {
this->last_selected = selected_item;
evt.SetInt(this->preset_type);
evt.Skip();
} else {
evt.StopPropagation();
}
});
if (preset_type == Slic3r::Preset::TYPE_FILAMENT)
{
Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &event) {
PresetBundle* preset_bundle = wxGetApp().preset_bundle;
const Preset* selected_preset = preset_bundle->filaments.find_preset(preset_bundle->filament_presets[extruder_idx]);
// Wide icons are shown if the currently selected preset is not compatible with the current printer,
// and red flag is drown in front of the selected preset.
bool wide_icons = selected_preset != nullptr && !selected_preset->is_compatible;
float scale = m_em_unit*0.1f;
int shifl_Left = wide_icons ? int(scale * 16 + 0.5) : 0;
#if defined(wxBITMAPCOMBOBOX_OWNERDRAWN_BASED)
shifl_Left += int(scale * 4 + 0.5f); // IMAGE_SPACING_RIGHT = 4 for wxBitmapComboBox -> Space left of image
#endif
int icon_right_pos = shifl_Left + int(scale * (24+4) + 0.5);
int mouse_pos = event.GetLogicalPosition(wxClientDC(this)).x;
if (mouse_pos < shifl_Left || mouse_pos > icon_right_pos ) {
// Let the combo box process the mouse click.
event.Skip();
return;
}
// Swallow the mouse click and open the color picker.
// get current color
DynamicPrintConfig* cfg = wxGetApp().get_tab(Preset::TYPE_PRINTER)->get_config();
auto colors = static_cast<ConfigOptionStrings*>(cfg->option("extruder_colour")->clone());
wxColour clr(colors->values[extruder_idx]);
if (!clr.IsOk())
clr = wxColour(0,0,0); // Don't set alfa to transparence
auto data = new wxColourData();
data->SetChooseFull(1);
data->SetColour(clr);
wxColourDialog dialog(this, data);
dialog.CenterOnParent();
if (dialog.ShowModal() == wxID_OK)
{
colors->values[extruder_idx] = dialog.GetColourData().GetColour().GetAsString(wxC2S_HTML_SYNTAX).ToStdString();
DynamicPrintConfig cfg_new = *cfg;
cfg_new.set_key_value("extruder_colour", colors);
wxGetApp().get_tab(Preset::TYPE_PRINTER)->load_config(cfg_new);
preset_bundle->update_plater_filament_ui(extruder_idx, this);
wxGetApp().plater()->on_config_change(cfg_new);
}
});
}
edit_btn = new ScalableButton(parent, wxID_ANY, "cog");
edit_btn->SetToolTip(_L("Click to edit preset"));
edit_btn->Bind(wxEVT_BUTTON, ([preset_type, this](wxCommandEvent)
{
Tab* tab = wxGetApp().get_tab(preset_type);
if (!tab)
return;
int page_id = wxGetApp().tab_panel()->FindPage(tab);
if (page_id == wxNOT_FOUND)
return;
wxGetApp().tab_panel()->SetSelection(page_id);
// Switch to Settings NotePad
wxGetApp().mainframe->select_tab();
/* In a case of a multi-material printing, for editing another Filament Preset
* it's needed to select this preset for the "Filament settings" Tab
*/
if (preset_type == Preset::TYPE_FILAMENT && wxGetApp().extruders_edited_cnt() > 1)
{
const std::string& selected_preset = GetString(GetSelection()).ToUTF8().data();
// Call select_preset() only if there is new preset and not just modified
if ( !boost::algorithm::ends_with(selected_preset, Preset::suffix_modified()) )
{
const std::string& preset_name = wxGetApp().preset_bundle->filaments.get_preset_name_by_alias(selected_preset);
tab->select_preset(/*selected_preset*/preset_name);
}
}
}));
}
PresetComboBox::~PresetComboBox()
{
if (edit_btn)
edit_btn->Destroy();
}
void PresetComboBox::set_label_marker(int item, LabelItemType label_item_type)
{
this->SetClientData(item, (void*)label_item_type);
}
void PresetComboBox::check_selection(int selection)
{
this->last_selected = selection;
}
void PresetComboBox::msw_rescale()
{
m_em_unit = wxGetApp().em_unit();
edit_btn->msw_rescale();
}
// Frequently changed parameters
class FreqChangedParams : public OG_Settings
@ -697,12 +550,12 @@ struct Sidebar::priv
ModeSizer *mode_sizer;
wxFlexGridSizer *sizer_presets;
PresetComboBox *combo_print;
std::vector<PresetComboBox*> combos_filament;
PlaterPresetComboBox *combo_print;
std::vector<PlaterPresetComboBox*> combos_filament;
wxBoxSizer *sizer_filaments;
PresetComboBox *combo_sla_print;
PresetComboBox *combo_sla_material;
PresetComboBox *combo_printer;
PlaterPresetComboBox *combo_sla_print;
PlaterPresetComboBox *combo_sla_material;
PlaterPresetComboBox *combo_printer;
wxBoxSizer *sizer_params;
FreqChangedParams *frequently_changed_parameters{ nullptr };
@ -801,10 +654,10 @@ Sidebar::Sidebar(Plater *parent)
p->sizer_filaments = new wxBoxSizer(wxVERTICAL);
auto init_combo = [this](PresetComboBox **combo, wxString label, Preset::Type preset_type, bool filament) {
auto init_combo = [this](PlaterPresetComboBox **combo, wxString label, Preset::Type preset_type, bool filament) {
auto *text = new wxStaticText(p->presets_panel, wxID_ANY, label + " :");
text->SetFont(wxGetApp().small_font());
*combo = new PresetComboBox(p->presets_panel, preset_type);
*combo = new PlaterPresetComboBox(p->presets_panel, preset_type);
auto combo_and_btn_sizer = new wxBoxSizer(wxHORIZONTAL);
combo_and_btn_sizer->Add(*combo, 1, wxEXPAND);
@ -941,8 +794,8 @@ Sidebar::Sidebar(Plater *parent)
Sidebar::~Sidebar() {}
void Sidebar::init_filament_combo(PresetComboBox **combo, const int extr_idx) {
*combo = new PresetComboBox(p->presets_panel, Slic3r::Preset::TYPE_FILAMENT);
void Sidebar::init_filament_combo(PlaterPresetComboBox **combo, const int extr_idx) {
*combo = new PlaterPresetComboBox(p->presets_panel, Slic3r::Preset::TYPE_FILAMENT);
// # copy icons from first choice
// $choice->SetItemBitmap($_, $choices->[0]->GetItemBitmap($_)) for 0..$#presets;
@ -977,18 +830,18 @@ void Sidebar::update_all_preset_comboboxes()
// Update the print choosers to only contain the compatible presets, update the dirty flags.
if (print_tech == ptFFF)
preset_bundle.prints.update_plater_ui(p->combo_print);
p->combo_print->update();
else {
preset_bundle.sla_prints.update_plater_ui(p->combo_sla_print);
preset_bundle.sla_materials.update_plater_ui(p->combo_sla_material);
p->combo_sla_print->update();
p->combo_sla_material->update();
}
// Update the printer choosers, update the dirty flags.
preset_bundle.printers.update_plater_ui(p->combo_printer);
p->combo_printer->update();
// Update the filament choosers to only contain the compatible presets, update the color preview,
// update the dirty flags.
if (print_tech == ptFFF) {
for (size_t i = 0; i < p->combos_filament.size(); ++i)
preset_bundle.update_plater_filament_ui(i, p->combos_filament[i]);
for (PlaterPresetComboBox* cb : p->combos_filament)
cb->update();
}
}
@ -1010,23 +863,22 @@ void Sidebar::update_presets(Preset::Type preset_type)
preset_bundle.set_filament_preset(0, name);
}
for (size_t i = 0; i < filament_cnt; i++) {
preset_bundle.update_plater_filament_ui(i, p->combos_filament[i]);
}
for (size_t i = 0; i < filament_cnt; i++)
p->combos_filament[i]->update();
break;
}
case Preset::TYPE_PRINT:
preset_bundle.prints.update_plater_ui(p->combo_print);
p->combo_print->update();
break;
case Preset::TYPE_SLA_PRINT:
preset_bundle.sla_prints.update_plater_ui(p->combo_sla_print);
p->combo_sla_print->update();
break;
case Preset::TYPE_SLA_MATERIAL:
preset_bundle.sla_materials.update_plater_ui(p->combo_sla_material);
p->combo_sla_material->update();
break;
case Preset::TYPE_PRINTER:
@ -1062,18 +914,14 @@ void Sidebar::msw_rescale()
p->mode_sizer->msw_rescale();
// Rescale preset comboboxes in respect to the current em_unit ...
for (PresetComboBox* combo : std::vector<PresetComboBox*> { p->combo_print,
for (PlaterPresetComboBox* combo : std::vector<PlaterPresetComboBox*> { p->combo_print,
p->combo_sla_print,
p->combo_sla_material,
p->combo_printer } )
combo->msw_rescale();
for (PresetComboBox* combo : p->combos_filament)
for (PlaterPresetComboBox* combo : p->combos_filament)
combo->msw_rescale();
// ... then refill them and set min size to correct layout of the sidebar
update_all_preset_comboboxes();
p->frequently_changed_parameters->msw_rescale();
p->object_list->msw_rescale();
p->object_manipulation->msw_rescale();
@ -1096,12 +944,12 @@ void Sidebar::sys_color_changed()
{
// Update preset comboboxes in respect to the system color ...
// combo->msw_rescale() updates icon on button, so use it
for (PresetComboBox* combo : std::vector<PresetComboBox*>{ p->combo_print,
for (PlaterPresetComboBox* combo : std::vector<PlaterPresetComboBox*>{ p->combo_print,
p->combo_sla_print,
p->combo_sla_material,
p->combo_printer })
combo->msw_rescale();
for (PresetComboBox* combo : p->combos_filament)
for (PlaterPresetComboBox* combo : p->combos_filament)
combo->msw_rescale();
// ... then refill them and set min size to correct layout of the sidebar
@ -1458,7 +1306,7 @@ void Sidebar::update_ui_from_settings()
update_sliced_info_sizer();
}
std::vector<PresetComboBox*>& Sidebar::combos_filament()
std::vector<PlaterPresetComboBox*>& Sidebar::combos_filament()
{
return p->combos_filament;
}
@ -3339,7 +3187,7 @@ void Plater::priv::set_current_panel(wxPanel* panel)
void Plater::priv::on_select_preset(wxCommandEvent &evt)
{
auto preset_type = static_cast<Preset::Type>(evt.GetInt());
auto *combo = static_cast<PresetComboBox*>(evt.GetEventObject());
auto *combo = static_cast<PlaterPresetComboBox*>(evt.GetEventObject());
// see https://github.com/prusa3d/PrusaSlicer/issues/3889
// Under OSX: in case of use of a same names written in different case (like "ENDER" and "Ender"),
@ -3368,7 +3216,7 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt)
// TODO: ?
if (preset_type == Preset::TYPE_FILAMENT && sidebar->is_multifilament()) {
// Only update the plater UI for the 2nd and other filaments.
wxGetApp().preset_bundle->update_plater_filament_ui(idx, combo);
combo->update();
}
else {
wxWindowUpdateLocker noUpdates(sidebar->presets_panel());
@ -5154,12 +5002,12 @@ void Plater::on_extruders_change(size_t num_extruders)
size_t i = choices.size();
while ( i < num_extruders )
{
PresetComboBox* choice/*{ nullptr }*/;
PlaterPresetComboBox* choice/*{ nullptr }*/;
sidebar().init_filament_combo(&choice, i);
choices.push_back(choice);
// initialize selection
wxGetApp().preset_bundle->update_plater_filament_ui(i, choice);
choice->update();
++i;
}

View file

@ -6,14 +6,12 @@
#include <boost/filesystem/path.hpp>
#include <wx/panel.h>
#include <wx/bmpcbox.h>
#include "Preset.hpp"
#include "Selection.hpp"
#include "libslic3r/BoundingBox.hpp"
#include "Jobs/Job.hpp"
#include "wxExtensions.hpp"
#include "Search.hpp"
class wxButton;
@ -50,46 +48,13 @@ class Mouse3DController;
struct Camera;
class Bed3D;
class GLToolbar;
class PlaterPresetComboBox;
using t_optgroups = std::vector <std::shared_ptr<ConfigOptionsGroup>>;
class Plater;
enum class ActionButtonType : int;
class PresetComboBox : public PresetBitmapComboBox
{
public:
PresetComboBox(wxWindow *parent, Preset::Type preset_type);
~PresetComboBox();
ScalableButton* edit_btn { nullptr };
enum LabelItemType {
LABEL_ITEM_MARKER = 0xffffff01,
LABEL_ITEM_WIZARD_PRINTERS,
LABEL_ITEM_WIZARD_FILAMENTS,
LABEL_ITEM_WIZARD_MATERIALS,
LABEL_ITEM_MAX,
};
void set_label_marker(int item, LabelItemType label_item_type = LABEL_ITEM_MARKER);
void set_extruder_idx(const int extr_idx) { extruder_idx = extr_idx; }
int get_extruder_idx() const { return extruder_idx; }
int em_unit() const { return m_em_unit; }
void check_selection(int selection);
void msw_rescale();
private:
typedef std::size_t Marker;
Preset::Type preset_type;
int last_selected;
int extruder_idx = -1;
int m_em_unit;
};
class Sidebar : public wxPanel
{
ConfigOptionMode m_mode;
@ -101,7 +66,7 @@ public:
Sidebar &operator=(const Sidebar &) = delete;
~Sidebar();
void init_filament_combo(PresetComboBox **combo, const int extr_idx);
void init_filament_combo(PlaterPresetComboBox **combo, const int extr_idx);
void remove_unused_filament_combos(const size_t current_extruder_count);
void update_all_preset_comboboxes();
void update_presets(Slic3r::Preset::Type preset_type);
@ -139,7 +104,7 @@ public:
void update_searcher();
void update_ui_from_settings();
std::vector<PresetComboBox*>& combos_filament();
std::vector<PlaterPresetComboBox*>& combos_filament();
Search::OptionsSearcher& get_searcher();
std::string& get_search_line();

View file

@ -2,9 +2,7 @@
#include "Preset.hpp"
#include "AppConfig.hpp"
#include "BitmapCache.hpp"
#include "I18N.hpp"
#include "wxExtensions.hpp"
#ifdef _MSC_VER
#define WIN32_LEAN_AND_MEAN
@ -30,15 +28,9 @@
#include <boost/locale.hpp>
#include <boost/log/trivial.hpp>
#include <wx/image.h>
#include <wx/choice.h>
#include <wx/bmpcbox.h>
#include <wx/wupdlock.h>
#include "libslic3r/libslic3r.h"
#include "libslic3r/Utils.hpp"
#include "libslic3r/PlaceholderParser.hpp"
#include "Plater.hpp"
using boost::property_tree::ptree;
@ -590,10 +582,7 @@ const std::vector<std::string>& Preset::sla_printer_options()
PresetCollection::PresetCollection(Preset::Type type, const std::vector<std::string> &keys, const Slic3r::StaticPrintConfig &defaults, const std::string &default_name) :
m_type(type),
m_edited_preset(type, "", false),
m_idx_selected(0),
m_bitmap_main_frame(new wxBitmap),
m_bitmap_add(new wxBitmap),
m_bitmap_cache(new GUI::BitmapCache)
m_idx_selected(0)
{
// Insert just the default preset.
this->add_default_preset(keys, defaults, default_name);
@ -602,12 +591,6 @@ PresetCollection::PresetCollection(Preset::Type type, const std::vector<std::str
PresetCollection::~PresetCollection()
{
delete m_bitmap_main_frame;
m_bitmap_main_frame = nullptr;
delete m_bitmap_add;
m_bitmap_add = nullptr;
delete m_bitmap_cache;
m_bitmap_cache = nullptr;
}
void PresetCollection::reset(bool delete_files)
@ -951,16 +934,6 @@ bool PresetCollection::delete_preset(const std::string& name)
return true;
}
void PresetCollection::load_bitmap_default(const std::string &file_name)
{
*m_bitmap_main_frame = create_scaled_bitmap(file_name);
}
void PresetCollection::load_bitmap_add(const std::string &file_name)
{
*m_bitmap_add = create_scaled_bitmap(file_name);
}
const Preset* PresetCollection::get_selected_preset_parent() const
{
if (this->get_selected_idx() == size_t(-1))
@ -1119,279 +1092,15 @@ size_t PresetCollection::update_compatible_internal(const PresetWithVendorProfil
// Delete the current preset, activate the first visible preset.
//void PresetCollection::delete_current_preset();
// Update the wxChoice UI component from this list of presets.
// Hide the
void PresetCollection::update_plater_ui(GUI::PresetComboBox *ui)
{
if (ui == nullptr)
return;
// Otherwise fill in the list from scratch.
ui->Freeze();
ui->Clear();
size_t selected_preset_item = INT_MAX; // some value meaning that no one item is selected
const Preset &selected_preset = this->get_selected_preset();
// Show wide icons if the currently selected preset is not compatible with the current printer,
// and draw a red flag in front of the selected preset.
bool wide_icons = ! selected_preset.is_compatible && m_bitmap_incompatible != nullptr;
/* It's supposed that standard size of an icon is 16px*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 float scale_f = ui->em_unit() * 0.1f;
const int icon_height = 16 * scale_f + 0.5f;
const int icon_width = 16 * scale_f + 0.5f;
const int thin_space_icon_width = 4 * scale_f + 0.5f;
const int wide_space_icon_width = 6 * scale_f + 0.5f;
std::map<wxString, wxBitmap*> nonsys_presets;
wxString selected = "";
wxString tooltip = "";
if (!this->m_presets.front().is_visible)
ui->set_label_marker(ui->Append(PresetCollection::separator(L("System presets")), wxNullBitmap));
for (size_t i = this->m_presets.front().is_visible ? 0 : m_num_default_presets; i < this->m_presets.size(); ++ i) {
const Preset &preset = this->m_presets[i];
if (! preset.is_visible || (! preset.is_compatible && i != m_idx_selected))
continue;
std::string bitmap_key = "";
// !!! Temporary solution, till refactoring: create and use "sla_printer" icon instead of m_bitmap_main_frame
wxBitmap main_bmp = m_bitmap_main_frame ? *m_bitmap_main_frame : wxNullBitmap;
if (m_type == Preset::TYPE_PRINTER && preset.printer_technology()==ptSLA ) {
bitmap_key = "sla_printer";
main_bmp = create_scaled_bitmap("sla_printer");
}
// If the filament preset is not compatible and there is a "red flag" icon loaded, show it left
// to the filament color image.
if (wide_icons)
bitmap_key += preset.is_compatible ? ",cmpt" : ",ncmpt";
bitmap_key += (preset.is_system || preset.is_default) ? ",syst" : ",nsyst";
wxBitmap *bmp = m_bitmap_cache->find(bitmap_key);
if (bmp == nullptr) {
// Create the bitmap with color bars.
std::vector<wxBitmap> bmps;
if (wide_icons)
// Paint a red flag for incompatible presets.
bmps.emplace_back(preset.is_compatible ? m_bitmap_cache->mkclear(icon_width, icon_height) : *m_bitmap_incompatible);
// Paint the color bars.
bmps.emplace_back(m_bitmap_cache->mkclear(thin_space_icon_width, icon_height));
bmps.emplace_back(main_bmp);
// Paint a lock at the system presets.
bmps.emplace_back(m_bitmap_cache->mkclear(wide_space_icon_width, icon_height));
bmps.emplace_back((preset.is_system || preset.is_default) ? *m_bitmap_lock : m_bitmap_cache->mkclear(icon_width, icon_height));
bmp = m_bitmap_cache->insert(bitmap_key, bmps);
}
const std::string name = preset.alias.empty() ? preset.name : preset.alias;
if (preset.is_default || preset.is_system) {
ui->Append(wxString::FromUTF8((/*preset.*/name + (preset.is_dirty ? g_suffix_modified : "")).c_str()),
(bmp == 0) ? main_bmp : *bmp);
if (i == m_idx_selected ||
// just in case: mark selected_preset_item as a first added element
selected_preset_item == INT_MAX) {
selected_preset_item = ui->GetCount() - 1;
tooltip = wxString::FromUTF8(preset.name.c_str());
}
}
else
{
nonsys_presets.emplace(wxString::FromUTF8((/*preset.*/name + (preset.is_dirty ? g_suffix_modified : "")).c_str()), bmp/*preset.is_compatible*/);
if (i == m_idx_selected) {
selected = wxString::FromUTF8((/*preset.*/name + (preset.is_dirty ? g_suffix_modified : "")).c_str());
tooltip = wxString::FromUTF8(preset.name.c_str());
}
}
if (i + 1 == m_num_default_presets)
ui->set_label_marker(ui->Append(PresetCollection::separator(L("System presets")), wxNullBitmap));
}
if (!nonsys_presets.empty())
{
ui->set_label_marker(ui->Append(PresetCollection::separator(L("User presets")), wxNullBitmap));
for (std::map<wxString, wxBitmap*>::iterator it = nonsys_presets.begin(); it != nonsys_presets.end(); ++it) {
ui->Append(it->first, *it->second);
if (it->first == selected ||
// just in case: mark selected_preset_item as a first added element
selected_preset_item == INT_MAX)
selected_preset_item = ui->GetCount() - 1;
}
}
if (m_type == Preset::TYPE_PRINTER || m_type == Preset::TYPE_SLA_MATERIAL) {
std::string bitmap_key = "";
// If the filament preset is not compatible and there is a "red flag" icon loaded, show it left
// to the filament color image.
if (wide_icons)
bitmap_key += "wide,";
bitmap_key += "edit_preset_list";
wxBitmap *bmp = m_bitmap_cache->find(bitmap_key);
if (bmp == nullptr) {
// Create the bitmap with color bars.
std::vector<wxBitmap> bmps;
if (wide_icons)
// Paint a red flag for incompatible presets.
bmps.emplace_back(m_bitmap_cache->mkclear(icon_width, icon_height));
// Paint the color bars.
bmps.emplace_back(m_bitmap_cache->mkclear(thin_space_icon_width, icon_height));
bmps.emplace_back(*m_bitmap_main_frame);
// Paint a lock at the system presets.
bmps.emplace_back(m_bitmap_cache->mkclear(wide_space_icon_width, icon_height));
// bmps.emplace_back(m_bitmap_add ? *m_bitmap_add : wxNullBitmap);
bmps.emplace_back(create_scaled_bitmap("edit_uni"));
bmp = m_bitmap_cache->insert(bitmap_key, bmps);
}
if (m_type == Preset::TYPE_SLA_MATERIAL)
ui->set_label_marker(ui->Append(PresetCollection::separator(L("Add/Remove materials")), *bmp), GUI::PresetComboBox::LABEL_ITEM_WIZARD_MATERIALS);
else
ui->set_label_marker(ui->Append(PresetCollection::separator(L("Add/Remove printers")), *bmp), GUI::PresetComboBox::LABEL_ITEM_WIZARD_PRINTERS);
}
/* But, if selected_preset_item is still equal to INT_MAX, it means that
* there is no presets added to the list.
* So, select last combobox item ("Add/Remove preset")
*/
if (selected_preset_item == INT_MAX)
selected_preset_item = ui->GetCount() - 1;
ui->SetSelection(selected_preset_item);
ui->SetToolTip(tooltip.IsEmpty() ? ui->GetString(selected_preset_item) : tooltip);
ui->check_selection(selected_preset_item);
ui->Thaw();
// Update control min size after rescale (changed Display DPI under MSW)
if (ui->GetMinWidth() != 20 * ui->em_unit())
ui->SetMinSize(wxSize(20 * ui->em_unit(), ui->GetSize().GetHeight()));
}
size_t PresetCollection::update_tab_ui(wxBitmapComboBox *ui, bool show_incompatible, const int em/* = 10*/)
{
if (ui == nullptr)
return 0;
ui->Freeze();
ui->Clear();
size_t selected_preset_item = INT_MAX; // some value meaning that no one item is selected
/* It's supposed that standard size of an icon is 16px*16px for 100% scaled display.
* So set sizes for solid_colored(empty) icons used for preset
* and scale them in respect to em_unit value
*/
const float scale_f = em * 0.1f;
const int icon_height = 16 * scale_f + 0.5f;
const int icon_width = 16 * scale_f + 0.5f;
std::map<wxString, wxBitmap*> nonsys_presets;
wxString selected = "";
if (!this->m_presets.front().is_visible)
ui->Append(PresetCollection::separator(L("System presets")), wxNullBitmap);
for (size_t i = this->m_presets.front().is_visible ? 0 : m_num_default_presets; i < this->m_presets.size(); ++i) {
const Preset &preset = this->m_presets[i];
if (! preset.is_visible || (! show_incompatible && ! preset.is_compatible && i != m_idx_selected))
continue;
std::string bitmap_key = "tab";
// !!! Temporary solution, till refactoring: create and use "sla_printer" icon instead of m_bitmap_main_frame
wxBitmap main_bmp = m_bitmap_main_frame ? *m_bitmap_main_frame : wxNullBitmap;
if (m_type == Preset::TYPE_PRINTER && preset.printer_technology() == ptSLA) {
bitmap_key = "sla_printer";
main_bmp = create_scaled_bitmap("sla_printer");
}
bitmap_key += preset.is_compatible ? ",cmpt" : ",ncmpt";
bitmap_key += (preset.is_system || preset.is_default) ? ",syst" : ",nsyst";
wxBitmap *bmp = m_bitmap_cache->find(bitmap_key);
if (bmp == nullptr) {
// Create the bitmap with color bars.
std::vector<wxBitmap> bmps;
const wxBitmap* tmp_bmp = preset.is_compatible ? m_bitmap_compatible : m_bitmap_incompatible;
bmps.emplace_back((tmp_bmp == 0) ? main_bmp : *tmp_bmp);
// Paint a lock at the system presets.
bmps.emplace_back((preset.is_system || preset.is_default) ? *m_bitmap_lock : m_bitmap_cache->mkclear(icon_width, icon_height));
bmp = m_bitmap_cache->insert(bitmap_key, bmps);
}
if (preset.is_default || preset.is_system) {
ui->Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()),
(bmp == 0) ? main_bmp : *bmp);
if (i == m_idx_selected ||
// just in case: mark selected_preset_item as a first added element
selected_preset_item == INT_MAX)
selected_preset_item = ui->GetCount() - 1;
}
else
{
nonsys_presets.emplace(wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()), bmp/*preset.is_compatible*/);
if (i == m_idx_selected)
selected = wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str());
}
if (i + 1 == m_num_default_presets)
ui->Append(PresetCollection::separator(L("System presets")), wxNullBitmap);
}
if (!nonsys_presets.empty())
{
ui->Append(PresetCollection::separator(L("User presets")), wxNullBitmap);
for (std::map<wxString, wxBitmap*>::iterator it = nonsys_presets.begin(); it != nonsys_presets.end(); ++it) {
ui->Append(it->first, *it->second);
if (it->first == selected ||
// just in case: mark selected_preset_item as a first added element
selected_preset_item == INT_MAX)
selected_preset_item = ui->GetCount() - 1;
}
}
if (m_type == Preset::TYPE_PRINTER) {
wxBitmap *bmp = m_bitmap_cache->find("edit_printer_list");
if (bmp == nullptr) {
// Create the bitmap with color bars.
std::vector<wxBitmap> bmps;
bmps.emplace_back(*m_bitmap_main_frame);
// bmps.emplace_back(m_bitmap_add ? *m_bitmap_add : wxNullBitmap);
bmps.emplace_back(create_scaled_bitmap("edit_uni"));
bmp = m_bitmap_cache->insert("add_printer_tab", bmps);
}
ui->Append(PresetCollection::separator("Add a new printer"), *bmp);
}
/* But, if selected_preset_item is still equal to INT_MAX, it means that
* there is no presets added to the list.
* So, select last combobox item ("Add/Remove preset")
*/
if (selected_preset_item == INT_MAX)
selected_preset_item = ui->GetCount() - 1;
ui->SetSelection(selected_preset_item);
ui->SetToolTip(ui->GetString(selected_preset_item));
ui->Thaw();
return selected_preset_item;
}
// Update a dirty floag of the current preset, update the labels of the UI component accordingly.
// Update a dirty flag of the current preset
// Return true if the dirty flag changed.
bool PresetCollection::update_dirty_ui(wxBitmapComboBox *ui)
bool PresetCollection::update_dirty()
{
wxWindowUpdateLocker noUpdates(ui);
// 1) Update the dirty flag of the current preset.
bool was_dirty = this->get_selected_preset().is_dirty;
bool is_dirty = current_is_dirty();
this->get_selected_preset().is_dirty = is_dirty;
this->get_edited_preset().is_dirty = is_dirty;
// 2) Update the labels.
for (unsigned int ui_id = 0; ui_id < ui->GetCount(); ++ ui_id) {
std::string old_label = ui->GetString(ui_id).utf8_str().data();
std::string preset_name = Preset::remove_suffix_modified(old_label);
const Preset *preset = this->find_preset(preset_name, false);
// The old_label could be the "----- system presets ------" or the "------- user presets --------" separator.
// assert(preset != nullptr);
if (preset != nullptr) {
std::string new_label = preset->is_dirty ? preset->name + g_suffix_modified : preset->name;
if (old_label != new_label)
ui->SetString(ui_id, wxString::FromUTF8(new_label.c_str()));
}
}
#ifdef __APPLE__
// wxWidgets on OSX do not upload the text of the combo box line automatically.
// Force it to update by re-selecting.
ui->SetSelection(ui->GetSelection());
#endif /* __APPLE __ */
return was_dirty != is_dirty;
}
@ -1605,16 +1314,6 @@ std::string PresetCollection::path_from_name(const std::string &new_name) const
return (boost::filesystem::path(m_dir_path) / file_name).make_preferred().string();
}
void PresetCollection::clear_bitmap_cache()
{
m_bitmap_cache->clear();
}
wxString PresetCollection::separator(const std::string &label)
{
return wxString::FromUTF8(PresetCollection::separator_head()) + _(label) + wxString::FromUTF8(PresetCollection::separator_tail());
}
const Preset& PrinterPresetCollection::default_preset_for(const DynamicPrintConfig &config) const
{
const ConfigOptionEnumGeneric *opt_printer_technology = config.opt<ConfigOptionEnumGeneric>("printer_technology");
@ -1631,7 +1330,108 @@ const Preset* PrinterPresetCollection::find_by_model_id(const std::string &model
return it != cend() ? &*it : nullptr;
}
/*
PhysicalPrinter& PhysicalPrinterCollection::load_external_printer(
// Path to the profile source file (a G-code, an AMF or 3MF file, a config file)
const std::string& path,
// Name of the profile, derived from the source file name.
const std::string& name,
// Original name of the profile, extracted from the loaded config. Empty, if the name has not been stored.
const std::string& original_name,
// Config to initialize the preset from.
const DynamicPrintConfig& config,
// Select the preset after loading?
bool select)
{
// Load the preset over a default preset, so that the missing fields are filled in from the default preset.
DynamicPrintConfig cfg(this->default_printer().config);
cfg.apply_only(config, cfg.keys(), true);
// Is there a preset already loaded with the name stored inside the config?
std::deque<PhysicalPrinter>::iterator it = this->find_printer_internal(original_name);
bool found = it != m_printers.end() && it->name == original_name;
if (!found) {
// Try to match the original_name against the "renamed_from" profile names of loaded system profiles.
/ *
it = this->find_preset_renamed(original_name);
found = it != m_presets.end();
* /
}
if (found) {
if (profile_print_params_same(it->config, cfg)) {
// The preset exists and it matches the values stored inside config.
if (select)
this->select_printer(it - m_printers.begin());
return *it;
}
if (profile_host_params_same_or_anonymized(it->config, cfg) == ProfileHostParams::Anonymized) {
// The project being loaded is anonymized. Replace the empty host keys of the loaded profile with the data from the original profile.
// See "Octoprint Settings when Opening a .3MF file" GH issue #3244
auto opt_update = [it, &cfg](const std::string& opt_key) {
auto opt = it->config.option<ConfigOptionString>(opt_key);
if (opt != nullptr)
cfg.set_key_value(opt_key, opt->clone());
};
opt_update("print_host");
opt_update("printhost_apikey");
opt_update("printhost_cafile");
}
}
// The external preset does not match an internal preset, load the external preset.
std::string new_name;
for (size_t idx = 0;; ++idx) {
std::string suffix;
if (original_name.empty()) {
if (idx > 0)
suffix = " (" + std::to_string(idx) + ")";
}
else {
if (idx == 0)
suffix = " (" + original_name + ")";
else
suffix = " (" + original_name + "-" + std::to_string(idx) + ")";
}
new_name = name + suffix;
it = this->find_printer_internal(new_name);
if (it == m_printers.end() || it->name != new_name)
// Unique profile name. Insert a new profile.
break;
if (profile_print_params_same(it->config, cfg)) {
// The preset exists and it matches the values stored inside config.
if (select)
this->select_printer(it - m_printers.begin());
return *it;
}
// Form another profile name.
}
// Insert a new profile.
PhysicalPrinter& printer = this->load_printer(path, new_name, std::move(cfg), select);
return printer;
}
void PhysicalPrinterCollection::save_printer(const std::string& new_name)
{
// 1) Find the printer with a new_name or create a new one,
// initialize it with the edited config.
auto it = this->find_printer_internal(new_name);
if (it != m_printers.end() && it->name == new_name) {
// Preset with the same name found.
PhysicalPrinter& printer = *it;
// Overwriting an existing preset.
printer.config = std::move(m_edited_printer.config);
}
else {
// Creating a new printer.
PhysicalPrinter& printer = *m_printers.insert(it, m_edited_printer);
std::string old_name = printer.name;
printer.name = new_name;
}
// 2) Activate the saved preset.
this->select_printer_by_name(new_name, true);
// 3) Store the active preset to disk.
this->get_selected_preset().save();
}
*/
namespace PresetUtils {
const VendorProfile::PrinterModel* system_printer_model(const Preset &preset)
{

View file

@ -24,11 +24,6 @@ namespace Slic3r {
class AppConfig;
class PresetBundle;
namespace GUI {
class BitmapCache;
class PresetComboBox;
}
enum ConfigFileType
{
CONFIG_FILE_TYPE_UNKNOWN,
@ -322,18 +317,6 @@ public:
// returns true if the preset was deleted successfully.
bool delete_preset(const std::string& name);
// Load default bitmap to be placed at the wxBitmapComboBox of a MainFrame.
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(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; }
void set_bitmap_incompatible(const wxBitmap *bmp) { m_bitmap_incompatible = bmp; }
void set_bitmap_lock (const wxBitmap *bmp) { m_bitmap_lock = bmp; }
void set_bitmap_lock_open (const wxBitmap *bmp) { m_bitmap_lock_open = bmp; }
// Enable / disable the "- default -" preset.
void set_default_suppressed(bool default_suppressed);
bool is_default_suppressed() const { return m_default_suppressed; }
@ -446,18 +429,9 @@ public:
// Return a sorted list of system preset names.
std::vector<std::string> system_preset_names() const;
// Update the choice UI from the list of presets.
// If show_incompatible, all presets are shown, otherwise only the compatible presets are shown.
// If an incompatible preset is selected, it is shown as well.
size_t update_tab_ui(wxBitmapComboBox *ui, bool show_incompatible, const int em = 10);
// Update the choice UI from the list of presets.
// Only the compatible presets are shown.
// If an incompatible preset is selected, it is shown as well.
void update_plater_ui(GUI::PresetComboBox *ui);
// Update a dirty floag of the current preset, update the labels of the UI component accordingly.
// Update a dirty flag of the current preset
// Return true if the dirty flag changed.
bool update_dirty_ui(wxBitmapComboBox *ui);
bool update_dirty();
// Select a profile by its name. Return true if the selection changed.
// Without force, the selection is only updated if the index changes.
@ -467,16 +441,7 @@ public:
// Generate a file path from a profile name. Add the ".ini" suffix if it is missing.
std::string path_from_name(const std::string &new_name) const;
void clear_bitmap_cache();
#ifdef __linux__
static const char* separator_head() { return "------- "; }
static const char* separator_tail() { return " -------"; }
#else /* __linux__ */
static const char* separator_head() { return "————— "; }
static const char* separator_tail() { return " —————"; }
#endif /* __linux__ */
static wxString separator(const std::string &label);
size_t num_default_presets() { return m_num_default_presets; }
protected:
// Select a preset, if it exists. If it does not exist, select an invalid (-1) index.
@ -547,23 +512,10 @@ private:
// Is the "- default -" preset suppressed?
bool m_default_suppressed = true;
size_t m_num_default_presets = 0;
// Compatible & incompatible marks, to be placed at the wxBitmapComboBox items of a Plater.
// These bitmaps are not owned by PresetCollection, but by a PresetBundle.
const wxBitmap *m_bitmap_compatible = nullptr;
const wxBitmap *m_bitmap_incompatible = nullptr;
const wxBitmap *m_bitmap_lock = nullptr;
const wxBitmap *m_bitmap_lock_open = nullptr;
// Marks placed at the wxBitmapComboBox of a MainFrame.
// These bitmaps are owned by PresetCollection.
wxBitmap *m_bitmap_main_frame;
// "Add printer profile" icon, owned by PresetCollection.
wxBitmap *m_bitmap_add;
// Path to the directory to store the config files into.
std::string m_dir_path;
// Caching color bitmaps for the filament combo box.
GUI::BitmapCache *m_bitmap_cache = nullptr;
// to access select_preset_by_name_strict()
friend class PresetBundle;
};
@ -585,6 +537,178 @@ namespace PresetUtils {
const VendorProfile::PrinterModel* system_printer_model(const Preset &preset);
} // namespace PresetUtils
//////////////////////////////////////////////////////////////////////
class PhysicalPrinter
{
public:
PhysicalPrinter(const std::string& name) : name(name) {}
// Name of the Physical Printer, usually derived form the file name.
std::string name;
// File name of the Physical Printer.
std::string file;
// Name of the related Printer preset
std::string preset_name;
// Has this profile been loaded?
bool loaded = false;
// Configuration data, loaded from a file, or set from the defaults.
DynamicPrintConfig config;
void save() { this->config.save(this->file); }
// Return a printer technology, return ptFFF if the printer technology is not set.
static PrinterTechnology printer_technology(const DynamicPrintConfig& cfg) {
auto* opt = cfg.option<ConfigOptionEnum<PrinterTechnology>>("printer_technology");
// The following assert may trigger when importing some legacy profile,
// but it is safer to keep it here to capture the cases where the "printer_technology" key is queried, where it should not.
return (opt == nullptr) ? ptFFF : opt->value;
}
PrinterTechnology printer_technology() const { return printer_technology(this->config); }
// Sort lexicographically by a preset name. The preset name shall be unique across a single PresetCollection.
bool operator<(const Preset& other) const { return this->name < other.name; }
protected:
friend class PhysicalPrinterCollection;
};
/*
// Collections of presets of the same type (one of the Print, Filament or Printer type).
class PhysicalPrinterCollection
{
public:
// Initialize the PresetCollection with the "- default -" preset.
PhysicalPrinterCollection(const std::vector<std::string>& keys) : m_idx_selected(0) {}
~PhysicalPrinterCollection() {}
typedef std::deque<PhysicalPrinter>::iterator Iterator;
typedef std::deque<PhysicalPrinter>::const_iterator ConstIterator;
Iterator begin() { return m_printers.begin(); }
ConstIterator begin() const { return m_printers.cbegin(); }
ConstIterator cbegin() const { return m_printers.cbegin(); }
Iterator end() { return m_printers.end(); }
ConstIterator end() const { return m_printers.cend(); }
ConstIterator cend() const { return m_printers.cend(); }
void reset(bool delete_files) {};
const std::deque<PhysicalPrinter>& operator()() const { return m_printers; }
// Load ini files of the particular type from the provided directory path.
void load_printers(const std::string& dir_path, const std::string& subdir){};
// Load a preset from an already parsed config file, insert it into the sorted sequence of presets
// and select it, losing previous modifications.
PhysicalPrinter& load_printer(const std::string& path, const std::string& name, const DynamicPrintConfig& config, bool select = true);
PhysicalPrinter& load_printer(const std::string& path, const std::string& name, DynamicPrintConfig&& config, bool select = true);
PhysicalPrinter& load_external_printer(
// Path to the profile source file (a G-code, an AMF or 3MF file, a config file)
const std::string& path,
// Name of the profile, derived from the source file name.
const std::string& name,
// Original name of the profile, extracted from the loaded config. Empty, if the name has not been stored.
const std::string& original_name,
// Config to initialize the preset from.
const DynamicPrintConfig& config,
// Select the preset after loading?
bool select = true);
// Save the printer under a new name. If the name is different from the old one,
// a new printer is stored into the list of printers.
// ? New printer is activated.
void save_printer(const std::string& new_name);
// Delete the current preset, activate the first visible preset.
// returns true if the preset was deleted successfully.
bool delete_current_printer() {return true;}
// Delete the current preset, activate the first visible preset.
// returns true if the preset was deleted successfully.
bool delete_printer(const std::string& name) { return true; }
// Select a printer. If an invalid index is provided, the first visible printer is selected.
PhysicalPrinter& select_printer(size_t idx);
// Return the selected preset, without the user modifications applied.
PhysicalPrinter& get_selected_preset() { return m_printers[m_idx_selected]; }
const PhysicalPrinter& get_selected_preset() const { return m_printers[m_idx_selected]; }
size_t get_selected_idx() const { return m_idx_selected; }
// Returns the name of the selected preset, or an empty string if no preset is selected.
std::string get_selected_preset_name() const { return (m_idx_selected == size_t(-1)) ? std::string() : this->get_selected_preset().name; }
PhysicalPrinter& get_edited_preset() { return m_edited_printer; }
const PhysicalPrinter& get_edited_preset() const { return m_edited_printer; }
// Return a preset possibly with modifications.
PhysicalPrinter& default_printer(size_t idx = 0) { return m_printers[idx]; }
const PhysicalPrinter& default_printer(size_t idx = 0) const { return m_printers[idx]; }
// used to update preset_choice from Tab
const std::deque<PhysicalPrinter>& get_presets() const { return m_printers; }
size_t get_idx_selected() { return m_idx_selected; }
// Return a preset by an index. If the preset is active, a temporary copy is returned.
PhysicalPrinter& printer(size_t idx) { return (idx == m_idx_selected) ? m_edited_printer : m_printers[idx]; }
const PhysicalPrinter& printer(size_t idx) const { return const_cast<PhysicalPrinterCollection*>(this)->printer(idx); }
// Return a preset by its name. If the preset is active, a temporary copy is returned.
// If a preset is not found by its name, null is returned.
PhysicalPrinter* find_printer(const std::string& name, bool first_visible_if_not_found = false);
const PhysicalPrinter* find_printer(const std::string& name, bool first_visible_if_not_found = false) const
{
return const_cast<PhysicalPrinterCollection*>(this)->find_printer(name, first_visible_if_not_found);
}
// Return number of presets including the "- default -" preset.
size_t size() const { return m_printers.size(); }
// Select a profile by its name. Return true if the selection changed.
// Without force, the selection is only updated if the index changes.
// With force, the changes are reverted if the new index is the same as the old index.
bool select_printer_by_name(const std::string& name, bool force) {};
// Generate a file path from a profile name. Add the ".ini" suffix if it is missing.
std::string path_from_name(const std::string& new_name) const;
private:
// PhysicalPrinterCollection();
PhysicalPrinterCollection(const PhysicalPrinterCollection& other);
PhysicalPrinterCollection& operator=(const PhysicalPrinterCollection& other);
// Find a preset position in the sorted list of presets.
// The "-- default -- " preset is always the first, so it needs
// to be handled differently.
// If a preset does not exist, an iterator is returned indicating where to insert a preset with the same name.
std::deque<PhysicalPrinter>::iterator find_printer_internal(const std::string& name)
{
PhysicalPrinter key(name);
auto it = std::lower_bound(m_printers.begin()+0, m_printers.end(), key);
return it;
}
std::deque<PhysicalPrinter>::const_iterator find_printer_internal(const std::string& name) const
{
return const_cast<PhysicalPrinterCollection*>(this)->find_printer_internal(name);
}
static std::vector<std::string> dirty_options(const Preset* edited, const Preset* reference, const bool is_printer_type = false);
// List of presets, starting with the "- default -" preset.
// Use deque to force the container to allocate an object per each entry,
// so that the addresses of the presets don't change during resizing of the container.
std::deque<PhysicalPrinter> m_printers;
// Initially this printer contains a copy of the selected printer. Later on, this copy may be modified by the user.
PhysicalPrinter m_edited_printer;
// Selected preset.
size_t m_idx_selected;
// Path to the directory to store the config files into.
std::string m_dir_path;
};
//////////////////////////////////////////////////////////////////////
*/
} // namespace Slic3r
#endif /* slic3r_Preset_hpp_ */

View file

@ -1,12 +1,10 @@
#include <cassert>
#include "PresetBundle.hpp"
#include "BitmapCache.hpp"
#include "Plater.hpp"
#include "I18N.hpp"
#include "wxExtensions.hpp"
#include <algorithm>
#include <set>
#include <fstream>
#include <unordered_set>
#include <boost/filesystem.hpp>
@ -21,16 +19,13 @@
#include <boost/locale.hpp>
#include <boost/log/trivial.hpp>
#include <wx/dcmemory.h>
#include <wx/image.h>
#include <wx/choice.h>
#include <wx/bmpcbox.h>
#include <wx/wupdlock.h>
#include "libslic3r/libslic3r.h"
#include "libslic3r/Utils.hpp"
#include "libslic3r/Model.hpp"
#include "GUI_App.hpp"
#include "libslic3r/CustomGCode.hpp"
// Store the print/filament/printer presets into a "presets" subdirectory of the Slic3rPE config dir.
@ -52,12 +47,7 @@ PresetBundle::PresetBundle() :
filaments(Preset::TYPE_FILAMENT, Preset::filament_options(), static_cast<const HostConfig&>(FullPrintConfig::defaults())),
sla_materials(Preset::TYPE_SLA_MATERIAL, Preset::sla_material_options(), static_cast<const SLAMaterialConfig&>(SLAFullPrintConfig::defaults())),
sla_prints(Preset::TYPE_SLA_PRINT, Preset::sla_print_options(), static_cast<const SLAPrintObjectConfig&>(SLAFullPrintConfig::defaults())),
printers(Preset::TYPE_PRINTER, Preset::printer_options(), static_cast<const HostConfig&>(FullPrintConfig::defaults()), "- default FFF -"),
m_bitmapCompatible(new wxBitmap),
m_bitmapIncompatible(new wxBitmap),
m_bitmapLock(new wxBitmap),
m_bitmapLockOpen(new wxBitmap),
m_bitmapCache(new GUI::BitmapCache)
printers(Preset::TYPE_PRINTER, Preset::printer_options(), static_cast<const HostConfig&>(FullPrintConfig::defaults()), "- default FFF -")
{
if (wxImage::FindHandler(wxBITMAP_TYPE_PNG) == nullptr)
wxImage::AddHandler(new wxPNGHandler);
@ -112,16 +102,6 @@ PresetBundle::PresetBundle() :
preset.inherits();
}
// Load the default preset bitmaps.
// #ys_FIXME_to_delete we'll load them later, using em_unit()
// this->prints .load_bitmap_default("cog");
// this->sla_prints .load_bitmap_default("package_green.png");
// this->filaments .load_bitmap_default("spool.png");
// this->sla_materials.load_bitmap_default("package_green.png");
// this->printers .load_bitmap_default("printer_empty.png");
// this->printers .load_bitmap_add("add.png");
// this->load_compatible_bitmaps();
// Re-activate the default presets, so their "edited" preset copies will be updated with the additional configuration values above.
this->prints .select_preset(0);
this->sla_prints .select_preset(0);
@ -134,20 +114,6 @@ PresetBundle::PresetBundle() :
PresetBundle::~PresetBundle()
{
assert(m_bitmapCompatible != nullptr);
assert(m_bitmapIncompatible != nullptr);
assert(m_bitmapLock != nullptr);
assert(m_bitmapLockOpen != nullptr);
delete m_bitmapCompatible;
m_bitmapCompatible = nullptr;
delete m_bitmapIncompatible;
m_bitmapIncompatible = nullptr;
delete m_bitmapLock;
m_bitmapLock = nullptr;
delete m_bitmapLockOpen;
m_bitmapLockOpen = nullptr;
delete m_bitmapCache;
m_bitmapCache = nullptr;
}
void PresetBundle::reset(bool delete_files)
@ -486,36 +452,6 @@ void PresetBundle::export_selections(AppConfig &config)
config.set("presets", "printer", printers.get_selected_preset_name());
}
void PresetBundle::load_compatible_bitmaps()
{
*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);
sla_prints .set_bitmap_compatible(m_bitmapCompatible);
sla_materials.set_bitmap_compatible(m_bitmapCompatible);
prints .set_bitmap_incompatible(m_bitmapIncompatible);
filaments .set_bitmap_incompatible(m_bitmapIncompatible);
sla_prints .set_bitmap_incompatible(m_bitmapIncompatible);
sla_materials.set_bitmap_incompatible(m_bitmapIncompatible);
prints .set_bitmap_lock(m_bitmapLock);
filaments .set_bitmap_lock(m_bitmapLock);
sla_prints .set_bitmap_lock(m_bitmapLock);
sla_materials.set_bitmap_lock(m_bitmapLock);
printers .set_bitmap_lock(m_bitmapLock);
prints .set_bitmap_lock_open(m_bitmapLock);
filaments .set_bitmap_lock_open(m_bitmapLock);
sla_prints .set_bitmap_lock_open(m_bitmapLock);
sla_materials.set_bitmap_lock_open(m_bitmapLock);
printers .set_bitmap_lock_open(m_bitmapLock);
}
DynamicPrintConfig PresetBundle::full_config() const
{
return (this->printers.get_edited_preset().printer_technology() == ptFFF) ?
@ -886,7 +822,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
// 4) Load the project config values (the per extruder wipe matrix etc).
this->project_config.apply_only(config, s_project_options);
update_custom_gcode_per_print_z_from_config(GUI::wxGetApp().plater()->model().custom_gcode_per_print_z, &this->project_config);
CustomGCode::update_custom_gcode_per_print_z_from_config(GUI::wxGetApp().plater()->model().custom_gcode_per_print_z, &this->project_config);
break;
}
@ -1544,207 +1480,11 @@ void PresetBundle::export_configbundle(const std::string &path, bool export_syst
// an optional "(modified)" suffix will be removed from the filament name.
void PresetBundle::set_filament_preset(size_t idx, const std::string &name)
{
if (name.find_first_of(PresetCollection::separator_head()) == 0)
return;
if (idx >= filament_presets.size())
if (idx >= filament_presets.size())
filament_presets.resize(idx + 1, filaments.default_preset().name);
filament_presets[idx] = Preset::remove_suffix_modified(name);
}
void PresetBundle::load_default_preset_bitmaps()
{
// Clear bitmap cache, before load new scaled default preset bitmaps
m_bitmapCache->clear();
this->prints.clear_bitmap_cache();
this->sla_prints.clear_bitmap_cache();
this->filaments.clear_bitmap_cache();
this->sla_materials.clear_bitmap_cache();
this->printers.clear_bitmap_cache();
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)
{
if (ui == nullptr || this->printers.get_edited_preset().printer_technology() == ptSLA ||
this->filament_presets.size() <= idx_extruder )
return;
unsigned char rgb[3];
std::string extruder_color = this->printers.get_edited_preset().config.opt_string("extruder_colour", idx_extruder);
if (!m_bitmapCache->parse_color(extruder_color, rgb))
// Extruder color is not defined.
extruder_color.clear();
// Fill in the list from scratch.
ui->Freeze();
ui->Clear();
size_t selected_preset_item = INT_MAX; // some value meaning that no one item is selected
const Preset *selected_preset = this->filaments.find_preset(this->filament_presets[idx_extruder]);
// Show wide icons if the currently selected preset is not compatible with the current printer,
// and draw a red flag in front of the selected preset.
bool wide_icons = selected_preset != nullptr && ! selected_preset->is_compatible && m_bitmapIncompatible != nullptr;
assert(selected_preset != nullptr);
std::map<wxString, wxBitmap*> nonsys_presets;
wxString selected_str = "";
if (!this->filaments().front().is_visible)
ui->set_label_marker(ui->Append(PresetCollection::separator(L("System presets")), wxNullBitmap));
/* It's supposed that standard size of an icon is 16px*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 float scale_f = ui->em_unit() * 0.1f;
// To avoid the errors of number rounding for different combination of monitor configuration,
// let use scaled 8px, as a smallest icon unit
const int icon_unit = 8 * scale_f + 0.5f;
const int normal_icon_width = 2 * icon_unit; //16 * scale_f + 0.5f;
const int thin_icon_width = icon_unit; //8 * scale_f + 0.5f;
const int wide_icon_width = 3 * icon_unit; //24 * scale_f + 0.5f;
const int space_icon_width = 2 * scale_f + 0.5f;
// To avoid asserts, each added bitmap to wxBitmapCombobox should be the same size, so
// set a bitmap height to m_bitmapLock->GetHeight()
//
// To avoid asserts, each added bitmap to wxBitmapCombobox should be the same size.
// But for some display scaling (for example 125% or 175%) normal_icon_width differs from icon width.
// So:
// for nonsystem presets set a width of empty bitmap to m_bitmapLock->GetWidth()
// for compatible presets set a width of empty bitmap to m_bitmapIncompatible->GetWidth()
//
// Note, under OSX we should use a Scaled Height/Width because of Retina scale
#ifdef __APPLE__
const int icon_height = m_bitmapLock->GetScaledHeight();
const int lock_icon_width = m_bitmapLock->GetScaledWidth();
const int flag_icon_width = m_bitmapIncompatible->GetScaledWidth();
#else
const int icon_height = m_bitmapLock->GetHeight();
const int lock_icon_width = m_bitmapLock->GetWidth();
const int flag_icon_width = m_bitmapIncompatible->GetWidth();
#endif
wxString tooltip = "";
for (int i = this->filaments().front().is_visible ? 0 : 1; i < int(this->filaments().size()); ++i) {
const Preset &preset = this->filaments.preset(i);
bool selected = this->filament_presets[idx_extruder] == preset.name;
if (! preset.is_visible || (! preset.is_compatible && ! selected))
continue;
// Assign an extruder color to the selected item if the extruder color is defined.
std::string filament_rgb = preset.config.opt_string("filament_colour", 0);
std::string extruder_rgb = (selected && !extruder_color.empty()) ? extruder_color : filament_rgb;
bool single_bar = filament_rgb == extruder_rgb;
std::string bitmap_key = single_bar ? filament_rgb : filament_rgb + extruder_rgb;
// If the filament preset is not compatible and there is a "red flag" icon loaded, show it left
// to the filament color image.
if (wide_icons)
bitmap_key += preset.is_compatible ? ",cmpt" : ",ncmpt";
bitmap_key += (preset.is_system || preset.is_default) ? ",syst" : ",nsyst";
if (preset.is_dirty)
bitmap_key += ",drty";
wxBitmap *bitmap = m_bitmapCache->find(bitmap_key);
if (bitmap == nullptr) {
// Create the bitmap with color bars.
std::vector<wxBitmap> bmps;
if (wide_icons)
// Paint a red flag for incompatible presets.
bmps.emplace_back(preset.is_compatible ? m_bitmapCache->mkclear(flag_icon_width, icon_height) : *m_bitmapIncompatible);
// Paint the color bars.
m_bitmapCache->parse_color(filament_rgb, rgb);
bmps.emplace_back(m_bitmapCache->mksolid(single_bar ? wide_icon_width : normal_icon_width, icon_height, rgb));
if (! single_bar) {
m_bitmapCache->parse_color(extruder_rgb, rgb);
bmps.emplace_back(m_bitmapCache->mksolid(thin_icon_width, icon_height, rgb));
}
// Paint a lock at the system presets.
bmps.emplace_back(m_bitmapCache->mkclear(space_icon_width, icon_height));
bmps.emplace_back((preset.is_system || preset.is_default) ? *m_bitmapLock : m_bitmapCache->mkclear(lock_icon_width, icon_height));
// (preset.is_dirty ? *m_bitmapLockOpen : *m_bitmapLock) : m_bitmapCache->mkclear(16, 16));
bitmap = m_bitmapCache->insert(bitmap_key, bmps);
}
const std::string name = preset.alias.empty() ? preset.name : preset.alias;
if (preset.is_default || preset.is_system) {
ui->Append(wxString::FromUTF8((/*preset.*/name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str()),
(bitmap == 0) ? wxNullBitmap : *bitmap);
if (selected ||
// just in case: mark selected_preset_item as a first added element
selected_preset_item == INT_MAX ) {
selected_preset_item = ui->GetCount() - 1;
tooltip = wxString::FromUTF8(preset.name.c_str());
}
}
else
{
nonsys_presets.emplace(wxString::FromUTF8((/*preset.*/name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str()),
(bitmap == 0) ? &wxNullBitmap : bitmap);
if (selected) {
selected_str = wxString::FromUTF8((/*preset.*/name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str());
tooltip = wxString::FromUTF8(preset.name.c_str());
}
}
if (preset.is_default)
ui->set_label_marker(ui->Append(PresetCollection::separator(L("System presets")), wxNullBitmap));
}
if (!nonsys_presets.empty())
{
ui->set_label_marker(ui->Append(PresetCollection::separator(L("User presets")), wxNullBitmap));
for (std::map<wxString, wxBitmap*>::iterator it = nonsys_presets.begin(); it != nonsys_presets.end(); ++it) {
ui->Append(it->first, *it->second);
if (it->first == selected_str ||
// just in case: mark selected_preset_item as a first added element
selected_preset_item == INT_MAX) {
selected_preset_item = ui->GetCount() - 1;
}
}
}
std::string bitmap_key = "";
if (wide_icons)
bitmap_key += "wide,";
bitmap_key += "edit_preset_list";
wxBitmap* bmp = m_bitmapCache->find(bitmap_key);
if (bmp == nullptr) {
// Create the bitmap with color bars.
std::vector<wxBitmap> bmps;
if (wide_icons)
// Paint a red flag for incompatible presets.
bmps.emplace_back(m_bitmapCache->mkclear(flag_icon_width, icon_height));
// Paint the color bars + a lock at the system presets.
bmps.emplace_back(m_bitmapCache->mkclear(wide_icon_width+space_icon_width, icon_height));
bmps.emplace_back(create_scaled_bitmap("edit_uni"));
bmp = m_bitmapCache->insert(bitmap_key, bmps);
}
ui->set_label_marker(ui->Append(PresetCollection::separator(L("Add/Remove filaments")), *bmp), GUI::PresetComboBox::LABEL_ITEM_WIZARD_FILAMENTS);
/* But, if selected_preset_item is still equal to INT_MAX, it means that
* there is no presets added to the list.
* So, select last combobox item ("Add/Remove filaments")
*/
if (selected_preset_item == INT_MAX)
selected_preset_item = ui->GetCount() - 1;
ui->SetSelection(selected_preset_item);
ui->SetToolTip(tooltip.IsEmpty() ? ui->GetString(selected_preset_item) : tooltip);
ui->check_selection(selected_preset_item);
ui->Thaw();
// Update control min size after rescale (changed Display DPI under MSW)
if (ui->GetMinWidth() != 20 * ui->em_unit())
ui->SetMinSize(wxSize(20 * ui->em_unit(), ui->GetSize().GetHeight()));
}
void PresetBundle::set_default_suppressed(bool default_suppressed)
{
prints.set_default_suppressed(default_suppressed);

View file

@ -5,7 +5,6 @@
#include "Preset.hpp"
#include <memory>
#include <set>
#include <unordered_map>
#include <boost/filesystem/path.hpp>
@ -13,10 +12,6 @@ class wxWindow;
namespace Slic3r {
namespace GUI {
class BitmapCache;
};
// Bundle of Print + Filament + Printer presets.
class PresetBundle
{
@ -110,9 +105,6 @@ public:
// Export a config bundle file containing all the presets and the names of the active presets.
void export_configbundle(const std::string &path, bool export_system_settings = false);
// Update a filament selection combo box on the plater for an idx_extruder.
void update_plater_filament_ui(unsigned int idx_extruder, GUI::PresetComboBox *ui);
// Enable / disable the "- default -" preset.
void set_default_suppressed(bool default_suppressed);
@ -132,8 +124,6 @@ public:
void update_compatible(PresetSelectCompatibleType select_other_print_if_incompatible, PresetSelectCompatibleType select_other_filament_if_incompatible);
void update_compatible(PresetSelectCompatibleType select_other_if_incompatible) { this->update_compatible(select_other_if_incompatible, select_other_if_incompatible); }
void load_default_preset_bitmaps();
// Set the is_visible flag for printer vendors, printer models and printer variants
// based on the user configuration.
// If the "vendor" section is missing, enable all models and variants of the particular vendor.
@ -163,21 +153,9 @@ 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();
DynamicPrintConfig full_fff_config() const;
DynamicPrintConfig full_sla_config() const;
// Indicator, that the preset is compatible with the selected printer.
wxBitmap *m_bitmapCompatible;
// Indicator, that the preset is NOT compatible with the selected printer.
wxBitmap *m_bitmapIncompatible;
// Indicator, that the preset is system and not modified.
wxBitmap *m_bitmapLock;
// Indicator, that the preset is system and user modified.
wxBitmap *m_bitmapLockOpen;
// Caching color bitmaps for the filament combo box.
GUI::BitmapCache *m_bitmapCache;
};
} // namespace Slic3r

View file

@ -0,0 +1,794 @@
#include "PresetComboBoxes.hpp"
#include <cstddef>
#include <vector>
#include <string>
#include <boost/algorithm/string.hpp>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include <wx/button.h>
#include <wx/statbox.h>
#include <wx/colordlg.h>
#include <wx/wupdlock.h>
#include "libslic3r/libslic3r.h"
#include "libslic3r/PrintConfig.hpp"
#include "GUI.hpp"
#include "GUI_App.hpp"
#include "Plater.hpp"
#include "MainFrame.hpp"
#include "format.hpp"
#include "Tab.hpp"
#include "PresetBundle.hpp"
#include "PrintHostDialogs.hpp"
#include "ConfigWizard.hpp"
#include "../Utils/ASCIIFolding.hpp"
#include "../Utils/PrintHost.hpp"
#include "../Utils/FixModelByWin10.hpp"
#include "../Utils/UndoRedo.hpp"
#include "RemovableDriveManager.hpp"
#include "BitmapCache.hpp"
using Slic3r::GUI::format_wxstr;
static const std::pair<unsigned int, unsigned int> THUMBNAIL_SIZE_3MF = { 256, 256 };
namespace Slic3r {
namespace GUI {
// ---------------------------------
// *** PresetComboBox ***
// ---------------------------------
/* For PresetComboBox 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.
**/
PresetComboBox::PresetComboBox(wxWindow* parent, Preset::Type preset_type, const wxSize& size) :
wxBitmapComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, size, 0, nullptr, wxCB_READONLY),
m_type(preset_type),
m_last_selected(wxNOT_FOUND),
m_em_unit(wxGetApp().em_unit()),
m_preset_bundle(wxGetApp().preset_bundle),
m_bitmap_cache(new BitmapCache)
{
SetFont(wxGetApp().normal_font());
#ifdef _WIN32
// Workaround for ignoring CBN_EDITCHANGE events, which are processed after the content of the combo box changes, so that
// the index of the item inside CBN_EDITCHANGE may no more be valid.
EnableTextChangedEvents(false);
#endif /* _WIN32 */
switch (m_type)
{
case Preset::TYPE_PRINT: {
m_collection = &m_preset_bundle->prints;
m_main_bitmap_name = "cog";
break;
}
case Preset::TYPE_FILAMENT: {
m_collection = &m_preset_bundle->filaments;
m_main_bitmap_name = "spool";
break;
}
case Preset::TYPE_SLA_PRINT: {
m_collection = &m_preset_bundle->sla_prints;
m_main_bitmap_name = "cog";
break;
}
case Preset::TYPE_SLA_MATERIAL: {
m_collection = &m_preset_bundle->sla_materials;
m_main_bitmap_name = "resin";
break;
}
case Preset::TYPE_PRINTER: {
m_collection = &m_preset_bundle->printers;
m_main_bitmap_name = "printer";
break;
}
default: break;
}
m_bitmapCompatible = ScalableBitmap(nullptr, "flag_green");
m_bitmapIncompatible = ScalableBitmap(nullptr, "flag_red");
m_bitmapLock = ScalableBitmap(nullptr, "lock_closed");
// parameters for an icon's drawing
fill_width_height();
}
PresetComboBox::~PresetComboBox()
{
delete m_bitmap_cache;
m_bitmap_cache = nullptr;
}
void PresetComboBox::set_label_marker(int item, LabelItemType label_item_type)
{
this->SetClientData(item, (void*)label_item_type);
}
void PresetComboBox::msw_rescale()
{
m_em_unit = wxGetApp().em_unit();
m_bitmapLock.msw_rescale();
m_bitmapIncompatible.msw_rescale();
m_bitmapCompatible.msw_rescale();
// parameters for an icon's drawing
fill_width_height();
// update the control to redraw the icons
update();
}
void PresetComboBox::fill_width_height()
{
// To avoid asserts, each added bitmap to wxBitmapCombobox should be the same size, so
// set a bitmap's height to m_bitmapLock->GetHeight() and norm_icon_width to m_bitmapLock->GetWidth()
icon_height = m_bitmapLock.GetBmpHeight();
norm_icon_width = m_bitmapLock.GetBmpWidth();
/* It's supposed that standard size of an icon is 16px*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 float scale_f = (float)m_em_unit * 0.1f;
thin_icon_width = lroundf(8 * scale_f); // analogue to 8px;
wide_icon_width = norm_icon_width + thin_icon_width;
space_icon_width = lroundf(2 * scale_f);
thin_space_icon_width = 2 * space_icon_width;
wide_space_icon_width = 3 * space_icon_width;
}
wxString PresetComboBox::separator(const std::string& label)
{
return wxString::FromUTF8(separator_head()) + _(label) + wxString::FromUTF8(separator_tail());
}
#ifdef __APPLE__
bool PresetComboBox::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 PresetComboBox::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
// ---------------------------------
// *** PlaterPresetComboBox ***
// ---------------------------------
PlaterPresetComboBox::PlaterPresetComboBox(wxWindow *parent, Preset::Type preset_type) :
PresetComboBox(parent, preset_type, wxSize(15 * wxGetApp().em_unit(), -1))
{
Bind(wxEVT_COMBOBOX, [this](wxCommandEvent &evt) {
auto selected_item = evt.GetSelection();
auto marker = reinterpret_cast<Marker>(this->GetClientData(selected_item));
if (marker >= LABEL_ITEM_MARKER && marker < LABEL_ITEM_MAX) {
this->SetSelection(this->m_last_selected);
evt.StopPropagation();
if (marker == LABEL_ITEM_PHYSICAL_PRINTERS)
{
PhysicalPrinterDialog dlg;
dlg.ShowModal();
return;
}
if (marker >= LABEL_ITEM_WIZARD_PRINTERS) {
ConfigWizard::StartPage sp = ConfigWizard::SP_WELCOME;
switch (marker) {
case LABEL_ITEM_WIZARD_PRINTERS: sp = ConfigWizard::SP_PRINTERS; break;
case LABEL_ITEM_WIZARD_FILAMENTS: sp = ConfigWizard::SP_FILAMENTS; break;
case LABEL_ITEM_WIZARD_MATERIALS: sp = ConfigWizard::SP_MATERIALS; break;
default: break;
}
wxTheApp->CallAfter([sp]() { wxGetApp().run_wizard(ConfigWizard::RR_USER, sp); });
}
} else if ( this->m_last_selected != selected_item || m_collection->current_is_dirty() ) {
this->m_last_selected = selected_item;
evt.SetInt(this->m_type);
evt.Skip();
} else {
evt.StopPropagation();
}
});
if (m_type == Preset::TYPE_FILAMENT)
{
Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &event) {
const Preset* selected_preset = m_collection->find_preset(m_preset_bundle->filament_presets[m_extruder_idx]);
// Wide icons are shown if the currently selected preset is not compatible with the current printer,
// and red flag is drown in front of the selected preset.
bool wide_icons = selected_preset != nullptr && !selected_preset->is_compatible;
float scale = m_em_unit*0.1f;
int shifl_Left = wide_icons ? int(scale * 16 + 0.5) : 0;
#if defined(wxBITMAPCOMBOBOX_OWNERDRAWN_BASED)
shifl_Left += int(scale * 4 + 0.5f); // IMAGE_SPACING_RIGHT = 4 for wxBitmapComboBox -> Space left of image
#endif
int icon_right_pos = shifl_Left + int(scale * (24+4) + 0.5);
int mouse_pos = event.GetLogicalPosition(wxClientDC(this)).x;
if (mouse_pos < shifl_Left || mouse_pos > icon_right_pos ) {
// Let the combo box process the mouse click.
event.Skip();
return;
}
// Swallow the mouse click and open the color picker.
// get current color
DynamicPrintConfig* cfg = wxGetApp().get_tab(Preset::TYPE_PRINTER)->get_config();
auto colors = static_cast<ConfigOptionStrings*>(cfg->option("extruder_colour")->clone());
wxColour clr(colors->values[m_extruder_idx]);
if (!clr.IsOk())
clr = wxColour(0,0,0); // Don't set alfa to transparence
auto data = new wxColourData();
data->SetChooseFull(1);
data->SetColour(clr);
wxColourDialog dialog(this, data);
dialog.CenterOnParent();
if (dialog.ShowModal() == wxID_OK)
{
colors->values[m_extruder_idx] = dialog.GetColourData().GetColour().GetAsString(wxC2S_HTML_SYNTAX).ToStdString();
DynamicPrintConfig cfg_new = *cfg;
cfg_new.set_key_value("extruder_colour", colors);
wxGetApp().get_tab(Preset::TYPE_PRINTER)->load_config(cfg_new);
this->update();
wxGetApp().plater()->on_config_change(cfg_new);
}
});
}
edit_btn = new ScalableButton(parent, wxID_ANY, "cog");
edit_btn->SetToolTip(_L("Click to edit preset"));
edit_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent)
{
Tab* tab = wxGetApp().get_tab(m_type);
if (!tab)
return;
int page_id = wxGetApp().tab_panel()->FindPage(tab);
if (page_id == wxNOT_FOUND)
return;
wxGetApp().tab_panel()->SetSelection(page_id);
// Switch to Settings NotePad
wxGetApp().mainframe->select_tab();
/* In a case of a multi-material printing, for editing another Filament Preset
* it's needed to select this preset for the "Filament settings" Tab
*/
if (m_type == Preset::TYPE_FILAMENT && wxGetApp().extruders_edited_cnt() > 1)
{
const std::string& selected_preset = GetString(GetSelection()).ToUTF8().data();
// Call select_preset() only if there is new preset and not just modified
if ( !boost::algorithm::ends_with(selected_preset, Preset::suffix_modified()) )
{
const std::string& preset_name = wxGetApp().preset_bundle->filaments.get_preset_name_by_alias(selected_preset);
tab->select_preset(preset_name);
}
}
});
}
PlaterPresetComboBox::~PlaterPresetComboBox()
{
if (edit_btn)
edit_btn->Destroy();
}
// Only the compatible presets are shown.
// If an incompatible preset is selected, it is shown as well.
void PlaterPresetComboBox::update()
{
if (m_type == Preset::TYPE_FILAMENT &&
(m_collection->get_edited_preset().printer_technology() == ptSLA ||
m_preset_bundle->filament_presets.size() <= m_extruder_idx) )
return;
// Otherwise fill in the list from scratch.
this->Freeze();
this->Clear();
size_t selected_preset_item = INT_MAX; // some value meaning that no one item is selected
const Preset* selected_filament_preset;
std::string extruder_color;
if (m_type == Preset::TYPE_FILAMENT)
{
unsigned char rgb[3];
extruder_color = m_preset_bundle->printers.get_edited_preset().config.opt_string("extruder_colour", (unsigned int)m_extruder_idx);
if (!m_bitmap_cache->parse_color(extruder_color, rgb))
// Extruder color is not defined.
extruder_color.clear();
selected_filament_preset = m_collection->find_preset(m_preset_bundle->filament_presets[m_extruder_idx]);
assert(selected_filament_preset);
}
const Preset& selected_preset = m_type == Preset::TYPE_FILAMENT ? *selected_filament_preset : m_collection->get_selected_preset();
// Show wide icons if the currently selected preset is not compatible with the current printer,
// and draw a red flag in front of the selected preset.
bool wide_icons = !selected_preset.is_compatible;
std::map<wxString, wxBitmap*> nonsys_presets;
std::map<wxString, wxBitmap*> physical_printers;
wxString selected = "";
wxString tooltip = "";
const std::deque<Preset>& presets = m_collection->get_presets();
if (!presets.front().is_visible)
this->set_label_marker(this->Append(separator(L("System presets")), wxNullBitmap));
for (size_t i = presets.front().is_visible ? 0 : m_collection->num_default_presets(); i < presets.size(); ++i)
{
const Preset& preset = presets[i];
bool is_selected = m_type == Preset::TYPE_FILAMENT ?
m_preset_bundle->filament_presets[m_extruder_idx] == preset.name :
i == m_collection->get_selected_idx();
if (!preset.is_visible || (!preset.is_compatible && !is_selected))
continue;
std::string bitmap_key, filament_rgb, extruder_rgb;
bool single_bar = false;
if (m_type == Preset::TYPE_PRINTER && preset.printer_technology() == ptSLA)
bitmap_key = "sla_printer";
else if (m_type == Preset::TYPE_FILAMENT)
{
// Assign an extruder color to the selected item if the extruder color is defined.
filament_rgb = preset.config.opt_string("filament_colour", 0);
extruder_rgb = (selected && !extruder_color.empty()) ? extruder_color : filament_rgb;
single_bar = filament_rgb == extruder_rgb;
bitmap_key = single_bar ? filament_rgb : filament_rgb + extruder_rgb;
}
wxBitmap main_bmp = create_scaled_bitmap(m_type == Preset::TYPE_PRINTER && preset.printer_technology() == ptSLA ? "sla_printer" : m_main_bitmap_name);
// If the filament preset is not compatible and there is a "red flag" icon loaded, show it left
// to the filament color image.
if (wide_icons)
bitmap_key += preset.is_compatible ? ",cmpt" : ",ncmpt";
bitmap_key += (preset.is_system || preset.is_default) ? ",syst" : ",nsyst";
bitmap_key += "-h" + std::to_string(icon_height);
wxBitmap* bmp = m_bitmap_cache->find(bitmap_key);
if (bmp == nullptr) {
// Create the bitmap with color bars.
std::vector<wxBitmap> bmps;
if (wide_icons)
// Paint a red flag for incompatible presets.
bmps.emplace_back(preset.is_compatible ? m_bitmap_cache->mkclear(norm_icon_width, icon_height) : m_bitmapIncompatible.bmp());
if (m_type == Preset::TYPE_FILAMENT)
{
unsigned char rgb[3];
// Paint the color bars.
m_bitmap_cache->parse_color(filament_rgb, rgb);
bmps.emplace_back(m_bitmap_cache->mksolid(single_bar ? wide_icon_width : norm_icon_width, icon_height, rgb));
if (!single_bar) {
m_bitmap_cache->parse_color(extruder_rgb, rgb);
bmps.emplace_back(m_bitmap_cache->mksolid(thin_icon_width, icon_height, rgb));
}
// Paint a lock at the system presets.
bmps.emplace_back(m_bitmap_cache->mkclear(space_icon_width, icon_height));
}
else
{
// Paint the color bars.
bmps.emplace_back(m_bitmap_cache->mkclear(thin_space_icon_width, icon_height));
bmps.emplace_back(main_bmp);
// Paint a lock at the system presets.
bmps.emplace_back(m_bitmap_cache->mkclear(wide_space_icon_width, icon_height));
}
bmps.emplace_back((preset.is_system || preset.is_default) ? m_bitmapLock.bmp() : m_bitmap_cache->mkclear(norm_icon_width, icon_height));
bmp = m_bitmap_cache->insert(bitmap_key, bmps);
}
const std::string name = preset.alias.empty() ? preset.name : preset.alias;
if (preset.is_default || preset.is_system) {
Append(wxString::FromUTF8((name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str()),
!bmp ? main_bmp : *bmp);
if (is_selected ||
// just in case: mark selected_preset_item as a first added element
selected_preset_item == INT_MAX) {
selected_preset_item = GetCount() - 1;
tooltip = wxString::FromUTF8(preset.name.c_str());
}
}
else
{
nonsys_presets.emplace(wxString::FromUTF8((name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str()), bmp);
if (is_selected) {
selected = wxString::FromUTF8((name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str());
tooltip = wxString::FromUTF8(preset.name.c_str());
}
}
if (i + 1 == m_collection->num_default_presets())
set_label_marker(Append(separator(L("System presets")), wxNullBitmap));
}
if (!nonsys_presets.empty())
{
set_label_marker(Append(separator(L("User presets")), wxNullBitmap));
for (std::map<wxString, wxBitmap*>::iterator it = nonsys_presets.begin(); it != nonsys_presets.end(); ++it) {
Append(it->first, *it->second);
if (it->first == selected ||
// just in case: mark selected_preset_item as a first added element
selected_preset_item == INT_MAX)
selected_preset_item = GetCount() - 1;
}
}
if (!physical_printers.empty())
{
set_label_marker(Append(separator(L("Physical printers")), wxNullBitmap));
for (std::map<wxString, wxBitmap*>::iterator it = physical_printers.begin(); it != physical_printers.end(); ++it) {
Append(it->first, *it->second);
if (it->first == selected ||
// just in case: mark selected_preset_item as a first added element
selected_preset_item == INT_MAX)
selected_preset_item = GetCount() - 1;
}
}
if (m_type == Preset::TYPE_PRINTER || m_type == Preset::TYPE_SLA_MATERIAL) {
std::string bitmap_key = "";
// If the filament preset is not compatible and there is a "red flag" icon loaded, show it left
// to the filament color image.
if (wide_icons)
bitmap_key += "wide,";
bitmap_key += "edit_preset_list";
bitmap_key += "-h" + std::to_string(icon_height);
wxBitmap* bmp = m_bitmap_cache->find(bitmap_key);
if (bmp == nullptr) {
// Create the bitmap with color bars.update_plater_ui
std::vector<wxBitmap> bmps;
if (wide_icons)
// Paint a red flag for incompatible presets.
bmps.emplace_back(m_bitmap_cache->mkclear(norm_icon_width, icon_height));
// Paint the color bars.
bmps.emplace_back(m_bitmap_cache->mkclear(thin_space_icon_width, icon_height));
bmps.emplace_back(create_scaled_bitmap(m_main_bitmap_name));
// Paint a lock at the system presets.
bmps.emplace_back(m_bitmap_cache->mkclear(wide_space_icon_width, icon_height));
bmps.emplace_back(create_scaled_bitmap("edit_uni"));
bmp = m_bitmap_cache->insert(bitmap_key, bmps);
}
if (m_type == Preset::TYPE_SLA_MATERIAL)
set_label_marker(Append(separator(L("Add/Remove materials")), *bmp), LABEL_ITEM_WIZARD_MATERIALS);
else
set_label_marker(Append(separator(L("Add/Remove printers")), *bmp), LABEL_ITEM_WIZARD_PRINTERS);
}
if (m_type == Preset::TYPE_PRINTER) {
std::string bitmap_key = "";
if (wide_icons)
bitmap_key += "wide,";
bitmap_key += "edit_preset_list";
bitmap_key += "-h" + std::to_string(icon_height);
wxBitmap* bmp = m_bitmap_cache->find(bitmap_key);
if (bmp == nullptr) {
// Create the bitmap with color bars.
std::vector<wxBitmap> bmps;
if (wide_icons)
// Paint a red flag for incompatible presets.
bmps.emplace_back(m_bitmap_cache->mkclear(norm_icon_width, icon_height));
// Paint the color bars.
bmps.emplace_back(m_bitmap_cache->mkclear(thin_space_icon_width, icon_height));
bmps.emplace_back(create_scaled_bitmap("printer"));
// Paint a lock at the system presets.
bmps.emplace_back(m_bitmap_cache->mkclear(wide_space_icon_width, icon_height));
bmps.emplace_back(create_scaled_bitmap("edit_uni"));
bmp = m_bitmap_cache->insert(bitmap_key, bmps);
}
set_label_marker(Append(separator(L("Add physical printer")), *bmp), LABEL_ITEM_PHYSICAL_PRINTERS);
}
/* But, if selected_preset_item is still equal to INT_MAX, it means that
* there is no presets added to the list.
* So, select last combobox item ("Add/Remove preset")
*/
if (selected_preset_item == INT_MAX)
selected_preset_item = GetCount() - 1;
SetSelection(selected_preset_item);
SetToolTip(tooltip.IsEmpty() ? GetString(selected_preset_item) : tooltip);
m_last_selected = selected_preset_item;
Thaw();
// Update control min size after rescale (changed Display DPI under MSW)
if (GetMinWidth() != 20 * m_em_unit)
SetMinSize(wxSize(20 * m_em_unit, GetSize().GetHeight()));
}
void PlaterPresetComboBox::msw_rescale()
{
PresetComboBox::msw_rescale();
edit_btn->msw_rescale();
}
// ---------------------------------
// *** PlaterPresetComboBox ***
// ---------------------------------
TabPresetComboBox::TabPresetComboBox(wxWindow* parent, Preset::Type preset_type) :
PresetComboBox(parent, preset_type, wxSize(35 * wxGetApp().em_unit(), -1))
{
Bind(wxEVT_COMBOBOX, [this](wxCommandEvent& evt) {
// see https://github.com/prusa3d/PrusaSlicer/issues/3889
// Under OSX: in case of use of a same names written in different case (like "ENDER" and "Ender")
// m_presets_choice->GetSelection() will return first item, because search in PopupListCtrl is case-insensitive.
// So, use GetSelection() from event parameter
auto selected_item = evt.GetSelection();
auto marker = reinterpret_cast<Marker>(this->GetClientData(selected_item));
if (marker >= LABEL_ITEM_MARKER && marker < LABEL_ITEM_MAX) {
this->SetSelection(this->m_last_selected);
if (marker == LABEL_ITEM_WIZARD_PRINTERS)
wxTheApp->CallAfter([]() { wxGetApp().run_wizard(ConfigWizard::RR_USER, ConfigWizard::SP_PRINTERS); });
}
else if (m_last_selected != selected_item || m_collection->current_is_dirty()) {
std::string selected_string = this->GetString(selected_item).ToUTF8().data();
Tab* tab = wxGetApp().get_tab(this->m_type);
assert (tab);
tab->select_preset(selected_string);
}
evt.StopPropagation();
});
}
// Update the choice UI from the list of presets.
// If show_incompatible, all presets are shown, otherwise only the compatible presets are shown.
// If an incompatible preset is selected, it is shown as well.
void TabPresetComboBox::update()
{
Freeze();
Clear();
size_t selected_preset_item = INT_MAX; // some value meaning that no one item is selected
const std::deque<Preset>& presets = m_collection->get_presets();
std::map<wxString, wxBitmap*> nonsys_presets;
wxString selected = "";
if (!presets.front().is_visible)
set_label_marker(Append(separator(L("System presets")), wxNullBitmap));
int idx_selected = m_collection->get_selected_idx();
for (size_t i = presets.front().is_visible ? 0 : m_collection->num_default_presets(); i < presets.size(); ++i) {
const Preset& preset = presets[i];
if (!preset.is_visible || (!show_incompatible && !preset.is_compatible && i != idx_selected))
continue;
std::string bitmap_key = "tab";
wxBitmap main_bmp = create_scaled_bitmap(m_type == Preset::TYPE_PRINTER && preset.printer_technology() == ptSLA ? "sla_printer" : m_main_bitmap_name);
if (m_type == Preset::TYPE_PRINTER) {
bitmap_key += "_printer";
if (preset.printer_technology() == ptSLA)
bitmap_key += "_sla";
}
bitmap_key += preset.is_compatible ? ",cmpt" : ",ncmpt";
bitmap_key += (preset.is_system || preset.is_default) ? ",syst" : ",nsyst";
bitmap_key += "-h" + std::to_string(icon_height);
wxBitmap* bmp = m_bitmap_cache->find(bitmap_key);
if (bmp == nullptr) {
// Create the bitmap with color bars.
std::vector<wxBitmap> bmps;
bmps.emplace_back(m_type == Preset::TYPE_PRINTER ? main_bmp : preset.is_compatible ? m_bitmapCompatible.bmp() : m_bitmapIncompatible.bmp());
// Paint a lock at the system presets.
bmps.emplace_back((preset.is_system || preset.is_default) ? m_bitmapLock.bmp() : m_bitmap_cache->mkclear(norm_icon_width, icon_height));
bmp = m_bitmap_cache->insert(bitmap_key, bmps);
}
if (preset.is_default || preset.is_system) {
Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str()),
(bmp == 0) ? main_bmp : *bmp);
if (i == idx_selected ||
// just in case: mark selected_preset_item as a first added element
selected_preset_item == INT_MAX)
selected_preset_item = GetCount() - 1;
}
else
{
nonsys_presets.emplace(wxString::FromUTF8((preset.name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str()), bmp);
if (i == idx_selected)
selected = wxString::FromUTF8((preset.name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str());
}
if (i + 1 == m_collection->num_default_presets())
set_label_marker(Append(separator(L("System presets")), wxNullBitmap));
}
if (!nonsys_presets.empty())
{
set_label_marker(Append(separator(L("User presets")), wxNullBitmap));
for (std::map<wxString, wxBitmap*>::iterator it = nonsys_presets.begin(); it != nonsys_presets.end(); ++it) {
Append(it->first, *it->second);
if (it->first == selected ||
// just in case: mark selected_preset_item as a first added element
selected_preset_item == INT_MAX)
selected_preset_item = GetCount() - 1;
}
}
if (m_type == Preset::TYPE_PRINTER) {
std::string bitmap_key = "edit_preset_list";
bitmap_key += "-h" + std::to_string(icon_height);
wxBitmap* bmp = m_bitmap_cache->find(bitmap_key);
if (bmp == nullptr) {
// Create the bitmap with color bars.
std::vector<wxBitmap> bmps;
bmps.emplace_back(create_scaled_bitmap(m_main_bitmap_name));
bmps.emplace_back(create_scaled_bitmap("edit_uni"));
bmp = m_bitmap_cache->insert(bitmap_key, bmps);
}
set_label_marker(Append(separator(L("Add/Remove printers")), *bmp), LABEL_ITEM_WIZARD_PRINTERS);
}
/* But, if selected_preset_item is still equal to INT_MAX, it means that
* there is no presets added to the list.
* So, select last combobox item ("Add/Remove preset")
*/
if (selected_preset_item == INT_MAX)
selected_preset_item = GetCount() - 1;
SetSelection(selected_preset_item);
SetToolTip(GetString(selected_preset_item));
Thaw();
m_last_selected = selected_preset_item;
}
void TabPresetComboBox::msw_rescale()
{
PresetComboBox::msw_rescale();
wxSize sz = wxSize(35 * m_em_unit, -1);
SetMinSize(sz);
SetSize(sz);
}
void TabPresetComboBox::update_dirty()
{
// 1) Update the dirty flag of the current preset.
m_collection->update_dirty();
// 2) Update the labels.
wxWindowUpdateLocker noUpdates(this);
for (unsigned int ui_id = 0; ui_id < GetCount(); ++ui_id) {
std::string old_label = GetString(ui_id).utf8_str().data();
std::string preset_name = Preset::remove_suffix_modified(old_label);
const Preset* preset = m_collection->find_preset(preset_name, false);
if (preset) {
std::string new_label = preset->is_dirty ? preset->name + Preset::suffix_modified() : preset->name;
if (old_label != new_label)
SetString(ui_id, wxString::FromUTF8(new_label.c_str()));
}
}
#ifdef __APPLE__
// wxWidgets on OSX do not upload the text of the combo box line automatically.
// Force it to update by re-selecting.
SetSelection(GetSelection());
#endif /* __APPLE __ */
}
//------------------------------------------
// PhysicalPrinterDialog
//------------------------------------------
PhysicalPrinterDialog::PhysicalPrinterDialog()
: DPIDialog(NULL, wxID_ANY, _L("Search"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
{
SetFont(wxGetApp().normal_font());
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
int border = 10;
int em = em_unit();
printer_text = new wxTextCtrl(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER);
printer_presets = new PlaterPresetComboBox(this, Preset::TYPE_PRINTER);
wxStdDialogButtonSizer* btns = this->CreateStdDialogButtonSizer(wxOK | wxCANCEL);
wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL);
topSizer->Add(printer_text , 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, border);
topSizer->Add(printer_presets , 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, border);
topSizer->Add(btns , 0, wxEXPAND | wxALL, border);
SetSizer(topSizer);
topSizer->SetSizeHints(this);
}
void PhysicalPrinterDialog::on_dpi_changed(const wxRect& suggested_rect)
{
const int& em = em_unit();
msw_buttons_rescale(this, em, { wxID_OK, wxID_CANCEL });
const wxSize& size = wxSize(40 * em, 30 * em);
SetMinSize(size);
Fit();
Refresh();
}
}} // namespace Slic3r::GUI

View file

@ -0,0 +1,179 @@
#ifndef slic3r_PresetComboBoxes_hpp_
#define slic3r_PresetComboBoxes_hpp_
#include <vector>
#include <wx/panel.h>
#include <wx/bmpcbox.h>
#include <wx/gdicmn.h>
#include "Preset.hpp"
#include "wxExtensions.hpp"
#include "GUI_Utils.hpp"
class wxString;
class wxTextCtrl;
namespace Slic3r {
namespace GUI {
class BitmapCache;
// ---------------------------------
// *** PresetComboBox ***
// ---------------------------------
// BitmapComboBox used to presets list on Sidebar and Tabs
class PresetComboBox : public wxBitmapComboBox
{
public:
PresetComboBox(wxWindow* parent, Preset::Type preset_type, const wxSize& size = wxDefaultSize);
~PresetComboBox();
enum LabelItemType {
LABEL_ITEM_MARKER = 0xffffff01,
LABEL_ITEM_PHYSICAL_PRINTERS,
LABEL_ITEM_WIZARD_PRINTERS,
LABEL_ITEM_WIZARD_FILAMENTS,
LABEL_ITEM_WIZARD_MATERIALS,
LABEL_ITEM_MAX,
};
void set_label_marker(int item, LabelItemType label_item_type = LABEL_ITEM_MARKER);
int em_unit() const { return m_em_unit; }
virtual void update() {};
virtual void msw_rescale();
protected:
typedef std::size_t Marker;
Preset::Type m_type;
std::string m_main_bitmap_name;
PresetBundle* m_preset_bundle {nullptr};
PresetCollection* m_collection {nullptr};
// Caching color bitmaps for the filament combo box.
BitmapCache* m_bitmap_cache {nullptr};
// Indicator, that the preset is compatible with the selected printer.
ScalableBitmap m_bitmapCompatible;
// Indicator, that the preset is NOT compatible with the selected printer.
ScalableBitmap m_bitmapIncompatible;
// Indicator, that the preset is system and not modified.
ScalableBitmap m_bitmapLock;
int m_last_selected;
int m_em_unit;
// parameters for an icon's drawing
int icon_height;
int norm_icon_width;
int thin_icon_width;
int wide_icon_width;
int space_icon_width;
int thin_space_icon_width;
int wide_space_icon_width;
#ifdef __linux__
static const char* separator_head() { return "------- "; }
static const char* separator_tail() { return " -------"; }
#else // __linux__
static const char* separator_head() { return "————— "; }
static const char* separator_tail() { return " —————"; }
#endif // __linux__
static wxString separator(const std::string& label);
#ifdef __APPLE__
/* For PresetComboBox 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
private:
void fill_width_height();
};
// ---------------------------------
// *** PlaterPresetComboBox ***
// ---------------------------------
class PlaterPresetComboBox : public PresetComboBox
{
public:
PlaterPresetComboBox(wxWindow *parent, Preset::Type preset_type);
~PlaterPresetComboBox();
ScalableButton* edit_btn { nullptr };
void set_extruder_idx(const int extr_idx) { m_extruder_idx = extr_idx; }
int get_extruder_idx() const { return m_extruder_idx; }
void update() override;
void msw_rescale() override;
private:
int m_extruder_idx = -1;
};
// ---------------------------------
// *** PlaterPresetComboBox ***
// ---------------------------------
class TabPresetComboBox : public PresetComboBox
{
public:
TabPresetComboBox(wxWindow *parent, Preset::Type preset_type);
~TabPresetComboBox() {}
void set_show_incompatible_presets(bool show_incompatible_presets) {
show_incompatible = show_incompatible_presets;
}
void update() override;
void update_dirty();
void msw_rescale() override;
private:
bool show_incompatible{false};
};
//------------------------------------------
// PhysicalPrinterDialog
//------------------------------------------
class PhysicalPrinterDialog : public DPIDialog
{
std::string printer_name;
std::string preset_name;
wxTextCtrl* printer_text { nullptr };
PresetComboBox* printer_presets;
public:
PhysicalPrinterDialog();
~PhysicalPrinterDialog() {}
protected:
void on_dpi_changed(const wxRect& suggested_rect) override;
void on_sys_color_changed() override {};
};
} // namespace GUI
} // namespace Slic3r
#endif

View file

@ -27,6 +27,7 @@
#include <boost/algorithm/string/predicate.hpp>
#include "wxExtensions.hpp"
#include "PresetComboBoxes.hpp"
#include <wx/wupdlock.h>
#include "GUI_App.hpp"
@ -160,10 +161,7 @@ void Tab::create_preset_tab()
#endif //__WXOSX__
// preset chooser
m_presets_choice = new PresetBitmapComboBox(panel, wxSize(35 * m_em_unit, -1));
// search combox
// m_search = new Search::SearchCtrl(panel);
m_presets_choice = new TabPresetComboBox(panel, m_type);
auto color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
@ -278,35 +276,6 @@ void Tab::create_preset_tab()
m_treectrl->Bind(wxEVT_TREE_SEL_CHANGED, &Tab::OnTreeSelChange, this);
m_treectrl->Bind(wxEVT_KEY_DOWN, &Tab::OnKeyDown, this);
m_presets_choice->Bind(wxEVT_COMBOBOX, ([this](wxCommandEvent e) {
//! Because of The MSW and GTK version of wxBitmapComboBox derived from wxComboBox,
//! but the OSX version derived from wxOwnerDrawnCombo, instead of:
//! select_preset(m_presets_choice->GetStringSelection().ToUTF8().data());
//! we doing next:
// int selected_item = m_presets_choice->GetSelection();
// see https://github.com/prusa3d/PrusaSlicer/issues/3889
// Under OSX: in case of use of a same names written in different case (like "ENDER" and "Ender")
// m_presets_choice->GetSelection() will return first item, because search in PopupListCtrl is case-insensitive.
// So, use GetSelection() from event parameter
int selected_item = e.GetSelection();
if (m_selected_preset_item == size_t(selected_item) && !m_presets->current_is_dirty())
return;
if (selected_item >= 0) {
std::string selected_string = m_presets_choice->GetString(selected_item).ToUTF8().data();
if (selected_string.find(PresetCollection::separator_head()) == 0
/*selected_string == "------- System presets -------" ||
selected_string == "------- User presets -------"*/) {
m_presets_choice->SetSelection(m_selected_preset_item);
if (wxString::FromUTF8(selected_string.c_str()) == PresetCollection::separator(L("Add a new printer")))
wxTheApp->CallAfter([]() { wxGetApp().run_wizard(ConfigWizard::RR_USER); });
return;
}
m_selected_preset_item = selected_item;
select_preset(selected_string);
}
}));
m_btn_save_preset->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e) { save_preset(); }));
m_btn_delete_preset->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e) { delete_preset(); }));
m_btn_hide_incompatible_presets->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e) {
@ -778,14 +747,14 @@ void Tab::on_roll_back_value(const bool to_sys /*= true*/)
// comparing the selected preset config with $self->{config}.
void Tab::update_dirty()
{
m_presets->update_dirty_ui(m_presets_choice);
m_presets_choice->update_dirty();
on_presets_changed();
update_changed_ui();
}
void Tab::update_tab_ui()
{
m_selected_preset_item = m_presets->update_tab_ui(m_presets_choice, m_show_incompatible_presets, m_em_unit);
m_presets_choice->update();
}
// Load a provied DynamicConfig into the tab, modifying the active preset.
@ -850,12 +819,10 @@ void Tab::msw_rescale()
m_em_unit = wxGetApp().em_unit();
m_mode_sizer->msw_rescale();
m_presets_choice->msw_rescale();
m_presets_choice->SetSize(35 * m_em_unit, -1);
m_treectrl->SetMinSize(wxSize(20 * m_em_unit, -1));
update_tab_ui();
// rescale buttons and cached bitmaps
for (const auto btn : m_scaled_buttons)
btn->msw_rescale();
@ -963,7 +930,7 @@ void Tab::load_key_value(const std::string& opt_key, const boost::any& value, bo
// Don't select another profile if this profile happens to become incompatible.
m_preset_bundle->update_compatible(PresetSelectCompatibleType::Never);
}
m_presets->update_dirty_ui(m_presets_choice);
m_presets_choice->update_dirty();
on_presets_changed();
update();
}
@ -3360,6 +3327,7 @@ void Tab::delete_preset()
void Tab::toggle_show_hide_incompatible()
{
m_show_incompatible_presets = !m_show_incompatible_presets;
m_presets_choice->set_show_incompatible_presets(m_show_incompatible_presets);
update_show_hide_incompatible_button();
update_tab_ui();
}

View file

@ -39,6 +39,8 @@
namespace Slic3r {
namespace GUI {
class TabPresetComboBox;
// Single Tab page containing a{ vsizer } of{ optgroups }
// package Slic3r::GUI::Tab::Page;
using ConfigOptionsGroupShp = std::shared_ptr<ConfigOptionsGroup>;
@ -113,7 +115,7 @@ protected:
Preset::Type m_type;
std::string m_name;
const wxString m_title;
PresetBitmapComboBox* m_presets_choice;
TabPresetComboBox* m_presets_choice;
ScalableButton* m_search_btn;
ScalableButton* m_btn_save_preset;
ScalableButton* m_btn_delete_preset;
@ -206,8 +208,6 @@ protected:
bool m_is_nonsys_values{ true };
bool m_postpone_update_ui {false};
size_t m_selected_preset_item{ 0 };
void set_type();
int m_em_unit;
@ -320,7 +320,6 @@ public:
DynamicPrintConfig* get_config() { return m_config; }
PresetCollection* get_presets() { return m_presets; }
size_t get_selected_preset_item() { return m_selected_preset_item; }
void on_value_change(const std::string& opt_key, const boost::any& value);

View file

@ -300,94 +300,6 @@ 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;

View file

@ -95,37 +95,6 @@ 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 ***