* Upgrade wxWidgets to 3.2.1 Based on prusa3d/PrusaSlicer@9a7e024 Co-authored-by: tamasmeszaros <meszaros.q@gmail.com> * Implement BitmapCache * update wxExtensions while keeping legacy items * update dc.DrawBitmap calls to use get_bitmap * Fix GetSize/Width/Height calls * update BitmapComboBox * fix ifndef in wxExtensions.hpp * update my todos to OcraftyoneTODO * Get to a compilable state Everything seems to be working (including the plater). I am not seeing any graphical issues * fix extruder color icons * fix crash on opening support tab * remove GetBmpSize method from DropDown.cpp * Update TextInput to use bitmap bundles * update a TODO after testing * fix the rendering of the icons on combobox * fix a few todos * fix WipeTowerDialog.cpp * Overhaul WipeTowerDialog Removed simple version of the dialog since BBS removed the functionality but left the code. Center the table (only seen when the table is smaller than the minimum size of the dialog) Fix issue where editing a value causes the m_min_flush_label to change colors slightly Fix an issue where changing a value or running an auto calc changes the disabled value from "-" to "0" * update a few todos * Update some todos * Show dropdown when editing is started * Update NanoSVG.cmake Update NanoSVG to work with PR #2780 * Dim the icon on ComboBox when disabled * solve ObjectDataViewModel todos leaving colPrint and colEditing cases alone as it does not seem to impact anything * Update names in wxExtensions -Rename msw_rescale to sys_color_changed -Replace GetBmpSize, GetBmpWidth, GetBmpHeight with renamed version (same name without "Bmp") Both of these changes were also made by PrusaSlicer. Original Commit: Prusa3D/PrusaSlicer@066b567 Co-authored-by: YuSanka <yusanka@gmail.com> * update BitmapCache::from_svg disable finding bundle in the cache to match load_svg update to match values used in load_svg * Update ScalableButton change the signature and remove functions/vars pertaining to a default bmp fix TODOs in ScalableButton Original Commit: Prusa3D/PrusaSlicer@066b567 Co-authored-by: YuSanka <yusanka@gmail.com> * fix up some more todos in wxExtensions * update ScalableBitmap to use bmp bundles use wxBitmapBundle by default add flag to use old scaled bitmap function (specifically to solve issue with advanced toggle) * attempt to fix macos deps build * fix ubuntu build * Revert "attempt to fix macos deps build" Mistakenly made change to wrong file This reverts commit d9c20b51216db1d409aeb0420d9d901000ad1b00. * update wxWidgets patch an attempt to fix macOS build * Remove duplicate variable from OrcaSlicer.cpp * Fix macOS build issue * Fix blank DataViewItem being added to objects list * Filament ComboBox editor updates -Add show drop down feature to ObjectTable -Call finish editing when ComboBox is closed in ObjectList * remove Apple specific declarations missed during refactor * delete old wxWidgets patch * fix ubuntu seg fault * include patch from #2926 * update patch to include wxWidgets/wxWidgets@991a74c * fix deps not compiling on Windows * update WipeTowerDialog relocates the recalculate button back to its previous position changes the wording of the tip message label add spacing below the matrix * finish patching wxWidgets from prusa3d/PrusaSlicer@f8477d1 and prusa3d/PrusaSlicer@066b567 Co-authored-by: YuSanka <yusanka@gmail.com> * fix combobox crash * revert outside plate changes --------- Co-authored-by: tamasmeszaros <meszaros.q@gmail.com> Co-authored-by: YuSanka <yusanka@gmail.com>
425 lines
15 KiB
C++
425 lines
15 KiB
C++
#include "GUI_ObjectLayers.hpp"
|
|
#include "GUI_ObjectList.hpp"
|
|
|
|
#include "OptionsGroup.hpp"
|
|
#include "GUI_App.hpp"
|
|
#include "libslic3r/PresetBundle.hpp"
|
|
#include "libslic3r/Model.hpp"
|
|
#include "GLCanvas3D.hpp"
|
|
#include "Plater.hpp"
|
|
|
|
#include <boost/algorithm/string.hpp>
|
|
|
|
#include "I18N.hpp"
|
|
|
|
#include <wx/wupdlock.h>
|
|
|
|
namespace Slic3r
|
|
{
|
|
namespace GUI
|
|
{
|
|
|
|
ObjectLayers::ObjectLayers(wxWindow* parent) :
|
|
OG_Settings(parent, true)
|
|
{
|
|
m_grid_sizer = new wxFlexGridSizer(5, 0, wxGetApp().em_unit()); // Title, Min Z, "to", Max Z, unit & buttons sizer
|
|
m_grid_sizer->SetFlexibleDirection(wxHORIZONTAL);
|
|
m_grid_sizer->AddGrowableCol(1);
|
|
m_grid_sizer->AddGrowableCol(3);
|
|
|
|
m_og->activate();
|
|
m_og->sizer->Clear(true);
|
|
m_og->sizer->Add(m_grid_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, wxOSX ? 0 : 5);
|
|
|
|
m_bmp_delete = ScalableBitmap(parent, "delete_filament"/*"cross"*/);
|
|
m_bmp_add = ScalableBitmap(parent, "add_filament");
|
|
}
|
|
|
|
void ObjectLayers::select_editor(LayerRangeEditor* editor, const bool is_last_edited_range)
|
|
{
|
|
//if (is_last_edited_range && m_selection_type == editor->type()) {
|
|
/* Workaround! Under OSX we should use CallAfter() for SetFocus() after LayerEditors "reorganizations",
|
|
* because of selected control's strange behavior:
|
|
* cursor is set to the control, but blue border - doesn't.
|
|
* And as a result we couldn't edit this control.
|
|
* */
|
|
#ifdef __WXOSX__
|
|
wxTheApp->CallAfter([editor]() {
|
|
#endif
|
|
//editor->SetFocus();
|
|
//editor->SelectAll();
|
|
#ifdef __WXOSX__
|
|
});
|
|
#endif
|
|
//}
|
|
}
|
|
|
|
wxSizer* ObjectLayers::create_layer(const t_layer_height_range& range, PlusMinusButton *delete_button, PlusMinusButton *add_button)
|
|
{
|
|
const bool is_last_edited_range = range == m_selectable_range;
|
|
|
|
auto set_focus_data = [range, this](const EditorType type)
|
|
{
|
|
m_selectable_range = range;
|
|
m_selection_type = type;
|
|
};
|
|
|
|
auto update_focus_data = [range, this](const t_layer_height_range& new_range, EditorType type, bool enter_pressed)
|
|
{
|
|
// change selectable range for new one, if enter was pressed or if same range was selected
|
|
if (enter_pressed || m_selectable_range == range)
|
|
m_selectable_range = new_range;
|
|
if (enter_pressed)
|
|
m_selection_type = type;
|
|
};
|
|
|
|
// Add text
|
|
auto head_text = new wxStaticText(m_parent, wxID_ANY, _L("Height Range"), wxDefaultPosition, wxDefaultSize, wxST_ELLIPSIZE_END);
|
|
head_text->SetBackgroundStyle(wxBG_STYLE_PAINT);
|
|
head_text->SetFont(wxGetApp().normal_font());
|
|
m_grid_sizer->Add(head_text, 0, wxALIGN_CENTER_VERTICAL);
|
|
|
|
// Add control for the "Min Z"
|
|
|
|
auto editor = new LayerRangeEditor(this, double_to_string(range.first), etMinZ, set_focus_data,
|
|
[range, update_focus_data, this, delete_button, add_button](coordf_t min_z, bool enter_pressed, bool dont_update_ui)
|
|
{
|
|
if (fabs(min_z - range.first) < EPSILON) {
|
|
m_selection_type = etUndef;
|
|
return false;
|
|
}
|
|
|
|
// data for next focusing
|
|
coordf_t max_z = min_z < range.second ? range.second : min_z + 0.5;
|
|
const t_layer_height_range new_range = { min_z, max_z };
|
|
if (delete_button)
|
|
delete_button->range = new_range;
|
|
if (add_button)
|
|
add_button->range = new_range;
|
|
update_focus_data(new_range, etMinZ, enter_pressed);
|
|
|
|
return wxGetApp().obj_list()->edit_layer_range(range, new_range, dont_update_ui);
|
|
});
|
|
|
|
select_editor(editor, is_last_edited_range);
|
|
|
|
m_grid_sizer->Add(editor, 1, wxEXPAND);
|
|
|
|
auto middle_text = new wxStaticText(m_parent, wxID_ANY, _L("to"), wxDefaultPosition, wxDefaultSize, wxST_ELLIPSIZE_END);
|
|
middle_text->SetBackgroundStyle(wxBG_STYLE_PAINT);
|
|
middle_text->SetFont(wxGetApp().normal_font());
|
|
m_grid_sizer->Add(middle_text, 0, wxALIGN_CENTER_VERTICAL);
|
|
|
|
// Add control for the "Max Z"
|
|
|
|
editor = new LayerRangeEditor(this, double_to_string(range.second), etMaxZ, set_focus_data,
|
|
[range, update_focus_data, this, delete_button, add_button](coordf_t max_z, bool enter_pressed, bool dont_update_ui)
|
|
{
|
|
if (fabs(max_z - range.second) < EPSILON || range.first > max_z) {
|
|
m_selection_type = etUndef;
|
|
return false; // LayersList would not be updated/recreated
|
|
}
|
|
|
|
// data for next focusing
|
|
const t_layer_height_range& new_range = { range.first, max_z };
|
|
if (delete_button)
|
|
delete_button->range = new_range;
|
|
if (add_button)
|
|
add_button->range = new_range;
|
|
update_focus_data(new_range, etMaxZ, enter_pressed);
|
|
|
|
return wxGetApp().obj_list()->edit_layer_range(range, new_range, dont_update_ui);
|
|
});
|
|
|
|
//select_editor(editor, is_last_edited_range);
|
|
m_grid_sizer->Add(editor, 1, wxEXPAND);
|
|
|
|
auto sizer2 = new wxBoxSizer(wxHORIZONTAL);
|
|
auto unit_text = new wxStaticText(m_parent, wxID_ANY, _L("mm"), wxDefaultPosition, wxDefaultSize, wxST_ELLIPSIZE_END);
|
|
unit_text->SetBackgroundStyle(wxBG_STYLE_PAINT);
|
|
unit_text->SetFont(wxGetApp().normal_font());
|
|
sizer2->Add(unit_text, 0, wxALIGN_CENTER_VERTICAL);
|
|
|
|
m_grid_sizer->Add(sizer2);
|
|
|
|
// BBS
|
|
// Add control for the "Layer height"
|
|
|
|
//editor = new LayerRangeEditor(this, double_to_string(m_object->layer_config_ranges[range].option("layer_height")->getFloat()), etLayerHeight, set_focus_data,
|
|
// [range](coordf_t layer_height, bool, bool)
|
|
//{
|
|
// return wxGetApp().obj_list()->edit_layer_range(range, layer_height);
|
|
//});
|
|
|
|
//select_editor(editor, is_last_edited_range);
|
|
|
|
//auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
|
//sizer->Add(editor);
|
|
|
|
//auto temp = new wxStaticText(m_parent, wxID_ANY, _L("mm"));
|
|
//temp->SetBackgroundStyle(wxBG_STYLE_PAINT);
|
|
//temp->SetFont(wxGetApp().normal_font());
|
|
//sizer->Add(temp, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, wxGetApp().em_unit());
|
|
|
|
//m_grid_sizer->Add(sizer);
|
|
|
|
return sizer2;
|
|
}
|
|
|
|
void ObjectLayers::create_layers_list()
|
|
{
|
|
for (const auto &layer : m_object->layer_config_ranges) {
|
|
const t_layer_height_range& range = layer.first;
|
|
auto del_btn = new PlusMinusButton(m_parent, m_bmp_delete, range);
|
|
del_btn->DisableFocusFromKeyboard();
|
|
del_btn->SetBackgroundColour(m_parent->GetBackgroundColour());
|
|
del_btn->SetToolTip(_L("Remove height range"));
|
|
|
|
auto add_btn = new PlusMinusButton(m_parent, m_bmp_add, range);
|
|
add_btn->DisableFocusFromKeyboard();
|
|
add_btn->SetBackgroundColour(m_parent->GetBackgroundColour());
|
|
wxString tooltip = wxGetApp().obj_list()->can_add_new_range_after_current(range);
|
|
add_btn->SetToolTip(tooltip.IsEmpty() ? _L("Add height range") : tooltip);
|
|
add_btn->Enable(tooltip.IsEmpty());
|
|
|
|
auto sizer = create_layer(range, del_btn, add_btn);
|
|
sizer->Add(del_btn, 0, wxRIGHT | wxLEFT, em_unit(m_parent));
|
|
sizer->Add(add_btn);
|
|
|
|
del_btn->Bind(wxEVT_BUTTON, [del_btn](wxEvent &) {
|
|
wxGetApp().obj_list()->del_layer_range(del_btn->range);
|
|
});
|
|
|
|
add_btn->Bind(wxEVT_BUTTON, [add_btn](wxEvent &) {
|
|
wxGetApp().obj_list()->add_layer_range_after_current(add_btn->range);
|
|
});
|
|
}
|
|
}
|
|
|
|
void ObjectLayers::update_layers_list()
|
|
{
|
|
ObjectList* objects_ctrl = wxGetApp().obj_list();
|
|
if (objects_ctrl->multiple_selection()) return;
|
|
|
|
const auto item = objects_ctrl->GetSelection();
|
|
if (!item) return;
|
|
|
|
const int obj_idx = objects_ctrl->get_selected_obj_idx();
|
|
if (obj_idx < 0) return;
|
|
|
|
const ItemType type = objects_ctrl->GetModel()->GetItemType(item);
|
|
if (!(type & (itLayerRoot | itLayer))) return;
|
|
|
|
m_object = objects_ctrl->object(obj_idx);
|
|
if (!m_object || m_object->layer_config_ranges.empty()) return;
|
|
|
|
auto range = objects_ctrl->GetModel()->GetLayerRangeByItem(item);
|
|
|
|
// only call sizer->Clear(true) via CallAfter, otherwise crash happens in Linux when press enter in Height Range
|
|
// because an element cannot be destroyed while there are pending events for this element.(https://github.com/wxWidgets/Phoenix/issues/1854)
|
|
wxGetApp().CallAfter([this, type, objects_ctrl, range]() {
|
|
// Delete all controls from options group
|
|
m_grid_sizer->Clear(true);
|
|
|
|
// Add new control according to the selected item
|
|
|
|
if (type & itLayerRoot)
|
|
create_layers_list();
|
|
else
|
|
create_layer(range, nullptr, nullptr);
|
|
|
|
m_parent->Layout();
|
|
});
|
|
}
|
|
|
|
void ObjectLayers::update_scene_from_editor_selection() const
|
|
{
|
|
// needed to show the visual hints in 3D scene
|
|
wxGetApp().plater()->canvas3D()->handle_layers_data_focus_event(m_selectable_range, m_selection_type);
|
|
}
|
|
|
|
void ObjectLayers::UpdateAndShow(const bool show)
|
|
{
|
|
if (show)
|
|
update_layers_list();
|
|
|
|
OG_Settings::UpdateAndShow(show);
|
|
}
|
|
|
|
void ObjectLayers::msw_rescale()
|
|
{
|
|
//Orca: deleted what PS commented out
|
|
m_grid_sizer->Layout();
|
|
}
|
|
|
|
void ObjectLayers::sys_color_changed()
|
|
{
|
|
m_bmp_delete.sys_color_changed();
|
|
m_bmp_add.sys_color_changed();
|
|
|
|
// rescale edit-boxes
|
|
const int cells_cnt = m_grid_sizer->GetCols() * m_grid_sizer->GetEffectiveRowsCount();
|
|
for (int i = 0; i < cells_cnt; ++i) {
|
|
const wxSizerItem* item = m_grid_sizer->GetItem(i);
|
|
if (item->IsSizer()) {// case when we have editor with buttons
|
|
for (size_t btn : {2, 3}) { // del_btn, add_btn
|
|
wxSizerItem* b_item = item->GetSizer()->GetItem(btn);
|
|
if (b_item && b_item->IsWindow()) {
|
|
auto button = dynamic_cast<PlusMinusButton*>(b_item->GetWindow());
|
|
if (button != nullptr)
|
|
button->sys_color_changed();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
m_og->sys_color_changed();
|
|
for (int i = 0; i < cells_cnt; ++i) {
|
|
const wxSizerItem* item = m_grid_sizer->GetItem(i);
|
|
if (item->IsWindow()) {
|
|
if (LayerRangeEditor* editor = dynamic_cast<LayerRangeEditor*>(item->GetWindow()))
|
|
wxGetApp().UpdateDarkUI(editor);
|
|
}
|
|
else if (item->IsSizer()) {// case when we have editor with buttons
|
|
if (wxSizerItem* e_item = item->GetSizer()->GetItem(size_t(0)); e_item->IsWindow()) {
|
|
if (LayerRangeEditor* editor = dynamic_cast<LayerRangeEditor*>(e_item->GetWindow()))
|
|
wxGetApp().UpdateDarkUI(editor);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
void ObjectLayers::reset_selection()
|
|
{
|
|
m_selectable_range = { 0.0, 0.0 };
|
|
m_selection_type = etLayerHeight;
|
|
}
|
|
|
|
LayerRangeEditor::LayerRangeEditor( ObjectLayers* parent,
|
|
const wxString& value,
|
|
EditorType type,
|
|
std::function<void(EditorType)> set_focus_data_fn,
|
|
std::function<bool(coordf_t, bool, bool)> edit_fn
|
|
) :
|
|
m_valid_value(value),
|
|
m_type(type),
|
|
m_set_focus_data(set_focus_data_fn),
|
|
wxTextCtrl(parent->m_parent, wxID_ANY, value, wxDefaultPosition,
|
|
wxSize(em_unit(parent->m_parent), wxDefaultCoord), wxTE_PROCESS_ENTER
|
|
#ifdef _WIN32
|
|
| wxBORDER_SIMPLE
|
|
#endif
|
|
)
|
|
{
|
|
this->SetFont(wxGetApp().normal_font());
|
|
wxGetApp().UpdateDarkUI(this);
|
|
|
|
// Reset m_enter_pressed flag to _false_, when value is editing
|
|
this->Bind(wxEVT_TEXT, [this](wxEvent&) { m_enter_pressed = false; }, this->GetId());
|
|
|
|
this->Bind(wxEVT_TEXT_ENTER, [this, edit_fn](wxEvent&)
|
|
{
|
|
m_enter_pressed = true;
|
|
// If LayersList wasn't updated/recreated, we can call wxEVT_KILL_FOCUS.Skip()
|
|
if (m_type&etLayerHeight) {
|
|
if (!edit_fn(get_value(), true, false))
|
|
SetValue(m_valid_value);
|
|
else
|
|
m_valid_value = double_to_string(get_value());
|
|
m_call_kill_focus = true;
|
|
}
|
|
else if (!edit_fn(get_value(), true, false)) {
|
|
SetValue(m_valid_value);
|
|
m_call_kill_focus = true;
|
|
}
|
|
}, this->GetId());
|
|
|
|
this->Bind(wxEVT_KILL_FOCUS, [this, edit_fn](wxFocusEvent& e)
|
|
{
|
|
if (!m_enter_pressed) {
|
|
#ifndef __WXGTK__
|
|
/* Update data for next editor selection.
|
|
* But under GTK it looks like there is no information about selected control at e.GetWindow(),
|
|
* so we'll take it from wxEVT_LEFT_DOWN event
|
|
* */
|
|
LayerRangeEditor* new_editor = dynamic_cast<LayerRangeEditor*>(e.GetWindow());
|
|
if (new_editor)
|
|
new_editor->set_focus_data();
|
|
#endif // not __WXGTK__
|
|
// If LayersList wasn't updated/recreated, we should call e.Skip()
|
|
if (m_type & etLayerHeight) {
|
|
if (!edit_fn(get_value(), false, dynamic_cast<ObjectLayers::PlusMinusButton*>(e.GetWindow()) != nullptr))
|
|
SetValue(m_valid_value);
|
|
else
|
|
m_valid_value = double_to_string(get_value());
|
|
e.Skip();
|
|
}
|
|
else if (!edit_fn(get_value(), false, dynamic_cast<ObjectLayers::PlusMinusButton*>(e.GetWindow()) != nullptr)) {
|
|
SetValue(m_valid_value);
|
|
e.Skip();
|
|
}
|
|
}
|
|
else if (m_call_kill_focus) {
|
|
m_call_kill_focus = false;
|
|
e.Skip();
|
|
}
|
|
}, this->GetId());
|
|
|
|
this->Bind(wxEVT_SET_FOCUS, [this, parent](wxFocusEvent& e)
|
|
{
|
|
set_focus_data();
|
|
parent->update_scene_from_editor_selection();
|
|
e.Skip();
|
|
}, this->GetId());
|
|
|
|
#ifdef __WXGTK__ // Workaround! To take information about selectable range
|
|
this->Bind(wxEVT_LEFT_DOWN, [this](wxEvent& e)
|
|
{
|
|
set_focus_data();
|
|
e.Skip();
|
|
}, this->GetId());
|
|
#endif //__WXGTK__
|
|
|
|
this->Bind(wxEVT_CHAR, ([this](wxKeyEvent& event)
|
|
{
|
|
// select all text using Ctrl+A
|
|
if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_CONTROL))
|
|
this->SetSelection(-1, -1); //select all
|
|
event.Skip();
|
|
}));
|
|
}
|
|
|
|
coordf_t LayerRangeEditor::get_value()
|
|
{
|
|
wxString str = GetValue();
|
|
|
|
coordf_t layer_height;
|
|
const char dec_sep = is_decimal_separator_point() ? '.' : ',';
|
|
const char dec_sep_alt = dec_sep == '.' ? ',' : '.';
|
|
// Replace the first incorrect separator in decimal number.
|
|
if (str.Replace(dec_sep_alt, dec_sep, false) != 0)
|
|
SetValue(str);
|
|
|
|
if (str == ".")
|
|
layer_height = 0.0;
|
|
else {
|
|
if (!str.ToDouble(&layer_height) || layer_height < 0.0f) {
|
|
show_error(m_parent, _L("Invalid numeric."));
|
|
SetValue(double_to_string(layer_height));
|
|
}
|
|
}
|
|
|
|
return layer_height;
|
|
}
|
|
|
|
void LayerRangeEditor::msw_rescale()
|
|
{
|
|
SetMinSize(wxSize(wxGetApp().em_unit(), wxDefaultCoord));
|
|
}
|
|
|
|
} //namespace GUI
|
|
} //namespace Slic3r
|