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/listctrl.h>
|
||||||
#include <wx/stattext.h>
|
#include <wx/stattext.h>
|
||||||
#include <wx/timer.h>
|
#include <wx/timer.h>
|
||||||
|
#include <wx/wupdlock.h>
|
||||||
|
|
||||||
#include "slic3r/GUI/GUI.hpp"
|
#include "slic3r/GUI/GUI.hpp"
|
||||||
|
#include "slic3r/GUI/GUI_App.hpp"
|
||||||
#include "slic3r/GUI/I18N.hpp"
|
#include "slic3r/GUI/I18N.hpp"
|
||||||
#include "slic3r/Utils/Bonjour.hpp"
|
#include "slic3r/Utils/Bonjour.hpp"
|
||||||
|
|
||||||
|
@ -49,31 +51,36 @@ struct LifetimeGuard
|
||||||
LifetimeGuard(BonjourDialog *dialog) : dialog(dialog) {}
|
LifetimeGuard(BonjourDialog *dialog) : dialog(dialog) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
BonjourDialog::BonjourDialog(wxWindow *parent, Slic3r::PrinterTechnology tech)
|
||||||
BonjourDialog::BonjourDialog(wxWindow *parent) :
|
: wxDialog(parent, wxID_ANY, _(L("Network lookup")), wxDefaultPosition, wxDefaultSize, wxRESIZE_BORDER)
|
||||||
wxDialog(parent, wxID_ANY, _(L("Network lookup"))),
|
, list(new wxListView(this, wxID_ANY))
|
||||||
list(new wxListView(this, wxID_ANY, wxDefaultPosition, wxSize(800, 300))),
|
, replies(new ReplySet)
|
||||||
replies(new ReplySet),
|
, label(new wxStaticText(this, wxID_ANY, ""))
|
||||||
label(new wxStaticText(this, wxID_ANY, "")),
|
, timer(new wxTimer())
|
||||||
timer(new wxTimer()),
|
, timer_state(0)
|
||||||
timer_state(0)
|
, tech(tech)
|
||||||
{
|
{
|
||||||
|
const int em = GUI::wxGetApp().em_unit();
|
||||||
|
list->SetMinSize(wxSize(80 * em, 30 * em));
|
||||||
|
|
||||||
wxBoxSizer *vsizer = new wxBoxSizer(wxVERTICAL);
|
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_SINGLE_SEL);
|
||||||
list->SetSingleStyle(wxLC_SORT_DESCENDING);
|
list->SetSingleStyle(wxLC_SORT_DESCENDING);
|
||||||
list->AppendColumn(_(L("Address")), wxLIST_FORMAT_LEFT, 50);
|
list->AppendColumn(_(L("Address")), wxLIST_FORMAT_LEFT, 5 * em);
|
||||||
list->AppendColumn(_(L("Hostname")), wxLIST_FORMAT_LEFT, 100);
|
list->AppendColumn(_(L("Hostname")), wxLIST_FORMAT_LEFT, 10 * em);
|
||||||
list->AppendColumn(_(L("Service name")), wxLIST_FORMAT_LEFT, 200);
|
list->AppendColumn(_(L("Service name")), wxLIST_FORMAT_LEFT, 20 * em);
|
||||||
list->AppendColumn(_(L("OctoPrint version")), wxLIST_FORMAT_LEFT, 50);
|
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);
|
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_OK, "OK"), 0, wxALL, em);
|
||||||
button_sizer->Add(new wxButton(this, wxID_CANCEL, "Cancel"), 0, wxALL, 10);
|
button_sizer->Add(new wxButton(this, wxID_CANCEL, "Cancel"), 0, wxALL, em);
|
||||||
// ^ Note: The Ok/Cancel labels are translated by wxWidgets
|
// ^ Note: The Ok/Cancel labels are translated by wxWidgets
|
||||||
|
|
||||||
vsizer->Add(button_sizer, 0, wxALIGN_CENTER);
|
vsizer->Add(button_sizer, 0, wxALIGN_CENTER);
|
||||||
|
@ -110,7 +117,11 @@ bool BonjourDialog::show_and_lookup()
|
||||||
// so that both threads can access it safely.
|
// so that both threads can access it safely.
|
||||||
auto dguard = std::make_shared<LifetimeGuard>(this);
|
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")
|
bonjour = std::move(Bonjour("octoprint")
|
||||||
|
.set_txt_keys(std::move(txt_keys))
|
||||||
.set_retries(3)
|
.set_retries(3)
|
||||||
.set_timeout(4)
|
.set_timeout(4)
|
||||||
.on_reply([dguard](BonjourReply &&reply) {
|
.on_reply([dguard](BonjourReply &&reply) {
|
||||||
|
@ -157,9 +168,20 @@ void BonjourDialog::on_reply(BonjourReplyEvent &e)
|
||||||
return;
|
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));
|
replies->insert(std::move(e.reply));
|
||||||
|
|
||||||
auto selected = get_selected();
|
auto selected = get_selected();
|
||||||
|
|
||||||
|
wxWindowUpdateLocker freeze_guard(this);
|
||||||
|
(void)freeze_guard;
|
||||||
|
|
||||||
list->DeleteAllItems();
|
list->DeleteAllItems();
|
||||||
|
|
||||||
// The whole list is recreated so that we benefit from it already being sorted in the set.
|
// 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);
|
auto item = list->InsertItem(0, reply.full_address);
|
||||||
list->SetItem(item, 1, reply.hostname);
|
list->SetItem(item, 1, reply.hostname);
|
||||||
list->SetItem(item, 2, reply.service_name);
|
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++) {
|
const int em = GUI::wxGetApp().em_unit();
|
||||||
this->list->SetColumnWidth(i, wxLIST_AUTOSIZE);
|
|
||||||
if (this->list->GetColumnWidth(i) < 100) { this->list->SetColumnWidth(i, 100); }
|
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()) {
|
if (!selected.IsEmpty()) {
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
#include <wx/dialog.h>
|
#include <wx/dialog.h>
|
||||||
|
|
||||||
|
#include "libslic3r/PrintConfig.hpp"
|
||||||
|
|
||||||
class wxListView;
|
class wxListView;
|
||||||
class wxStaticText;
|
class wxStaticText;
|
||||||
class wxTimer;
|
class wxTimer;
|
||||||
|
@ -21,7 +23,7 @@ class ReplySet;
|
||||||
class BonjourDialog: public wxDialog
|
class BonjourDialog: public wxDialog
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BonjourDialog(wxWindow *parent);
|
BonjourDialog(wxWindow *parent, Slic3r::PrinterTechnology);
|
||||||
BonjourDialog(BonjourDialog &&) = delete;
|
BonjourDialog(BonjourDialog &&) = delete;
|
||||||
BonjourDialog(const BonjourDialog &) = delete;
|
BonjourDialog(const BonjourDialog &) = delete;
|
||||||
BonjourDialog &operator=(BonjourDialog &&) = delete;
|
BonjourDialog &operator=(BonjourDialog &&) = delete;
|
||||||
|
@ -37,6 +39,7 @@ private:
|
||||||
std::shared_ptr<Bonjour> bonjour;
|
std::shared_ptr<Bonjour> bonjour;
|
||||||
std::unique_ptr<wxTimer> timer;
|
std::unique_ptr<wxTimer> timer;
|
||||||
unsigned timer_state;
|
unsigned timer_state;
|
||||||
|
Slic3r::PrinterTechnology tech;
|
||||||
|
|
||||||
void on_reply(BonjourReplyEvent &);
|
void on_reply(BonjourReplyEvent &);
|
||||||
void on_timer(wxTimerEvent &);
|
void on_timer(wxTimerEvent &);
|
||||||
|
|
|
@ -43,6 +43,18 @@ static PrinterTechnology printer_technology()
|
||||||
return wxGetApp().preset_bundle->printers.get_selected_preset().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) :
|
ObjectList::ObjectList(wxWindow* parent) :
|
||||||
wxDataViewCtrl(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxDV_MULTIPLE),
|
wxDataViewCtrl(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxDV_MULTIPLE),
|
||||||
m_parent(parent)
|
m_parent(parent)
|
||||||
|
@ -430,6 +442,9 @@ void ObjectList::OnContextMenu(wxDataViewEvent&)
|
||||||
if (is_windows10())
|
if (is_windows10())
|
||||||
fix_through_netfabb();
|
fix_through_netfabb();
|
||||||
}
|
}
|
||||||
|
else if (title == _("Extruder"))
|
||||||
|
show_extruder_selection_menu();
|
||||||
|
|
||||||
#ifndef __WXMSW__
|
#ifndef __WXMSW__
|
||||||
GetMainWindow()->SetToolTip(""); // hide tooltip
|
GetMainWindow()->SetToolTip(""); // hide tooltip
|
||||||
#endif //__WXMSW__
|
#endif //__WXMSW__
|
||||||
|
@ -437,9 +452,13 @@ void ObjectList::OnContextMenu(wxDataViewEvent&)
|
||||||
|
|
||||||
void ObjectList::show_context_menu()
|
void ObjectList::show_context_menu()
|
||||||
{
|
{
|
||||||
if (multiple_selection() && selected_instances_of_same_object())
|
if (multiple_selection())
|
||||||
{
|
{
|
||||||
wxGetApp().plater()->PopupMenu(&m_menu_instance);
|
if (selected_instances_of_same_object())
|
||||||
|
wxGetApp().plater()->PopupMenu(&m_menu_instance);
|
||||||
|
else
|
||||||
|
show_extruder_selection_menu();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -644,8 +663,7 @@ void ObjectList::get_options_menu(settings_menu_hierarchy& settings_menu, const
|
||||||
{
|
{
|
||||||
auto options = get_options(is_part);
|
auto options = get_options(is_part);
|
||||||
|
|
||||||
auto extruders_cnt = printer_technology() == ptSLA ? 1 :
|
const int extruders_cnt = extruders_count();
|
||||||
wxGetApp().preset_bundle->printers.get_edited_preset().config.option<ConfigOptionFloats>("nozzle_diameter")->values.size();
|
|
||||||
|
|
||||||
DynamicPrintConfig config;
|
DynamicPrintConfig config;
|
||||||
for (auto& option : options)
|
for (auto& option : options)
|
||||||
|
@ -1079,8 +1097,7 @@ void ObjectList::create_freq_settings_popupmenu(wxMenu *menu)
|
||||||
const FreqSettingsBundle& bundle = printer_technology() == ptFFF ?
|
const FreqSettingsBundle& bundle = printer_technology() == ptFFF ?
|
||||||
FREQ_SETTINGS_BUNDLE_FFF : FREQ_SETTINGS_BUNDLE_SLA;
|
FREQ_SETTINGS_BUNDLE_FFF : FREQ_SETTINGS_BUNDLE_SLA;
|
||||||
|
|
||||||
auto extruders_cnt = printer_technology() == ptSLA ? 1 :
|
const int extruders_cnt = extruders_count();
|
||||||
wxGetApp().preset_bundle->printers.get_edited_preset().config.option<ConfigOptionFloats>("nozzle_diameter")->values.size();
|
|
||||||
|
|
||||||
for (auto& it : bundle) {
|
for (auto& it : bundle) {
|
||||||
if (it.first.empty() || it.first == "Extruders" && extruders_cnt == 1)
|
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);
|
const wxString name = _(L("Generic")) + "-" + _(type_name);
|
||||||
TriangleMesh mesh;
|
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& sz = BoundingBoxf(bed_shape).size();
|
||||||
const auto side = 0.1 * std::max(sz(0), sz(1));
|
const auto side = 0.1 * std::max(sz(0), sz(1));
|
||||||
|
|
||||||
|
@ -1456,7 +1473,7 @@ void ObjectList::split()
|
||||||
|
|
||||||
ModelVolume* volume;
|
ModelVolume* volume;
|
||||||
if (!get_volume_by_item(item, volume)) return;
|
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 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();
|
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) {
|
if (volume->split(nozzle_dmrs_cnt) == 1) {
|
||||||
|
@ -2338,5 +2355,86 @@ void ObjectList::OnEditingDone(wxDataViewEvent &event)
|
||||||
_(L("the following characters are not allowed:")) + " <>:/\\|?*\"");
|
_(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 GUI
|
||||||
} //namespace Slic3r
|
} //namespace Slic3r
|
|
@ -283,6 +283,10 @@ private:
|
||||||
void ItemValueChanged(wxDataViewEvent &event);
|
void ItemValueChanged(wxDataViewEvent &event);
|
||||||
void OnEditingDone(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);
|
std::vector<std::string> get_options(const bool is_part);
|
||||||
const std::vector<std::string>& get_options_for_bundle(const wxString& bundle_name);
|
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);
|
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::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(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) :
|
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)),
|
boldfont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)),
|
||||||
content_sizer(new wxBoxSizer(wxVERTICAL)),
|
content_sizer(new wxBoxSizer(wxVERTICAL)),
|
||||||
btn_sizer(new wxBoxSizer(wxHORIZONTAL))
|
btn_sizer(new wxBoxSizer(wxHORIZONTAL))
|
||||||
|
@ -70,7 +69,6 @@ MsgDialog::~MsgDialog() {}
|
||||||
|
|
||||||
ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg)
|
ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg)
|
||||||
: MsgDialog(parent, _(L("Slic3r error")), _(L("Slic3r has encountered an error")),
|
: 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"),
|
create_scaled_bitmap("Slic3r_192px_grayscale.png"),
|
||||||
wxID_NONE)
|
wxID_NONE)
|
||||||
, msg(msg)
|
, msg(msg)
|
||||||
|
|
|
@ -1612,25 +1612,21 @@ bool Tab::current_preset_is_dirty()
|
||||||
|
|
||||||
void TabPrinter::build_printhost(ConfigOptionsGroup *optgroup)
|
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)
|
// 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");
|
optgroup->append_single_option_line("host_type");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto printhost_browse = [this, optgroup] (wxWindow* parent) {
|
auto printhost_browse = [=](wxWindow* parent) {
|
||||||
|
|
||||||
// TODO: SLA Bonjour
|
|
||||||
|
|
||||||
auto btn = m_printhost_browse_btn = new wxButton(parent, wxID_ANY, _(L(" Browse "))+dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT);
|
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"));
|
btn->SetBitmap(create_scaled_bitmap("zoom.png"));
|
||||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
sizer->Add(btn);
|
sizer->Add(btn);
|
||||||
|
|
||||||
btn->Bind(wxEVT_BUTTON, [this, parent, optgroup](wxCommandEvent &e) {
|
btn->Bind(wxEVT_BUTTON, [=](wxCommandEvent &e) {
|
||||||
BonjourDialog dialog(parent);
|
BonjourDialog dialog(parent, tech);
|
||||||
if (dialog.show_and_lookup()) {
|
if (dialog.show_and_lookup()) {
|
||||||
optgroup->set_value("print_host", std::move(dialog.get_selected()), true);
|
optgroup->set_value("print_host", std::move(dialog.get_selected()), true);
|
||||||
optgroup->get_field("print_host")->field_changed();
|
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 print_host_test = [this](wxWindow* parent) {
|
||||||
auto btn = m_print_host_test_btn = new wxButton(parent, wxID_ANY, _(L("Test")),
|
auto btn = m_print_host_test_btn = new wxButton(parent, wxID_ANY, _(L("Test")),
|
||||||
wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT);
|
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"));
|
btn->SetBitmap(create_scaled_bitmap("wrench.png"));
|
||||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
sizer->Add(btn);
|
sizer->Add(btn);
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <map>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
#include <boost/system/error_code.hpp>
|
#include <boost/system/error_code.hpp>
|
||||||
|
@ -33,7 +34,9 @@ namespace Slic3r {
|
||||||
// the implementations has been tested with AFL.
|
// 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
|
struct DnsName: public std::string
|
||||||
|
@ -156,9 +159,9 @@ struct DnsQuestion
|
||||||
uint16_t type;
|
uint16_t type;
|
||||||
uint16_t qclass;
|
uint16_t qclass;
|
||||||
|
|
||||||
DnsQuestion() :
|
DnsQuestion()
|
||||||
type(0),
|
: type(0)
|
||||||
qclass(0)
|
, qclass(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
static optional<DnsQuestion> decode(const std::vector<char> &buffer, size_t &offset)
|
static optional<DnsQuestion> decode(const std::vector<char> &buffer, size_t &offset)
|
||||||
|
@ -187,10 +190,10 @@ struct DnsResource
|
||||||
uint32_t ttl;
|
uint32_t ttl;
|
||||||
std::vector<char> data;
|
std::vector<char> data;
|
||||||
|
|
||||||
DnsResource() :
|
DnsResource()
|
||||||
type(0),
|
: type(0)
|
||||||
rclass(0),
|
, rclass(0)
|
||||||
ttl(0)
|
, ttl(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
static optional<DnsResource> decode(const std::vector<char> &buffer, size_t &offset, size_t &dataoffset)
|
static optional<DnsResource> decode(const std::vector<char> &buffer, size_t &offset, size_t &dataoffset)
|
||||||
|
@ -310,9 +313,9 @@ struct DnsRR_TXT
|
||||||
TAG = 0x10,
|
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();
|
const size_t size = rr.data.size();
|
||||||
if (size < 2) {
|
if (size < 2) {
|
||||||
|
@ -328,11 +331,21 @@ struct DnsRR_TXT
|
||||||
}
|
}
|
||||||
++it;
|
++it;
|
||||||
|
|
||||||
std::string value(val_size, ' ');
|
const auto it_end = it + val_size;
|
||||||
std::copy(it, it + val_size, value.begin());
|
const auto it_eq = std::find(it, it_end, '=');
|
||||||
res.values.push_back(std::move(value));
|
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);
|
return std::move(res);
|
||||||
|
@ -389,7 +402,7 @@ struct DnsMessage
|
||||||
|
|
||||||
DnsSDMap sdmap;
|
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();
|
const auto size = buffer.size();
|
||||||
if (size < DnsHeader::SIZE + DnsQuestion::MIN_SIZE || size > MAX_SIZE) {
|
if (size < DnsHeader::SIZE + DnsQuestion::MIN_SIZE || size > MAX_SIZE) {
|
||||||
|
@ -414,14 +427,15 @@ struct DnsMessage
|
||||||
if (!rr) {
|
if (!rr) {
|
||||||
return boost::none;
|
return boost::none;
|
||||||
} else {
|
} else {
|
||||||
res.parse_rr(buffer, std::move(*rr), dataoffset);
|
res.parse_rr(buffer, std::move(*rr), dataoffset, txt_keys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::move(res);
|
return std::move(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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) {
|
switch (rr.type) {
|
||||||
case DnsRR_A::TAG: DnsRR_A::decode(this->rr_a, rr); break;
|
case DnsRR_A::TAG: DnsRR_A::decode(this->rr_a, rr); break;
|
||||||
|
@ -432,7 +446,7 @@ private:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DnsRR_TXT::TAG: {
|
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)); }
|
if (txt) { this->sdmap.insert_txt(std::move(rr.name), std::move(*txt)); }
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -442,26 +456,28 @@ private:
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream &os, const DnsMessage &msg)
|
std::ostream& operator<<(std::ostream &os, const DnsMessage &msg)
|
||||||
{
|
{
|
||||||
os << "DnsMessage(ID: " << msg.header.id << ", "
|
os << boost::format("DnsMessage(ID: %1%, Q: %2%, A: %3%, AAAA: %4%, services: [")
|
||||||
<< "Q: " << (msg.question ? msg.question->name.c_str() : "none") << ", "
|
% msg.header.id
|
||||||
<< "A: " << (msg.rr_a ? msg.rr_a->ip.to_string() : "none") << ", "
|
% (msg.question ? msg.question->name.c_str() : "none")
|
||||||
<< "AAAA: " << (msg.rr_aaaa ? msg.rr_aaaa->ip.to_string() : "none") << ", "
|
% (msg.rr_a ? msg.rr_a->ip.to_string() : "none")
|
||||||
<< "services: [";
|
% (msg.rr_aaaa ? msg.rr_aaaa->ip.to_string() : "none");
|
||||||
|
|
||||||
enum { SRV_PRINT_MAX = 3 };
|
enum { SRV_PRINT_MAX = 3 };
|
||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
for (const auto &sdpair : msg.sdmap) {
|
for (const auto &sdpair : msg.sdmap) {
|
||||||
os << sdpair.first << ", ";
|
if (i > 0) { os << ", "; }
|
||||||
|
|
||||||
if (++i >= SRV_PRINT_MAX) {
|
if (i < SRV_PRINT_MAX) {
|
||||||
os << "...";
|
os << sdpair.first;
|
||||||
break;
|
} else {
|
||||||
}
|
os << "...";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
os << "])";
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
return os;
|
return os << "])";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -525,8 +541,9 @@ optional<BonjourRequest> BonjourRequest::make(const std::string &service, const
|
||||||
struct Bonjour::priv
|
struct Bonjour::priv
|
||||||
{
|
{
|
||||||
const std::string service;
|
const std::string service;
|
||||||
const std::string protocol;
|
std::string protocol;
|
||||||
const std::string service_dn;
|
std::string service_dn;
|
||||||
|
TxtKeys txt_keys;
|
||||||
unsigned timeout;
|
unsigned timeout;
|
||||||
unsigned retries;
|
unsigned retries;
|
||||||
|
|
||||||
|
@ -535,19 +552,18 @@ struct Bonjour::priv
|
||||||
Bonjour::ReplyFn replyfn;
|
Bonjour::ReplyFn replyfn;
|
||||||
Bonjour::CompleteFn completefn;
|
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;
|
std::string strip_service_dn(const std::string &service_name) const;
|
||||||
void udp_receive(udp::endpoint from, size_t bytes);
|
void udp_receive(udp::endpoint from, size_t bytes);
|
||||||
void lookup_perform();
|
void lookup_perform();
|
||||||
};
|
};
|
||||||
|
|
||||||
Bonjour::priv::priv(std::string service, std::string protocol) :
|
Bonjour::priv::priv(std::string &&service)
|
||||||
service(std::move(service)),
|
: service(std::move(service))
|
||||||
protocol(std::move(protocol)),
|
, protocol("tcp")
|
||||||
service_dn((boost::format("_%1%._%2%.local") % this->service % this->protocol).str()),
|
, timeout(10)
|
||||||
timeout(10),
|
, retries(1)
|
||||||
retries(1)
|
|
||||||
{
|
{
|
||||||
buffer.resize(DnsMessage::MAX_SIZE);
|
buffer.resize(DnsMessage::MAX_SIZE);
|
||||||
}
|
}
|
||||||
|
@ -573,13 +589,13 @@ void Bonjour::priv::udp_receive(udp::endpoint from, size_t bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.resize(bytes);
|
buffer.resize(bytes);
|
||||||
const auto dns_msg = DnsMessage::decode(buffer);
|
auto dns_msg = DnsMessage::decode(buffer, txt_keys);
|
||||||
if (dns_msg) {
|
if (dns_msg) {
|
||||||
asio::ip::address ip = from.address();
|
asio::ip::address ip = from.address();
|
||||||
if (dns_msg->rr_a) { ip = dns_msg->rr_a->ip; }
|
if (dns_msg->rr_a) { ip = dns_msg->rr_a->ip; }
|
||||||
else if (dns_msg->rr_aaaa) { ip = dns_msg->rr_aaaa->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) {
|
if (! sdpair.second.srv) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -590,20 +606,12 @@ void Bonjour::priv::udp_receive(udp::endpoint from, size_t bytes)
|
||||||
std::string path;
|
std::string path;
|
||||||
std::string version;
|
std::string version;
|
||||||
|
|
||||||
|
BonjourReply::TxtData txt_data;
|
||||||
if (sdpair.second.txt) {
|
if (sdpair.second.txt) {
|
||||||
static const std::string tag_path = "path=";
|
txt_data = std::move(sdpair.second.txt->data);
|
||||||
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()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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));
|
replyfn(std::move(reply));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -611,6 +619,8 @@ void Bonjour::priv::udp_receive(udp::endpoint from, size_t bytes)
|
||||||
|
|
||||||
void Bonjour::priv::lookup_perform()
|
void Bonjour::priv::lookup_perform()
|
||||||
{
|
{
|
||||||
|
service_dn = (boost::format("_%1%._%2%.local") % service % protocol).str();
|
||||||
|
|
||||||
const auto brq = BonjourRequest::make(service, protocol);
|
const auto brq = BonjourRequest::make(service, protocol);
|
||||||
if (!brq) {
|
if (!brq) {
|
||||||
return;
|
return;
|
||||||
|
@ -671,21 +681,29 @@ void Bonjour::priv::lookup_perform()
|
||||||
|
|
||||||
// API - public part
|
// 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) :
|
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)),
|
: ip(std::move(ip))
|
||||||
port(port),
|
, port(port)
|
||||||
service_name(std::move(service_name)),
|
, service_name(std::move(service_name))
|
||||||
hostname(std::move(hostname)),
|
, hostname(std::move(hostname))
|
||||||
path(path.empty() ? std::move(std::string("/")) : std::move(path)),
|
, txt_data(std::move(txt_data))
|
||||||
version(version.empty() ? std::move(std::string("Unknown")) : std::move(version))
|
|
||||||
{
|
{
|
||||||
std::string proto;
|
std::string proto;
|
||||||
std::string port_suffix;
|
std::string port_suffix;
|
||||||
if (port == 443) { proto = "https://"; }
|
if (port == 443) { proto = "https://"; }
|
||||||
if (port != 443 && port != 80) { port_suffix = std::to_string(port).insert(0, 1, ':'); }
|
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;
|
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
|
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)
|
std::ostream& operator<<(std::ostream &os, const BonjourReply &reply)
|
||||||
{
|
{
|
||||||
os << "BonjourReply(" << reply.ip.to_string() << ", " << reply.service_name << ", "
|
os << boost::format("BonjourReply(%1%, %2%, %3%, %4%")
|
||||||
<< reply.hostname << ", " << reply.path << ", " << reply.version << ")";
|
% reply.ip.to_string()
|
||||||
return os;
|
% 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) :
|
Bonjour::Bonjour(std::string service)
|
||||||
p(new priv(std::move(service), std::move(protocol)))
|
: p(new priv(std::move(service)))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
Bonjour::Bonjour(Bonjour &&other) : p(std::move(other.p)) {}
|
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)
|
Bonjour& Bonjour::set_timeout(unsigned timeout)
|
||||||
{
|
{
|
||||||
if (p) { p->timeout = timeout; }
|
if (p) { p->timeout = timeout; }
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <set>
|
||||||
|
#include <unordered_map>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <boost/asio/ip/address.hpp>
|
#include <boost/asio/ip/address.hpp>
|
||||||
|
|
||||||
|
@ -13,16 +15,24 @@ namespace Slic3r {
|
||||||
|
|
||||||
struct BonjourReply
|
struct BonjourReply
|
||||||
{
|
{
|
||||||
|
typedef std::unordered_map<std::string, std::string> TxtData;
|
||||||
|
|
||||||
boost::asio::ip::address ip;
|
boost::asio::ip::address ip;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
std::string service_name;
|
std::string service_name;
|
||||||
std::string hostname;
|
std::string hostname;
|
||||||
std::string full_address;
|
std::string full_address;
|
||||||
std::string path;
|
|
||||||
std::string version;
|
TxtData txt_data;
|
||||||
|
|
||||||
BonjourReply() = delete;
|
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;
|
||||||
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::shared_ptr<Bonjour> Ptr;
|
||||||
typedef std::function<void(BonjourReply &&)> ReplyFn;
|
typedef std::function<void(BonjourReply &&)> ReplyFn;
|
||||||
typedef std::function<void()> CompleteFn;
|
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(Bonjour &&other);
|
||||||
~Bonjour();
|
~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_timeout(unsigned timeout);
|
||||||
Bonjour& set_retries(unsigned retries);
|
Bonjour& set_retries(unsigned retries);
|
||||||
// ^ Note: By default there is 1 retry (meaning 1 broadcast is sent).
|
// ^ Note: By default there is 1 retry (meaning 1 broadcast is sent).
|
||||||
|
|
Loading…
Reference in a new issue