diff options
Diffstat (limited to 'src/slic3r')
-rw-r--r-- | src/slic3r/GUI/3DScene.cpp | 14 | ||||
-rw-r--r-- | src/slic3r/GUI/DoubleSlider.cpp | 84 | ||||
-rw-r--r-- | src/slic3r/GUI/DoubleSlider.hpp | 11 | ||||
-rw-r--r-- | src/slic3r/GUI/GLCanvas3D.cpp | 2 | ||||
-rw-r--r-- | src/slic3r/GUI/GUI_App.cpp | 22 | ||||
-rw-r--r-- | src/slic3r/GUI/GUI_ObjectList.cpp | 15 | ||||
-rw-r--r-- | src/slic3r/GUI/GUI_ObjectList.hpp | 3 | ||||
-rw-r--r-- | src/slic3r/GUI/GUI_Preview.cpp | 30 | ||||
-rw-r--r-- | src/slic3r/GUI/GalleryDialog.cpp | 15 | ||||
-rw-r--r-- | src/slic3r/GUI/MainFrame.cpp | 2 | ||||
-rw-r--r-- | src/slic3r/GUI/NotificationManager.cpp | 4 | ||||
-rw-r--r-- | src/slic3r/GUI/NotificationManager.hpp | 3 | ||||
-rw-r--r-- | src/slic3r/GUI/OG_CustomCtrl.cpp | 77 | ||||
-rw-r--r-- | src/slic3r/GUI/OG_CustomCtrl.hpp | 9 | ||||
-rw-r--r-- | src/slic3r/GUI/OptionsGroup.cpp | 20 | ||||
-rw-r--r-- | src/slic3r/GUI/OptionsGroup.hpp | 11 | ||||
-rw-r--r-- | src/slic3r/GUI/Preferences.cpp | 99 | ||||
-rw-r--r-- | src/slic3r/GUI/Preferences.hpp | 8 | ||||
-rw-r--r-- | src/slic3r/GUI/Selection.cpp | 14 | ||||
-rw-r--r-- | src/slic3r/Utils/PresetUpdater.cpp | 73 | ||||
-rw-r--r-- | src/slic3r/Utils/PresetUpdater.hpp | 4 |
21 files changed, 432 insertions, 88 deletions
diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index dfc10658d..27eb69363 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -464,9 +464,15 @@ std::array<float, 4> color_from_model_volume(const ModelVolume& model_volume) color[2] = 0.2f; } else if (model_volume.is_modifier()) { +#if ENABLE_MODIFIERS_ALWAYS_TRANSPARENT + color[0] = 1.0f; + color[1] = 1.0f; + color[2] = 0.2f; +#else color[0] = 0.2f; color[1] = 1.0f; color[2] = 0.2f; +#endif // ENABLE_MODIFIERS_ALWAYS_TRANSPARENT } else if (model_volume.is_support_blocker()) { color[0] = 1.0f; @@ -836,7 +842,15 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab glsafe(::glDisable(GL_CULL_FACE)); for (GLVolumeWithIdAndZ& volume : to_render) { +#if ENABLE_MODIFIERS_ALWAYS_TRANSPARENT + if (type == ERenderType::Transparent) + volume.first->force_transparent = true; +#endif // ENABLE_MODIFIERS_ALWAYS_TRANSPARENT volume.first->set_render_color(); +#if ENABLE_MODIFIERS_ALWAYS_TRANSPARENT + if (type == ERenderType::Transparent) + volume.first->force_transparent = false; +#endif // ENABLE_MODIFIERS_ALWAYS_TRANSPARENT // render sinking contours of non-hovered volumes if (m_show_sinking_contours) diff --git a/src/slic3r/GUI/DoubleSlider.cpp b/src/slic3r/GUI/DoubleSlider.cpp index 77679a1ad..d0b29165c 100644 --- a/src/slic3r/GUI/DoubleSlider.cpp +++ b/src/slic3r/GUI/DoubleSlider.cpp @@ -38,6 +38,14 @@ using GUI::format_wxstr; namespace DoubleSlider { +constexpr double min_delta_area = scale_(scale_(25)); // equal to 25 mm2 +constexpr double miscalculation = scale_(scale_(1)); // equal to 1 mm2 + +bool equivalent_areas(const double& bottom_area, const double& top_area) +{ + return fabs(bottom_area - top_area) <= miscalculation; +} + wxDEFINE_EVENT(wxCUSTOMEVT_TICKSCHANGED, wxEvent); static std::string gcode(Type type) @@ -2034,6 +2042,32 @@ void Control::show_cog_icon_context_menu() GUI::wxGetApp().plater()->PopupMenu(&menu); } +bool check_color_change(PrintObject* object, size_t frst_layer_id, size_t layers_cnt, bool check_overhangs, std::function<bool(Layer*)> break_condition) +{ + double prev_area = area(object->get_layer(frst_layer_id)->lslices); + + bool detected = false; + for (size_t i = frst_layer_id+1; i < layers_cnt; i++) { + Layer* layer = object->get_layer(i); + double cur_area = area(layer->lslices); + + // check for overhangs + if (check_overhangs && cur_area > prev_area && !equivalent_areas(prev_area, cur_area)) + break; + + // Check percent of the area decrease. + // This value have to be more than min_delta_area and more then 10% + if ((prev_area - cur_area > min_delta_area) && (cur_area / prev_area < 0.9)) { + detected = true; + if (break_condition(layer)) + break; + } + + prev_area = cur_area; + } + return detected; +} + void Control::auto_color_change() { if (!m_ticks.empty()) { @@ -2049,45 +2083,33 @@ void Control::auto_color_change() int extruder = 2; const Print& print = GUI::wxGetApp().plater()->fff_print(); - double delta_area = scale_(scale_(25)); // equal to 25 mm2 - for (auto object : print.objects()) { if (object->layer_count() == 0) continue; - double prev_area = area(object->get_layer(0)->lslices); - - for (size_t i = 1; i < object->layers().size(); i++) { - Layer* layer = object->get_layer(i); - double cur_area = area(layer->lslices); - if (cur_area > prev_area && prev_area - cur_area > scale_(scale_(1))) - break; - - if (prev_area - cur_area > delta_area) { - // Check percent of the area decrease. - // Ignore it, if this value is less than 10% - if (cur_area / prev_area > 0.9) - continue; - int tick = get_tick_from_value(layer->print_z); - if (tick >= 0 && !m_ticks.has_tick(tick)) { - if (m_mode == SingleExtruder) { - m_ticks.set_default_colors(true); - m_ticks.add_tick(tick, ColorChange, 1, layer->print_z); - } - else { - m_ticks.add_tick(tick, ToolChange, extruder, layer->print_z); - if (++extruder > extruders_cnt) + check_color_change(object, 1, object->layers().size(), false, [this, extruders_cnt](Layer* layer) + { + int tick = get_tick_from_value(layer->print_z); + if (tick >= 0 && !m_ticks.has_tick(tick)) { + if (m_mode == SingleExtruder) { + m_ticks.set_default_colors(true); + m_ticks.add_tick(tick, ColorChange, 1, layer->print_z); + } + else { + int extruder = 2; + if (!m_ticks.empty()) { + auto it = m_ticks.ticks.end(); + it--; + extruder = it->extruder + 1; + if (extruder > extruders_cnt) extruder = 1; } + m_ticks.add_tick(tick, ToolChange, extruder, layer->print_z); } - - // allow max 3 auto color changes - if (m_ticks.ticks.size() == 3) - break; } - - prev_area = cur_area; - } + // allow max 3 auto color changes + return m_ticks.ticks.size() > 2; + }); } if (m_ticks.empty()) diff --git a/src/slic3r/GUI/DoubleSlider.hpp b/src/slic3r/GUI/DoubleSlider.hpp index 0f663f663..8f88de472 100644 --- a/src/slic3r/GUI/DoubleSlider.hpp +++ b/src/slic3r/GUI/DoubleSlider.hpp @@ -17,6 +17,8 @@ class wxMenu; namespace Slic3r { using namespace CustomGCode; +class PrintObject; +class Layer; namespace DoubleSlider { @@ -25,6 +27,15 @@ namespace DoubleSlider { */ constexpr double epsilon() { return 0.0011; } +// return true when areas are mostly equivalent +bool equivalent_areas(const double& bottom_area, const double& top_area); + +// return true if color change was detected +bool check_color_change(PrintObject* object, size_t frst_layer_id, size_t layers_cnt, bool check_overhangs, + // what to do with detected color change + // and return true when detection have to be desturbed + std::function<bool(Layer*)> break_condition); + // custom message the slider sends to its parent to notify a tick-change: wxDECLARE_EVENT(wxCUSTOMEVT_TICKSCHANGED, wxEvent); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 9ba72e629..ca31645c1 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1286,12 +1286,14 @@ bool GLCanvas3D::is_reload_delayed() const void GLCanvas3D::enable_layers_editing(bool enable) { m_layers_editing.set_enabled(enable); +#if !ENABLE_MODIFIERS_ALWAYS_TRANSPARENT const Selection::IndicesList& idxs = m_selection.get_volume_idxs(); for (unsigned int idx : idxs) { GLVolume* v = m_volumes.volumes[idx]; if (v->is_modifier) v->force_transparent = enable; } +#endif // !ENABLE_MODIFIERS_ALWAYS_TRANSPARENT set_as_dirty(); } diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index e2a9df25d..a19858eea 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -865,8 +865,11 @@ bool GUI_App::on_init_inner() wxInitAllImageHandlers(); #ifdef _MSW_DARK_MODE - if (app_config->get("dark_color_mode") == "1") + if (bool dark_mode = app_config->get("dark_color_mode") == "1") { NppDarkMode::InitDarkMode(); + if (dark_mode != NppDarkMode::IsDarkMode()) + NppDarkMode::SetDarkMode(dark_mode); + } #endif SplashScreen* scrn = nullptr; if (app_config->get("show_splash_screen") == "1") { @@ -915,6 +918,23 @@ bool GUI_App::on_init_inner() } } }); + Bind(EVT_SLIC3R_ALPHA_VERSION_ONLINE, [this](const wxCommandEvent& evt) { + app_config->save(); + if (this->plater_ != nullptr && app_config->get("notify_testing_release") == "1") { + if (*Semver::parse(SLIC3R_VERSION) < *Semver::parse(into_u8(evt.GetString()))) { + this->plater_->get_notification_manager()->push_notification(NotificationType::NewAlphaAvailable); + } + } + }); + Bind(EVT_SLIC3R_BETA_VERSION_ONLINE, [this](const wxCommandEvent& evt) { + app_config->save(); + if (this->plater_ != nullptr && app_config->get("notify_testing_release") == "1") { + if (*Semver::parse(SLIC3R_VERSION) < *Semver::parse(into_u8(evt.GetString()))) { + this->plater_->get_notification_manager()->close_notification_of_type(NotificationType::NewAlphaAvailable); + this->plater_->get_notification_manager()->push_notification(NotificationType::NewBetaAvailable); + } + } + }); } else { #ifdef __WXMSW__ diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index e6e7336f7..83f9d1ec1 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1405,9 +1405,11 @@ void ObjectList::load_subobject(ModelVolumeType type, bool from_galery/* = false item = m_objects_model->GetItemById(obj_idx); std::vector<ModelVolume*> volumes; + // ! ysFIXME - delete commented code after testing and rename "load_modifier" to something common + /* if (type == ModelVolumeType::MODEL_PART) load_part(*(*m_objects)[obj_idx], volumes, type, from_galery); - else + else*/ load_modifier(*(*m_objects)[obj_idx], volumes, type, from_galery); if (volumes.empty()) @@ -1430,8 +1432,8 @@ void ObjectList::load_subobject(ModelVolumeType type, bool from_galery/* = false selection_changed(); } - -void ObjectList::load_part(ModelObject& model_object, std::vector<ModelVolume*>& added_volumes, ModelVolumeType type, bool from_galery/* = false*/) +/* +void ObjectList::load_part(ModelObject& model_object, std::vector<ModelVolume*>& added_volumes, ModelVolumeType type, bool from_galery/* = false* /) { if (type != ModelVolumeType::MODEL_PART) return; @@ -1489,11 +1491,12 @@ void ObjectList::load_part(ModelObject& model_object, std::vector<ModelVolume*>& } } } - +*/ void ObjectList::load_modifier(ModelObject& model_object, std::vector<ModelVolume*>& added_volumes, ModelVolumeType type, bool from_galery) { - if (type == ModelVolumeType::MODEL_PART) - return; + // ! ysFIXME - delete commented code after testing and rename "load_modifier" to something common + //if (type == ModelVolumeType::MODEL_PART) + // return; wxWindow* parent = wxGetApp().tab_panel()->GetPage(0); diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index cc619fc45..535bfa7a7 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -249,7 +249,8 @@ public: bool is_instance_or_object_selected(); void load_subobject(ModelVolumeType type, bool from_galery = false); - void load_part(ModelObject& model_object, std::vector<ModelVolume*>& added_volumes, ModelVolumeType type, bool from_galery = false); + // ! ysFIXME - delete commented code after testing and rename "load_modifier" to something common + //void load_part(ModelObject& model_object, std::vector<ModelVolume*>& added_volumes, ModelVolumeType type, bool from_galery = false); void load_modifier(ModelObject& model_object, std::vector<ModelVolume*>& added_volumes, ModelVolumeType type, bool from_galery = false); void load_generic_subobject(const std::string& type_name, const ModelVolumeType type); void load_shape_object(const std::string &type_name); diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 8a1e9121d..f5168649a 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -13,6 +13,7 @@ #include "DoubleSlider.hpp" #include "Plater.hpp" #include "MainFrame.hpp" +#include "format.hpp" #include <wx/listbook.h> #include <wx/notebook.h> @@ -708,7 +709,6 @@ void Preview::update_layers_slider(const std::vector<double>& layers_z, bool kee if (m_layers_slider->IsNewPrint()) { const Print& print = wxGetApp().plater()->fff_print(); - double delta_area = scale_(scale_(25)); // equal to 25 mm2 //bool is_possible_auto_color_change = false; for (auto object : print.objects()) { @@ -729,7 +729,7 @@ void Preview::update_layers_slider(const std::vector<double>& layers_z, bool kee int i, min_solid_height = int(0.25 * num_layers); for (i = 1; i <= min_solid_height; ++ i) { double cur_area = area(object->get_layer(i)->lslices); - if (cur_area != bottom_area && fabs(cur_area - bottom_area) > scale_(scale_(1))) { + if (!DoubleSlider::equivalent_areas(bottom_area, cur_area)) { // but due to the elephant foot compensation, the first layer may be slightly smaller than the others if (i == 1 && fabs(cur_area - bottom_area) / bottom_area < 0.1) { // So, let process this case and use second layer as a bottom @@ -742,33 +742,23 @@ void Preview::update_layers_slider(const std::vector<double>& layers_z, bool kee if (i < min_solid_height) continue; - // bottom layer have to be a biggest, so control relation between bottom layer and object size - double prev_area = area(object->get_layer(i)->lslices); - for ( i++; i < num_layers; i++) { - double cur_area = area(object->get_layer(i)->lslices); - if (cur_area > prev_area && prev_area - cur_area > scale_(scale_(1))) - break; - prev_area = cur_area; - } - if (i < num_layers) - continue; - - double top_area = area(object->get_layer(int(object->layers().size()) - 1)->lslices); - if( bottom_area - top_area > delta_area) { - NotificationManager *notif_mngr = wxGetApp().plater()->get_notification_manager(); + if (DoubleSlider::check_color_change(object, i, num_layers, true, [this, object](Layer*) { + NotificationManager* notif_mngr = wxGetApp().plater()->get_notification_manager(); notif_mngr->push_notification( NotificationType::SignDetected, NotificationManager::NotificationLevel::PrintInfoNotificationLevel, - _u8L("NOTE:") + "\n" + _u8L("Sliced object looks like the sign") + "\n", - _u8L("Apply auto color change to print"), + _u8L("NOTE:") + "\n" + + format(_u8L("Sliced object \"%1%\" looks like a logo or a sign"), object->model_object()->name) + "\n", + _u8L("Apply automatic color change"), [this](wxEvtHandler*) { m_layers_slider->auto_color_change(); return true; }); notif_mngr->apply_in_preview(); - + return true; + }) ) + // first object with color chnages is found break; - } } } diff --git a/src/slic3r/GUI/GalleryDialog.cpp b/src/slic3r/GUI/GalleryDialog.cpp index 5429e2658..fef131b88 100644 --- a/src/slic3r/GUI/GalleryDialog.cpp +++ b/src/slic3r/GUI/GalleryDialog.cpp @@ -66,7 +66,7 @@ bool GalleryDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& f GalleryDialog::GalleryDialog(wxWindow* parent, bool modify_gallery/* = false*/) : - DPIDialog(parent, wxID_ANY, _L("Shapes Gallery"), wxDefaultPosition, wxSize(45 * wxGetApp().em_unit(), -1), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) + DPIDialog(parent, wxID_ANY, _L("Shape Gallery"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) { #ifndef _WIN32 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); @@ -75,7 +75,7 @@ GalleryDialog::GalleryDialog(wxWindow* parent, bool modify_gallery/* = false*/) wxStaticText* label_top = new wxStaticText(this, wxID_ANY, _L("Select shape from the gallery") + ":"); - m_list_ctrl = new wxListCtrl(this, wxID_ANY, wxDefaultPosition, wxSize(55 * wxGetApp().em_unit(), 35 * wxGetApp().em_unit()), + m_list_ctrl = new wxListCtrl(this, wxID_ANY, wxDefaultPosition, wxSize(50 * wxGetApp().em_unit(), 35 * wxGetApp().em_unit()), wxLC_ICON | wxSIMPLE_BORDER); m_list_ctrl->Bind(wxEVT_LIST_ITEM_SELECTED, &GalleryDialog::select, this); m_list_ctrl->Bind(wxEVT_LIST_ITEM_DESELECTED, &GalleryDialog::deselect, this); @@ -152,7 +152,7 @@ void GalleryDialog::on_dpi_changed(const wxRect& suggested_rect) msw_buttons_rescale(this, em, { ID_BTN_ADD_CUSTOM_SHAPE, ID_BTN_DEL_CUSTOM_SHAPE, ID_BTN_REPLACE_CUSTOM_PNG, wxID_OK, wxID_CLOSE }); - wxSize size = wxSize(55 * em, 35 * em); + wxSize size = wxSize(50 * em, 35 * em); m_list_ctrl->SetMinSize(size); m_list_ctrl->SetSize(size); @@ -461,8 +461,11 @@ void GalleryDialog::replace_custom_png(wxEvent& event) } try { + fs::path png_path = fs::path(get_dir(false) / m_selected_items[0].name); + png_path.replace_extension("png"); + fs::path current = fs::path(into_u8(input_files.Item(0))); - fs::copy_file(current, get_dir(false) / (m_selected_items[0].name + ".png"), fs::copy_option::overwrite_if_exists); + fs::copy_file(current, png_path, fs::copy_option::overwrite_if_exists); } catch (fs::filesystem_error const& e) { std::cerr << e.what() << '\n'; @@ -535,12 +538,12 @@ bool GalleryDialog::load_files(const wxArrayString& input_files) if (!fs::exists(dest_dir / current.filename())) fs::copy_file(current, dest_dir / current.filename()); else { - std::string filename = current.filename().string(); + std::string filename = current.stem().string(); int file_idx = 0; for (auto& dir_entry : fs::directory_iterator(dest_dir)) if (is_gallery_file(dir_entry, ".stl") || is_gallery_file(dir_entry, ".obj")) { - std::string name = dir_entry.path().filename().string(); + std::string name = dir_entry.path().stem().string(); if (filename == name) { if (file_idx == 0) file_idx++; diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 66e22c694..799c4e793 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -1400,7 +1400,7 @@ void MainFrame::init_menubar_as_editor() } windowMenu->AppendSeparator(); - append_menu_item(windowMenu, wxID_ANY, _L("Modify Shapes Gallery"), _L("Open the dialog to modify shapes gallery"), + append_menu_item(windowMenu, wxID_ANY, _L("Shape Gallery"), _L("Open the dialog to modify shape gallery"), [this](wxCommandEvent&) { GalleryDialog dlg(this, true); if (dlg.ShowModal() == wxID_OK) { diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index ed6f11ddb..b12256cf0 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -43,6 +43,10 @@ const NotificationManager::NotificationData NotificationManager::basic_notificat }, {NotificationType::NewAppAvailable, NotificationLevel::ImportantNotificationLevel, 20, _u8L("New version is available."), _u8L("See Releases page."), [](wxEvtHandler* evnthndlr) { wxGetApp().open_browser_with_warning_dialog("https://github.com/prusa3d/PrusaSlicer/releases"); return true; }}, + {NotificationType::NewAlphaAvailable, NotificationLevel::ImportantNotificationLevel, 20, _u8L("New alpha release is available."), _u8L("See Releases page."), [](wxEvtHandler* evnthndlr) { + wxGetApp().open_browser_with_warning_dialog("https://github.com/prusa3d/PrusaSlicer/releases"); return true; }}, + {NotificationType::NewBetaAvailable, NotificationLevel::ImportantNotificationLevel, 20, _u8L("New beta release is available."), _u8L("See Releases page."), [](wxEvtHandler* evnthndlr) { + wxGetApp().open_browser_with_warning_dialog("https://github.com/prusa3d/PrusaSlicer/releases"); return true; }}, {NotificationType::EmptyColorChangeCode, NotificationLevel::PrintInfoNotificationLevel, 10, _u8L("You have just added a G-code for color change, but its value is empty.\n" "To export the G-code correctly, check the \"Color Change G-code\" in \"Printer Settings > Custom G-code\"") }, diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index ad2e315b7..00065f795 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -52,6 +52,9 @@ enum class NotificationType // Notification on the start of PrusaSlicer, when a new PrusaSlicer version is published. // Contains a hyperlink to open a web browser pointing to the PrusaSlicer download location. NewAppAvailable, + // Like NewAppAvailable but with text and link for alpha / bet release + NewAlphaAvailable, + NewBetaAvailable, // Notification on the start of PrusaSlicer, when updates of system profiles are detected. // Contains a hyperlink to execute installation of the new system profiles. PresetUpdateAvailable, diff --git a/src/slic3r/GUI/OG_CustomCtrl.cpp b/src/slic3r/GUI/OG_CustomCtrl.cpp index f01a1e962..9c31f679b 100644 --- a/src/slic3r/GUI/OG_CustomCtrl.cpp +++ b/src/slic3r/GUI/OG_CustomCtrl.cpp @@ -72,6 +72,11 @@ void OG_CustomCtrl::init_ctrl_lines() const std::vector<Line>& og_lines = opt_group->get_lines(); for (const Line& line : og_lines) { + if (line.is_separator()) { + ctrl_lines.emplace_back(CtrlLine(0, this, line)); + continue; + } + if (line.full_width && ( // description line line.widget != nullptr || @@ -124,6 +129,15 @@ wxPoint OG_CustomCtrl::get_pos(const Line& line, Field* field_in/* = nullptr*/) line_height = win_height; }; + auto correct_horiz_pos = [this](int& h_pos, Field* field) { + if (m_max_win_width > 0 && field->getWindow()) { + int win_width = field->getWindow()->GetSize().GetWidth(); + if (dynamic_cast<CheckBox*>(field)) + win_width *= 0.5; + h_pos += m_max_win_width - win_width; + } + }; + for (CtrlLine& ctrl_line : ctrl_lines) { if (&ctrl_line.og_line == &line) { @@ -160,6 +174,7 @@ wxPoint OG_CustomCtrl::get_pos(const Line& line, Field* field_in/* = nullptr*/) h_pos += 3 * blinking_button_width; Field* field = opt_group->get_field(option_set.front().opt_id); correct_line_height(ctrl_line.height, field->getWindow()); + correct_horiz_pos(h_pos, field); break; } @@ -189,8 +204,10 @@ wxPoint OG_CustomCtrl::get_pos(const Line& line, Field* field_in/* = nullptr*/) } h_pos += (opt.opt.gui_type == ConfigOptionDef::GUIType::legend ? 1 : 3) * blinking_button_width; - if (field == field_in) + if (field == field_in) { + correct_horiz_pos(h_pos, field); break; + } if (opt.opt.gui_type == ConfigOptionDef::GUIType::legend) h_pos += 2 * blinking_button_width; @@ -361,6 +378,28 @@ void OG_CustomCtrl::correct_widgets_position(wxSizer* widget, const Line& line, } }; +void OG_CustomCtrl::init_max_win_width() +{ + if (opt_group->ctrl_horiz_alignment == wxALIGN_RIGHT && m_max_win_width == 0) + for (CtrlLine& line : ctrl_lines) { + if (int max_win_width = line.get_max_win_width(); + m_max_win_width < max_win_width) + m_max_win_width = max_win_width; + } +} + +void OG_CustomCtrl::set_max_win_width(int max_win_width) +{ + if (m_max_win_width == max_win_width) + return; + m_max_win_width = max_win_width; + for (CtrlLine& line : ctrl_lines) + line.correct_items_positions(); + + GetParent()->Layout(); +} + + void OG_CustomCtrl::msw_rescale() { #ifdef __WXOSX__ @@ -374,6 +413,8 @@ void OG_CustomCtrl::msw_rescale() m_bmp_mode_sz = create_scaled_bitmap("mode_simple", this, wxOSX ? 10 : 12).GetSize(); m_bmp_blinking_sz = create_scaled_bitmap("search_blink", this).GetSize(); + m_max_win_width = 0; + wxCoord v_pos = 0; for (CtrlLine& line : ctrl_lines) { line.msw_rescale(); @@ -407,6 +448,21 @@ OG_CustomCtrl::CtrlLine::CtrlLine( wxCoord height, } } +int OG_CustomCtrl::CtrlLine::get_max_win_width() +{ + int max_win_width = 0; + if (!draw_just_act_buttons) { + const std::vector<Option>& option_set = og_line.get_options(); + for (auto opt : option_set) { + Field* field = ctrl->opt_group->get_field(opt.opt_id); + if (field && field->getWindow()) + max_win_width = field->getWindow()->GetSize().GetWidth(); + } + } + + return max_win_width; +} + void OG_CustomCtrl::CtrlLine::correct_items_positions() { if (draw_just_act_buttons || !is_visible) @@ -447,6 +503,8 @@ void OG_CustomCtrl::CtrlLine::msw_rescale() void OG_CustomCtrl::CtrlLine::update_visibility(ConfigOptionMode mode) { + if (og_line.is_separator()) + return; const std::vector<Option>& option_set = og_line.get_options(); const ConfigOptionMode& line_mode = option_set.front().opt.mode; @@ -480,8 +538,25 @@ void OG_CustomCtrl::CtrlLine::update_visibility(ConfigOptionMode mode) correct_items_positions(); } +void OG_CustomCtrl::CtrlLine::render_separator(wxDC& dc, wxCoord v_pos) +{ + wxPoint begin(ctrl->m_h_gap, v_pos); + wxPoint end(ctrl->GetSize().GetWidth() - ctrl->m_h_gap, v_pos); + + wxPen pen, old_pen = pen = dc.GetPen(); + pen.SetColour(*wxLIGHT_GREY); + dc.SetPen(pen); + dc.DrawLine(begin, end); + dc.SetPen(old_pen); +} + void OG_CustomCtrl::CtrlLine::render(wxDC& dc, wxCoord v_pos) { + if (is_separator()) { + render_separator(dc, v_pos); + return; + } + Field* field = ctrl->opt_group->get_field(og_line.get_options().front().opt_id); bool suppress_hyperlinks = get_app_config()->get("suppress_hyperlinks") == "1"; diff --git a/src/slic3r/GUI/OG_CustomCtrl.hpp b/src/slic3r/GUI/OG_CustomCtrl.hpp index afbc6c930..117ca6920 100644 --- a/src/slic3r/GUI/OG_CustomCtrl.hpp +++ b/src/slic3r/GUI/OG_CustomCtrl.hpp @@ -33,6 +33,8 @@ class OG_CustomCtrl :public wxPanel wxSize m_bmp_mode_sz; wxSize m_bmp_blinking_sz; + int m_max_win_width{0}; + struct CtrlLine { wxCoord height { wxDefaultCoord }; OG_CustomCtrl* ctrl { nullptr }; @@ -50,16 +52,20 @@ class OG_CustomCtrl :public wxPanel bool draw_mode_bitmap = true); ~CtrlLine() { ctrl = nullptr; } + int get_max_win_width(); void correct_items_positions(); void msw_rescale(); void update_visibility(ConfigOptionMode mode); + void render_separator(wxDC& dc, wxCoord v_pos); + void render(wxDC& dc, wxCoord v_pos); wxCoord draw_mode_bmp(wxDC& dc, wxCoord v_pos); wxCoord draw_text (wxDC& dc, wxPoint pos, const wxString& text, const wxColour* color, int width, bool is_url = false); wxPoint draw_blinking_bmp(wxDC& dc, wxPoint pos, bool is_blinking); wxCoord draw_act_bmps(wxDC& dc, wxPoint pos, const wxBitmap& bmp_undo_to_sys, const wxBitmap& bmp_undo, bool is_blinking, size_t rect_id = 0); bool launch_browser() const; + bool is_separator() const { return og_line.is_separator(); } std::vector<wxRect> rects_undo_icon; std::vector<wxRect> rects_undo_to_sys_icon; @@ -86,6 +92,9 @@ public: bool update_visibility(ConfigOptionMode mode); void correct_window_position(wxWindow* win, const Line& line, Field* field = nullptr); void correct_widgets_position(wxSizer* widget, const Line& line, Field* field = nullptr); + void init_max_win_width(); + void set_max_win_width(int max_win_width); + int get_max_win_width() { return m_max_win_width; } void msw_rescale(); void sys_color_changed(); diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index b57b7f302..fd9f4b5e8 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -126,6 +126,12 @@ bool OptionsGroup::is_legend_line() return false; } +void OptionsGroup::set_max_win_width(int max_win_width) +{ + if (custom_ctrl) + custom_ctrl->set_max_win_width(max_win_width); +} + void OptionsGroup::show_field(const t_config_option_key& opt_key, bool show/* = true*/) { Field* field = get_field(opt_key); @@ -185,8 +191,16 @@ void OptionsGroup::append_line(const Line& line) m_options_mode.push_back(option_set[0].opt.mode); } +void OptionsGroup::append_separator() +{ + m_lines.emplace_back(Line()); +} + void OptionsGroup::activate_line(Line& line) { + if (line.is_separator()) + return; + m_use_custom_ctrl_as_parent = false; if (line.full_width && ( @@ -396,7 +410,7 @@ void OptionsGroup::activate_line(Line& line) } // create all controls for the option group from the m_lines -bool OptionsGroup::activate(std::function<void()> throw_if_canceled) +bool OptionsGroup::activate(std::function<void()> throw_if_canceled/* = [](){}*/, int horiz_alignment/* = wxALIGN_LEFT*/) { if (sizer)//(!sizer->IsEmpty()) return false; @@ -436,6 +450,10 @@ bool OptionsGroup::activate(std::function<void()> throw_if_canceled) throw_if_canceled(); activate_line(line); } + + ctrl_horiz_alignment = horiz_alignment; + if (custom_ctrl) + custom_ctrl->init_max_win_width(); } catch (UIBuildCanceled&) { auto p = sizer; this->clear(); diff --git a/src/slic3r/GUI/OptionsGroup.hpp b/src/slic3r/GUI/OptionsGroup.hpp index 592f2cd76..597527aef 100644 --- a/src/slic3r/GUI/OptionsGroup.hpp +++ b/src/slic3r/GUI/OptionsGroup.hpp @@ -49,6 +49,7 @@ using t_option = std::unique_ptr<Option>; //! /// Represents option lines class Line { + bool m_is_separator{ false }; public: wxString label; wxString label_tooltip; @@ -71,6 +72,9 @@ public: } Line(wxString label, wxString tooltip) : label(_(label)), label_tooltip(_(tooltip)) {} + Line() : m_is_separator(true) {} + + bool is_separator() const { return m_is_separator; } const std::vector<widget_t>& get_extra_widgets() const {return m_extra_widgets;} const std::vector<Option>& get_options() const { return m_options; } @@ -95,6 +99,7 @@ public: size_t label_width = 20 ;// {200}; wxSizer* sizer {nullptr}; OG_CustomCtrl* custom_ctrl{ nullptr }; + int ctrl_horiz_alignment{ wxALIGN_LEFT}; column_t extra_column {nullptr}; t_change m_on_change { nullptr }; // To be called when the field loses focus, to assign a new initial value to the field. @@ -124,12 +129,13 @@ public: void activate_line(Line& line); // create all controls for the option group from the m_lines - bool activate(std::function<void()> throw_if_canceled = [](){}); + bool activate(std::function<void()> throw_if_canceled = [](){}, int horiz_alignment = wxALIGN_LEFT); // delete all controls from the option group void clear(bool destroy_custom_ctrl = false); Line create_single_option_line(const Option& option, const wxString& path = wxEmptyString) const; void append_single_option_line(const Option& option, const wxString& path = wxEmptyString) { append_line(create_single_option_line(option, path)); } + void append_separator(); // return a non-owning pointer reference inline Field* get_field(const t_config_option_key& id) const{ @@ -171,6 +177,9 @@ public: wxGridSizer* get_grid_sizer() { return m_grid_sizer; } const std::vector<Line>& get_lines() { return m_lines; } bool is_legend_line(); + // if we have to set the same control alignment for different option groups, + // we have to set same max contrtol width to all of them + void set_max_win_width(int max_win_width); protected: std::map<t_config_option_key, Option> m_options; diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 9d1236922..ae52b52a9 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -8,8 +8,39 @@ #include <wx/notebook.h> #include "Notebook.hpp" #include "ButtonsDescription.hpp" +#include "OG_CustomCtrl.hpp" +#include <initializer_list> namespace Slic3r { + + static t_config_enum_names enum_names_from_keys_map(const t_config_enum_values& enum_keys_map) + { + t_config_enum_names names; + int cnt = 0; + for (const auto& kvp : enum_keys_map) + cnt = std::max(cnt, kvp.second); + cnt += 1; + names.assign(cnt, ""); + for (const auto& kvp : enum_keys_map) + names[kvp.second] = kvp.first; + return names; + } + +#define CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(NAME) \ + static t_config_enum_names s_keys_names_##NAME = enum_names_from_keys_map(s_keys_map_##NAME); \ + template<> const t_config_enum_values& ConfigOptionEnum<NAME>::get_enum_values() { return s_keys_map_##NAME; } \ + template<> const t_config_enum_names& ConfigOptionEnum<NAME>::get_enum_names() { return s_keys_names_##NAME; } + + + + static const t_config_enum_values s_keys_map_NotifyReleaseMode = { + {"all", NotifyReleaseAll}, + {"release", NotifyReleaseOnly}, + {"none", NotifyReleaseNone}, + }; + + CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(NotifyReleaseMode) + namespace GUI { PreferencesDialog::PreferencesDialog(wxWindow* parent, int selected_tab) : @@ -39,7 +70,7 @@ static std::shared_ptr<ConfigOptionsGroup>create_options_tab(const wxString& tit static void activate_options_tab(std::shared_ptr<ConfigOptionsGroup> optgroup) { - optgroup->activate(); + optgroup->activate([](){}, wxALIGN_RIGHT); optgroup->update_visibility(comSimple); wxBoxSizer* sizer = static_cast<wxBoxSizer*>(static_cast<wxPanel*>(optgroup->parent())->GetSizer()); sizer->Add(optgroup->sizer, 0, wxEXPAND | wxALL, 10); @@ -116,6 +147,8 @@ void PreferencesDialog::build(size_t selected_tab) option = Option(def, "version_check"); m_optgroup_general->append_single_option_line(option); + m_optgroup_general->append_separator(); + // Please keep in sync with ConfigWizard def.label = L("Export sources full pathnames to 3mf and amf"); def.type = coBool; @@ -141,6 +174,8 @@ void PreferencesDialog::build(size_t selected_tab) m_optgroup_general->append_single_option_line(option); #endif // _WIN32 + m_optgroup_general->append_separator(); + // Please keep in sync with ConfigWizard def.label = L("Update built-in Presets automatically"); def.type = coBool; @@ -165,6 +200,8 @@ void PreferencesDialog::build(size_t selected_tab) option = Option(def, "show_incompatible_presets"); m_optgroup_general->append_single_option_line(option); + m_optgroup_general->append_separator(); + def.label = L("Show drop project dialog"); def.type = coBool; def.tooltip = L("When checked, whenever dragging and dropping a project file on the application, shows a dialog asking to select the action to take on the file to load."); @@ -172,7 +209,6 @@ void PreferencesDialog::build(size_t selected_tab) option = Option(def, "show_drop_project_dialog"); m_optgroup_general->append_single_option_line(option); - #if __APPLE__ def.label = L("Allow just a single PrusaSlicer instance"); def.type = coBool; @@ -186,6 +222,8 @@ void PreferencesDialog::build(size_t selected_tab) option = Option(def, "single_instance"); m_optgroup_general->append_single_option_line(option); + m_optgroup_general->append_separator(); + def.label = L("Ask for unsaved changes when closing application or loading new project"); def.type = coBool; def.tooltip = L("Always ask for unsaved changes, when: \n" @@ -230,6 +268,8 @@ void PreferencesDialog::build(size_t selected_tab) m_optgroup_general->append_single_option_line(option); #endif + m_optgroup_general->append_separator(); + // Show/Hide splash screen def.label = L("Show splash screen"); def.type = coBool; @@ -291,7 +331,15 @@ void PreferencesDialog::build(size_t selected_tab) m_optgroup_gui->m_on_change = [this, tabs](t_config_option_key opt_key, boost::any value) { if (opt_key == "suppress_hyperlinks") m_values[opt_key] = boost::any_cast<bool>(value) ? "1" : ""; - else + else if (opt_key == "notify_release") { + int val_int = boost::any_cast<int>(value); + for (const auto& item : s_keys_map_NotifyReleaseMode) { + if (item.second == val_int) { + m_values[opt_key] = item.first; + break; + } + } + } else m_values[opt_key] = boost::any_cast<bool>(value) ? "1" : "0"; if (opt_key == "use_custom_toolbar_size") { @@ -300,6 +348,8 @@ void PreferencesDialog::build(size_t selected_tab) tabs->Layout(); this->layout(); } + + }; def.label = L("Sequential slider applied only to top layer"); @@ -361,7 +411,9 @@ void PreferencesDialog::build(size_t selected_tab) option = Option(def, "tabs_as_menu"); m_optgroup_gui->append_single_option_line(option); #endif - + + m_optgroup_gui->append_separator(); + def.label = L("Show \"Tip of the day\" notification after start"); def.type = coBool; def.tooltip = L("If enabled, useful hints are displayed at startup."); @@ -369,15 +421,37 @@ void PreferencesDialog::build(size_t selected_tab) option = Option(def, "show_hints"); m_optgroup_gui->append_single_option_line(option); + ConfigOptionDef def_enum; + def_enum.label = L("Notify about new releases"); + def_enum.type = coEnum; + def_enum.tooltip = L("You will be notified about new release after startup acordingly: All = Regular release and alpha / beta releases. Release only = regular release."); + def_enum.enum_keys_map = &ConfigOptionEnum<NotifyReleaseMode>::get_enum_values(); + def_enum.enum_values.push_back("all"); + def_enum.enum_values.push_back("release"); + def_enum.enum_values.push_back("none"); + def_enum.enum_labels.push_back(L("All")); + def_enum.enum_labels.push_back(L("Release only")); + def_enum.enum_labels.push_back(L("None")); + def_enum.mode = comSimple; + def_enum.set_default_value(new ConfigOptionEnum<NotifyReleaseMode>(static_cast<NotifyReleaseMode>(s_keys_map_NotifyReleaseMode.at(app_config->get("notify_release"))))); + option = Option(def_enum, "notify_release"); + m_optgroup_gui->append_single_option_line(option); + + m_optgroup_gui->append_separator(); + def.label = L("Use custom size for toolbar icons"); def.type = coBool; def.tooltip = L("If enabled, you can change size of toolbar icons manually."); def.set_default_value(new ConfigOptionBool{ app_config->get("use_custom_toolbar_size") == "1" }); option = Option(def, "use_custom_toolbar_size"); m_optgroup_gui->append_single_option_line(option); + } activate_options_tab(m_optgroup_gui); + // set Field for notify_release to its value to activate the object + boost::any val = s_keys_map_NotifyReleaseMode.at(app_config->get("notify_release")); + m_optgroup_gui->get_field("notify_release")->set_value(val, false); if (is_editor) { create_icon_size_slider(); @@ -406,6 +480,9 @@ void PreferencesDialog::build(size_t selected_tab) } #endif // ENABLE_ENVIRONMENT_MAP + // update alignment of the controls for all tabs + update_ctrls_alignment(); + if (selected_tab < tabs->GetPageCount()) tabs->SetSelection(selected_tab); @@ -425,6 +502,20 @@ void PreferencesDialog::build(size_t selected_tab) this->CenterOnParent(); } +void PreferencesDialog::update_ctrls_alignment() +{ + int max_ctrl_width{ 0 }; + std::initializer_list<ConfigOptionsGroup*> og_list = { m_optgroup_general.get(), m_optgroup_camera.get(), m_optgroup_gui.get() }; + for (auto og : og_list) { + if (int max = og->custom_ctrl->get_max_win_width(); + max_ctrl_width < max) + max_ctrl_width = max; + } + if (max_ctrl_width) + for (auto og : og_list) + og->custom_ctrl->set_max_win_width(max_ctrl_width); +} + void PreferencesDialog::accept(wxEvent&) { // if (m_values.find("no_defaults") != m_values.end() diff --git a/src/slic3r/GUI/Preferences.hpp b/src/slic3r/GUI/Preferences.hpp index 4e5b58df0..7f708ff9c 100644 --- a/src/slic3r/GUI/Preferences.hpp +++ b/src/slic3r/GUI/Preferences.hpp @@ -10,6 +10,13 @@ class wxColourPickerCtrl; namespace Slic3r { + + enum NotifyReleaseMode { + NotifyReleaseAll, + NotifyReleaseOnly, + NotifyReleaseNone + }; + namespace GUI { class ConfigOptionsGroup; @@ -39,6 +46,7 @@ public: bool seq_top_layer_only_changed() const { return m_seq_top_layer_only_changed; } bool recreate_GUI() const { return m_recreate_GUI; } void build(size_t selected_tab = 0); + void update_ctrls_alignment(); void accept(wxEvent&); protected: diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 3ab9b7bdc..6a82ca8d3 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -444,11 +444,25 @@ void Selection::clear() if (m_list.empty()) return; +#if ENABLE_MODIFIERS_ALWAYS_TRANSPARENT + // ensure that the volumes get the proper color before next call to render (expecially needed for transparent volumes) + for (unsigned int i : m_list) { + GLVolume& volume = *(*m_volumes)[i]; + volume.selected = false; + bool transparent = volume.color[3] < 1.0f; + if (transparent) + volume.force_transparent = true; + volume.set_render_color(); + if (transparent) + volume.force_transparent = false; + } +#else for (unsigned int i : m_list) { (*m_volumes)[i]->selected = false; // ensure the volume gets the proper color before next call to render (expecially needed for transparent volumes) (*m_volumes)[i]->set_render_color(); } +#endif // ENABLE_MODIFIERS_ALWAYS_TRANSPARENT m_list.clear(); diff --git a/src/slic3r/Utils/PresetUpdater.cpp b/src/slic3r/Utils/PresetUpdater.cpp index 97c6cb2a5..13c631c9c 100644 --- a/src/slic3r/Utils/PresetUpdater.cpp +++ b/src/slic3r/Utils/PresetUpdater.cpp @@ -141,7 +141,8 @@ struct Updates wxDEFINE_EVENT(EVT_SLIC3R_VERSION_ONLINE, wxCommandEvent); - +wxDEFINE_EVENT(EVT_SLIC3R_ALPHA_VERSION_ONLINE, wxCommandEvent); +wxDEFINE_EVENT(EVT_SLIC3R_BETA_VERSION_ONLINE, wxCommandEvent); struct PresetUpdater::priv { @@ -167,6 +168,7 @@ struct PresetUpdater::priv bool get_file(const std::string &url, const fs::path &target_path) const; void prune_tmps() const; void sync_version() const; + void parse_version_string(const std::string& body) const; void sync_config(const VendorMap vendors); void check_install_indices() const; @@ -262,23 +264,68 @@ void PresetUpdater::priv::sync_version() const }) .on_complete([&](std::string body, unsigned /* http_status */) { boost::trim(body); - const auto nl_pos = body.find_first_of("\n\r"); - if (nl_pos != std::string::npos) { - body.resize(nl_pos); - } + parse_version_string(body); + }) + .perform_sync(); +} - if (! Semver::parse(body)) { - BOOST_LOG_TRIVIAL(warning) << format("Received invalid contents from `%1%`: Not a correct semver: `%2%`", SLIC3R_APP_NAME, body); +// Parses version string obtained in sync_version() and sends events to UI thread. +// Version string must contain release version on first line. Follows non-mandatory alpha / beta releases on following lines (alpha=2.0.0-alpha1). +void PresetUpdater::priv::parse_version_string(const std::string& body) const +{ + // release version + std::string version; + const auto first_nl_pos = body.find_first_of("\n\r"); + if (first_nl_pos != std::string::npos) + version = body.substr(0, first_nl_pos); + else + version = body; + if (!Semver::parse(version)) { + BOOST_LOG_TRIVIAL(warning) << format("Received invalid contents from `%1%`: Not a correct semver: `%2%`", SLIC3R_APP_NAME, version); + return; + } + BOOST_LOG_TRIVIAL(info) << format("Got %1% online version: `%2%`. Sending to GUI thread...", SLIC3R_APP_NAME, version); + wxCommandEvent* evt = new wxCommandEvent(EVT_SLIC3R_VERSION_ONLINE); + evt->SetString(GUI::from_u8(version)); + GUI::wxGetApp().QueueEvent(evt); + + // alpha / beta version + size_t nexn_nl_pos = first_nl_pos; + while (nexn_nl_pos != std::string::npos && body.size() > nexn_nl_pos + 1) { + const auto last_nl_pos = nexn_nl_pos; + nexn_nl_pos = body.find_first_of("\n\r", last_nl_pos + 1); + std::string line; + if (nexn_nl_pos == std::string::npos) + line = body.substr(last_nl_pos + 1); + else + line = body.substr(last_nl_pos + 1, nexn_nl_pos - last_nl_pos - 1); + + // alpha + if (line.substr(0, 6) == "alpha=") { + version = line.substr(6); + if (!Semver::parse(version)) { + BOOST_LOG_TRIVIAL(warning) << format("Received invalid contents for alpha release from `%1%`: Not a correct semver: `%2%`", SLIC3R_APP_NAME, version); return; } + BOOST_LOG_TRIVIAL(info) << format("Got %1% online version of alpha release: `%2%`. Sending to GUI thread...", SLIC3R_APP_NAME, version); + wxCommandEvent* evt = new wxCommandEvent(EVT_SLIC3R_ALPHA_VERSION_ONLINE); + evt->SetString(GUI::from_u8(version)); + GUI::wxGetApp().QueueEvent(evt); - BOOST_LOG_TRIVIAL(info) << format("Got %1% online version: `%2%`. Sending to GUI thread...", SLIC3R_APP_NAME, body); - - wxCommandEvent* evt = new wxCommandEvent(EVT_SLIC3R_VERSION_ONLINE); - evt->SetString(GUI::from_u8(body)); + // beta + } + else if (line.substr(0, 5) == "beta=") { + version = line.substr(5); + if (!Semver::parse(version)) { + BOOST_LOG_TRIVIAL(warning) << format("Received invalid contents for beta release from `%1%`: Not a correct semver: `%2%`", SLIC3R_APP_NAME, version); + return; + } + BOOST_LOG_TRIVIAL(info) << format("Got %1% online version of beta release: `%2%`. Sending to GUI thread...", SLIC3R_APP_NAME, version); + wxCommandEvent* evt = new wxCommandEvent(EVT_SLIC3R_BETA_VERSION_ONLINE); + evt->SetString(GUI::from_u8(version)); GUI::wxGetApp().QueueEvent(evt); - }) - .perform_sync(); + } + } } // Download vendor indices. Also download new bundles if an index indicates there's a new one available. diff --git a/src/slic3r/Utils/PresetUpdater.hpp b/src/slic3r/Utils/PresetUpdater.hpp index d7eeb5604..b7937c574 100644 --- a/src/slic3r/Utils/PresetUpdater.hpp +++ b/src/slic3r/Utils/PresetUpdater.hpp @@ -61,7 +61,7 @@ private: }; wxDECLARE_EVENT(EVT_SLIC3R_VERSION_ONLINE, wxCommandEvent); - - +wxDECLARE_EVENT(EVT_SLIC3R_ALPHA_VERSION_ONLINE, wxCommandEvent); +wxDECLARE_EVENT(EVT_SLIC3R_BETA_VERSION_ONLINE, wxCommandEvent); } #endif |