Merge branch 'et_gcode_viewer' of https://github.com/prusa3d/PrusaSlicer into et_gcode_viewer
This commit is contained in:
commit
e2bf72a494
54
resources/icons/thumb_left.svg
Normal file
54
resources/icons/thumb_left.svg
Normal file
@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
|
||||
sodipodi:docname="thumb_left.svg"
|
||||
xml:space="preserve"
|
||||
enable-background="new 0 0 16 16"
|
||||
viewBox="0 0 16 16"
|
||||
y="0px"
|
||||
x="0px"
|
||||
id="Layer_1"
|
||||
version="1.0"><metadata
|
||||
id="metadata32"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs30" /><sodipodi:namedview
|
||||
inkscape:current-layer="Layer_1"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-x="1268"
|
||||
inkscape:cy="8"
|
||||
inkscape:cx="8"
|
||||
inkscape:zoom="63"
|
||||
showgrid="false"
|
||||
id="namedview28"
|
||||
inkscape:window-height="1368"
|
||||
inkscape:window-width="1283"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0"
|
||||
guidetolerance="10"
|
||||
gridtolerance="10"
|
||||
objecttolerance="10"
|
||||
borderopacity="1"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#ffffff" />
|
||||
<g
|
||||
transform="rotate(-90,8.0158731,7.984127)"
|
||||
id="hex_x5F_plus">
|
||||
<g
|
||||
id="g24">
|
||||
<polygon
|
||||
id="polygon22"
|
||||
style="stroke:#ffffff;stroke-width:1"
|
||||
points="15,7 15,5 8,0 1,5 1,7 1,8 15,8 "
|
||||
fill="#ed6b21" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
54
resources/icons/thumb_right.svg
Normal file
54
resources/icons/thumb_right.svg
Normal file
@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
|
||||
sodipodi:docname="thumb_right.svg"
|
||||
xml:space="preserve"
|
||||
enable-background="new 0 0 16 16"
|
||||
viewBox="0 0 16 16"
|
||||
y="0px"
|
||||
x="0px"
|
||||
id="Layer_1"
|
||||
version="1.0"><metadata
|
||||
id="metadata32"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs30" /><sodipodi:namedview
|
||||
inkscape:current-layer="Layer_1"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-x="1268"
|
||||
inkscape:cy="8"
|
||||
inkscape:cx="8"
|
||||
inkscape:zoom="63"
|
||||
showgrid="false"
|
||||
id="namedview28"
|
||||
inkscape:window-height="1368"
|
||||
inkscape:window-width="1283"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0"
|
||||
guidetolerance="10"
|
||||
gridtolerance="10"
|
||||
objecttolerance="10"
|
||||
borderopacity="1"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#ffffff" />
|
||||
<g
|
||||
transform="matrix(0,-1,-1,0,16.012532,16)"
|
||||
id="hex_x5F_plus">
|
||||
<g
|
||||
id="g24">
|
||||
<polygon
|
||||
id="polygon22"
|
||||
style="stroke:#ffffff;stroke-width:1"
|
||||
points="15,8 15,7 15,5 8,0 1,5 1,7 1,8 "
|
||||
fill="#ed6b21" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
@ -450,6 +450,31 @@ void Model::convert_multipart_object(unsigned int max_extruders)
|
||||
this->objects.push_back(object);
|
||||
}
|
||||
|
||||
bool Model::looks_like_imperial_units() const
|
||||
{
|
||||
if (this->objects.size() == 0)
|
||||
return false;
|
||||
|
||||
stl_vertex size = this->objects[0]->get_object_stl_stats().size;
|
||||
|
||||
for (ModelObject* o : this->objects) {
|
||||
auto sz = o->get_object_stl_stats().size;
|
||||
|
||||
if (size[0] < sz[0]) size[0] = sz[0];
|
||||
if (size[1] < sz[1]) size[1] = sz[1];
|
||||
if (size[2] < sz[2]) size[2] = sz[2];
|
||||
}
|
||||
|
||||
return (size[0] < 3 && size[1] < 3 && size[2] < 3);
|
||||
}
|
||||
|
||||
void Model::convert_from_imperial_units()
|
||||
{
|
||||
double in_to_mm = 25.4;
|
||||
for (ModelObject* o : this->objects)
|
||||
o->scale_mesh_after_creation(Vec3d(in_to_mm, in_to_mm, in_to_mm));
|
||||
}
|
||||
|
||||
void Model::adjust_min_z()
|
||||
{
|
||||
if (objects.empty())
|
||||
|
@ -851,6 +851,8 @@ public:
|
||||
|
||||
bool looks_like_multipart_object() const;
|
||||
void convert_multipart_object(unsigned int max_extruders);
|
||||
bool looks_like_imperial_units() const;
|
||||
void convert_from_imperial_units();
|
||||
|
||||
// Ensures that the min z of the model is not negative
|
||||
void adjust_min_z();
|
||||
|
@ -64,8 +64,13 @@ Control::Control( wxWindow *parent,
|
||||
if (!is_osx)
|
||||
SetDoubleBuffered(true);// SetDoubleBuffered exists on Win and Linux/GTK, but is missing on OSX
|
||||
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
m_bmp_thumb_higher = (style == wxSL_HORIZONTAL ? ScalableBitmap(this, "thumb_right") : ScalableBitmap(this, "thumb_up"));
|
||||
m_bmp_thumb_lower = (style == wxSL_HORIZONTAL ? ScalableBitmap(this, "thumb_left") : ScalableBitmap(this, "thumb_down"));
|
||||
#else
|
||||
m_bmp_thumb_higher = (style == wxSL_HORIZONTAL ? ScalableBitmap(this, "right_half_circle.png") : ScalableBitmap(this, "thumb_up"));
|
||||
m_bmp_thumb_lower = (style == wxSL_HORIZONTAL ? ScalableBitmap(this, "left_half_circle.png" ) : ScalableBitmap(this, "thumb_down"));
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
m_thumb_size = m_bmp_thumb_lower.GetBmpSize();
|
||||
|
||||
m_bmp_add_tick_on = ScalableBitmap(this, "colorchange_add");
|
||||
@ -576,6 +581,10 @@ void Control::draw_thumb_text(wxDC& dc, const wxPoint& pos, const SelectedSlider
|
||||
|
||||
void Control::draw_thumb_item(wxDC& dc, const wxPoint& pos, const SelectedSlider& selection)
|
||||
{
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
wxCoord x_draw = pos.x - int(0.5 * m_thumb_size.x);
|
||||
wxCoord y_draw = pos.y - int(0.5 * m_thumb_size.y);
|
||||
#else
|
||||
wxCoord x_draw, y_draw;
|
||||
if (selection == ssLower) {
|
||||
if (is_horizontal()) {
|
||||
@ -587,7 +596,7 @@ void Control::draw_thumb_item(wxDC& dc, const wxPoint& pos, const SelectedSlider
|
||||
y_draw = pos.y - int(0.5*m_thumb_size.y);
|
||||
}
|
||||
}
|
||||
else{
|
||||
else {
|
||||
if (is_horizontal()) {
|
||||
x_draw = pos.x;
|
||||
y_draw = pos.y - int(0.5*m_thumb_size.y);
|
||||
@ -597,6 +606,7 @@ void Control::draw_thumb_item(wxDC& dc, const wxPoint& pos, const SelectedSlider
|
||||
y_draw = pos.y - int(0.5*m_thumb_size.y);
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
dc.DrawBitmap(selection == ssLower ? m_bmp_thumb_lower.bmp() : m_bmp_thumb_higher.bmp(), x_draw, y_draw);
|
||||
|
||||
// Update thumb rect
|
||||
|
@ -613,7 +613,7 @@ void GUI_App::set_auto_toolbar_icon_scale(float scale) const
|
||||
const float icon_sc = m_em_unit * 0.1f;
|
||||
#endif // __APPLE__
|
||||
|
||||
int int_val = std::min(int(scale / icon_sc * 100), 100);
|
||||
long int_val = std::min(int(std::lround(scale / icon_sc * 100)), 100);
|
||||
std::string val = std::to_string(int_val);
|
||||
|
||||
app_config->set("auto_toolbar_size", val);
|
||||
|
@ -17,6 +17,8 @@ namespace Slic3r
|
||||
namespace GUI
|
||||
{
|
||||
|
||||
const double ObjectManipulation::in_to_mm = 25.4;
|
||||
const double ObjectManipulation::mm_to_in = 0.0393700787;
|
||||
|
||||
// Helper function to be used by drop to bed button. Returns lowest point of this
|
||||
// volume in world coordinate system.
|
||||
@ -121,6 +123,8 @@ static void set_font_and_background_style(wxWindow* win, const wxFont& font)
|
||||
ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
OG_Settings(parent, true)
|
||||
{
|
||||
m_imperial_units = wxGetApp().app_config->get("use_inches") == "1";
|
||||
|
||||
m_manifold_warning_bmp = ScalableBitmap(parent, "exclamation");
|
||||
|
||||
// Load bitmaps to be used for the mirroring buttons:
|
||||
@ -314,15 +318,15 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
};
|
||||
|
||||
// add Units
|
||||
auto add_unit_text = [this, parent, editors_grid_sizer, height](std::string unit)
|
||||
auto add_unit_text = [this, parent, editors_grid_sizer, height](std::string unit, wxStaticText** unit_text)
|
||||
{
|
||||
wxStaticText* unit_text = new wxStaticText(parent, wxID_ANY, _(unit));
|
||||
set_font_and_background_style(unit_text, wxGetApp().normal_font());
|
||||
*unit_text = new wxStaticText(parent, wxID_ANY, _(unit));
|
||||
set_font_and_background_style(*unit_text, wxGetApp().normal_font());
|
||||
|
||||
// Unit text should be the same height as labels
|
||||
wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer->SetMinSize(wxSize(-1, height));
|
||||
sizer->Add(unit_text, 0, wxALIGN_CENTER_VERTICAL);
|
||||
sizer->Add(*unit_text, 0, wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
editors_grid_sizer->Add(sizer);
|
||||
m_rescalable_sizers.push_back(sizer);
|
||||
@ -330,7 +334,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
|
||||
for (size_t axis_idx = 0; axis_idx < sizeof(axes); axis_idx++)
|
||||
add_edit_boxes("position", axis_idx);
|
||||
add_unit_text(L("mm"));
|
||||
add_unit_text(m_imperial_units ? L("in") : L("mm"), &m_position_unit);
|
||||
|
||||
// Add drop to bed button
|
||||
m_drop_to_bed_button = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "drop_to_bed"));
|
||||
@ -356,7 +360,8 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
|
||||
for (size_t axis_idx = 0; axis_idx < sizeof(axes); axis_idx++)
|
||||
add_edit_boxes("rotation", axis_idx);
|
||||
add_unit_text("°");
|
||||
wxStaticText* rotation_unit{ nullptr };
|
||||
add_unit_text("°", &rotation_unit);
|
||||
|
||||
// Add reset rotation button
|
||||
m_reset_rotation_button = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "undo"));
|
||||
@ -390,7 +395,8 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
|
||||
for (size_t axis_idx = 0; axis_idx < sizeof(axes); axis_idx++)
|
||||
add_edit_boxes("scale", axis_idx);
|
||||
add_unit_text("%");
|
||||
wxStaticText* scale_unit{ nullptr };
|
||||
add_unit_text("%", &scale_unit);
|
||||
|
||||
// Add reset scale button
|
||||
m_reset_scale_button = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "undo"));
|
||||
@ -405,11 +411,20 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
|
||||
for (size_t axis_idx = 0; axis_idx < sizeof(axes); axis_idx++)
|
||||
add_edit_boxes("size", axis_idx);
|
||||
add_unit_text("mm");
|
||||
add_unit_text(m_imperial_units ? L("in") : L("mm"), &m_size_unit);
|
||||
editors_grid_sizer->AddStretchSpacer(1);
|
||||
|
||||
m_main_grid_sizer->Add(editors_grid_sizer, 1, wxEXPAND);
|
||||
|
||||
m_check_inch = new wxCheckBox(parent, wxID_ANY, "Inches");
|
||||
m_check_inch->SetValue(m_imperial_units);
|
||||
m_check_inch->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent&) {
|
||||
wxGetApp().app_config->set("use_inches", m_check_inch->GetValue() ? "1" : "0");
|
||||
wxGetApp().sidebar().update_ui_from_settings();
|
||||
});
|
||||
|
||||
m_main_grid_sizer->Add(m_check_inch, 1, wxEXPAND);
|
||||
|
||||
m_og->sizer->Clear(true);
|
||||
m_og->sizer->Add(m_main_grid_sizer, 1, wxEXPAND | wxALL, border);
|
||||
}
|
||||
@ -452,6 +467,32 @@ void ObjectManipulation::UpdateAndShow(const bool show)
|
||||
OG_Settings::UpdateAndShow(show);
|
||||
}
|
||||
|
||||
void ObjectManipulation::update_ui_from_settings()
|
||||
{
|
||||
if (m_imperial_units != (wxGetApp().app_config->get("use_inches") == "1")) {
|
||||
m_imperial_units = wxGetApp().app_config->get("use_inches") == "1";
|
||||
|
||||
auto update_unit_text = [](const wxString& new_unit_text, wxStaticText* widget) {
|
||||
widget->SetLabel(new_unit_text);
|
||||
if (wxOSX) set_font_and_background_style(widget, wxGetApp().normal_font());
|
||||
};
|
||||
update_unit_text(m_imperial_units ? _L("in") : _L("mm"), m_position_unit);
|
||||
update_unit_text(m_imperial_units ? _L("in") : _L("mm"), m_size_unit);
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
auto update = [this, i](/*ManipulationEditorKey*/int key_id, const Vec3d& new_value) {
|
||||
wxString new_text = double_to_string(m_imperial_units ? new_value(i) * mm_to_in : new_value(i), 2);
|
||||
const int id = key_id * 3 + i;
|
||||
if (id >= 0) m_editors[id]->set_value(new_text);
|
||||
};
|
||||
update(0/*mePosition*/, m_new_position);
|
||||
update(3/*meSize*/, m_new_size);
|
||||
}
|
||||
}
|
||||
|
||||
m_check_inch->SetValue(m_imperial_units);
|
||||
}
|
||||
|
||||
void ObjectManipulation::update_settings_value(const Selection& selection)
|
||||
{
|
||||
m_new_move_label_string = L("Position");
|
||||
@ -562,6 +603,8 @@ void ObjectManipulation::update_if_dirty()
|
||||
if (std::abs(cached_rounded(i) - new_rounded) > EPSILON) {
|
||||
cached_rounded(i) = new_rounded;
|
||||
const int id = key_id*3+i;
|
||||
if (m_imperial_units && (key_id == mePosition || key_id == meSize))
|
||||
new_text = double_to_string(new_value(i)*mm_to_in, 2);
|
||||
if (id >= 0) m_editors[id]->set_value(new_text);
|
||||
}
|
||||
cached(i) = new_value(i);
|
||||
@ -851,6 +894,9 @@ void ObjectManipulation::on_change(const std::string& opt_key, int axis, double
|
||||
if (!m_cache.is_valid())
|
||||
return;
|
||||
|
||||
if (m_imperial_units && (opt_key == "position" || opt_key == "size"))
|
||||
new_value *= in_to_mm;
|
||||
|
||||
if (opt_key == "position")
|
||||
change_position_value(axis, new_value);
|
||||
else if (opt_key == "rotation")
|
||||
@ -929,6 +975,9 @@ void ObjectManipulation::msw_rescale()
|
||||
for (ManipulationEditor* editor : m_editors)
|
||||
editor->msw_rescale();
|
||||
|
||||
// rescale "inches" checkbox
|
||||
m_check_inch->SetMinSize(wxSize(-1, int(1.5f * m_check_inch->GetFont().GetPixelSize().y + 0.5f)));
|
||||
|
||||
get_og()->msw_rescale();
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ class wxBitmapComboBox;
|
||||
class wxStaticText;
|
||||
class LockButton;
|
||||
class wxStaticBitmap;
|
||||
class wxCheckBox;
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
@ -41,6 +42,11 @@ private:
|
||||
|
||||
class ObjectManipulation : public OG_Settings
|
||||
{
|
||||
public:
|
||||
static const double in_to_mm;
|
||||
static const double mm_to_in;
|
||||
|
||||
private:
|
||||
struct Cache
|
||||
{
|
||||
Vec3d position;
|
||||
@ -76,6 +82,10 @@ class ObjectManipulation : public OG_Settings
|
||||
wxStaticText* m_scale_Label = nullptr;
|
||||
wxStaticText* m_rotate_Label = nullptr;
|
||||
|
||||
bool m_imperial_units { false };
|
||||
wxStaticText* m_position_unit { nullptr };
|
||||
wxStaticText* m_size_unit { nullptr };
|
||||
|
||||
wxStaticText* m_item_name = nullptr;
|
||||
wxStaticText* m_empty_str = nullptr;
|
||||
|
||||
@ -84,6 +94,8 @@ class ObjectManipulation : public OG_Settings
|
||||
ScalableButton* m_reset_rotation_button = nullptr;
|
||||
ScalableButton* m_drop_to_bed_button = nullptr;
|
||||
|
||||
wxCheckBox* m_check_inch {nullptr};
|
||||
|
||||
// Mirroring buttons and their current state
|
||||
enum MirrorButtonState {
|
||||
mbHidden,
|
||||
@ -138,6 +150,7 @@ public:
|
||||
void Show(const bool show) override;
|
||||
bool IsShown() override;
|
||||
void UpdateAndShow(const bool show) override;
|
||||
void update_ui_from_settings();
|
||||
|
||||
void set_dirty() { m_dirty = true; }
|
||||
// Called from the App to update the UI if dirty.
|
||||
|
@ -184,8 +184,8 @@ Preview::Preview(
|
||||
: m_canvas_widget(nullptr)
|
||||
, m_canvas(nullptr)
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
, m_bottom_toolbar_sizer(nullptr)
|
||||
, m_layers_slider_sizer(nullptr)
|
||||
, m_bottom_toolbar_panel(nullptr)
|
||||
#else
|
||||
, m_double_slider_sizer(nullptr)
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
@ -194,6 +194,7 @@ Preview::Preview(
|
||||
, m_label_show(nullptr)
|
||||
, m_combochecklist_features(nullptr)
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
, m_combochecklist_features_pos(0)
|
||||
, m_combochecklist_options(nullptr)
|
||||
#else
|
||||
, m_checkbox_travel(nullptr)
|
||||
@ -251,14 +252,20 @@ bool Preview::init(wxWindow* parent, Model* model)
|
||||
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
m_layers_slider_sizer = create_layers_slider_sizer();
|
||||
|
||||
m_bottom_toolbar_panel = new wxPanel(this);
|
||||
|
||||
m_label_view_type = new wxStaticText(m_bottom_toolbar_panel, wxID_ANY, _L("View"));
|
||||
|
||||
m_choice_view_type = new wxChoice(m_bottom_toolbar_panel, wxID_ANY);
|
||||
#else
|
||||
m_double_slider_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
create_double_slider();
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
m_label_view_type = new wxStaticText(this, wxID_ANY, _L("View"));
|
||||
|
||||
m_choice_view_type = new wxChoice(this, wxID_ANY);
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
m_choice_view_type->Append(_L("Feature type"));
|
||||
m_choice_view_type->Append(_L("Height"));
|
||||
m_choice_view_type->Append(_L("Width"));
|
||||
@ -269,10 +276,18 @@ bool Preview::init(wxWindow* parent, Model* model)
|
||||
m_choice_view_type->Append(_L("Color Print"));
|
||||
m_choice_view_type->SetSelection(0);
|
||||
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
m_label_show = new wxStaticText(m_bottom_toolbar_panel, wxID_ANY, _L("Show"));
|
||||
#else
|
||||
m_label_show = new wxStaticText(this, wxID_ANY, _L("Show"));
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
m_combochecklist_features = new wxComboCtrl();
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
m_combochecklist_features->Create(m_bottom_toolbar_panel, wxID_ANY, _L("Feature types"), wxDefaultPosition, wxDefaultSize, wxCB_READONLY);
|
||||
#else
|
||||
m_combochecklist_features->Create(this, wxID_ANY, _L("Feature types"), wxDefaultPosition, wxDefaultSize, wxCB_READONLY);
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
std::string feature_items = GUI::into_u8(
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
_L("Unknown") + "|1|" +
|
||||
@ -296,7 +311,7 @@ bool Preview::init(wxWindow* parent, Model* model)
|
||||
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
m_combochecklist_options = new wxComboCtrl();
|
||||
m_combochecklist_options->Create(this, wxID_ANY, _L("Options"), wxDefaultPosition, wxDefaultSize, wxCB_READONLY);
|
||||
m_combochecklist_options->Create(m_bottom_toolbar_panel, wxID_ANY, _L("Options"), wxDefaultPosition, wxDefaultSize, wxCB_READONLY);
|
||||
std::string options_items = GUI::into_u8(
|
||||
get_option_type_string(OptionType::Travel) + "|0|" +
|
||||
get_option_type_string(OptionType::Retractions) + "|0|" +
|
||||
@ -328,20 +343,23 @@ bool Preview::init(wxWindow* parent, Model* model)
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
m_moves_slider = new DoubleSlider::Control(this, wxID_ANY, 0, 0, 0, 100, wxDefaultPosition, wxSize(-1, 3 * GetTextExtent("m").y), wxSL_HORIZONTAL);
|
||||
m_moves_slider = new DoubleSlider::Control(m_bottom_toolbar_panel, wxID_ANY, 0, 0, 0, 100, wxDefaultPosition, wxSize(-1, 4 * GetTextExtent("m").y), wxSL_HORIZONTAL);
|
||||
m_moves_slider->SetDrawMode(DoubleSlider::dmSequentialGCodeView);
|
||||
m_moves_slider->Bind(wxEVT_SCROLL_CHANGED, &Preview::on_moves_slider_scroll_changed, this);
|
||||
|
||||
m_bottom_toolbar_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
m_bottom_toolbar_sizer->AddSpacer(5);
|
||||
m_bottom_toolbar_sizer->Add(m_label_view_type, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
|
||||
m_bottom_toolbar_sizer->Add(m_choice_view_type, 0, wxALIGN_CENTER_VERTICAL, 0);
|
||||
m_bottom_toolbar_sizer->AddSpacer(5);
|
||||
m_bottom_toolbar_sizer->Add(m_label_show, 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, 5);
|
||||
m_bottom_toolbar_sizer->Add(m_combochecklist_options, 0, wxALIGN_CENTER_VERTICAL, 0);
|
||||
m_bottom_toolbar_sizer->Add(m_combochecklist_features, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 5);
|
||||
m_bottom_toolbar_sizer->AddSpacer(5);
|
||||
m_bottom_toolbar_sizer->Add(m_moves_slider, 1, wxALL | wxEXPAND, 5);
|
||||
wxBoxSizer* bottom_toolbar_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
bottom_toolbar_sizer->AddSpacer(5);
|
||||
bottom_toolbar_sizer->Add(m_label_view_type, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
|
||||
bottom_toolbar_sizer->Add(m_choice_view_type, 0, wxALIGN_CENTER_VERTICAL, 0);
|
||||
bottom_toolbar_sizer->AddSpacer(5);
|
||||
bottom_toolbar_sizer->Add(m_label_show, 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, 5);
|
||||
bottom_toolbar_sizer->Add(m_combochecklist_options, 0, wxALIGN_CENTER_VERTICAL, 0);
|
||||
// change the following number if editing the layout of the bottom toolbar sizer. It is used into update_bottom_toolbar()
|
||||
m_combochecklist_features_pos = 6;
|
||||
bottom_toolbar_sizer->Add(m_combochecklist_features, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 5);
|
||||
bottom_toolbar_sizer->Hide(m_combochecklist_features);
|
||||
bottom_toolbar_sizer->AddSpacer(5);
|
||||
bottom_toolbar_sizer->Add(m_moves_slider, 1, wxALL | wxEXPAND, 0);
|
||||
m_bottom_toolbar_panel->SetSizer(bottom_toolbar_sizer);
|
||||
#else
|
||||
wxBoxSizer* bottom_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
bottom_sizer->Add(m_label_view_type, 0, wxALIGN_CENTER_VERTICAL, 5);
|
||||
@ -364,8 +382,8 @@ bool Preview::init(wxWindow* parent, Model* model)
|
||||
wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
main_sizer->Add(top_sizer, 1, wxALL | wxEXPAND, 0);
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
main_sizer->Add(m_bottom_toolbar_sizer, 0, wxALL | wxEXPAND, 0);
|
||||
main_sizer->Hide(m_bottom_toolbar_sizer);
|
||||
main_sizer->Add(m_bottom_toolbar_panel, 0, wxALL | wxEXPAND, 0);
|
||||
main_sizer->Hide(m_bottom_toolbar_panel);
|
||||
#else
|
||||
main_sizer->Add(bottom_sizer, 0, wxALL | wxEXPAND, 0);
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
@ -565,6 +583,7 @@ void Preview::bind_event_handlers()
|
||||
m_combochecklist_features->Bind(wxEVT_CHECKLISTBOX, &Preview::on_combochecklist_features, this);
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
m_combochecklist_options->Bind(wxEVT_CHECKLISTBOX, &Preview::on_combochecklist_options, this);
|
||||
m_moves_slider->Bind(wxEVT_SCROLL_CHANGED, &Preview::on_moves_slider_scroll_changed, this);
|
||||
#else
|
||||
m_checkbox_travel->Bind(wxEVT_CHECKBOX, &Preview::on_checkbox_travel, this);
|
||||
m_checkbox_retractions->Bind(wxEVT_CHECKBOX, &Preview::on_checkbox_retractions, this);
|
||||
@ -581,6 +600,7 @@ void Preview::unbind_event_handlers()
|
||||
m_combochecklist_features->Unbind(wxEVT_CHECKLISTBOX, &Preview::on_combochecklist_features, this);
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
m_combochecklist_options->Unbind(wxEVT_CHECKLISTBOX, &Preview::on_combochecklist_options, this);
|
||||
m_moves_slider->Unbind(wxEVT_SCROLL_CHANGED, &Preview::on_moves_slider_scroll_changed, this);
|
||||
#else
|
||||
m_checkbox_travel->Unbind(wxEVT_CHECKBOX, &Preview::on_checkbox_travel, this);
|
||||
m_checkbox_retractions->Unbind(wxEVT_CHECKBOX, &Preview::on_checkbox_retractions, this);
|
||||
@ -773,10 +793,33 @@ void Preview::update_bottom_toolbar()
|
||||
combochecklist_set_flags(m_combochecklist_features, m_canvas->get_toolpath_role_visibility_flags());
|
||||
combochecklist_set_flags(m_combochecklist_options, m_canvas->get_gcode_options_visibility_flags());
|
||||
|
||||
m_bottom_toolbar_sizer->Show(m_combochecklist_features,
|
||||
!m_canvas->is_gcode_legend_enabled() || m_canvas->get_gcode_view_type() != GCodeViewer::EViewType::FeatureType);
|
||||
m_bottom_toolbar_sizer->Layout();
|
||||
Refresh();
|
||||
// updates visibility of features combobox
|
||||
if (m_bottom_toolbar_panel->IsShown())
|
||||
{
|
||||
wxSizer* sizer = m_bottom_toolbar_panel->GetSizer();
|
||||
bool show = !m_canvas->is_gcode_legend_enabled() || m_canvas->get_gcode_view_type() != GCodeViewer::EViewType::FeatureType;
|
||||
|
||||
if (show)
|
||||
{
|
||||
if (sizer->GetItem(m_combochecklist_features) == nullptr)
|
||||
{
|
||||
sizer->Insert(m_combochecklist_features_pos, m_combochecklist_features, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 5);
|
||||
sizer->Show(m_combochecklist_features);
|
||||
sizer->Layout();
|
||||
Refresh();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sizer->GetItem(m_combochecklist_features) != nullptr)
|
||||
{
|
||||
sizer->Hide(m_combochecklist_features);
|
||||
sizer->Detach(m_combochecklist_features);
|
||||
sizer->Layout();
|
||||
Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
@ -1243,8 +1286,9 @@ void Preview::load_print_as_fff(bool keep_z_range)
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
m_canvas->load_gcode_preview(*m_gcode_result);
|
||||
m_canvas->refresh_gcode_preview(*m_gcode_result, colors);
|
||||
GetSizer()->Show(m_bottom_toolbar_sizer);
|
||||
GetSizer()->Show(m_bottom_toolbar_panel);
|
||||
GetSizer()->Layout();
|
||||
Refresh();
|
||||
zs = m_canvas->get_gcode_layers_zs();
|
||||
#else
|
||||
m_canvas->load_gcode_preview(*m_gcode_preview_data, colors);
|
||||
@ -1254,8 +1298,9 @@ void Preview::load_print_as_fff(bool keep_z_range)
|
||||
// Load the initial preview based on slices, not the final G-code.
|
||||
m_canvas->load_preview(colors, color_print_values);
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
GetSizer()->Hide(m_bottom_toolbar_sizer);
|
||||
GetSizer()->Hide(m_bottom_toolbar_panel);
|
||||
GetSizer()->Layout();
|
||||
Refresh();
|
||||
zs = m_canvas->get_volumes_print_zs(true);
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
}
|
||||
@ -1316,8 +1361,9 @@ void Preview::load_print_as_sla()
|
||||
{
|
||||
m_canvas->load_sla_preview();
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
GetSizer()->Hide(m_bottom_toolbar_sizer);
|
||||
GetSizer()->Hide(m_bottom_toolbar_panel);
|
||||
GetSizer()->Layout();
|
||||
Refresh();
|
||||
#else
|
||||
show_hide_ui_elements("none");
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
@ -84,7 +84,7 @@ class Preview : public wxPanel
|
||||
GLCanvas3D* m_canvas;
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
wxBoxSizer* m_layers_slider_sizer;
|
||||
wxBoxSizer* m_bottom_toolbar_sizer;
|
||||
wxPanel* m_bottom_toolbar_panel;
|
||||
#else
|
||||
wxBoxSizer* m_double_slider_sizer;
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
@ -93,6 +93,7 @@ class Preview : public wxPanel
|
||||
wxStaticText* m_label_show;
|
||||
wxComboCtrl* m_combochecklist_features;
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
size_t m_combochecklist_features_pos;
|
||||
wxComboCtrl* m_combochecklist_options;
|
||||
#else
|
||||
wxCheckBox* m_checkbox_travel;
|
||||
|
@ -15,6 +15,8 @@
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
static constexpr size_t MaxVertexBuffers = 50;
|
||||
|
||||
GLGizmoFdmSupports::GLGizmoFdmSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
||||
: GLGizmoBase(parent, icon_filename, sprite_id)
|
||||
, m_quadric(nullptr)
|
||||
@ -123,10 +125,9 @@ void GLGizmoFdmSupports::render_triangles(const Selection& selection) const
|
||||
|
||||
// Now render both enforcers and blockers.
|
||||
for (int i=0; i<2; ++i) {
|
||||
if (m_ivas[mesh_id][i].has_VBOs()) {
|
||||
glsafe(::glColor4f(i ? 1.f : 0.2f, 0.2f, i ? 0.2f : 1.0f, 0.5f));
|
||||
m_ivas[mesh_id][i].render();
|
||||
}
|
||||
glsafe(::glColor4f(i ? 1.f : 0.2f, 0.2f, i ? 0.2f : 1.0f, 0.5f));
|
||||
for (const GLIndexedVertexArray& iva : m_ivas[mesh_id][i])
|
||||
iva.render();
|
||||
}
|
||||
glsafe(::glPopMatrix());
|
||||
}
|
||||
@ -205,8 +206,14 @@ void GLGizmoFdmSupports::update_from_model_object()
|
||||
++num_of_volumes;
|
||||
m_selected_facets.resize(num_of_volumes);
|
||||
m_neighbors.resize(num_of_volumes);
|
||||
|
||||
m_ivas.clear();
|
||||
m_ivas.resize(num_of_volumes);
|
||||
for (size_t i=0; i<num_of_volumes; ++i) {
|
||||
m_ivas[i][0].reserve(MaxVertexBuffers);
|
||||
m_ivas[i][1].reserve(MaxVertexBuffers);
|
||||
}
|
||||
|
||||
|
||||
int volume_id = -1;
|
||||
for (const ModelVolume* mv : mo->volumes) {
|
||||
@ -226,7 +233,8 @@ void GLGizmoFdmSupports::update_from_model_object()
|
||||
for (int i : list)
|
||||
m_selected_facets[volume_id][i] = type;
|
||||
}
|
||||
update_vertex_buffers(mv, volume_id, true, true);
|
||||
update_vertex_buffers(mesh, volume_id, FacetSupportType::ENFORCER);
|
||||
update_vertex_buffers(mesh, volume_id, FacetSupportType::BLOCKER);
|
||||
|
||||
m_neighbors[volume_id].resize(3 * mesh->its.indices.size());
|
||||
|
||||
@ -325,7 +333,7 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
||||
Vec3f closest_hit = Vec3f::Zero();
|
||||
double closest_hit_squared_distance = std::numeric_limits<double>::max();
|
||||
size_t closest_facet = 0;
|
||||
size_t closest_hit_mesh_id = size_t(-1);
|
||||
int closest_hit_mesh_id = -1;
|
||||
|
||||
// Transformations of individual meshes
|
||||
std::vector<Transform3d> trafo_matrices;
|
||||
@ -368,17 +376,22 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
||||
}
|
||||
// We now know where the ray hit, let's save it and cast another ray
|
||||
if (closest_hit_mesh_id != size_t(-1)) // only if there is at least one hit
|
||||
hit_positions_and_facet_ids[closest_hit_mesh_id].emplace_back(closest_hit, closest_facet);
|
||||
some_mesh_was_hit = true;
|
||||
|
||||
if (some_mesh_was_hit) {
|
||||
// Now propagate the hits
|
||||
mesh_id = -1;
|
||||
const TriangleMesh* mesh = nullptr;
|
||||
for (const ModelVolume* mv : mo->volumes) {
|
||||
if (! mv->is_model_part())
|
||||
continue;
|
||||
++mesh_id;
|
||||
if (mesh_id == closest_hit_mesh_id) {
|
||||
mesh = &mv->mesh();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Now propagate the hits
|
||||
mesh_id = -1;
|
||||
for (const ModelVolume* mv : mo->volumes) {
|
||||
|
||||
if (! mv->is_model_part())
|
||||
continue;
|
||||
|
||||
++mesh_id;
|
||||
bool update_both = false;
|
||||
|
||||
const Transform3d& trafo_matrix = trafo_matrices[mesh_id];
|
||||
@ -389,89 +402,96 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
||||
const float avg_scaling = (sf(0) + sf(1) + sf(2))/3.;
|
||||
const float limit = pow(m_cursor_radius/avg_scaling , 2.f);
|
||||
|
||||
// For all hits on this mesh...
|
||||
for (const std::pair<Vec3f, size_t>& hit_and_facet : hit_positions_and_facet_ids[mesh_id]) {
|
||||
some_mesh_was_hit = true;
|
||||
const TriangleMesh* mesh = &mv->mesh();
|
||||
std::vector<NeighborData>& neighbors = m_neighbors[mesh_id];
|
||||
const std::pair<Vec3f, size_t>& hit_and_facet = { closest_hit, closest_facet };
|
||||
|
||||
// Calculate direction from camera to the hit (in mesh coords):
|
||||
Vec3f dir = ((trafo_matrix.inverse() * camera.get_position()).cast<float>() - hit_and_facet.first).normalized();
|
||||
const std::vector<NeighborData>& neighbors = m_neighbors[mesh_id];
|
||||
|
||||
// A lambda to calculate distance from the centerline:
|
||||
auto squared_distance_from_line = [&hit_and_facet, &dir](const Vec3f point) -> float {
|
||||
Vec3f diff = hit_and_facet.first - point;
|
||||
return (diff - diff.dot(dir) * dir).squaredNorm();
|
||||
};
|
||||
// Calculate direction from camera to the hit (in mesh coords):
|
||||
Vec3f dir = ((trafo_matrix.inverse() * camera.get_position()).cast<float>() - hit_and_facet.first).normalized();
|
||||
|
||||
// A lambda to determine whether this facet is potentionally visible (still can be obscured)
|
||||
auto faces_camera = [&dir](const ModelVolume* mv, const size_t& facet) -> bool {
|
||||
return (mv->mesh().stl.facet_start[facet].normal.dot(dir) > 0.);
|
||||
};
|
||||
// Now start with the facet the pointer points to and check all adjacent facets. neighbors vector stores
|
||||
// pairs of vertex_idx - facet_idx and is sorted with respect to the former. Neighboring facet index can be
|
||||
// quickly found by finding a vertex in the list and read the respective facet ids.
|
||||
std::vector<size_t> facets_to_select{hit_and_facet.second};
|
||||
NeighborData vertex = std::make_pair(0, 0);
|
||||
std::vector<bool> visited(m_selected_facets[mesh_id].size(), false); // keep track of facets we already processed
|
||||
size_t facet_idx = 0; // index into facets_to_select
|
||||
auto it = neighbors.end();
|
||||
while (facet_idx < facets_to_select.size()) {
|
||||
size_t facet = facets_to_select[facet_idx];
|
||||
if (! visited[facet]) {
|
||||
// check all three vertices and in case they're close enough, find the remaining facets
|
||||
// and add them to the list to be proccessed later
|
||||
for (size_t i=0; i<3; ++i) {
|
||||
vertex.first = mesh->its.indices[facet](i); // vertex index
|
||||
float dist = squared_distance_from_line(mesh->its.vertices[vertex.first]);
|
||||
if (dist < limit) {
|
||||
it = std::lower_bound(neighbors.begin(), neighbors.end(), vertex);
|
||||
while (it != neighbors.end() && it->first == vertex.first) {
|
||||
if (it->second != facet && faces_camera(mv, it->second))
|
||||
facets_to_select.push_back(it->second);
|
||||
++it;
|
||||
}
|
||||
// A lambda to calculate distance from the centerline:
|
||||
auto squared_distance_from_line = [&hit_and_facet, &dir](const Vec3f& point) -> float {
|
||||
Vec3f diff = hit_and_facet.first - point;
|
||||
return (diff - diff.dot(dir) * dir).squaredNorm();
|
||||
};
|
||||
|
||||
// A lambda to determine whether this facet is potentionally visible (still can be obscured)
|
||||
auto faces_camera = [&dir, &mesh](const size_t& facet) -> bool {
|
||||
return (mesh->stl.facet_start[facet].normal.dot(dir) > 0.);
|
||||
};
|
||||
// Now start with the facet the pointer points to and check all adjacent facets. neighbors vector stores
|
||||
// pairs of vertex_idx - facet_idx and is sorted with respect to the former. Neighboring facet index can be
|
||||
// quickly found by finding a vertex in the list and read the respective facet ids.
|
||||
std::vector<size_t> facets_to_select{hit_and_facet.second};
|
||||
NeighborData vertex = std::make_pair(0, 0);
|
||||
std::vector<bool> visited(m_selected_facets[mesh_id].size(), false); // keep track of facets we already processed
|
||||
size_t facet_idx = 0; // index into facets_to_select
|
||||
auto it = neighbors.end();
|
||||
while (facet_idx < facets_to_select.size()) {
|
||||
size_t facet = facets_to_select[facet_idx];
|
||||
if (! visited[facet]) {
|
||||
// check all three vertices and in case they're close enough, find the remaining facets
|
||||
// and add them to the list to be proccessed later
|
||||
for (size_t i=0; i<3; ++i) {
|
||||
vertex.first = mesh->its.indices[facet](i); // vertex index
|
||||
float dist = squared_distance_from_line(mesh->its.vertices[vertex.first]);
|
||||
if (dist < limit) {
|
||||
it = std::lower_bound(neighbors.begin(), neighbors.end(), vertex);
|
||||
while (it != neighbors.end() && it->first == vertex.first) {
|
||||
if (it->second != facet && faces_camera(it->second))
|
||||
facets_to_select.push_back(it->second);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
visited[facet] = true;
|
||||
}
|
||||
++facet_idx;
|
||||
visited[facet] = true;
|
||||
}
|
||||
++facet_idx;
|
||||
}
|
||||
|
||||
// Now just select all facets that passed.
|
||||
for (size_t next_facet : facets_to_select) {
|
||||
FacetSupportType& facet = m_selected_facets[mesh_id][next_facet];
|
||||
std::vector<size_t> new_facets;
|
||||
new_facets.reserve(facets_to_select.size());
|
||||
|
||||
if (facet != new_state && facet != FacetSupportType::NONE) {
|
||||
// Now just select all facets that passed and remember which
|
||||
// ones have really changed state.
|
||||
for (size_t next_facet : facets_to_select) {
|
||||
FacetSupportType& facet = m_selected_facets[mesh_id][next_facet];
|
||||
|
||||
if (facet != new_state) {
|
||||
if (facet != FacetSupportType::NONE) {
|
||||
// this triangle is currently in the other VBA.
|
||||
// Both VBAs need to be refreshed.
|
||||
update_both = true;
|
||||
}
|
||||
facet = new_state;
|
||||
new_facets.push_back(next_facet);
|
||||
}
|
||||
}
|
||||
|
||||
if (! new_facets.empty()) {
|
||||
if (new_state != FacetSupportType::NONE) {
|
||||
// append triangles into the respective VBA
|
||||
update_vertex_buffers(mesh, mesh_id, new_state, &new_facets);
|
||||
if (update_both) {
|
||||
auto other = new_state == FacetSupportType::ENFORCER
|
||||
? FacetSupportType::BLOCKER
|
||||
: FacetSupportType::ENFORCER;
|
||||
update_vertex_buffers(mesh, mesh_id, other); // regenerate the other VBA
|
||||
}
|
||||
}
|
||||
else {
|
||||
update_vertex_buffers(mesh, mesh_id, FacetSupportType::ENFORCER);
|
||||
update_vertex_buffers(mesh, mesh_id, FacetSupportType::BLOCKER);
|
||||
}
|
||||
}
|
||||
|
||||
update_vertex_buffers(mv, mesh_id,
|
||||
new_state == FacetSupportType::ENFORCER || update_both,
|
||||
new_state == FacetSupportType::BLOCKER || update_both
|
||||
);
|
||||
}
|
||||
|
||||
if (some_mesh_was_hit)
|
||||
{
|
||||
if (m_button_down == Button::None)
|
||||
m_button_down = ((action == SLAGizmoEventType::LeftDown) ? Button::Left : Button::Right);
|
||||
// Force rendering. In case the user is dragging, the queue can be
|
||||
// flooded by wxEVT_MOVING event and rendering would be skipped.
|
||||
m_parent.render();
|
||||
return true;
|
||||
}
|
||||
if (action == SLAGizmoEventType::Dragging && m_button_down != Button::None) {
|
||||
// Same as above. We don't want the cursor to freeze when we
|
||||
// leave the mesh while painting.
|
||||
m_parent.render();
|
||||
if (action == SLAGizmoEventType::Dragging && m_button_down != Button::None)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::RightUp)
|
||||
@ -493,34 +513,54 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
||||
}
|
||||
|
||||
|
||||
void GLGizmoFdmSupports::update_vertex_buffers(const ModelVolume* mv,
|
||||
void GLGizmoFdmSupports::update_vertex_buffers(const TriangleMesh* mesh,
|
||||
int mesh_id,
|
||||
bool update_enforcers,
|
||||
bool update_blockers)
|
||||
FacetSupportType type,
|
||||
const std::vector<size_t>* new_facets)
|
||||
{
|
||||
const TriangleMesh* mesh = &mv->mesh();
|
||||
std::vector<GLIndexedVertexArray>& ivas = m_ivas[mesh_id][type == FacetSupportType::ENFORCER ? 0 : 1];
|
||||
|
||||
for (FacetSupportType type : {FacetSupportType::ENFORCER, FacetSupportType::BLOCKER}) {
|
||||
if ((type == FacetSupportType::ENFORCER && ! update_enforcers)
|
||||
|| (type == FacetSupportType::BLOCKER && ! update_blockers))
|
||||
continue;
|
||||
// lambda to push facet into vertex buffer
|
||||
auto push_facet = [this, &mesh, &mesh_id](size_t idx, GLIndexedVertexArray& iva) {
|
||||
for (int i=0; i<3; ++i)
|
||||
iva.push_geometry(
|
||||
mesh->its.vertices[mesh->its.indices[idx](i)].cast<double>(),
|
||||
m_c->raycaster()->raycasters()[mesh_id]->get_triangle_normal(idx).cast<double>()
|
||||
);
|
||||
size_t num = iva.triangle_indices_size;
|
||||
iva.push_triangle(num, num+1, num+2);
|
||||
};
|
||||
|
||||
GLIndexedVertexArray& iva = m_ivas[mesh_id][type==FacetSupportType::ENFORCER ? 0 : 1];
|
||||
iva.release_geometry();
|
||||
size_t triangle_cnt=0;
|
||||
|
||||
if (ivas.size() == MaxVertexBuffers || ! new_facets) {
|
||||
// If there are too many or they should be regenerated, make one large
|
||||
// GLVertexBufferArray.
|
||||
ivas.clear(); // destructors release geometry
|
||||
ivas.push_back(GLIndexedVertexArray());
|
||||
|
||||
bool pushed = false;
|
||||
for (size_t facet_idx=0; facet_idx<m_selected_facets[mesh_id].size(); ++facet_idx) {
|
||||
FacetSupportType status = m_selected_facets[mesh_id][facet_idx];
|
||||
if (status != type)
|
||||
continue;
|
||||
for (int i=0; i<3; ++i)
|
||||
iva.push_geometry(mesh->its.vertices[mesh->its.indices[facet_idx](i)].cast<double>(),
|
||||
MeshRaycaster::get_triangle_normal(mesh->its, facet_idx).cast<double>());
|
||||
iva.push_triangle(3*triangle_cnt, 3*triangle_cnt+1, 3*triangle_cnt+2);
|
||||
++triangle_cnt;
|
||||
if (m_selected_facets[mesh_id][facet_idx] == type) {
|
||||
push_facet(facet_idx, ivas.back());
|
||||
pushed = true;
|
||||
}
|
||||
}
|
||||
if (! m_selected_facets[mesh_id].empty())
|
||||
iva.finalize_geometry(true);
|
||||
if (pushed)
|
||||
ivas.back().finalize_geometry(true);
|
||||
else
|
||||
ivas.pop_back();
|
||||
} else {
|
||||
// we are only appending - let's make new vertex array and let the old ones live
|
||||
ivas.push_back(GLIndexedVertexArray());
|
||||
for (size_t facet_idx : *new_facets)
|
||||
push_facet(facet_idx, ivas.back());
|
||||
|
||||
if (! new_facets->empty())
|
||||
ivas.back().finalize_geometry(true);
|
||||
else
|
||||
ivas.pop_back();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -553,7 +593,8 @@ void GLGizmoFdmSupports::select_facets_by_angle(float threshold_deg, bool overwr
|
||||
? FacetSupportType::BLOCKER
|
||||
: FacetSupportType::ENFORCER;
|
||||
}
|
||||
update_vertex_buffers(mv, mesh_id, true, true);
|
||||
update_vertex_buffers(&mv->mesh(), mesh_id, FacetSupportType::ENFORCER);
|
||||
update_vertex_buffers(&mv->mesh(), mesh_id, FacetSupportType::BLOCKER);
|
||||
}
|
||||
|
||||
Plater::TakeSnapshot(wxGetApp().plater(), block ? _L("Block supports by angle")
|
||||
@ -623,7 +664,8 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
|
||||
if (mv->is_model_part()) {
|
||||
m_selected_facets[idx].assign(m_selected_facets[idx].size(), FacetSupportType::NONE);
|
||||
mv->m_supported_facets.clear();
|
||||
update_vertex_buffers(mv, idx, true, true);
|
||||
update_vertex_buffers(&mv->mesh(), idx, FacetSupportType::ENFORCER);
|
||||
update_vertex_buffers(&mv->mesh(), idx, FacetSupportType::BLOCKER);
|
||||
m_parent.set_as_dirty();
|
||||
}
|
||||
}
|
||||
|
@ -33,14 +33,16 @@ private:
|
||||
// individual facets (one of the enum values above).
|
||||
std::vector<std::vector<FacetSupportType>> m_selected_facets;
|
||||
|
||||
// Store two vertex buffer arrays (for enforcers/blockers)
|
||||
// for each model-part volume.
|
||||
std::vector<std::array<GLIndexedVertexArray, 2>> m_ivas;
|
||||
// Vertex buffer arrays for each model-part volume. There is a vector of
|
||||
// arrays so that adding triangles can be done without regenerating all
|
||||
// other triangles. Enforcers and blockers are of course separate.
|
||||
std::vector<std::array<std::vector<GLIndexedVertexArray>, 2>> m_ivas;
|
||||
|
||||
void update_vertex_buffers(const ModelVolume* mv,
|
||||
void update_vertex_buffers(const TriangleMesh* mesh,
|
||||
int mesh_id,
|
||||
bool update_enforcers,
|
||||
bool update_blockers);
|
||||
FacetSupportType type, // enforcers / blockers
|
||||
const std::vector<size_t>* new_facets = nullptr); // nullptr -> regenerate all
|
||||
|
||||
|
||||
public:
|
||||
GLGizmoFdmSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||
|
@ -623,6 +623,10 @@ void MainFrame::init_menubar()
|
||||
[this](wxCommandEvent&) { if (m_plater) m_plater->add_model(); }, "import_plater", nullptr,
|
||||
[this](){return m_plater != nullptr; }, this);
|
||||
|
||||
append_menu_item(import_menu, wxID_ANY, _L("Import STL (imperial units)"), _L("Load an model saved with imperial units"),
|
||||
[this](wxCommandEvent&) { if (m_plater) m_plater->add_model(true); }, "import_plater", nullptr,
|
||||
[this](){return m_plater != nullptr; }, this);
|
||||
|
||||
append_menu_item(import_menu, wxID_ANY, _(L("Import SL1 archive")) + dots, _(L("Load an SL1 output archive")),
|
||||
[this](wxCommandEvent&) { if (m_plater) m_plater->import_sl1_archive(); }, "import_plater", nullptr,
|
||||
[this](){return m_plater != nullptr; }, this);
|
||||
|
@ -95,11 +95,9 @@ void MeshClipper::recalculate_triangles()
|
||||
}
|
||||
|
||||
|
||||
Vec3f MeshRaycaster::get_triangle_normal(const indexed_triangle_set& its, size_t facet_idx)
|
||||
Vec3f MeshRaycaster::get_triangle_normal(size_t facet_idx) const
|
||||
{
|
||||
Vec3f a(its.vertices[its.indices[facet_idx](1)] - its.vertices[its.indices[facet_idx](0)]);
|
||||
Vec3f b(its.vertices[its.indices[facet_idx](2)] - its.vertices[its.indices[facet_idx](0)]);
|
||||
return Vec3f(a.cross(b)).normalized();
|
||||
return m_normals[facet_idx];
|
||||
}
|
||||
|
||||
void MeshRaycaster::line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera,
|
||||
@ -218,12 +216,9 @@ Vec3f MeshRaycaster::get_closest_point(const Vec3f& point, Vec3f* normal) const
|
||||
int idx = 0;
|
||||
Vec3d closest_point;
|
||||
m_emesh.squared_distance(point.cast<double>(), idx, closest_point);
|
||||
if (normal) {
|
||||
auto indices = m_emesh.F().row(idx);
|
||||
Vec3d a(m_emesh.V().row(indices(1)) - m_emesh.V().row(indices(0)));
|
||||
Vec3d b(m_emesh.V().row(indices(2)) - m_emesh.V().row(indices(0)));
|
||||
*normal = Vec3f(a.cross(b).cast<float>());
|
||||
}
|
||||
if (normal)
|
||||
*normal = m_normals[idx];
|
||||
|
||||
return closest_point.cast<float>();
|
||||
}
|
||||
|
||||
|
@ -108,7 +108,11 @@ public:
|
||||
// The pointer can be invalidated after constructor returns.
|
||||
MeshRaycaster(const TriangleMesh& mesh)
|
||||
: m_emesh(mesh)
|
||||
{}
|
||||
{
|
||||
m_normals.reserve(mesh.stl.facet_start.size());
|
||||
for (const stl_facet& facet : mesh.stl.facet_start)
|
||||
m_normals.push_back(facet.normal);
|
||||
}
|
||||
|
||||
void line_from_mouse_pos(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera,
|
||||
Vec3d& point, Vec3d& direction) const;
|
||||
@ -140,10 +144,11 @@ public:
|
||||
|
||||
Vec3f get_closest_point(const Vec3f& point, Vec3f* normal = nullptr) const;
|
||||
|
||||
static Vec3f get_triangle_normal(const indexed_triangle_set& its, size_t facet_idx);
|
||||
Vec3f get_triangle_normal(size_t facet_idx) const;
|
||||
|
||||
private:
|
||||
sla::EigenMesh3D m_emesh;
|
||||
std::vector<stl_normal> m_normals;
|
||||
};
|
||||
|
||||
|
||||
|
@ -1170,12 +1170,15 @@ void Sidebar::show_info_sizer()
|
||||
return;
|
||||
}
|
||||
|
||||
bool imperial_units = wxGetApp().app_config->get("use_inches") == "1";
|
||||
double koef = imperial_units ? ObjectManipulation::mm_to_in : 1.0f;
|
||||
|
||||
auto size = model_object->bounding_box().size();
|
||||
p->object_info->info_size->SetLabel(wxString::Format("%.2f x %.2f x %.2f",size(0), size(1), size(2)));
|
||||
p->object_info->info_size->SetLabel(wxString::Format("%.2f x %.2f x %.2f",size(0)*koef, size(1)*koef, size(2)*koef));
|
||||
p->object_info->info_materials->SetLabel(wxString::Format("%d", static_cast<int>(model_object->materials_count())));
|
||||
|
||||
const auto& stats = model_object->get_object_stl_stats();//model_object->volumes.front()->mesh.stl.stats;
|
||||
p->object_info->info_volume->SetLabel(wxString::Format("%.2f", stats.volume));
|
||||
p->object_info->info_volume->SetLabel(wxString::Format("%.2f", stats.volume*pow(koef,3)));
|
||||
p->object_info->info_facets->SetLabel(wxString::Format(_L("%d (%d shells)"), static_cast<int>(model_object->facets_count()), stats.number_of_parts));
|
||||
|
||||
int errors = stats.degenerate_facets + stats.edges_fixed + stats.facets_removed +
|
||||
@ -1253,18 +1256,24 @@ void Sidebar::update_sliced_info_sizer()
|
||||
const PrintStatistics& ps = p->plater->fff_print().print_statistics();
|
||||
const bool is_wipe_tower = ps.total_wipe_tower_filament > 0;
|
||||
|
||||
wxString new_label = _L("Used Filament (m)");
|
||||
bool imperial_units = wxGetApp().app_config->get("use_inches") == "1";
|
||||
double koef = imperial_units ? ObjectManipulation::in_to_mm : 1000.0;
|
||||
|
||||
wxString new_label = imperial_units ? _L("Used Filament (in)") : _L("Used Filament (m)");
|
||||
if (is_wipe_tower)
|
||||
new_label += format_wxstr(":\n - %1%\n - %2%", _L("objects"), _L("wipe tower"));
|
||||
|
||||
wxString info_text = is_wipe_tower ?
|
||||
wxString::Format("%.2f \n%.2f \n%.2f", ps.total_used_filament / 1000,
|
||||
(ps.total_used_filament - ps.total_wipe_tower_filament) / 1000,
|
||||
ps.total_wipe_tower_filament / 1000) :
|
||||
wxString::Format("%.2f", ps.total_used_filament / 1000);
|
||||
wxString::Format("%.2f \n%.2f \n%.2f", ps.total_used_filament / /*1000*/koef,
|
||||
(ps.total_used_filament - ps.total_wipe_tower_filament) / /*1000*/koef,
|
||||
ps.total_wipe_tower_filament / /*1000*/koef) :
|
||||
wxString::Format("%.2f", ps.total_used_filament / /*1000*/koef);
|
||||
p->sliced_info->SetTextAndShow(siFilament_m, info_text, new_label);
|
||||
|
||||
p->sliced_info->SetTextAndShow(siFilament_mm3, wxString::Format("%.2f", ps.total_extruded_volume));
|
||||
koef = imperial_units ? pow(ObjectManipulation::mm_to_in, 3) : 1.0f;
|
||||
new_label = imperial_units ? _L("Used Filament (in³)") : _L("Used Filament (mm³)");
|
||||
info_text = wxString::Format("%.2f", imperial_units ? ps.total_extruded_volume * koef : ps.total_extruded_volume);
|
||||
p->sliced_info->SetTextAndShow(siFilament_mm3, info_text, new_label);
|
||||
p->sliced_info->SetTextAndShow(siFilament_g, ps.total_weight == 0.0 ? "N/A" : wxString::Format("%.2f", ps.total_weight));
|
||||
|
||||
new_label = _L("Cost");
|
||||
@ -1414,6 +1423,13 @@ void Sidebar::collapse(bool collapse)
|
||||
}
|
||||
|
||||
|
||||
void Sidebar::update_ui_from_settings()
|
||||
{
|
||||
p->object_manipulation->update_ui_from_settings();
|
||||
show_info_sizer();
|
||||
update_sliced_info_sizer();
|
||||
}
|
||||
|
||||
std::vector<PresetComboBox*>& Sidebar::combos_filament()
|
||||
{
|
||||
return p->combos_filament;
|
||||
@ -1653,7 +1669,7 @@ struct Plater::priv
|
||||
BoundingBoxf bed_shape_bb() const;
|
||||
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_files(const std::vector<fs::path>& input_files, bool load_model, bool load_config, bool used_inches = false);
|
||||
std::vector<size_t> load_model_objects(const ModelObjectPtrs &model_objects);
|
||||
wxString get_export_file(GUI::FileType file_type);
|
||||
|
||||
@ -2134,6 +2150,8 @@ void Plater::priv::update_ui_from_settings()
|
||||
|
||||
view3D->get_canvas3d()->update_ui_from_settings();
|
||||
preview->get_canvas3d()->update_ui_from_settings();
|
||||
|
||||
sidebar->update_ui_from_settings();
|
||||
}
|
||||
|
||||
// Called after the print technology was changed.
|
||||
@ -2166,7 +2184,7 @@ BoundingBox Plater::priv::scaled_bed_shape_bb() const
|
||||
return bed_shape.bounding_box();
|
||||
}
|
||||
|
||||
std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_files, bool load_model, bool load_config)
|
||||
std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_files, bool load_model, bool load_config, bool imperial_units/* = false*/)
|
||||
{
|
||||
if (input_files.empty()) { return std::vector<size_t>(); }
|
||||
|
||||
@ -2263,6 +2281,23 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
||||
{
|
||||
// The model should now be initialized
|
||||
|
||||
auto convert_from_imperial_units = [](Model& model) {
|
||||
model.convert_from_imperial_units();
|
||||
wxGetApp().app_config->set("use_inches", "1");
|
||||
wxGetApp().sidebar().update_ui_from_settings();
|
||||
};
|
||||
|
||||
if (imperial_units)
|
||||
convert_from_imperial_units(model);
|
||||
else if (model.looks_like_imperial_units()) {
|
||||
wxMessageDialog msg_dlg(q, _L(
|
||||
"This model looks like saved in inches.\n"
|
||||
"Should I consider this model as a saved in inches and convert it?") + "\n",
|
||||
_L("Saved in inches object detected"), wxICON_WARNING | wxYES | wxNO);
|
||||
if (msg_dlg.ShowModal() == wxID_YES)
|
||||
convert_from_imperial_units(model);
|
||||
}
|
||||
|
||||
if (! is_project_file) {
|
||||
if (model.looks_like_multipart_object()) {
|
||||
wxMessageDialog msg_dlg(q, _L(
|
||||
@ -4317,7 +4352,7 @@ void Sidebar::set_btn_label(const ActionButtonType btn_type, const wxString& lab
|
||||
// Plater / Public
|
||||
|
||||
Plater::Plater(wxWindow *parent, MainFrame *main_frame)
|
||||
: wxPanel(parent)
|
||||
: wxPanel(parent, wxID_ANY, wxDefaultPosition, wxSize(76 * wxGetApp().em_unit(), 49 * wxGetApp().em_unit()))
|
||||
, p(new priv(this, main_frame))
|
||||
{
|
||||
// Initialization performed in the private c-tor
|
||||
@ -4369,7 +4404,7 @@ void Plater::load_project(const wxString& filename)
|
||||
p->set_project_filename(filename);
|
||||
}
|
||||
|
||||
void Plater::add_model()
|
||||
void Plater::add_model(bool imperial_units/* = false*/)
|
||||
{
|
||||
wxArrayString input_files;
|
||||
wxGetApp().import_model(this, input_files);
|
||||
@ -4397,7 +4432,7 @@ void Plater::add_model()
|
||||
}
|
||||
|
||||
Plater::TakeSnapshot snapshot(this, snapshot_label);
|
||||
load_files(paths, true, false);
|
||||
load_files(paths, true, false, imperial_units);
|
||||
}
|
||||
|
||||
void Plater::import_sl1_archive()
|
||||
@ -4418,16 +4453,16 @@ void Plater::extract_config_from_project()
|
||||
load_files(input_paths, false, true);
|
||||
}
|
||||
|
||||
std::vector<size_t> Plater::load_files(const std::vector<fs::path>& input_files, bool load_model, bool load_config) { return p->load_files(input_files, load_model, load_config); }
|
||||
std::vector<size_t> Plater::load_files(const std::vector<fs::path>& input_files, bool load_model, bool load_config, bool imperial_units /*= false*/) { return p->load_files(input_files, load_model, load_config, imperial_units); }
|
||||
|
||||
// To be called when providing a list of files to the GUI slic3r on command line.
|
||||
std::vector<size_t> Plater::load_files(const std::vector<std::string>& input_files, bool load_model, bool load_config)
|
||||
std::vector<size_t> Plater::load_files(const std::vector<std::string>& input_files, bool load_model, bool load_config, bool imperial_units /*= false*/)
|
||||
{
|
||||
std::vector<fs::path> paths;
|
||||
paths.reserve(input_files.size());
|
||||
for (const std::string& path : input_files)
|
||||
paths.emplace_back(path);
|
||||
return p->load_files(paths, load_model, load_config);
|
||||
return p->load_files(paths, load_model, load_config, imperial_units);
|
||||
}
|
||||
|
||||
void Plater::update() { p->update(); }
|
||||
|
@ -133,6 +133,7 @@ public:
|
||||
bool is_collapsed();
|
||||
void collapse(bool collapse);
|
||||
void update_searcher();
|
||||
void update_ui_from_settings();
|
||||
|
||||
std::vector<PresetComboBox*>& combos_filament();
|
||||
Search::OptionsSearcher& get_searcher();
|
||||
@ -165,13 +166,13 @@ public:
|
||||
void new_project();
|
||||
void load_project();
|
||||
void load_project(const wxString& filename);
|
||||
void add_model();
|
||||
void add_model(bool imperial_units = false);
|
||||
void import_sl1_archive();
|
||||
void extract_config_from_project();
|
||||
|
||||
std::vector<size_t> load_files(const std::vector<boost::filesystem::path>& input_files, bool load_model = true, bool load_config = true);
|
||||
std::vector<size_t> load_files(const std::vector<boost::filesystem::path>& input_files, bool load_model = true, bool load_config = true, bool imperial_units = false);
|
||||
// To be called when providing a list of files to the GUI slic3r on command line.
|
||||
std::vector<size_t> load_files(const std::vector<std::string>& input_files, bool load_model = true, bool load_config = true);
|
||||
std::vector<size_t> load_files(const std::vector<std::string>& input_files, bool load_model = true, bool load_config = true, bool imperial_units = false);
|
||||
|
||||
void update();
|
||||
void stop_jobs();
|
||||
|
@ -120,7 +120,16 @@ void PreferencesDialog::build()
|
||||
option = Option (def, "use_retina_opengl");
|
||||
m_optgroup_general->append_single_option_line(option);
|
||||
#endif
|
||||
|
||||
/* // ysFIXME THis part is temporary commented
|
||||
// The using of inches is implemented just for object's size and position
|
||||
|
||||
def.label = L("Use inches instead of millimeters");
|
||||
def.type = coBool;
|
||||
def.tooltip = L("Use inches instead of millimeters for the object's size");
|
||||
def.set_default_value(new ConfigOptionBool{ app_config->get("use_inches") == "1" });
|
||||
option = Option(def, "use_inches");
|
||||
m_optgroup_general->append_single_option_line(option);
|
||||
*/
|
||||
m_optgroup_camera = std::make_shared<ConfigOptionsGroup>(this, _(L("Camera")));
|
||||
m_optgroup_camera->label_width = 40;
|
||||
m_optgroup_camera->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
|
||||
|
@ -460,7 +460,7 @@ SearchDialog::SearchDialog(OptionsSearcher* searcher)
|
||||
|
||||
check_sizer->Add(new wxStaticText(this, wxID_ANY, _L("Use for search") + ":"), 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, border);
|
||||
check_sizer->Add(check_category, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, border);
|
||||
if (GUI::wxGetApp().is_localized())
|
||||
if (check_english)
|
||||
check_sizer->Add(check_english, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, border);
|
||||
check_sizer->AddStretchSpacer(border);
|
||||
check_sizer->Add(cancel_btn, 0, wxALIGN_CENTER_VERTICAL);
|
||||
@ -484,7 +484,7 @@ SearchDialog::SearchDialog(OptionsSearcher* searcher)
|
||||
#endif //__WXMSW__
|
||||
|
||||
check_category->Bind(wxEVT_CHECKBOX, &SearchDialog::OnCheck, this);
|
||||
if (GUI::wxGetApp().is_localized())
|
||||
if (check_english)
|
||||
check_english ->Bind(wxEVT_CHECKBOX, &SearchDialog::OnCheck, this);
|
||||
|
||||
Bind(wxEVT_MOTION, &SearchDialog::OnMotion, this);
|
||||
@ -505,7 +505,8 @@ void SearchDialog::Popup(wxPoint position /*= wxDefaultPosition*/)
|
||||
|
||||
const OptionViewParameters& params = searcher->view_params;
|
||||
check_category->SetValue(params.category);
|
||||
check_english->SetValue(params.english);
|
||||
if (check_english)
|
||||
check_english->SetValue(params.english);
|
||||
|
||||
this->SetPosition(position);
|
||||
this->ShowModal();
|
||||
@ -594,6 +595,9 @@ void SearchDialog::OnSelect(wxDataViewEvent& event)
|
||||
|
||||
void SearchDialog::update_list()
|
||||
{
|
||||
// Under OSX model->Clear invoke wxEVT_DATAVIEW_SELECTION_CHANGED, so
|
||||
// set prevent_list_events to true already here
|
||||
prevent_list_events = true;
|
||||
search_list_model->Clear();
|
||||
|
||||
const std::vector<FoundOption>& filters = searcher->found_options();
|
||||
@ -601,7 +605,6 @@ void SearchDialog::update_list()
|
||||
search_list_model->Prepend(item.label);
|
||||
|
||||
// select first item
|
||||
prevent_list_events = true;
|
||||
search_list->Select(search_list_model->GetItem(0));
|
||||
prevent_list_events = false;
|
||||
}
|
||||
@ -609,7 +612,8 @@ void SearchDialog::update_list()
|
||||
void SearchDialog::OnCheck(wxCommandEvent& event)
|
||||
{
|
||||
OptionViewParameters& params = searcher->view_params;
|
||||
params.english = check_english->GetValue();
|
||||
if (check_english)
|
||||
params.english = check_english->GetValue();
|
||||
params.category = check_category->GetValue();
|
||||
|
||||
searcher->search();
|
||||
|
Loading…
Reference in New Issue
Block a user