mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-11-02 20:51:23 -07:00 
			
		
		
		
	Merge branch 'master' of https://github.com/prusa3d/Slic3r
This commit is contained in:
		
						commit
						8245921e74
					
				
					 8 changed files with 297 additions and 115 deletions
				
			
		| 
						 | 
				
			
			@ -10,8 +10,10 @@
 | 
			
		|||
#include <wx/listctrl.h>
 | 
			
		||||
#include <wx/stattext.h>
 | 
			
		||||
#include <wx/timer.h>
 | 
			
		||||
#include <wx/wupdlock.h>
 | 
			
		||||
 | 
			
		||||
#include "slic3r/GUI/GUI.hpp"
 | 
			
		||||
#include "slic3r/GUI/GUI_App.hpp"
 | 
			
		||||
#include "slic3r/GUI/I18N.hpp"
 | 
			
		||||
#include "slic3r/Utils/Bonjour.hpp"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -49,31 +51,36 @@ struct LifetimeGuard
 | 
			
		|||
	LifetimeGuard(BonjourDialog *dialog) : dialog(dialog) {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
BonjourDialog::BonjourDialog(wxWindow *parent) :
 | 
			
		||||
	wxDialog(parent, wxID_ANY, _(L("Network lookup"))),
 | 
			
		||||
	list(new wxListView(this, wxID_ANY, wxDefaultPosition, wxSize(800, 300))),
 | 
			
		||||
	replies(new ReplySet),
 | 
			
		||||
	label(new wxStaticText(this, wxID_ANY, "")),
 | 
			
		||||
	timer(new wxTimer()),
 | 
			
		||||
	timer_state(0)
 | 
			
		||||
BonjourDialog::BonjourDialog(wxWindow *parent, Slic3r::PrinterTechnology tech)
 | 
			
		||||
	: wxDialog(parent, wxID_ANY, _(L("Network lookup")), wxDefaultPosition, wxDefaultSize, wxRESIZE_BORDER)
 | 
			
		||||
	, list(new wxListView(this, wxID_ANY))
 | 
			
		||||
	, replies(new ReplySet)
 | 
			
		||||
	, label(new wxStaticText(this, wxID_ANY, ""))
 | 
			
		||||
	, timer(new wxTimer())
 | 
			
		||||
	, timer_state(0)
 | 
			
		||||
	, tech(tech)
 | 
			
		||||
{
 | 
			
		||||
	const int em = GUI::wxGetApp().em_unit();
 | 
			
		||||
	list->SetMinSize(wxSize(80 * em, 30 * em));
 | 
			
		||||
 | 
			
		||||
	wxBoxSizer *vsizer = new wxBoxSizer(wxVERTICAL);
 | 
			
		||||
 | 
			
		||||
	vsizer->Add(label, 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, 10);
 | 
			
		||||
	vsizer->Add(label, 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, em);
 | 
			
		||||
 | 
			
		||||
	list->SetSingleStyle(wxLC_SINGLE_SEL);
 | 
			
		||||
	list->SetSingleStyle(wxLC_SORT_DESCENDING);
 | 
			
		||||
	list->AppendColumn(_(L("Address")), wxLIST_FORMAT_LEFT, 50);
 | 
			
		||||
	list->AppendColumn(_(L("Hostname")), wxLIST_FORMAT_LEFT, 100);
 | 
			
		||||
	list->AppendColumn(_(L("Service name")), wxLIST_FORMAT_LEFT, 200);
 | 
			
		||||
	list->AppendColumn(_(L("OctoPrint version")), wxLIST_FORMAT_LEFT, 50);
 | 
			
		||||
	list->AppendColumn(_(L("Address")), wxLIST_FORMAT_LEFT, 5 * em);
 | 
			
		||||
	list->AppendColumn(_(L("Hostname")), wxLIST_FORMAT_LEFT, 10 * em);
 | 
			
		||||
	list->AppendColumn(_(L("Service name")), wxLIST_FORMAT_LEFT, 20 * em);
 | 
			
		||||
	if (tech == ptFFF) {
 | 
			
		||||
		list->AppendColumn(_(L("OctoPrint version")), wxLIST_FORMAT_LEFT, 5 * em);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	vsizer->Add(list, 1, wxEXPAND | wxALL, 10);
 | 
			
		||||
	vsizer->Add(list, 1, wxEXPAND | wxALL, em);
 | 
			
		||||
 | 
			
		||||
	wxBoxSizer *button_sizer = new wxBoxSizer(wxHORIZONTAL);
 | 
			
		||||
	button_sizer->Add(new wxButton(this, wxID_OK, "OK"), 0, wxALL, 10);
 | 
			
		||||
	button_sizer->Add(new wxButton(this, wxID_CANCEL, "Cancel"), 0, wxALL, 10);
 | 
			
		||||
	button_sizer->Add(new wxButton(this, wxID_OK, "OK"), 0, wxALL, em);
 | 
			
		||||
	button_sizer->Add(new wxButton(this, wxID_CANCEL, "Cancel"), 0, wxALL, em);
 | 
			
		||||
	// ^ Note: The Ok/Cancel labels are translated by wxWidgets
 | 
			
		||||
 | 
			
		||||
	vsizer->Add(button_sizer, 0, wxALIGN_CENTER);
 | 
			
		||||
| 
						 | 
				
			
			@ -110,7 +117,11 @@ bool BonjourDialog::show_and_lookup()
 | 
			
		|||
	// so that both threads can access it safely.
 | 
			
		||||
	auto dguard = std::make_shared<LifetimeGuard>(this);
 | 
			
		||||
 | 
			
		||||
	// Note: More can be done here when we support discovery of hosts other than Octoprint and SL1
 | 
			
		||||
	Bonjour::TxtKeys txt_keys { "version", "model" };
 | 
			
		||||
 | 
			
		||||
	bonjour = std::move(Bonjour("octoprint")
 | 
			
		||||
		.set_txt_keys(std::move(txt_keys))
 | 
			
		||||
		.set_retries(3)
 | 
			
		||||
		.set_timeout(4)
 | 
			
		||||
		.on_reply([dguard](BonjourReply &&reply) {
 | 
			
		||||
| 
						 | 
				
			
			@ -157,9 +168,20 @@ void BonjourDialog::on_reply(BonjourReplyEvent &e)
 | 
			
		|||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Filter replies based on selected technology
 | 
			
		||||
	const auto model = e.reply.txt_data.find("model");
 | 
			
		||||
	const bool sl1 = model != e.reply.txt_data.end() && model->second == "SL1";
 | 
			
		||||
	if (tech == ptFFF && sl1 || tech == ptSLA && !sl1) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	replies->insert(std::move(e.reply));
 | 
			
		||||
 | 
			
		||||
	auto selected = get_selected();
 | 
			
		||||
 | 
			
		||||
	wxWindowUpdateLocker freeze_guard(this);
 | 
			
		||||
	(void)freeze_guard;
 | 
			
		||||
 | 
			
		||||
	list->DeleteAllItems();
 | 
			
		||||
 | 
			
		||||
	// The whole list is recreated so that we benefit from it already being sorted in the set.
 | 
			
		||||
| 
						 | 
				
			
			@ -168,12 +190,20 @@ void BonjourDialog::on_reply(BonjourReplyEvent &e)
 | 
			
		|||
		auto item = list->InsertItem(0, reply.full_address);
 | 
			
		||||
		list->SetItem(item, 1, reply.hostname);
 | 
			
		||||
		list->SetItem(item, 2, reply.service_name);
 | 
			
		||||
		list->SetItem(item, 3, reply.version);
 | 
			
		||||
 | 
			
		||||
		if (tech == ptFFF) {
 | 
			
		||||
			const auto it = reply.txt_data.find("version");
 | 
			
		||||
			if (it != reply.txt_data.end()) {
 | 
			
		||||
				list->SetItem(item, 3, GUI::from_u8(it->second));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < 4; i++) {
 | 
			
		||||
		this->list->SetColumnWidth(i, wxLIST_AUTOSIZE);
 | 
			
		||||
		if (this->list->GetColumnWidth(i) < 100) { this->list->SetColumnWidth(i, 100); }
 | 
			
		||||
	const int em = GUI::wxGetApp().em_unit();
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < list->GetColumnCount(); i++) {
 | 
			
		||||
		list->SetColumnWidth(i, wxLIST_AUTOSIZE);
 | 
			
		||||
		if (list->GetColumnWidth(i) < 10 * em) { list->SetColumnWidth(i, 10 * em); }
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!selected.IsEmpty()) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,8 @@
 | 
			
		|||
 | 
			
		||||
#include <wx/dialog.h>
 | 
			
		||||
 | 
			
		||||
#include "libslic3r/PrintConfig.hpp"
 | 
			
		||||
 | 
			
		||||
class wxListView;
 | 
			
		||||
class wxStaticText;
 | 
			
		||||
class wxTimer;
 | 
			
		||||
| 
						 | 
				
			
			@ -21,7 +23,7 @@ class ReplySet;
 | 
			
		|||
class BonjourDialog: public wxDialog
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	BonjourDialog(wxWindow *parent);
 | 
			
		||||
	BonjourDialog(wxWindow *parent, Slic3r::PrinterTechnology);
 | 
			
		||||
	BonjourDialog(BonjourDialog &&) = delete;
 | 
			
		||||
	BonjourDialog(const BonjourDialog &) = delete;
 | 
			
		||||
	BonjourDialog &operator=(BonjourDialog &&) = delete;
 | 
			
		||||
| 
						 | 
				
			
			@ -37,6 +39,7 @@ private:
 | 
			
		|||
	std::shared_ptr<Bonjour> bonjour;
 | 
			
		||||
	std::unique_ptr<wxTimer> timer;
 | 
			
		||||
	unsigned timer_state;
 | 
			
		||||
	Slic3r::PrinterTechnology tech;
 | 
			
		||||
 | 
			
		||||
	void on_reply(BonjourReplyEvent &);
 | 
			
		||||
	void on_timer(wxTimerEvent &);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,6 +43,18 @@ static PrinterTechnology printer_technology()
 | 
			
		|||
    return wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Config from current edited printer preset
 | 
			
		||||
DynamicPrintConfig& printer_config()
 | 
			
		||||
{
 | 
			
		||||
    return wxGetApp().preset_bundle->printers.get_edited_preset().config;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int extruders_count()
 | 
			
		||||
{
 | 
			
		||||
    return printer_technology() == ptSLA ? 1 :
 | 
			
		||||
        printer_config().option<ConfigOptionFloats>("nozzle_diameter")->values.size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ObjectList::ObjectList(wxWindow* parent) :
 | 
			
		||||
    wxDataViewCtrl(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxDV_MULTIPLE),
 | 
			
		||||
    m_parent(parent)
 | 
			
		||||
| 
						 | 
				
			
			@ -430,6 +442,9 @@ void ObjectList::OnContextMenu(wxDataViewEvent&)
 | 
			
		|||
        if (is_windows10())
 | 
			
		||||
            fix_through_netfabb();
 | 
			
		||||
    }
 | 
			
		||||
    else if (title == _("Extruder"))
 | 
			
		||||
        show_extruder_selection_menu();
 | 
			
		||||
 | 
			
		||||
#ifndef __WXMSW__
 | 
			
		||||
    GetMainWindow()->SetToolTip(""); // hide tooltip
 | 
			
		||||
#endif //__WXMSW__
 | 
			
		||||
| 
						 | 
				
			
			@ -437,9 +452,13 @@ void ObjectList::OnContextMenu(wxDataViewEvent&)
 | 
			
		|||
 | 
			
		||||
void ObjectList::show_context_menu()
 | 
			
		||||
{
 | 
			
		||||
    if (multiple_selection() && selected_instances_of_same_object())
 | 
			
		||||
    if (multiple_selection())
 | 
			
		||||
    {
 | 
			
		||||
        if (selected_instances_of_same_object())
 | 
			
		||||
            wxGetApp().plater()->PopupMenu(&m_menu_instance);
 | 
			
		||||
        else
 | 
			
		||||
            show_extruder_selection_menu();
 | 
			
		||||
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -644,8 +663,7 @@ void ObjectList::get_options_menu(settings_menu_hierarchy& settings_menu, const
 | 
			
		|||
{
 | 
			
		||||
    auto options = get_options(is_part);
 | 
			
		||||
 | 
			
		||||
    auto extruders_cnt = printer_technology() == ptSLA ? 1 :
 | 
			
		||||
        wxGetApp().preset_bundle->printers.get_edited_preset().config.option<ConfigOptionFloats>("nozzle_diameter")->values.size();
 | 
			
		||||
    const int extruders_cnt = extruders_count();
 | 
			
		||||
 | 
			
		||||
    DynamicPrintConfig config;
 | 
			
		||||
    for (auto& option : options)
 | 
			
		||||
| 
						 | 
				
			
			@ -1079,8 +1097,7 @@ void ObjectList::create_freq_settings_popupmenu(wxMenu *menu)
 | 
			
		|||
    const FreqSettingsBundle& bundle = printer_technology() == ptFFF ?
 | 
			
		||||
                                     FREQ_SETTINGS_BUNDLE_FFF : FREQ_SETTINGS_BUNDLE_SLA;
 | 
			
		||||
 | 
			
		||||
    auto extruders_cnt = printer_technology() == ptSLA ? 1 :
 | 
			
		||||
                         wxGetApp().preset_bundle->printers.get_edited_preset().config.option<ConfigOptionFloats>("nozzle_diameter")->values.size();
 | 
			
		||||
    const int extruders_cnt = extruders_count();
 | 
			
		||||
 | 
			
		||||
    for (auto& it : bundle) {
 | 
			
		||||
        if (it.first.empty() || it.first == "Extruders" && extruders_cnt == 1) 
 | 
			
		||||
| 
						 | 
				
			
			@ -1277,7 +1294,7 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode
 | 
			
		|||
    const wxString name = _(L("Generic")) + "-" + _(type_name);
 | 
			
		||||
    TriangleMesh mesh;
 | 
			
		||||
 | 
			
		||||
    auto& bed_shape = wxGetApp().preset_bundle->printers.get_edited_preset().config.option<ConfigOptionPoints>("bed_shape")->values;
 | 
			
		||||
    auto& bed_shape = printer_config().option<ConfigOptionPoints>("bed_shape")->values;
 | 
			
		||||
    const auto& sz = BoundingBoxf(bed_shape).size();
 | 
			
		||||
    const auto side = 0.1 * std::max(sz(0), sz(1));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1456,7 +1473,7 @@ void ObjectList::split()
 | 
			
		|||
 | 
			
		||||
    ModelVolume* volume;
 | 
			
		||||
    if (!get_volume_by_item(item, volume)) return;
 | 
			
		||||
    DynamicPrintConfig&	config = wxGetApp().preset_bundle->printers.get_edited_preset().config;
 | 
			
		||||
    DynamicPrintConfig&	config = printer_config();
 | 
			
		||||
	const ConfigOption *nozzle_dmtrs_opt = config.option("nozzle_diameter", false);
 | 
			
		||||
	const auto nozzle_dmrs_cnt = (nozzle_dmtrs_opt == nullptr) ? size_t(1) : dynamic_cast<const ConfigOptionFloats*>(nozzle_dmtrs_opt)->values.size();
 | 
			
		||||
    if (volume->split(nozzle_dmrs_cnt) == 1) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2338,5 +2355,86 @@ void ObjectList::OnEditingDone(wxDataViewEvent &event)
 | 
			
		|||
                         _(L("the following characters are not allowed:")) + " <>:/\\|?*\"");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ObjectList::show_extruder_selection_menu()
 | 
			
		||||
{
 | 
			
		||||
    wxDataViewItemArray sels;
 | 
			
		||||
    GetSelections(sels);
 | 
			
		||||
 | 
			
		||||
    for (const wxDataViewItem& item : sels)
 | 
			
		||||
        if (!(m_objects_model->GetItemType(item) & (itVolume | itObject)))
 | 
			
		||||
            // show this menu only for Object(s)/Volume(s) selection
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
    wxMenu* menu = new wxMenu();
 | 
			
		||||
    append_menu_item(menu, wxID_ANY, _(L("Set extruder for selected items")),
 | 
			
		||||
        _(L("Select extruder number for selected objects and/or parts")),
 | 
			
		||||
        [this](wxCommandEvent&) { extruder_selection(); }, "", menu);
 | 
			
		||||
    PopupMenu(menu);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ObjectList::extruder_selection()
 | 
			
		||||
{
 | 
			
		||||
    wxArrayString choices;
 | 
			
		||||
    choices.Add("default");
 | 
			
		||||
    for (int i = 1; i <= extruders_count(); ++i)
 | 
			
		||||
        choices.Add(wxString::Format("%d", i));
 | 
			
		||||
 | 
			
		||||
    const wxString& selected_extruder = wxGetSingleChoice(_(L("Select extruder number:")),
 | 
			
		||||
                                                          _(L("This extruder will be set for selected items")),
 | 
			
		||||
                                                          choices, 0, this);
 | 
			
		||||
    if (selected_extruder.IsEmpty())
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    const int extruder_num = selected_extruder == "default" ? 0 : atoi(selected_extruder.c_str());
 | 
			
		||||
 | 
			
		||||
//          /* Another variant for an extruder selection */
 | 
			
		||||
//     extruder_num = wxGetNumberFromUser(_(L("Attention!!! \n"
 | 
			
		||||
//                                              "It's a possibile to set an extruder number \n"
 | 
			
		||||
//                                              "for whole Object(s) and/or object Part(s), \n"
 | 
			
		||||
//                                              "not for an Instance. ")), 
 | 
			
		||||
//                                          _(L("Enter extruder number:")),
 | 
			
		||||
//                                          _(L("This extruder will be set for selected items")), 
 | 
			
		||||
//                                          1, 1, 5, this);
 | 
			
		||||
 | 
			
		||||
    set_extruder_for_selected_items(extruder_num);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ObjectList::set_extruder_for_selected_items(const int extruder) const 
 | 
			
		||||
{
 | 
			
		||||
    wxDataViewItemArray sels;
 | 
			
		||||
    GetSelections(sels);
 | 
			
		||||
 | 
			
		||||
    for (const wxDataViewItem& item : sels)
 | 
			
		||||
    {
 | 
			
		||||
        const ItemType type = m_objects_model->GetItemType(item);
 | 
			
		||||
 | 
			
		||||
        const int obj_idx = type & itObject ? m_objects_model->GetIdByItem(item) :
 | 
			
		||||
                            m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item));
 | 
			
		||||
 | 
			
		||||
        const int vol_idx = type & itVolume ? m_objects_model->GetVolumeIdByItem(item) : -1;
 | 
			
		||||
 | 
			
		||||
        DynamicPrintConfig& config = type & itObject ? (*m_objects)[obj_idx]->config : 
 | 
			
		||||
                                     (*m_objects)[obj_idx]->volumes[vol_idx]->config;
 | 
			
		||||
        
 | 
			
		||||
        if (config.has("extruder")) {
 | 
			
		||||
            if (extruder == 0)
 | 
			
		||||
                config.erase("extruder");
 | 
			
		||||
            else
 | 
			
		||||
                config.option<ConfigOptionInt>("extruder")->value = extruder;
 | 
			
		||||
        }
 | 
			
		||||
        else if (extruder > 0)
 | 
			
		||||
            config.set_key_value("extruder", new ConfigOptionInt(extruder));
 | 
			
		||||
 | 
			
		||||
        const wxString extruder_str = extruder == 0 ? wxString ("default") : 
 | 
			
		||||
                                      wxString::Format("%d", config.option<ConfigOptionInt>("extruder")->value);
 | 
			
		||||
        m_objects_model->SetValue(extruder_str, item, 1);
 | 
			
		||||
 | 
			
		||||
        wxGetApp().plater()->canvas3D()->ensure_on_bed(obj_idx);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // update scene
 | 
			
		||||
    wxGetApp().plater()->update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} //namespace GUI
 | 
			
		||||
} //namespace Slic3r 
 | 
			
		||||
| 
						 | 
				
			
			@ -283,6 +283,10 @@ private:
 | 
			
		|||
    void ItemValueChanged(wxDataViewEvent &event);
 | 
			
		||||
    void OnEditingDone(wxDataViewEvent &event);
 | 
			
		||||
 | 
			
		||||
    void show_extruder_selection_menu();
 | 
			
		||||
    void extruder_selection();
 | 
			
		||||
    void set_extruder_for_selected_items(const int extruder) const ;
 | 
			
		||||
 | 
			
		||||
    std::vector<std::string>        get_options(const bool is_part);
 | 
			
		||||
    const std::vector<std::string>& get_options_for_bundle(const wxString& bundle_name);
 | 
			
		||||
    void                            get_options_menu(settings_menu_hierarchy& settings_menu, const bool is_part);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,12 +24,11 @@ namespace GUI {
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &headline, wxWindowID button_id) :
 | 
			
		||||
// 	MsgDialog(parent, title, headline, wxBitmap(from_u8(Slic3r::var("Slic3r_192px.png")), wxBITMAP_TYPE_PNG), button_id)
 | 
			
		||||
	MsgDialog(parent, title, headline, create_scaled_bitmap("Slic3r_192px.png"), button_id)
 | 
			
		||||
{}
 | 
			
		||||
 | 
			
		||||
MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &headline, wxBitmap bitmap, wxWindowID button_id) :
 | 
			
		||||
	wxDialog(parent, wxID_ANY, title),
 | 
			
		||||
	wxDialog(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxRESIZE_BORDER),
 | 
			
		||||
	boldfont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)),
 | 
			
		||||
	content_sizer(new wxBoxSizer(wxVERTICAL)),
 | 
			
		||||
	btn_sizer(new wxBoxSizer(wxHORIZONTAL))
 | 
			
		||||
| 
						 | 
				
			
			@ -70,7 +69,6 @@ MsgDialog::~MsgDialog() {}
 | 
			
		|||
 | 
			
		||||
ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg)
 | 
			
		||||
	: MsgDialog(parent, _(L("Slic3r error")), _(L("Slic3r has encountered an error")),
 | 
			
		||||
// 		wxBitmap(from_u8(Slic3r::var("Slic3r_192px_grayscale.png")), wxBITMAP_TYPE_PNG),
 | 
			
		||||
        create_scaled_bitmap("Slic3r_192px_grayscale.png"),
 | 
			
		||||
		wxID_NONE)
 | 
			
		||||
	, msg(msg)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1612,25 +1612,21 @@ bool Tab::current_preset_is_dirty()
 | 
			
		|||
 | 
			
		||||
void TabPrinter::build_printhost(ConfigOptionsGroup *optgroup)
 | 
			
		||||
{
 | 
			
		||||
	const bool sla = m_presets->get_selected_preset().printer_technology() == ptSLA;
 | 
			
		||||
	const PrinterTechnology tech = m_presets->get_selected_preset().printer_technology();
 | 
			
		||||
 | 
			
		||||
	// Only offer the host type selection for FFF, for SLA it's always the SL1 printer (at the moment)
 | 
			
		||||
	if (! sla) {
 | 
			
		||||
	if (tech == ptFFF) {
 | 
			
		||||
		optgroup->append_single_option_line("host_type");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	auto printhost_browse = [this, optgroup] (wxWindow* parent) {
 | 
			
		||||
 | 
			
		||||
		// TODO: SLA Bonjour
 | 
			
		||||
 | 
			
		||||
	auto printhost_browse = [=](wxWindow* parent) {
 | 
			
		||||
		auto btn = m_printhost_browse_btn = new wxButton(parent, wxID_ANY, _(L(" Browse "))+dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT);
 | 
			
		||||
// 		btn->SetBitmap(wxBitmap(from_u8(Slic3r::var("zoom.png")), wxBITMAP_TYPE_PNG));
 | 
			
		||||
        btn->SetBitmap(create_scaled_bitmap("zoom.png"));
 | 
			
		||||
		auto sizer = new wxBoxSizer(wxHORIZONTAL);
 | 
			
		||||
		sizer->Add(btn);
 | 
			
		||||
 | 
			
		||||
		btn->Bind(wxEVT_BUTTON, [this, parent, optgroup](wxCommandEvent &e) {
 | 
			
		||||
			BonjourDialog dialog(parent);
 | 
			
		||||
		btn->Bind(wxEVT_BUTTON, [=](wxCommandEvent &e) {
 | 
			
		||||
			BonjourDialog dialog(parent, tech);
 | 
			
		||||
			if (dialog.show_and_lookup()) {
 | 
			
		||||
				optgroup->set_value("print_host", std::move(dialog.get_selected()), true);
 | 
			
		||||
				optgroup->get_field("print_host")->field_changed();
 | 
			
		||||
| 
						 | 
				
			
			@ -1643,7 +1639,6 @@ void TabPrinter::build_printhost(ConfigOptionsGroup *optgroup)
 | 
			
		|||
	auto print_host_test = [this](wxWindow* parent) {
 | 
			
		||||
		auto btn = m_print_host_test_btn = new wxButton(parent, wxID_ANY, _(L("Test")), 
 | 
			
		||||
			wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT);
 | 
			
		||||
// 		btn->SetBitmap(wxBitmap(from_u8(Slic3r::var("wrench.png")), wxBITMAP_TYPE_PNG));
 | 
			
		||||
        btn->SetBitmap(create_scaled_bitmap("wrench.png"));
 | 
			
		||||
		auto sizer = new wxBoxSizer(wxHORIZONTAL);
 | 
			
		||||
		sizer->Add(btn);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,7 @@
 | 
			
		|||
#include <array>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <map>
 | 
			
		||||
#include <thread>
 | 
			
		||||
#include <boost/optional.hpp>
 | 
			
		||||
#include <boost/system/error_code.hpp>
 | 
			
		||||
| 
						 | 
				
			
			@ -33,7 +34,9 @@ namespace Slic3r {
 | 
			
		|||
// the implementations has been tested with AFL.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Relevant RFC: https://www.ietf.org/rfc/rfc6762.txt
 | 
			
		||||
// Relevant RFCs:
 | 
			
		||||
//    https://tools.ietf.org/html/rfc6762.txt
 | 
			
		||||
//    https://tools.ietf.org/html/rfc6763.txt
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct DnsName: public std::string
 | 
			
		||||
| 
						 | 
				
			
			@ -156,9 +159,9 @@ struct DnsQuestion
 | 
			
		|||
	uint16_t type;
 | 
			
		||||
	uint16_t qclass;
 | 
			
		||||
 | 
			
		||||
	DnsQuestion() :
 | 
			
		||||
		type(0),
 | 
			
		||||
		qclass(0)
 | 
			
		||||
	DnsQuestion()
 | 
			
		||||
		: type(0)
 | 
			
		||||
		, qclass(0)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	static optional<DnsQuestion> decode(const std::vector<char> &buffer, size_t &offset)
 | 
			
		||||
| 
						 | 
				
			
			@ -187,10 +190,10 @@ struct DnsResource
 | 
			
		|||
	uint32_t ttl;
 | 
			
		||||
	std::vector<char> data;
 | 
			
		||||
 | 
			
		||||
	DnsResource() :
 | 
			
		||||
		type(0),
 | 
			
		||||
		rclass(0),
 | 
			
		||||
		ttl(0)
 | 
			
		||||
	DnsResource()
 | 
			
		||||
		: type(0)
 | 
			
		||||
		, rclass(0)
 | 
			
		||||
		, ttl(0)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	static optional<DnsResource> decode(const std::vector<char> &buffer, size_t &offset, size_t &dataoffset)
 | 
			
		||||
| 
						 | 
				
			
			@ -310,9 +313,9 @@ struct DnsRR_TXT
 | 
			
		|||
		TAG = 0x10,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	std::vector<std::string> values;
 | 
			
		||||
	BonjourReply::TxtData data;
 | 
			
		||||
 | 
			
		||||
	static optional<DnsRR_TXT> decode(const DnsResource &rr)
 | 
			
		||||
	static optional<DnsRR_TXT> decode(const DnsResource &rr, const Bonjour::TxtKeys &txt_keys)
 | 
			
		||||
	{
 | 
			
		||||
		const size_t size = rr.data.size();
 | 
			
		||||
		if (size < 2) {
 | 
			
		||||
| 
						 | 
				
			
			@ -328,11 +331,21 @@ struct DnsRR_TXT
 | 
			
		|||
			}
 | 
			
		||||
			++it;
 | 
			
		||||
 | 
			
		||||
			std::string value(val_size, ' ');
 | 
			
		||||
			std::copy(it, it + val_size, value.begin());
 | 
			
		||||
			res.values.push_back(std::move(value));
 | 
			
		||||
			const auto it_end = it + val_size;
 | 
			
		||||
			const auto it_eq = std::find(it, it_end, '=');
 | 
			
		||||
			if (it_eq > it && it_eq < it_end - 1) {
 | 
			
		||||
				std::string key(it_eq - it, ' ');
 | 
			
		||||
				std::copy(it, it_eq, key.begin());
 | 
			
		||||
 | 
			
		||||
			it += val_size;
 | 
			
		||||
				if (txt_keys.find(key) != txt_keys.end() || key == "path") {
 | 
			
		||||
					// This key-value has been requested for
 | 
			
		||||
					std::string value(it_end - it_eq - 1, ' ');
 | 
			
		||||
					std::copy(it_eq + 1, it_end, value.begin());
 | 
			
		||||
					res.data.insert(std::make_pair(std::move(key), std::move(value)));
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			it = it_end;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return std::move(res);
 | 
			
		||||
| 
						 | 
				
			
			@ -389,7 +402,7 @@ struct DnsMessage
 | 
			
		|||
 | 
			
		||||
	DnsSDMap sdmap;
 | 
			
		||||
 | 
			
		||||
	static optional<DnsMessage> decode(const std::vector<char> &buffer)
 | 
			
		||||
	static optional<DnsMessage> decode(const std::vector<char> &buffer, const Bonjour::TxtKeys &txt_keys)
 | 
			
		||||
	{
 | 
			
		||||
		const auto size = buffer.size();
 | 
			
		||||
		if (size < DnsHeader::SIZE + DnsQuestion::MIN_SIZE || size > MAX_SIZE) {
 | 
			
		||||
| 
						 | 
				
			
			@ -414,14 +427,15 @@ struct DnsMessage
 | 
			
		|||
			if (!rr) {
 | 
			
		||||
				return boost::none;
 | 
			
		||||
			} else {
 | 
			
		||||
				res.parse_rr(buffer, std::move(*rr), dataoffset);
 | 
			
		||||
				res.parse_rr(buffer, std::move(*rr), dataoffset, txt_keys);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return std::move(res);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	void parse_rr(const std::vector<char> &buffer, DnsResource &&rr, size_t dataoffset)
 | 
			
		||||
	void parse_rr(const std::vector<char> &buffer, DnsResource &&rr, size_t dataoffset, const Bonjour::TxtKeys &txt_keys)
 | 
			
		||||
	{
 | 
			
		||||
		switch (rr.type) {
 | 
			
		||||
			case DnsRR_A::TAG: DnsRR_A::decode(this->rr_a, rr); break;
 | 
			
		||||
| 
						 | 
				
			
			@ -432,7 +446,7 @@ private:
 | 
			
		|||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			case DnsRR_TXT::TAG: {
 | 
			
		||||
				auto txt = DnsRR_TXT::decode(rr);
 | 
			
		||||
				auto txt = DnsRR_TXT::decode(rr, txt_keys);
 | 
			
		||||
				if (txt) { this->sdmap.insert_txt(std::move(rr.name), std::move(*txt)); }
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -442,26 +456,28 @@ private:
 | 
			
		|||
 | 
			
		||||
std::ostream& operator<<(std::ostream &os, const DnsMessage &msg)
 | 
			
		||||
{
 | 
			
		||||
	os << "DnsMessage(ID: " << msg.header.id << ", "
 | 
			
		||||
		<< "Q: " << (msg.question ? msg.question->name.c_str() : "none") << ", "
 | 
			
		||||
		<< "A: " << (msg.rr_a ? msg.rr_a->ip.to_string() : "none") << ", "
 | 
			
		||||
		<< "AAAA: " << (msg.rr_aaaa ? msg.rr_aaaa->ip.to_string() : "none") << ", "
 | 
			
		||||
		<< "services: [";
 | 
			
		||||
	os << boost::format("DnsMessage(ID: %1%, Q: %2%, A: %3%, AAAA: %4%, services: [")
 | 
			
		||||
		% msg.header.id
 | 
			
		||||
		% (msg.question ? msg.question->name.c_str() : "none")
 | 
			
		||||
		% (msg.rr_a ? msg.rr_a->ip.to_string() : "none")
 | 
			
		||||
		% (msg.rr_aaaa ? msg.rr_aaaa->ip.to_string() : "none");
 | 
			
		||||
 | 
			
		||||
	enum { SRV_PRINT_MAX = 3 };
 | 
			
		||||
	unsigned i = 0;
 | 
			
		||||
	for (const auto &sdpair : msg.sdmap) {
 | 
			
		||||
			os << sdpair.first << ", ";
 | 
			
		||||
		if (i > 0) { os << ", "; }
 | 
			
		||||
 | 
			
		||||
			if (++i >= SRV_PRINT_MAX) {
 | 
			
		||||
		if (i < SRV_PRINT_MAX) {
 | 
			
		||||
			os << sdpair.first;
 | 
			
		||||
		} else {
 | 
			
		||||
			os << "...";
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		i++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
		os << "])";
 | 
			
		||||
 | 
			
		||||
	return os;
 | 
			
		||||
	return os << "])";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -525,8 +541,9 @@ optional<BonjourRequest> BonjourRequest::make(const std::string &service, const
 | 
			
		|||
struct Bonjour::priv
 | 
			
		||||
{
 | 
			
		||||
	const std::string service;
 | 
			
		||||
	const std::string protocol;
 | 
			
		||||
	const std::string service_dn;
 | 
			
		||||
	std::string protocol;
 | 
			
		||||
	std::string service_dn;
 | 
			
		||||
	TxtKeys txt_keys;
 | 
			
		||||
	unsigned timeout;
 | 
			
		||||
	unsigned retries;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -535,19 +552,18 @@ struct Bonjour::priv
 | 
			
		|||
	Bonjour::ReplyFn replyfn;
 | 
			
		||||
	Bonjour::CompleteFn completefn;
 | 
			
		||||
 | 
			
		||||
	priv(std::string service, std::string protocol);
 | 
			
		||||
	priv(std::string &&service);
 | 
			
		||||
 | 
			
		||||
	std::string strip_service_dn(const std::string &service_name) const;
 | 
			
		||||
	void udp_receive(udp::endpoint from, size_t bytes);
 | 
			
		||||
	void lookup_perform();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Bonjour::priv::priv(std::string service, std::string protocol) :
 | 
			
		||||
	service(std::move(service)),
 | 
			
		||||
	protocol(std::move(protocol)),
 | 
			
		||||
	service_dn((boost::format("_%1%._%2%.local") % this->service % this->protocol).str()),
 | 
			
		||||
	timeout(10),
 | 
			
		||||
	retries(1)
 | 
			
		||||
Bonjour::priv::priv(std::string &&service)
 | 
			
		||||
	: service(std::move(service))
 | 
			
		||||
	, protocol("tcp")
 | 
			
		||||
	, timeout(10)
 | 
			
		||||
	, retries(1)
 | 
			
		||||
{
 | 
			
		||||
	buffer.resize(DnsMessage::MAX_SIZE);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -573,13 +589,13 @@ void Bonjour::priv::udp_receive(udp::endpoint from, size_t bytes)
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	buffer.resize(bytes);
 | 
			
		||||
	const auto dns_msg = DnsMessage::decode(buffer);
 | 
			
		||||
	auto dns_msg = DnsMessage::decode(buffer, txt_keys);
 | 
			
		||||
	if (dns_msg) {
 | 
			
		||||
		asio::ip::address ip = from.address();
 | 
			
		||||
		if (dns_msg->rr_a) { ip = dns_msg->rr_a->ip; }
 | 
			
		||||
		else if (dns_msg->rr_aaaa) { ip = dns_msg->rr_aaaa->ip; }
 | 
			
		||||
 | 
			
		||||
		for (const auto &sdpair : dns_msg->sdmap) {
 | 
			
		||||
		for (auto &sdpair : dns_msg->sdmap) {
 | 
			
		||||
			if (! sdpair.second.srv) {
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -590,20 +606,12 @@ void Bonjour::priv::udp_receive(udp::endpoint from, size_t bytes)
 | 
			
		|||
			std::string path;
 | 
			
		||||
			std::string version;
 | 
			
		||||
 | 
			
		||||
			BonjourReply::TxtData txt_data;
 | 
			
		||||
			if (sdpair.second.txt) {
 | 
			
		||||
				static const std::string tag_path = "path=";
 | 
			
		||||
				static const std::string tag_version = "version=";
 | 
			
		||||
 | 
			
		||||
				for (const auto &value : sdpair.second.txt->values) {
 | 
			
		||||
					if (value.size() > tag_path.size() && value.compare(0, tag_path.size(), tag_path) == 0) {
 | 
			
		||||
						path = std::move(value.substr(tag_path.size()));
 | 
			
		||||
					} else if (value.size() > tag_version.size() && value.compare(0, tag_version.size(), tag_version) == 0) {
 | 
			
		||||
						version = std::move(value.substr(tag_version.size()));
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				txt_data = std::move(sdpair.second.txt->data);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			BonjourReply reply(ip, srv.port, std::move(service_name), srv.hostname, std::move(path), std::move(version));
 | 
			
		||||
			BonjourReply reply(ip, srv.port, std::move(service_name), srv.hostname, std::move(txt_data));
 | 
			
		||||
			replyfn(std::move(reply));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -611,6 +619,8 @@ void Bonjour::priv::udp_receive(udp::endpoint from, size_t bytes)
 | 
			
		|||
 | 
			
		||||
void Bonjour::priv::lookup_perform()
 | 
			
		||||
{
 | 
			
		||||
	service_dn = (boost::format("_%1%._%2%.local") % service % protocol).str();
 | 
			
		||||
 | 
			
		||||
	const auto brq = BonjourRequest::make(service, protocol);
 | 
			
		||||
	if (!brq) {
 | 
			
		||||
		return;
 | 
			
		||||
| 
						 | 
				
			
			@ -671,21 +681,29 @@ void Bonjour::priv::lookup_perform()
 | 
			
		|||
 | 
			
		||||
// API - public part
 | 
			
		||||
 | 
			
		||||
BonjourReply::BonjourReply(boost::asio::ip::address ip, uint16_t port, std::string service_name, std::string hostname, std::string path, std::string version) :
 | 
			
		||||
	ip(std::move(ip)),
 | 
			
		||||
	port(port),
 | 
			
		||||
	service_name(std::move(service_name)),
 | 
			
		||||
	hostname(std::move(hostname)),
 | 
			
		||||
	path(path.empty() ? std::move(std::string("/")) : std::move(path)),
 | 
			
		||||
	version(version.empty() ? std::move(std::string("Unknown")) : std::move(version))
 | 
			
		||||
BonjourReply::BonjourReply(boost::asio::ip::address ip, uint16_t port, std::string service_name, std::string hostname, BonjourReply::TxtData txt_data)
 | 
			
		||||
	: ip(std::move(ip))
 | 
			
		||||
	, port(port)
 | 
			
		||||
	, service_name(std::move(service_name))
 | 
			
		||||
	, hostname(std::move(hostname))
 | 
			
		||||
	, txt_data(std::move(txt_data))
 | 
			
		||||
{
 | 
			
		||||
	std::string proto;
 | 
			
		||||
	std::string port_suffix;
 | 
			
		||||
	if (port == 443) { proto = "https://"; }
 | 
			
		||||
	if (port != 443 && port != 80) { port_suffix = std::to_string(port).insert(0, 1, ':'); }
 | 
			
		||||
	if (this->path[0] != '/') { this->path.insert(0, 1, '/'); }
 | 
			
		||||
 | 
			
		||||
	std::string path = this->path();
 | 
			
		||||
	if (path[0] != '/') { path.insert(0, 1, '/'); }
 | 
			
		||||
	full_address = proto + ip.to_string() + port_suffix;
 | 
			
		||||
	if (this->path != "/") { full_address += path; }
 | 
			
		||||
	if (path != "/") { full_address += path; }
 | 
			
		||||
	txt_data["path"] = std::move(path);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string BonjourReply::path() const
 | 
			
		||||
{
 | 
			
		||||
	const auto it = txt_data.find("path");
 | 
			
		||||
	return it != txt_data.end() ? it->second : std::string("/");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool BonjourReply::operator==(const BonjourReply &other) const
 | 
			
		||||
| 
						 | 
				
			
			@ -707,14 +725,22 @@ bool BonjourReply::operator<(const BonjourReply &other) const
 | 
			
		|||
 | 
			
		||||
std::ostream& operator<<(std::ostream &os, const BonjourReply &reply)
 | 
			
		||||
{
 | 
			
		||||
	os << "BonjourReply(" << reply.ip.to_string() << ", " << reply.service_name << ", "
 | 
			
		||||
		<< reply.hostname << ", " << reply.path << ", " << reply.version << ")";
 | 
			
		||||
	return os;
 | 
			
		||||
	os << boost::format("BonjourReply(%1%, %2%, %3%, %4%")
 | 
			
		||||
		% reply.ip.to_string()
 | 
			
		||||
		% reply.service_name
 | 
			
		||||
		% reply.hostname
 | 
			
		||||
		% reply.full_address;
 | 
			
		||||
 | 
			
		||||
	for (const auto &kv : reply.txt_data) {
 | 
			
		||||
		os << boost::format(", %1%=%2%") % kv.first % kv.second;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return os << ')';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Bonjour::Bonjour(std::string service, std::string protocol) :
 | 
			
		||||
	p(new priv(std::move(service), std::move(protocol)))
 | 
			
		||||
Bonjour::Bonjour(std::string service)
 | 
			
		||||
	: p(new priv(std::move(service)))
 | 
			
		||||
{}
 | 
			
		||||
 | 
			
		||||
Bonjour::Bonjour(Bonjour &&other) : p(std::move(other.p)) {}
 | 
			
		||||
| 
						 | 
				
			
			@ -726,6 +752,18 @@ Bonjour::~Bonjour()
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Bonjour& Bonjour::set_protocol(std::string protocol)
 | 
			
		||||
{
 | 
			
		||||
	if (p) { p->protocol = std::move(protocol); }
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Bonjour& Bonjour::set_txt_keys(TxtKeys txt_keys)
 | 
			
		||||
{
 | 
			
		||||
	if (p) { p->txt_keys = std::move(txt_keys); }
 | 
			
		||||
	return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Bonjour& Bonjour::set_timeout(unsigned timeout)
 | 
			
		||||
{
 | 
			
		||||
	if (p) { p->timeout = timeout; }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,6 +4,8 @@
 | 
			
		|||
#include <cstdint>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <set>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <boost/asio/ip/address.hpp>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -13,16 +15,24 @@ namespace Slic3r {
 | 
			
		|||
 | 
			
		||||
struct BonjourReply
 | 
			
		||||
{
 | 
			
		||||
	typedef std::unordered_map<std::string, std::string> TxtData;
 | 
			
		||||
 | 
			
		||||
	boost::asio::ip::address ip;
 | 
			
		||||
	uint16_t port;
 | 
			
		||||
	std::string service_name;
 | 
			
		||||
	std::string hostname;
 | 
			
		||||
	std::string full_address;
 | 
			
		||||
	std::string path;
 | 
			
		||||
	std::string version;
 | 
			
		||||
 | 
			
		||||
	TxtData txt_data;
 | 
			
		||||
 | 
			
		||||
	BonjourReply() = delete;
 | 
			
		||||
	BonjourReply(boost::asio::ip::address ip, uint16_t port, std::string service_name, std::string hostname, std::string path, std::string version);
 | 
			
		||||
	BonjourReply(boost::asio::ip::address ip,
 | 
			
		||||
		uint16_t port,
 | 
			
		||||
		std::string service_name,
 | 
			
		||||
		std::string hostname,
 | 
			
		||||
		TxtData txt_data);
 | 
			
		||||
 | 
			
		||||
	std::string path() const;
 | 
			
		||||
 | 
			
		||||
	bool operator==(const BonjourReply &other) const;
 | 
			
		||||
	bool operator<(const BonjourReply &other) const;
 | 
			
		||||
| 
						 | 
				
			
			@ -39,11 +49,17 @@ public:
 | 
			
		|||
	typedef std::shared_ptr<Bonjour> Ptr;
 | 
			
		||||
	typedef std::function<void(BonjourReply &&)> ReplyFn;
 | 
			
		||||
	typedef std::function<void()> CompleteFn;
 | 
			
		||||
	typedef std::set<std::string> TxtKeys;
 | 
			
		||||
 | 
			
		||||
	Bonjour(std::string service, std::string protocol = "tcp");
 | 
			
		||||
	Bonjour(std::string service);
 | 
			
		||||
	Bonjour(Bonjour &&other);
 | 
			
		||||
	~Bonjour();
 | 
			
		||||
 | 
			
		||||
	// Set requested service protocol, "tcp" by default
 | 
			
		||||
	Bonjour& set_protocol(std::string protocol);
 | 
			
		||||
	// Set which TXT key-values should be collected
 | 
			
		||||
	// Note that "path" is always collected
 | 
			
		||||
	Bonjour& set_txt_keys(TxtKeys txt_keys);
 | 
			
		||||
	Bonjour& set_timeout(unsigned timeout);
 | 
			
		||||
	Bonjour& set_retries(unsigned retries);
 | 
			
		||||
	// ^ Note: By default there is 1 retry (meaning 1 broadcast is sent).
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue