Merge remote-tracking branch 'origin/master' into ys_selection

This commit is contained in:
YuSanka 2019-04-04 15:09:37 +02:00
commit 63dea6d5dc
43 changed files with 623 additions and 196 deletions

View file

@ -98,8 +98,9 @@ void BackgroundSlicingProcess::process_sla()
m_print->process();
if (this->set_step_started(bspsGCodeFinalize)) {
if (! m_export_path.empty()) {
m_sla_print->export_raster(m_export_path);
m_print->set_status(100, "Masked SLA file exported to " + m_export_path);
const std::string export_path = m_sla_print->print_statistics().finalize_output_path(m_export_path);
m_sla_print->export_raster(export_path);
m_print->set_status(100, "Masked SLA file exported to " + export_path);
} else if (! m_upload_job.empty()) {
prepare_upload();
} else {
@ -389,7 +390,7 @@ void BackgroundSlicingProcess::prepare_upload()
// Generate a unique temp path to which the gcode/zip file is copied/exported
boost::filesystem::path source_path = boost::filesystem::temp_directory_path()
/ boost::filesystem::unique_path(".printhost.%%%%-%%%%-%%%%-%%%%.gcode");
/ boost::filesystem::unique_path(".Slic3rPE.upload.%%%%-%%%%-%%%%-%%%%");
if (m_print == m_fff_print) {
m_print->set_status(95, "Running post-processing scripts");
@ -399,8 +400,8 @@ void BackgroundSlicingProcess::prepare_upload()
run_post_process_scripts(source_path.string(), m_fff_print->config());
m_upload_job.upload_data.upload_path = m_fff_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string());
} else {
m_sla_print->export_raster(source_path.string());
// TODO: Also finalize upload path like with FFF when there are statistics for SLA print
m_upload_job.upload_data.upload_path = m_sla_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string());
m_sla_print->export_raster(source_path.string(), m_upload_job.upload_data.upload_path.string());
}
m_print->set_status(100, (boost::format("Scheduling upload to `%1%`. See Window -> Print Host Upload Queue") % m_upload_job.printhost->get_host()).str());

View file

@ -1,5 +1,7 @@
#include "BitmapCache.hpp"
#include "libslic3r/Utils.hpp"
#if ! defined(WIN32) && ! defined(__APPLE__)
#define BROKEN_ALPHA
#endif
@ -9,6 +11,11 @@
#include <wx/rawbmp.h>
#endif /* BROKEN_ALPHA */
#define NANOSVG_IMPLEMENTATION
#include "nanosvg/nanosvg.h"
#define NANOSVGRAST_IMPLEMENTATION
#include "nanosvg/nanosvgrast.h"
namespace Slic3r { namespace GUI {
void BitmapCache::clear()
@ -155,6 +162,72 @@ wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap *beg
#endif
}
wxBitmap* BitmapCache::insert_raw_rgba(const std::string &bitmap_key, unsigned int width, unsigned int height, const unsigned char *raw_data)
{
wxImage image(width, height);
image.InitAlpha();
unsigned char *rgb = image.GetData();
unsigned char *alpha = image.GetAlpha();
unsigned int pixels = width * height;
for (unsigned int i = 0; i < pixels; ++ i) {
*rgb ++ = *raw_data ++;
*rgb ++ = *raw_data ++;
*rgb ++ = *raw_data ++;
*alpha ++ = *raw_data ++;
}
return this->insert(bitmap_key, wxImage_to_wxBitmap_with_alpha(std::move(image)));
}
wxBitmap* BitmapCache::load_png(const std::string &bitmap_name, unsigned int height)
{
std::string bitmap_key = bitmap_name + "-h" + std::to_string(height);
auto it = m_map.find(bitmap_key);
if (it != m_map.end())
return it->second;
wxImage image;
if (! image.LoadFile(Slic3r::GUI::from_u8(Slic3r::var(bitmap_name + ".png")), wxBITMAP_TYPE_PNG) ||
image.GetWidth() == 0 || image.GetHeight() == 0)
return nullptr;
if (image.GetHeight() != height)
image.Rescale(int(0.5f + float(image.GetWidth()) * height / image.GetHeight()), height, wxIMAGE_QUALITY_BILINEAR);
return this->insert(bitmap_key, wxImage_to_wxBitmap_with_alpha(std::move(image)));
}
wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned int target_height)
{
std::string bitmap_key = bitmap_name + "-h" + std::to_string(target_height);
auto it = m_map.find(bitmap_key);
if (it != m_map.end())
return it->second;
NSVGimage *image = ::nsvgParseFromFile(Slic3r::var(bitmap_name + ".svg").c_str(), "px", 96.0f);
if (image == nullptr)
return nullptr;
float scale = (float)target_height / image->height;
int width = (int)(scale * image->width + 0.5f);
int height = (int)(scale * image->height + 0.5f);
int n_pixels = width * height;
if (n_pixels <= 0) {
::nsvgDelete(image);
return nullptr;
}
NSVGrasterizer *rast = ::nsvgCreateRasterizer();
if (rast == nullptr) {
::nsvgDelete(image);
return nullptr;
}
std::vector<unsigned char> data(n_pixels * 4, 0);
::nsvgRasterize(rast, image, 0, 0, scale, data.data(), width, height, width * 4);
::nsvgDeleteRasterizer(rast);
::nsvgDelete(image);
return this->insert_raw_rgba(bitmap_key, width, height, data.data());
}
wxBitmap BitmapCache::mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency)
{
wxImage image(width, height);

View file

@ -29,6 +29,12 @@ public:
wxBitmap* insert(const std::string &name, const wxBitmap &bmp, const wxBitmap &bmp2, const wxBitmap &bmp3);
wxBitmap* insert(const std::string &name, const std::vector<wxBitmap> &bmps) { return this->insert(name, &bmps.front(), &bmps.front() + bmps.size()); }
wxBitmap* insert(const std::string &name, const wxBitmap *begin, const wxBitmap *end);
wxBitmap* insert_raw_rgba(const std::string &bitmap_key, unsigned int width, unsigned int height, const unsigned char *raw_data);
// Load png from resources/icons. bitmap_key is given without the .png suffix. Bitmap will be rescaled to provided height if nonzero.
wxBitmap* load_png(const std::string &bitmap_key, unsigned int height = 0);
// Load svg from resources/icons. bitmap_key is given without the .svg suffix. SVG will be rasterized to provided height.
wxBitmap* load_svg(const std::string &bitmap_key, unsigned int height);
static wxBitmap mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency);
static wxBitmap mksolid(size_t width, size_t height, const unsigned char rgb[3]) { return mksolid(width, height, rgb[0], rgb[1], rgb[2], wxALPHA_OPAQUE); }

View file

@ -11,15 +11,11 @@
#include <vector>
#include <algorithm>
#define NANOSVG_IMPLEMENTATION
#include "nanosvg/nanosvg.h"
#define NANOSVGRAST_IMPLEMENTATION
#include "nanosvg/nanosvgrast.h"
#include "libslic3r/Utils.hpp"
#include "libslic3r/Utils.hpp"
namespace Slic3r {
namespace GUI {
@ -378,6 +374,7 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, uns
if (n_pixels <= 0)
{
reset();
nsvgDelete(image);
return false;
}

View file

@ -525,7 +525,6 @@ void ObjectList::key_event(wxKeyEvent& event)
|| event.GetKeyCode() == WXK_BACK
#endif //__WXOSX__
) {
printf("WXK_BACK\n");
remove();
}
else if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_CONTROL/*WXK_SHIFT*/))

View file

@ -181,7 +181,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
changed_box = true;
}
if (changed_box || !m_cache.instance.matches_instance(instance_idx) || !m_cache.scale.isApprox(100.0 * m_new_scale))
m_new_size = volume->get_instance_transformation().get_matrix(true, true) * m_cache.instance.box_size;
m_new_size = (volume->get_instance_transformation().get_matrix(true, true) * m_cache.instance.box_size).cwiseAbs();
}
else
// this should never happen
@ -211,7 +211,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
m_new_position = volume->get_volume_offset();
m_new_rotation = volume->get_volume_rotation();
m_new_scale = volume->get_volume_scaling_factor();
m_new_size = volume->get_volume_transformation().get_matrix(true, true) * volume->bounding_box.size();
m_new_size = (volume->get_volume_transformation().get_matrix(true, true) * volume->bounding_box.size()).cwiseAbs();
m_new_enabled = true;
}
else if (obj_list->multiple_selection() || obj_list->is_selected(itInstanceRoot))

View file

@ -85,7 +85,8 @@ void ObjectSettings::update_settings_list()
#endif // __WXMSW__
btn->Bind(wxEVT_BUTTON, [opt_key, config, this](wxEvent &event) {
config->erase(opt_key);
wxTheApp->CallAfter([this]() {
wxGetApp().obj_list()->part_settings_changed();
wxTheApp->CallAfter([this]() {
wxWindowUpdateLocker noUpdates(m_parent);
update_settings_list();
m_parent->Layout();

View file

@ -15,12 +15,6 @@ namespace Slic3r {
namespace GUI {
// GLGizmoCut
class GLGizmoCutPanel : public wxPanel
{
public:
@ -192,7 +186,7 @@ void GLGizmoCut::on_render_input_window(float x, float y, float bottom_limit, co
m_imgui->set_next_window_bg_alpha(0.5f);
m_imgui->begin(_(L("Cut")), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
ImGui::PushItemWidth(100.0f);
ImGui::PushItemWidth(m_imgui->scaled(5.0f));
bool _value_changed = ImGui::InputDouble("Z", &m_cut_z, 0.0f, 0.0f, "%.2f");
m_imgui->checkbox(_(L("Keep upper part")), m_keep_upper);

View file

@ -330,8 +330,12 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
m_canvas_width = m_parent.get_canvas_size().get_width();
m_canvas_height = m_parent.get_canvas_size().get_height();
}
else
select_point(m_hover_id);
else {
if (m_editing_mode_cache[m_hover_id].selected)
unselect_point(m_hover_id);
else
select_point(m_hover_id);
}
return true;
}
@ -565,12 +569,12 @@ void GLGizmoSlaSupports::on_render_input_window(float x, float y, float bottom_l
RENDER_AGAIN:
m_imgui->set_next_window_pos(x, y, ImGuiCond_Always);
const ImVec2 window_size(m_imgui->scaled(15.f, 16.5f));
const ImVec2 window_size(m_imgui->scaled(17.f, 18.f));
ImGui::SetNextWindowPos(ImVec2(x, y - std::max(0.f, y+window_size.y-bottom_limit) ));
ImGui::SetNextWindowSize(ImVec2(window_size));
m_imgui->set_next_window_bg_alpha(0.5f);
m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
ImGui::PushItemWidth(100.0f);
@ -791,6 +795,19 @@ void GLGizmoSlaSupports::select_point(int i)
}
void GLGizmoSlaSupports::unselect_point(int i)
{
m_editing_mode_cache[i].selected = false;
m_selection_empty = true;
for (const CacheEntry& ce : m_editing_mode_cache) {
if (ce.selected) {
m_selection_empty = false;
break;
}
}
}
void GLGizmoSlaSupports::editing_mode_discard_changes()
{

View file

@ -93,6 +93,7 @@ private:
NoPoints,
};
void select_point(int i);
void unselect_point(int i);
void editing_mode_apply_changes();
void editing_mode_discard_changes();
void editing_mode_reload_cache();

View file

@ -340,13 +340,11 @@ bool ImGuiWrapper::want_any_input() const
void ImGuiWrapper::init_font()
{
const float font_size = m_font_size * m_style_scaling;
destroy_font();
ImGuiIO& io = ImGui::GetIO();
io.Fonts->Clear();
ImFont* font = io.Fonts->AddFontFromFileTTF((Slic3r::resources_dir() + "/fonts/NotoSans-Regular.ttf").c_str(), font_size, nullptr, m_glyph_ranges);
ImFont* font = io.Fonts->AddFontFromFileTTF((Slic3r::resources_dir() + "/fonts/NotoSans-Regular.ttf").c_str(), m_font_size, nullptr, m_glyph_ranges);
if (font == nullptr) {
font = io.Fonts->AddFontDefault();
if (font == nullptr) {

View file

@ -45,8 +45,8 @@ public:
void new_frame();
void render();
float scaled(float x) const { return x * m_font_size * m_style_scaling; }
ImVec2 scaled(float x, float y) const { return ImVec2(x * m_font_size * m_style_scaling, y * m_font_size * m_style_scaling); }
float scaled(float x) const { return x * m_font_size; }
ImVec2 scaled(float x, float y) const { return ImVec2(x * m_font_size, y * m_font_size); }
ImVec2 calc_text_size(const wxString &text);
void set_next_window_pos(float x, float y, int flag);

View file

@ -1199,7 +1199,7 @@ struct Plater::priv
BoundingBox scaled_bed_shape_bb() const;
std::vector<size_t> load_files(const std::vector<fs::path>& input_files, bool load_model, bool load_config);
std::vector<size_t> load_model_objects(const ModelObjectPtrs &model_objects);
std::unique_ptr<CheckboxFileDialog> get_export_file(GUI::FileType file_type);
wxString get_export_file(GUI::FileType file_type);
const Selection& get_selection() const;
Selection& get_selection();
@ -1617,6 +1617,45 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
}
#if ENABLE_VOLUMES_CENTERING_FIXES
}
else if ((wxGetApp().get_mode() == comSimple) && (type_3mf || type_any_amf))
{
bool advanced = false;
for (const ModelObject* model_object : model.objects)
{
// is there more than one instance ?
if (model_object->instances.size() > 1)
{
advanced = true;
break;
}
// is there any modifier ?
for (const ModelVolume* model_volume : model_object->volumes)
{
if (!model_volume->is_model_part())
{
advanced = true;
break;
}
}
if (advanced)
break;
}
if (advanced)
{
wxMessageDialog dlg(q, _(L("This file cannot be loaded in simple mode. Do you want to switch to expert mode?\n")),
_(L("Detected advanced data")), wxICON_WARNING | wxYES | wxNO);
if (dlg.ShowModal() == wxID_YES)
{
Slic3r::GUI::wxGetApp().save_mode(comExpert);
view3D->set_as_dirty();
}
else
return obj_idxs;
}
}
#endif // ENABLE_VOLUMES_CENTERING_FIXES
#if !ENABLE_VOLUMES_CENTERING_FIXES
@ -1642,7 +1681,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
Slic3r::GUI::show_error(nullptr,
wxString::Format(_(L("You can't to add the object(s) from %s because of one or some of them is(are) multi-part")),
from_path(filename)));
return std::vector<size_t>();
return obj_idxs;
}
}
@ -1784,7 +1823,7 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &mode
return obj_idxs;
}
std::unique_ptr<CheckboxFileDialog> Plater::priv::get_export_file(GUI::FileType file_type)
wxString Plater::priv::get_export_file(GUI::FileType file_type)
{
wxString wildcard;
switch (file_type) {
@ -1801,34 +1840,56 @@ std::unique_ptr<CheckboxFileDialog> Plater::priv::get_export_file(GUI::FileType
// Update printbility state of each of the ModelInstances.
this->update_print_volume_state();
// Find the file name of the first printable object.
fs::path output_file = this->model.propose_export_file_name_and_path();
const Selection& selection = get_selection();
int obj_idx = selection.get_object_idx();
fs::path output_file;
// first try to get the file name from the current selection
if ((0 <= obj_idx) && (obj_idx < (int)this->model.objects.size()))
output_file = this->model.objects[obj_idx]->get_export_filename();
if (output_file.empty())
// Find the file name of the first printable object.
output_file = this->model.propose_export_file_name_and_path();
wxString dlg_title;
switch (file_type) {
case FT_STL: output_file.replace_extension("stl"); break;
case FT_AMF: output_file.replace_extension("zip.amf"); break; // XXX: Problem on OS X with double extension?
case FT_3MF: output_file.replace_extension("3mf"); break;
case FT_STL:
{
output_file.replace_extension("stl");
dlg_title = _(L("Export STL file:"));
break;
}
case FT_AMF:
{
// XXX: Problem on OS X with double extension?
output_file.replace_extension("zip.amf");
dlg_title = _(L("Export AMF file:"));
break;
}
case FT_3MF:
{
output_file.replace_extension("3mf");
dlg_title = _(L("Save file as:"));
break;
}
default: break;
}
auto dlg = Slic3r::make_unique<CheckboxFileDialog>(q,
((file_type == FT_AMF) || (file_type == FT_3MF)) ? _(L("Export print config")) : "",
true,
_(L("Save file as:")),
from_path(output_file.parent_path()),
from_path(output_file.filename()),
wildcard,
wxFD_SAVE | wxFD_OVERWRITE_PROMPT
);
wxFileDialog* dlg = new wxFileDialog(q, dlg_title,
from_path(output_file.parent_path()), from_path(output_file.filename()),
wildcard, wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
if (dlg->ShowModal() != wxID_OK) {
return nullptr;
return wxEmptyString;
}
fs::path path(into_path(dlg->GetPath()));
wxString out_path = dlg->GetPath();
fs::path path(into_path(out_path));
wxGetApp().app_config->update_last_output_dir(path.parent_path().string());
return dlg;
return out_path;
}
const Selection& Plater::priv::get_selection() const
@ -3243,11 +3304,8 @@ void Plater::export_stl(bool selection_only)
{
if (p->model.objects.empty()) { return; }
auto dialog = p->get_export_file(FT_STL);
if (! dialog) { return; }
// Store a binary STL
const wxString path = dialog->GetPath();
wxString path = p->get_export_file(FT_STL);
if (path.empty()) { return; }
const std::string path_u8 = into_u8(path);
wxBusyCursor wait;
@ -3272,15 +3330,14 @@ void Plater::export_amf()
{
if (p->model.objects.empty()) { return; }
auto dialog = p->get_export_file(FT_AMF);
if (! dialog) { return; }
const wxString path = dialog->GetPath();
wxString path = p->get_export_file(FT_AMF);
if (path.empty()) { return; }
const std::string path_u8 = into_u8(path);
DynamicPrintConfig cfg = wxGetApp().preset_bundle->full_config_secure();
wxBusyCursor wait;
if (Slic3r::store_amf(path_u8.c_str(), &p->model, dialog->get_checkbox_value() ? &cfg : nullptr)) {
bool export_config = true;
DynamicPrintConfig cfg = wxGetApp().preset_bundle->full_config_secure();
if (Slic3r::store_amf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr)) {
// Success
p->statusbar()->set_status_text(wxString::Format(_(L("AMF file exported to %s")), path));
} else {
@ -3297,10 +3354,8 @@ void Plater::export_3mf(const boost::filesystem::path& output_path)
bool export_config = true;
if (output_path.empty())
{
auto dialog = p->get_export_file(FT_3MF);
if (!dialog) { return; }
path = dialog->GetPath();
export_config = dialog->get_checkbox_value();
path = p->get_export_file(FT_3MF);
if (path.empty()) { return; }
}
else
path = from_path(output_path);

View file

@ -108,21 +108,26 @@ void Selection::add(unsigned int volume_idx, bool as_single_selection)
if (is_wipe_tower() && volume->is_wipe_tower)
return;
bool keep_instance_mode = (m_mode == Instance) && !as_single_selection && (is_single_full_instance() || is_multiple_full_instance());
// resets the current list if needed
bool needs_reset = as_single_selection;
needs_reset |= volume->is_wipe_tower;
needs_reset |= is_wipe_tower() && !volume->is_wipe_tower;
needs_reset |= !is_modifier() && volume->is_modifier;
needs_reset |= !keep_instance_mode && !is_modifier() && volume->is_modifier;
needs_reset |= is_modifier() && !volume->is_modifier;
if (needs_reset)
clear();
if (!contains_volume(volume_idx))
m_mode = volume->is_modifier ? Volume : Instance;
{
if (!keep_instance_mode)
m_mode = volume->is_modifier ? Volume : Instance;
}
else
// keep current mode
return;
// keep current mode
return;
switch (m_mode)
{
@ -1142,16 +1147,12 @@ void Selection::_update_type()
}
if (modifiers_count == 0)
{
m_type = MultipleVolume;
requires_disable = true;
}
else if (modifiers_count == (unsigned int)m_list.size())
{
m_type = MultipleModifier;
requires_disable = true;
}
}
requires_disable = true;
}
else if ((selected_instances_count > 1) && (selected_instances_count * volumes_count == (unsigned int)m_list.size()))
{

View file

@ -1446,7 +1446,7 @@ void TabFilament::build()
line.append_option(optgroup->get_option("bed_temperature"));
optgroup->append_line(line);
page = add_options_page(_(L("Cooling")), "hourglass.png");
page = add_options_page(_(L("Cooling")), "cooling");
optgroup = page->new_optgroup(_(L("Enable")));
optgroup->append_single_option_line("fan_always_on");
optgroup->append_single_option_line("cooling");

View file

@ -8,6 +8,8 @@
#include <wx/dcclient.h>
#include <wx/numformatter.h>
#include <boost/algorithm/string/replace.hpp>
#include "BitmapCache.hpp"
#include "GUI.hpp"
#include "GUI_App.hpp"
@ -421,19 +423,16 @@ void PrusaCollapsiblePaneMSW::Collapse(bool collapse)
// PrusaObjectDataViewModelNode
// ----------------------------------------------------------------------------
wxBitmap create_scaled_bitmap(const std::string& bmp_name)
wxBitmap create_scaled_bitmap(const std::string& bmp_name_in)
{
const double scale_f = Slic3r::GUI::wxGetApp().em_unit()* 0.1;//GetContentScaleFactor();
if (scale_f == 1.0)
return wxBitmap(Slic3r::GUI::from_u8(Slic3r::var(bmp_name)), wxBITMAP_TYPE_PNG);
// else if (scale_f == 2.0) // use biger icon
// return wxBitmap(Slic3r::GUI::from_u8(Slic3r::var(bmp_name_X2)), wxBITMAP_TYPE_PNG);
wxImage img = wxImage(Slic3r::GUI::from_u8(Slic3r::var(bmp_name)), wxBITMAP_TYPE_PNG);
const int sz_w = int(img.GetWidth()*scale_f);
const int sz_h = int(img.GetHeight()*scale_f);
img.Rescale(sz_w, sz_h, wxIMAGE_QUALITY_BILINEAR);
return wxBitmap(img);
static Slic3r::GUI::BitmapCache cache;
const auto height = (unsigned int)(Slic3r::GUI::wxGetApp().em_unit() * 1.6f + 0.5f);
std::string bmp_name = bmp_name_in;
boost::replace_last(bmp_name, ".png", "");
wxBitmap *bmp = cache.load_svg(bmp_name, height);
if (bmp == nullptr)
bmp = cache.load_png(bmp_name, height);
return *bmp;
}
void PrusaObjectDataViewModelNode::set_object_action_icon() {