Imperial units: Implemented just for the object's position and size
This commit is contained in:
parent
9fdc54bfff
commit
495db2ff2e
@ -448,6 +448,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())
|
||||
|
@ -844,6 +844,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();
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -41,6 +41,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 +81,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 +93,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 +149,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.
|
||||
|
@ -590,6 +590,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);
|
||||
|
@ -1144,12 +1144,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 +
|
||||
@ -1227,18 +1230,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");
|
||||
@ -1356,6 +1365,13 @@ void Sidebar::update_mode()
|
||||
Layout();
|
||||
}
|
||||
|
||||
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;
|
||||
@ -1575,7 +1591,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);
|
||||
|
||||
@ -2018,6 +2034,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();
|
||||
}
|
||||
|
||||
std::shared_ptr<ProgressStatusBar> Plater::priv::statusbar()
|
||||
@ -2043,7 +2061,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>(); }
|
||||
|
||||
@ -2140,6 +2158,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(
|
||||
@ -4228,7 +4263,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);
|
||||
@ -4256,7 +4291,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()
|
||||
@ -4277,16 +4312,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(); }
|
||||
|
@ -129,6 +129,7 @@ public:
|
||||
bool show_export_removable(bool show) const;
|
||||
bool is_multifilament();
|
||||
void update_mode();
|
||||
void update_ui_from_settings();
|
||||
|
||||
std::vector<PresetComboBox*>& combos_filament();
|
||||
private:
|
||||
@ -158,13 +159,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();
|
||||
|
@ -109,7 +109,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) {
|
||||
|
Loading…
Reference in New Issue
Block a user