ImguiDoubleSlider: WIP: Control is split to DSManagerForGcode and DSManagerForLayers (both are derived from template class)

+ GLCanvas3D: refactoring for handle of events related to the manipulation with sliders
 + use callbacks to process navigation in sliders instead of wxEvents
This commit is contained in:
YuSanka 2024-03-23 08:28:08 +01:00 committed by Lukas Matena
parent 6ea3dc6c27
commit 56a3740fe4
10 changed files with 418 additions and 519 deletions

View File

@ -17,16 +17,9 @@
#include "Tab.hpp"
#include "GUI_ObjectList.hpp"
#include <wx/button.h>
#include <wx/dialog.h>
#include <wx/sizer.h>
#include <wx/slider.h>
#include <wx/menu.h>
#include <wx/bmpcbox.h>
#include <wx/statline.h>
#include <wx/dcclient.h>
#include <wx/colordlg.h>
#include <wx/glcanvas.h>
#include <cmath>
#include <boost/algorithm/string/replace.hpp>
@ -60,8 +53,6 @@ bool equivalent_areas(const double& bottom_area, const double& top_area)
return fabs(bottom_area - top_area) <= miscalculation;
}
wxDEFINE_EVENT(wxCUSTOMEVT_TICKSCHANGED, wxEvent);
static std::string gcode(Type type)
{
const PrintConfig& config = GUI::wxGetApp().plater()->fff_print().config();
@ -73,88 +64,7 @@ static std::string gcode(Type type)
}
}
Control::Control( wxWindow *parent,
int lowerValue,
int higherValue,
int minValue,
int maxValue,
long style,
const wxString& name) :
wxControl(parent, wxID_ANY, wxDefaultPosition, wxSize(0,0)),
m_allow_editing(wxGetApp().is_editor()),
m_show_estimated_times(style == wxSL_VERTICAL)
{
#ifdef __WXOSX__
is_osx = true;
#endif //__WXOSX__
m_ticks.set_pause_print_msg(_u8L("Place bearings in slots and resume printing"));
m_ticks.set_extruder_colors(&m_extruder_colors);
imgui_ctrl = ImGuiControl( lowerValue, higherValue,
minValue, maxValue,
ImVec2(0.f, 0.f), ImVec2(0.f, 0.f),
style == wxSL_VERTICAL ? ImGuiSliderFlags_Vertical : 0,
into_u8(name), style == wxSL_VERTICAL);
imgui_ctrl.set_get_label_cb([this](int pos) {return into_u8(get_label(pos)); });
if (!imgui_ctrl.is_horizontal()) {
imgui_ctrl.set_get_label_on_move_cb([this](int pos) { return m_show_estimated_times ? into_u8(get_label(pos, ltEstimatedTime)) : ""; });
imgui_ctrl.set_extra_draw_cb([this](const ImRect& draw_rc) {return draw_ticks(draw_rc); });
}
}
void Control::SetLowerValue(const int lower_val)
{
imgui_ctrl.SetLowerValue(lower_val);
wxCommandEvent e(wxEVT_SCROLL_CHANGED);
e.SetEventObject(this);
ProcessWindowEvent(e);
}
void Control::SetHigherValue(const int higher_val)
{
imgui_ctrl.SetHigherValue(higher_val);
wxCommandEvent e(wxEVT_SCROLL_CHANGED);
e.SetEventObject(this);
ProcessWindowEvent(e);
}
void Control::SetSelectionSpan(const int lower_val, const int higher_val)
{
imgui_ctrl.SetSelectionSpan(lower_val, higher_val);
wxCommandEvent e(wxEVT_SCROLL_CHANGED);
e.SetEventObject(this);
ProcessWindowEvent(e);
}
void Control::SetMaxValue(const int max_value)
{
imgui_ctrl.SetMaxValue(max_value);
}
void Control::SetSliderValues(const std::vector<double>& values)
{
m_values = values;
}
double Control::get_double_value(const SelectedSlider& selection)
{
if (m_values.empty() || imgui_ctrl.GetLowerValue() < 0)
return 0.0;
if (m_values.size() <= size_t(imgui_ctrl.GetHigherValue())) {
imgui_ctrl.correct_higher_value();
return m_values.back();
}
return m_values[selection == ssLower ? imgui_ctrl.GetLowerValue() : imgui_ctrl.GetHigherValue()];
}
int Control::get_tick_from_value(double value, bool force_lower_bound/* = false*/)
int DSManagerForLayers::get_tick_from_value(double value, bool force_lower_bound/* = false*/)
{
std::vector<double>::iterator it;
if (m_is_wipe_tower && !force_lower_bound)
@ -168,7 +78,7 @@ int Control::get_tick_from_value(double value, bool force_lower_bound/* = false*
return int(it - m_values.begin());
}
Info Control::GetTicksValues() const
Info DSManagerForLayers::GetTicksValues() const
{
Info custom_gcode_per_print_z;
std::vector<CustomGCode::Item>& values = custom_gcode_per_print_z.gcodes;
@ -187,7 +97,7 @@ Info Control::GetTicksValues() const
return custom_gcode_per_print_z;
}
void Control::SetTicksValues(const Info& custom_gcode_per_print_z)
void DSManagerForLayers::SetTicksValues(const Info& custom_gcode_per_print_z)
{
if (m_values.empty()) {
m_ticks.mode = m_mode;
@ -217,7 +127,7 @@ void Control::SetTicksValues(const Info& custom_gcode_per_print_z)
m_ticks.mode = custom_gcode_per_print_z.mode;
}
void Control::SetLayersTimes(const std::vector<float>& layers_times, float total_time)
void DSManagerForLayers::SetLayersTimes(const std::vector<float>& layers_times, float total_time)
{
m_layers_times.clear();
if (layers_times.empty())
@ -243,7 +153,7 @@ void Control::SetLayersTimes(const std::vector<float>& layers_times, float total
}
}
void Control::SetLayersTimes(const std::vector<double>& layers_times)
void DSManagerForLayers::SetLayersTimes(const std::vector<double>& layers_times)
{
m_is_wipe_tower = false;
m_layers_times = layers_times;
@ -251,15 +161,16 @@ void Control::SetLayersTimes(const std::vector<double>& layers_times)
m_layers_times[i] += m_layers_times[i - 1];
}
void Control::SetDrawMode(bool is_sla_print, bool is_sequential_print)
void DSManagerForLayers::SetDrawMode(bool is_sla_print, bool is_sequential_print)
{
m_draw_mode = is_sla_print ? dmSlaPrint :
is_sequential_print ? dmSequentialFffPrint :
dmRegular;
dmRegular;
update_callbacks();
}
void Control::SetModeAndOnlyExtruder(const bool is_one_extruder_printed_model, const int only_extruder)
void DSManagerForLayers::SetModeAndOnlyExtruder(const bool is_one_extruder_printed_model, const int only_extruder)
{
m_mode = !is_one_extruder_printed_model ? MultiExtruder :
only_extruder < 0 ? SingleExtruder :
@ -274,28 +185,21 @@ void Control::SetModeAndOnlyExtruder(const bool is_one_extruder_printed_model, c
m_is_wipe_tower = m_mode != SingleExtruder;
}
void Control::SetExtruderColors( const std::vector<std::string>& extruder_colors)
void DSManagerForLayers::SetExtruderColors( const std::vector<std::string>& extruder_colors)
{
m_extruder_colors = extruder_colors;
}
bool Control::IsNewPrint()
bool DSManagerForLayers::IsNewPrint(const std::string& idxs)
{
if (GUI::wxGetApp().plater()->printer_technology() == ptSLA)
return false;
const Print& print = GUI::wxGetApp().plater()->fff_print();
std::string idxs;
for (auto object : print.objects())
idxs += std::to_string(object->id().id) + "_";
if (idxs == m_print_obj_idxs)
if (idxs == "sla" || idxs == m_print_obj_idxs)
return false;
m_print_obj_idxs = idxs;
return true;
}
void Control::update_callbacks()
void DSManagerForLayers::update_callbacks()
{
if (m_ticks.empty() || m_draw_mode == dmSequentialFffPrint)
imgui_ctrl.set_draw_scroll_line_cb(nullptr);
@ -305,7 +209,7 @@ void Control::update_callbacks()
using namespace ImGui;
void Control::draw_ticks(const ImRect& slideable_region)
void DSManagerForLayers::draw_ticks(const ImRect& slideable_region)
{
//if(m_draw_mode != dmRegular)
// return;
@ -414,7 +318,7 @@ static std::array<float, 4> decode_color_to_float_array(const std::string color)
return ret;
}
void Control::draw_colored_band(const ImRect& groove, const ImRect& slideable_region)
void DSManagerForLayers::draw_colored_band(const ImRect& groove, const ImRect& slideable_region)
{
if (m_ticks.empty() || m_draw_mode == dmSequentialFffPrint)
return;
@ -476,7 +380,7 @@ void Control::draw_colored_band(const ImRect& groove, const ImRect& slideable_re
}
}
void Control::render_menu()
void DSManagerForLayers::render_menu()
{
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(10.0f, 10.0f) * m_scale);
ImGui::PushStyleVar(ImGuiStyleVar_PopupRounding, 4.0f * m_scale);
@ -538,7 +442,7 @@ void Control::render_menu()
ImGui::PopStyleVar(3);
}
bool Control::render_button(const wchar_t btn_icon, const wchar_t btn_icon_hovered, const std::string& label_id, const ImVec2& pos, FocusedItem focus, int tick /*= -1*/)
bool DSManagerForLayers::render_button(const wchar_t btn_icon, const wchar_t btn_icon_hovered, const std::string& label_id, const ImVec2& pos, FocusedItem focus, int tick /*= -1*/)
{
float scale = (float)wxGetApp().em_unit() / 10.0f;
@ -576,85 +480,76 @@ bool Control::render_button(const wchar_t btn_icon, const wchar_t btn_icon_hover
return ret;
}
void Control::imgui_render(GUI::GLCanvas3D& canvas, float extra_scale/* = 0.1f*/)
void DSManagerForGcode::imgui_render(const int canvas_width, const int canvas_height, float extra_scale/* = 0.1f*/)
{
if (!imgui_ctrl.IsShown())
return;
m_scale = extra_scale * 0.1f * wxGetApp().em_unit();
const Size cnv_size = canvas.get_canvas_size();
const int canvas_width = cnv_size.get_width();
const int canvas_height = cnv_size.get_height();
ImVec2 pos = ImVec2{std::max(LEFT_MARGIN, 0.2f * canvas_width), canvas_height - HORIZONTAL_SLIDER_WIDTH * m_scale};
ImVec2 size = ImVec2(canvas_width - 2 * pos.x, HORIZONTAL_SLIDER_WIDTH * m_scale);
imgui_ctrl.Init(pos, size, m_scale);
if (imgui_ctrl.render())
process_thumb_move();
}
void DSManagerForLayers::imgui_render(const int canvas_width, const int canvas_height, float extra_scale/* = 0.1f*/)
{
if (!imgui_ctrl.IsShown())
return;
m_scale = extra_scale * 0.1f * wxGetApp().em_unit();
const float action_btn_sz = wxGetApp().imgui()->GetTextureCustomRect(ImGui::DSRevert)->Height;
const float tick_icon_side = wxGetApp().imgui()->GetTextureCustomRect(ImGui::PausePrint)->Height;
ImVec2 pos;
ImVec2 size;
const float action_btn_sz = wxGetApp().imgui()->GetTextureCustomRect(ImGui::DSRevert)->Height;
if (imgui_ctrl.is_horizontal()) {
pos.x = std::max(LEFT_MARGIN, 0.2f * canvas_width);
pos.y = canvas_height - HORIZONTAL_SLIDER_WIDTH * m_scale;
size = ImVec2(canvas_width - 2 * pos.x, HORIZONTAL_SLIDER_WIDTH * m_scale);
imgui_ctrl.ShowLabelOnMouseMove(false);
}
else {
const float tick_icon_side = wxGetApp().imgui()->GetTextureCustomRect(ImGui::PausePrint)->Height;
pos.x = canvas_width - VERTICAL_SLIDER_HEIGHT * m_scale - tick_icon_side;
pos.y = 1.f * action_btn_sz;
if (m_allow_editing)
pos.y += 2.f;
size = ImVec2(VERTICAL_SLIDER_HEIGHT * m_scale, canvas_height - 4.f * action_btn_sz);
imgui_ctrl.ShowLabelOnMouseMove(true);
}
pos.x = canvas_width - VERTICAL_SLIDER_HEIGHT * m_scale - tick_icon_side;
pos.y = 1.f * action_btn_sz;
if (m_allow_editing)
pos.y += 2.f;
size = ImVec2(VERTICAL_SLIDER_HEIGHT * m_scale, canvas_height - 4.f * action_btn_sz);
imgui_ctrl.ShowLabelOnMouseMove(true);
imgui_ctrl.Init(pos, size, m_scale);
if (imgui_ctrl.render()) {
wxCommandEvent e(wxEVT_SCROLL_CHANGED);
e.SetEventObject(this);
ProcessWindowEvent(e);
}
if (imgui_ctrl.render()) {
// request one more frame if value was changes with mouse wheel
if (GImGui->IO.MouseWheel != 0.0f)
wxGetApp().imgui()->set_requires_extra_frame();
wxCommandEvent e(wxEVT_SCROLL_CHANGED);
e.SetEventObject(this);
ProcessWindowEvent(e);
process_thumb_move();
}
// draw action buttons
if (!imgui_ctrl.is_horizontal()) {
const float groove_center_x = imgui_ctrl.GetGrooveRect().GetCenter().x;
ImVec2 btn_pos = ImVec2(groove_center_x - 0.5f * action_btn_sz, pos.y - 0.25f * action_btn_sz);
if (!m_ticks.empty() && m_allow_editing &&
render_button(ImGui::DSRevert, ImGui::DSRevertHovered, "revert", btn_pos, fiRevertIcon))
discard_all_thicks();
const float groove_center_x = imgui_ctrl.GetGrooveRect().GetCenter().x;
btn_pos.y += 0.1f * action_btn_sz + size.y;
const bool is_one_layer = imgui_ctrl.IsCombineThumbs();
if (render_button(is_one_layer ? ImGui::Lock : ImGui::Unlock, is_one_layer ? ImGui::LockHovered : ImGui::UnlockHovered, "one_layer", btn_pos, fiOneLayerIcon))
imgui_ctrl.CombineThumbs(!is_one_layer);
ImVec2 btn_pos = ImVec2(groove_center_x - 0.5f * action_btn_sz, pos.y - 0.25f * action_btn_sz);
btn_pos.y += 1.2f * action_btn_sz;
if (render_button(ImGui::DSSettings, ImGui::DSSettingsHovered, "settings", btn_pos, fiCogIcon))
show_cog_icon_context_menu();
if (!m_ticks.empty() && m_allow_editing &&
render_button(ImGui::DSRevert, ImGui::DSRevertHovered, "revert", btn_pos, fiRevertIcon))
discard_all_thicks();
if (m_draw_mode == dmSequentialFffPrint && imgui_ctrl.is_rclick_on_thumb()) {
std::string tooltip = _u8L("The sequential print is on.\n"
"It's impossible to apply any custom G-code for objects printing sequentually.");
ImGuiPureWrap::tooltip(tooltip, ImGui::GetFontSize() * 20.0f);
}
else if (m_allow_editing)
render_menu();
btn_pos.y += 0.1f * action_btn_sz + size.y;
const bool is_one_layer = imgui_ctrl.IsCombineThumbs();
if (render_button(is_one_layer ? ImGui::Lock : ImGui::Unlock, is_one_layer ? ImGui::LockHovered : ImGui::UnlockHovered, "one_layer", btn_pos, fiOneLayerIcon))
ChangeOneLayerLock();
btn_pos.y += 1.2f * action_btn_sz;
if (render_button(ImGui::DSSettings, ImGui::DSSettingsHovered, "settings", btn_pos, fiCogIcon))
show_cog_icon_context_menu();
if (m_draw_mode == dmSequentialFffPrint && imgui_ctrl.is_rclick_on_thumb()) {
std::string tooltip = _u8L("The sequential print is on.\n"
"It's impossible to apply any custom G-code for objects printing sequentually.");
ImGuiPureWrap::tooltip(tooltip, ImGui::GetFontSize() * 20.0f);
}
else if (m_allow_editing)
render_menu();
}
bool Control::is_wipe_tower_layer(int tick) const
bool DSManagerForLayers::is_wipe_tower_layer(int tick) const
{
if (!m_is_wipe_tower || tick >= (int)m_values.size())
return false;
@ -667,7 +562,7 @@ bool Control::is_wipe_tower_layer(int tick) const
return false;
}
static wxString short_and_splitted_time(const std::string& time)
static std::string short_and_splitted_time(const std::string& time)
{
// Parse the dhms time format.
int days = 0;
@ -690,30 +585,30 @@ static wxString short_and_splitted_time(const std::string& time)
auto get_s = [seconds](){ return GUI::format(_u8L("%1%s"), seconds); };
if (days > 0)
return format_wxstr("%1%%2%\n%3%", get_d(), get_h(), get_m());
return GUI::format("%1%%2%\n%3%", get_d(), get_h(), get_m());
if (hours > 0) {
if (hours < 10 && minutes < 10 && seconds < 10)
return format_wxstr("%1%%2%%3%", get_h(), get_m(), get_s());
return GUI::format("%1%%2%%3%", get_h(), get_m(), get_s());
if (hours > 10 && minutes > 10 && seconds > 10)
return format_wxstr("%1%\n%2%\n%3%", get_h(), get_m(), get_s());
return GUI::format("%1%\n%2%\n%3%", get_h(), get_m(), get_s());
if ((minutes < 10 && seconds > 10) || (minutes > 10 && seconds < 10))
return format_wxstr("%1%\n%2%%3%", get_h(), get_m(), get_s());
return format_wxstr("%1%%2%\n%3%", get_h(), get_m(), get_s());
return GUI::format("%1%\n%2%%3%", get_h(), get_m(), get_s());
return GUI::format("%1%%2%\n%3%", get_h(), get_m(), get_s());
}
if (minutes > 0) {
if (minutes > 10 && seconds > 10)
return format_wxstr("%1%\n%2%", get_m(), get_s());
return format_wxstr("%1%%2%", get_m(), get_s());
return GUI::format("%1%\n%2%", get_m(), get_s());
return GUI::format("%1%%2%", get_m(), get_s());
}
return from_u8(get_s());
return get_s();
}
wxString Control::get_label(int tick, LabelType label_type/* = ltHeightWithLayer*/) const
std::string DSManagerForLayers::get_label(int pos, LabelType label_type/* = ltHeightWithLayer*/) const
{
const size_t value = tick;
const size_t value = pos;
if (m_values.empty())
return wxString::Format("%lu", static_cast<unsigned long>(value));
return GUI::format("%1%", pos);
if (value >= m_values.size())
return "ErrVal";
@ -738,29 +633,25 @@ wxString Control::get_label(int tick, LabelType label_type/* = ltHeightWithLayer
return size_t(it - m_layers_values.begin());
};
if (m_draw_mode == dmSequentialGCodeView)
return wxString::Format("%lu", static_cast<unsigned long>(m_alternate_values[value]));
else {
if (label_type == ltEstimatedTime) {
if (m_is_wipe_tower) {
size_t layer_number = get_layer_number(value, label_type);
return (layer_number == size_t(-1) || layer_number == m_layers_times.size()) ? "" : short_and_splitted_time(get_time_dhms(m_layers_times[layer_number]));
}
return value < m_layers_times.size() ? short_and_splitted_time(get_time_dhms(m_layers_times[value])) : "";
}
wxString str = wxString::Format("%.*f", 2, m_values[value]);
if (label_type == ltHeight)
return str;
if (label_type == ltHeightWithLayer) {
size_t layer_number = m_is_wipe_tower ? get_layer_number(value, label_type) + 1 : (m_values.empty() ? value : value + 1);
return format_wxstr("%1%\n(%2%)", str, layer_number);
if (label_type == ltEstimatedTime) {
if (m_is_wipe_tower) {
size_t layer_number = get_layer_number(value, label_type);
return (layer_number == size_t(-1) || layer_number == m_layers_times.size()) ? "" : short_and_splitted_time(get_time_dhms(m_layers_times[layer_number]));
}
return value < m_layers_times.size() ? short_and_splitted_time(get_time_dhms(m_layers_times[value])) : "";
}
std::string str = GUI::format("%1$.2f", m_values[value]);
if (label_type == ltHeight)
return str;
if (label_type == ltHeightWithLayer) {
size_t layer_number = m_is_wipe_tower ? get_layer_number(value, label_type) + 1 : (m_values.empty() ? value : value + 1);
return GUI::format("%1%\n(%2%)", str, layer_number);
}
return wxEmptyString;
return "";
}
std::string Control::get_color_for_tool_change_tick(std::set<TickCode>::const_iterator it) const
std::string DSManagerForLayers::get_color_for_tool_change_tick(std::set<TickCode>::const_iterator it) const
{
const int current_extruder = it->extruder == 0 ? std::max<int>(m_only_extruder, 1) : it->extruder;
@ -774,7 +665,7 @@ std::string Control::get_color_for_tool_change_tick(std::set<TickCode>::const_it
return m_extruder_colors[current_extruder-1]; // return a color for a specific extruder from the colors list
}
std::string Control::get_color_for_color_change_tick(std::set<TickCode>::const_iterator it) const
std::string DSManagerForLayers::get_color_for_color_change_tick(std::set<TickCode>::const_iterator it) const
{
const int def_extruder = std::max<int>(1, m_only_extruder);
auto it_n = it;
@ -796,23 +687,13 @@ std::string Control::get_color_for_color_change_tick(std::set<TickCode>::const_i
return "";
}
bool Control::is_lower_thumb_editable()
void DSManagerForLayers::ChangeOneLayerLock()
{
if (m_draw_mode == dmSequentialGCodeView)
return Slic3r::GUI::get_app_config()->get("seq_top_layer_only") == "0";
return true;
imgui_ctrl.CombineThumbs(!imgui_ctrl.IsCombineThumbs());
process_thumb_move();
}
void Control::ChangeOneLayerLock()
{
imgui_ctrl.CombineThumbs(imgui_ctrl.IsCombineThumbs());
wxCommandEvent e(wxEVT_SCROLL_CHANGED);
e.SetEventObject(this);
ProcessWindowEvent(e);
}
wxString Control::get_tooltip(int tick/*=-1*/)
wxString DSManagerForLayers::get_tooltip(int tick/*=-1*/)
{
if (m_focus == fiNone)
return "";
@ -822,15 +703,12 @@ wxString Control::get_tooltip(int tick/*=-1*/)
return _L("Discard all custom changes");
if (m_focus == fiCogIcon)
{
if (m_draw_mode == dmSequentialGCodeView)
return _L("Jump to move") + " (Shift + G)";
else
return m_mode == MultiAsSingle ?
GUI::from_u8((boost::format(_u8L("Jump to height %s\n"
"Set ruler mode\n"
"or Set extruder sequence for the entire print")) % "(Shift + G)").str()) :
GUI::from_u8((boost::format(_u8L("Jump to height %s\n"
"or Set ruler mode")) % "(Shift + G)").str());
return m_mode == MultiAsSingle ?
GUI::from_u8((boost::format(_u8L("Jump to height %s\n"
"Set ruler mode\n"
"or Set extruder sequence for the entire print")) % "(Shift + G)").str()) :
GUI::from_u8((boost::format(_u8L("Jump to height %s\n"
"or Set ruler mode")) % "(Shift + G)").str());
}
if (m_focus == fiColorBand)
return m_mode != SingleExtruder ? "" :
@ -943,7 +821,7 @@ wxString Control::get_tooltip(int tick/*=-1*/)
}
void Control::append_change_extruder_menu_item(wxMenu* menu, bool switch_current_code/* = false*/)
void DSManagerForLayers::append_change_extruder_menu_item(wxMenu* menu, bool switch_current_code/* = false*/)
{
const int extruders_cnt = GUI::wxGetApp().extruders_edited_cnt();
if (extruders_cnt > 1) {
@ -974,7 +852,7 @@ void Control::append_change_extruder_menu_item(wxMenu* menu, bool switch_current
}
}
void Control::append_add_color_change_menu_item(wxMenu* menu, bool switch_current_code/* = false*/)
void DSManagerForLayers::append_add_color_change_menu_item(wxMenu* menu, bool switch_current_code/* = false*/)
{
const int extruders_cnt = GUI::wxGetApp().extruders_edited_cnt();
if (extruders_cnt > 1) {
@ -1002,86 +880,16 @@ void Control::append_add_color_change_menu_item(wxMenu* menu, bool switch_curren
}
}
// "condition" have to be true for:
// - value increase (if wxSL_VERTICAL)
// - value decrease (if wxSL_HORIZONTAL)
void Control::move_current_thumb(const bool condition)
{
// m_is_one_layer = wxGetKeyState(WXK_CONTROL);
int delta = condition ? -1 : 1;
if (imgui_ctrl.is_horizontal())
delta *= -1;
// accelerators
int accelerator = 0;
if (wxGetKeyState(WXK_SHIFT))
accelerator += 5;
if (wxGetKeyState(WXK_CONTROL))
accelerator += 5;
if (accelerator > 0)
delta *= accelerator;
imgui_ctrl.MoveActiveThumb(delta);
wxCommandEvent e(wxEVT_SCROLL_CHANGED);
e.SetEventObject(this);
ProcessWindowEvent(e);
}
void Control::UseDefaultColors(bool def_colors_on)
void DSManagerForLayers::UseDefaultColors(bool def_colors_on)
{
m_ticks.set_default_colors(def_colors_on);
}
void Control::OnKeyDown(wxKeyEvent &event)
{
const int key = event.GetKeyCode();
if (m_draw_mode != dmSequentialGCodeView && key == WXK_NUMPAD_ADD) {
// OnChar() is called immediately after OnKeyDown(), which can cause call of add_tick() twice.
// To avoid this case we should suppress second add_tick() call.
m_ticks.suppress_plus(true);
add_current_tick(true);
}
else if (m_draw_mode != dmSequentialGCodeView && (key == WXK_NUMPAD_SUBTRACT || key == WXK_DELETE || key == WXK_BACK)) {
// OnChar() is called immediately after OnKeyDown(), which can cause call of delete_tick() twice.
// To avoid this case we should suppress second delete_tick() call.
m_ticks.suppress_minus(true);
delete_current_tick();
}
else if (m_draw_mode != dmSequentialGCodeView && event.GetKeyCode() == WXK_SHIFT)
UseDefaultColors(false);
else if (imgui_ctrl.is_horizontal()) {
if (key == WXK_LEFT || key == WXK_RIGHT)
move_current_thumb(key == WXK_LEFT);
}
else if (key == WXK_UP || key == WXK_DOWN)
move_current_thumb(key == WXK_UP);
event.Skip(); // !Needed to have EVT_CHAR generated as well
}
void Control::OnChar(wxKeyEvent& event)
{
const int key = event.GetKeyCode();
if (m_draw_mode != dmSequentialGCodeView) {
if (key == '+' && !m_ticks.suppressed_plus()) {
add_current_tick(true);
m_ticks.suppress_plus(false);
}
else if (key == '-' && !m_ticks.suppressed_minus()) {
delete_current_tick();
m_ticks.suppress_minus(false);
}
}
if (key == 'G')
jump_to_value();
}
// Get active extruders for tick.
// Means one current extruder for not existing tick OR
// 2 extruders - for existing tick (extruder before ToolChange and extruder of current existing tick)
// Use those values to disable selection of active extruders
std::array<int, 2> Control::get_active_extruders_for_tick(int tick) const
std::array<int, 2> DSManagerForLayers::get_active_extruders_for_tick(int tick) const
{
int default_initial_extruder = m_mode == MultiAsSingle ? std::max<int>(1, m_only_extruder) : 1;
std::array<int, 2> extruders = { default_initial_extruder, -1 };
@ -1164,7 +972,7 @@ std::set<int> TickCodeInfo::get_used_extruders_for_tick(int tick, int only_extru
return used_extruders;
}
void Control::show_cog_icon_context_menu()
void DSManagerForLayers::show_cog_icon_context_menu()
{
wxMenu menu;
@ -1217,12 +1025,12 @@ bool check_color_change(const PrintObject* object, size_t frst_layer_id, size_t
return detected;
}
void Control::auto_color_change()
void DSManagerForLayers::auto_color_change()
{
if (!m_ticks.empty()) {
wxString msg_text = _L("This action will cause deletion of all ticks on vertical slider.") + "\n\n" +
_L("This action is not revertible.\nDo you want to proceed?");
GUI::WarningDialog dialog(m_parent, msg_text, _L("Warning"), wxYES | wxNO);
GUI::WarningDialog dialog(nullptr, msg_text, _L("Warning"), wxYES | wxNO);
if (dialog.ShowModal() == wxID_NO)
return;
m_ticks.ticks.clear();
@ -1364,9 +1172,9 @@ static std::string get_pause_print_msg(const std::string& msg_in, double height)
static double get_value_to_jump(double active_value, double min_z, double max_z, DrawMode mode)
{
wxString msg_text = (mode == dmSequentialGCodeView) ? _L("Enter the move you want to jump to") + ":" : _L("Enter the height you want to jump to") + ":";
wxString msg_header = (mode == dmSequentialGCodeView) ? _L("Jump to move") : _L("Jump to height");
wxString msg_in = GUI::double_to_string(active_value);
wxString msg_text = _L("Enter the height you want to jump to") + ":";
wxString msg_header = _L("Jump to height");
wxString msg_in = GUI::double_to_string(active_value);
// get custom gcode
wxTextEntryDialog dlg(nullptr, msg_text, msg_header, msg_in, wxTextEntryDialogStyle);
@ -1379,7 +1187,7 @@ static double get_value_to_jump(double active_value, double min_z, double max_z,
return dlg.GetValue().ToDouble(&value) ? value : -1.0;
}
void Control::add_code_as_tick(Type type, int selected_extruder/* = -1*/)
void DSManagerForLayers::add_code_as_tick(Type type, int selected_extruder/* = -1*/)
{
const int tick = imgui_ctrl.GetActiveValue();
@ -1413,7 +1221,7 @@ void Control::add_code_as_tick(Type type, int selected_extruder/* = -1*/)
post_ticks_changed_event(type);
}
void Control::add_current_tick(bool call_from_keyboard /*= false*/)
void DSManagerForLayers::add_current_tick(bool call_from_keyboard /*= false*/)
{
const int tick = imgui_ctrl.GetActiveValue();
auto it = m_ticks.ticks.find(TickCode{ tick });
@ -1455,7 +1263,7 @@ void Control::add_current_tick(bool call_from_keyboard /*= false*/)
*/
}
void Control::delete_current_tick()
void DSManagerForLayers::delete_current_tick()
{
auto it = m_ticks.ticks.find(TickCode{ imgui_ctrl.GetActiveValue()});
if (it == m_ticks.ticks.end() ||
@ -1467,7 +1275,7 @@ void Control::delete_current_tick()
post_ticks_changed_event(type);
}
void Control::edit_tick(int tick/* = -1*/)
void DSManagerForLayers::edit_tick(int tick/* = -1*/)
{
if (tick < 0)
tick = imgui_ctrl.GetActiveValue();
@ -1482,14 +1290,8 @@ void Control::edit_tick(int tick/* = -1*/)
post_ticks_changed_event(type);
}
// switch on/off one layer mode
void Control::switch_one_layer_mode()
{
imgui_ctrl.CombineThumbs(!imgui_ctrl.IsCombineThumbs());
}
// discard all custom changes on DoubleSlider
void Control::discard_all_thicks()
void DSManagerForLayers::discard_all_thicks()
{
m_ticks.ticks.clear();
imgui_ctrl.ResetValues();
@ -1497,7 +1299,7 @@ void Control::discard_all_thicks()
post_ticks_changed_event();
}
void Control::edit_extruder_sequence()
void DSManagerForLayers::edit_extruder_sequence()
{
if (!check_ticks_changed_event(ToolChange))
return;
@ -1558,7 +1360,7 @@ void Control::edit_extruder_sequence()
post_ticks_changed_event(ToolChange);
}
void Control::jump_to_value()
void DSManagerForLayers::jump_to_value()
{
double value = get_value_to_jump(m_values[imgui_ctrl.GetActiveValue()],
m_values[imgui_ctrl.GetMinValue()], m_values[imgui_ctrl.GetMaxValue()], m_draw_mode);
@ -1573,14 +1375,13 @@ void Control::jump_to_value()
SetLowerValue(tick_value);
}
void Control::post_ticks_changed_event(Type type /*= Custom*/)
void DSManagerForLayers::post_ticks_changed_event(Type type /*= Custom*/)
{
// m_force_mode_apply = type != ToolChange; // It looks like this condition is no needed now. Leave it for the testing
wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED));
process_ticks_changed();
}
bool Control::check_ticks_changed_event(Type type)
bool DSManagerForLayers::check_ticks_changed_event(Type type)
{
if ( m_ticks.mode == m_mode ||
(type != ColorChange && type != ToolChange) ||
@ -1602,7 +1403,7 @@ bool Control::check_ticks_changed_event(Type type)
_L("Are you sure you want to continue?");
//wxMessageDialog msg(this, message, _L("Notice"), wxYES_NO);
GUI::MessageDialog msg(this, message, _L("Notice"), wxYES_NO);
GUI::MessageDialog msg(nullptr, message, _L("Notice"), wxYES_NO);
if (msg.ShowModal() == wxID_YES) {
m_ticks.erase_all_ticks_with_code(ColorChange);
post_ticks_changed_event(ColorChange);
@ -1622,7 +1423,7 @@ bool Control::check_ticks_changed_event(Type type)
_L("Your current changes will delete all saved extruder (tool) changes.") + "\n\n\t" +
_L("Are you sure you want to continue?") ) ;
GUI::MessageDialog msg(this, message, _L("Notice"), wxYES_NO | (m_mode == SingleExtruder ? wxCANCEL : 0));
GUI::MessageDialog msg(nullptr, message, _L("Notice"), wxYES_NO | (m_mode == SingleExtruder ? wxCANCEL : 0));
const int answer = msg.ShowModal();
if (answer == wxID_YES) {
m_ticks.erase_all_ticks_with_code(ToolChange);
@ -1638,6 +1439,25 @@ bool Control::check_ticks_changed_event(Type type)
return true;
}
DSManagerForLayers::DSManagerForLayers( int lowerValue,
int higherValue,
int minValue,
int maxValue,
bool allow_editing/* = true*/) :
m_allow_editing(allow_editing)
{
#ifdef __WXOSX__
is_osx = true;
#endif //__WXOSX__
Init(lowerValue, higherValue, minValue, maxValue, "layers_slider", false);
imgui_ctrl.set_get_label_on_move_cb([this](int pos) { return m_show_estimated_times ? into_u8(get_label(pos, ltEstimatedTime)) : ""; });
imgui_ctrl.set_extra_draw_cb([this](const ImRect& draw_rc) {return draw_ticks(draw_rc); });
m_ticks.set_pause_print_msg(_u8L("Place bearings in slots and resume printing"));
m_ticks.set_extruder_colors(&m_extruder_colors);
}
std::string TickCodeInfo::get_color_for_tick(TickCode tick, Type type, const int extruder)
{
auto opposite_one_color = [](const std::string& color) {

View File

@ -6,16 +6,8 @@
#define slic3r_GUI_DoubleSlider_hpp_
#include "libslic3r/CustomGCode.hpp"
#include "wxExtensions.hpp"
#include "GLCanvas3D.hpp"
#include "ImGuiDoubleSlider.hpp"
#include <wx/window.h>
#include <wx/control.h>
#include <wx/dc.h>
#include <wx/slider.h>
#include <vector>
#include <set>
@ -45,9 +37,6 @@ bool check_color_change(const PrintObject* object, size_t frst_layer_id, size_t
// and return true when detection have to be desturbed
std::function<bool(const Layer*)> break_condition);
// custom message the slider sends to its parent to notify a tick-change:
wxDECLARE_EVENT(wxCUSTOMEVT_TICKSCHANGED, wxEvent);
enum FocusedItem {
fiNone,
@ -90,7 +79,6 @@ enum DrawMode
dmRegular,
dmSlaPrint,
dmSequentialFffPrint,
dmSequentialGCodeView,
};
enum LabelType
@ -204,65 +192,164 @@ struct ExtrudersSequence
}
};
class Control : public wxControl
template<typename ValType>
class DSManager_t
{
public:
Control(
wxWindow *parent,
int lowerValue,
int higherValue,
int minValue,
int maxValue,
long style = wxSL_VERTICAL,
const wxString& name = wxEmptyString);
~Control() {}
void Init( int lowerValue,
int higherValue,
int minValue,
int maxValue,
const std::string& name,
bool is_horizontal)
{
imgui_ctrl = ImGuiControl( lowerValue, higherValue,
minValue, maxValue,
is_horizontal ? 0 : ImGuiSliderFlags_Vertical,
name, !is_horizontal);
imgui_ctrl.set_get_label_cb([this](int pos) {return get_label(pos); });
};
DSManager_t() {}
DSManager_t(int lowerValue,
int higherValue,
int minValue,
int maxValue,
const std::string& name,
bool is_horizontal)
{
Init (lowerValue, higherValue, minValue, maxValue, name, is_horizontal);
}
~DSManager_t() {}
int GetMinValue() const { return imgui_ctrl.GetMinValue(); }
int GetMaxValue() const { return imgui_ctrl.GetMaxValue(); }
double GetMinValueD() { return m_values.empty() ? 0. : m_values[GetMinValue()]; }
double GetMaxValueD() { return m_values.empty() ? 0. : m_values[GetMaxValue()]; }
int GetLowerValue() const { return imgui_ctrl.GetLowerValue(); }
int GetHigherValue()const { return imgui_ctrl.GetHigherValue(); }
double GetLowerValueD() { return get_double_value(ssLower); }
double GetHigherValueD() { return get_double_value(ssHigher); }
ValType GetMinValueD() { return m_values.empty() ? static_cast<ValType>(0) : m_values[GetMinValue()]; }
ValType GetMaxValueD() { return m_values.empty() ? static_cast<ValType>(0) : m_values[GetMaxValue()]; }
ValType GetLowerValueD() { return m_values.empty() ? static_cast<ValType>(0) : m_values[GetLowerValue()];}
ValType GetHigherValueD() { return m_values.empty() ? static_cast<ValType>(0) : m_values[GetHigherValue()]; }
// Set low and high slider position. If the span is non-empty, disable the "one layer" mode.
void SetLowerValue (const int lower_val);
void SetHigherValue(const int higher_val);
void SetSelectionSpan(const int lower_val, const int higher_val);
void SetLowerValue(const int lower_val) {
imgui_ctrl.SetLowerValue(lower_val);
process_thumb_move();
}
void SetHigherValue(const int higher_val) {
imgui_ctrl.SetHigherValue(higher_val);
process_thumb_move();
}
void SetSelectionSpan(const int lower_val, const int higher_val) {
imgui_ctrl.SetSelectionSpan(lower_val, higher_val);
process_thumb_move();
}
void SetMaxValue(const int max_value) {
imgui_ctrl.SetMaxValue(max_value);
process_thumb_move();
}
void SetMaxValue(const int max_value);
void SetSliderValues(const std::vector<double>& values);
void ChangeOneLayerLock();
void SetSliderAlternateValues(const std::vector<double>& values) { m_alternate_values = values; }
Info GetTicksValues() const;
void SetTicksValues(const Info &custom_gcode_per_print_z);
void SetLayersTimes(const std::vector<float>& layers_times, float total_time);
void SetLayersTimes(const std::vector<double>& layers_times);
void SetDrawMode(bool is_sla_print, bool is_sequential_print);
void SetDrawMode(DrawMode mode) { m_draw_mode = mode; }
void SetManipulationMode(Mode mode) { m_mode = mode; }
Mode GetManipulationMode() const { return m_mode; }
void SetModeAndOnlyExtruder(const bool is_one_extruder_printed_model, const int only_extruder);
void SetExtruderColors(const std::vector<std::string>& extruder_colors);
bool IsNewPrint();
void set_render_as_disabled(bool value) { m_render_as_disabled = value; }
bool is_rendering_as_disabled() const { return m_render_as_disabled; }
void SetSliderValues(const std::vector<ValType>& values) { m_values = values; }
// values used to show thumb labels
void SetSliderAlternateValues(const std::vector<ValType>& values) { m_alternate_values = values; }
bool is_lower_at_min() const { return imgui_ctrl.is_lower_at_min(); }
bool is_higher_at_max() const { return imgui_ctrl.is_higher_at_max(); }
void UseDefaultColors(bool def_colors_on);
void OnKeyDown(wxKeyEvent &event);
void OnChar(wxKeyEvent &event);
void Show(bool show = true) { imgui_ctrl.Show(show); }
void Hide() { Show(false); }
bool Show(bool show = true) override { imgui_ctrl.Show(show); return true; }
bool Hide() { return Show(false); }
virtual void imgui_render(const int canvas_width, const int canvas_height, float extra_scale = 1.f) = 0;
void set_callback_on_thumb_move(std::function<void()> cb) { m_cb_thumb_move = cb; };
void move_current_thumb(const int delta)
{
imgui_ctrl.MoveActiveThumb(delta);
process_thumb_move();
}
protected:
std::vector<ValType> m_values;
std::vector<ValType> m_alternate_values;
GUI::ImGuiControl imgui_ctrl;
float m_scale{ 1.f };
std::string get_label(int pos) const {
if (m_values.empty())
return GUI::format("%1%", pos);
if (pos >= m_values.size())
return "ErrVal";
return GUI::format("%1%", static_cast<ValType>(m_alternate_values.empty() ? m_values[pos] : m_alternate_values[pos]));
}
void process_thumb_move() {
if (m_cb_thumb_move)
m_cb_thumb_move();
}
private:
std::function<void()> m_cb_thumb_move{ nullptr };
};
class DSManagerForGcode : public DSManager_t<unsigned int>
{
public:
DSManagerForGcode() : DSManager_t<unsigned int>() {}
DSManagerForGcode( int lowerValue,
int higherValue,
int minValue,
int maxValue)
{
Init(lowerValue, higherValue, minValue, maxValue, "moves_slider", true);
}
~DSManagerForGcode() {}
void imgui_render(const int canvas_width, const int canvas_height, float extra_scale = 1.f) override;
void set_render_as_disabled(bool value) { m_render_as_disabled = value; }
bool is_rendering_as_disabled() const { return m_render_as_disabled; }
private:
bool m_render_as_disabled{ false };
};
class DSManagerForLayers : public DSManager_t<double>
{
public:
DSManagerForLayers() : DSManager_t<double>() {}
DSManagerForLayers( int lowerValue,
int higherValue,
int minValue,
int maxValue,
bool allow_editing = true);
~DSManagerForLayers() {}
void ChangeOneLayerLock();
Info GetTicksValues() const;
void SetTicksValues(const Info& custom_gcode_per_print_z);
void SetLayersTimes(const std::vector<float>& layers_times, float total_time);
void SetLayersTimes(const std::vector<double>& layers_times);
void SetDrawMode(bool is_sla_print, bool is_sequential_print);
void SetManipulationMode(Mode mode) { m_mode = mode; }
Mode GetManipulationMode() const { return m_mode; }
void SetModeAndOnlyExtruder(const bool is_one_extruder_printed_model, const int only_extruder);
void SetExtruderColors(const std::vector<std::string>& extruder_colors);
void UseDefaultColors(bool def_colors_on);
void add_code_as_tick(Type type, int selected_extruder = -1);
// add default action for tick, when press "+"
@ -270,31 +357,36 @@ public:
// delete current tick, when press "-"
void delete_current_tick();
void edit_tick(int tick = -1);
void switch_one_layer_mode();
void discard_all_thicks();
void edit_extruder_sequence();
void jump_to_value();
void enable_action_icon(bool enable) { m_enable_action_icon = enable; }
void show_cog_icon_context_menu();
void auto_color_change();
void jump_to_value();
void imgui_render(GUI::GLCanvas3D& canvas, float extra_scale = 1.f);
void set_callback_on_ticks_changed(std::function<void()> cb) { m_cb_ticks_changed = cb; };
void imgui_render(const int canvas_width, const int canvas_height, float extra_scale = 1.f) override;
bool IsNewPrint(const std::string& print_obj_idxs);
private:
bool is_lower_thumb_editable();
void move_current_thumb(const bool condition);
bool is_wipe_tower_layer(int tick) const;
wxString get_label(int tick, LabelType label_type = ltHeightWithLayer) const;
std::string get_label(int tick, LabelType label_type = ltHeightWithLayer) const;
double get_double_value(const SelectedSlider& selection);
int get_tick_from_value(double value, bool force_lower_bound = false);
wxString get_tooltip(int tick = -1);
std::string get_color_for_tool_change_tick(std::set<TickCode>::const_iterator it) const;
std::string get_color_for_color_change_tick(std::set<TickCode>::const_iterator it) const;
void process_ticks_changed() {
if (m_cb_ticks_changed)
m_cb_ticks_changed();
}
// Get active extruders for tick.
// Means one current extruder for not existing tick OR
// 2 extruders - for existing tick (extruder before ToolChangeCode and extruder of current existing tick)
@ -304,19 +396,17 @@ private:
void post_ticks_changed_event(Type type = Custom);
bool check_ticks_changed_event(Type type);
void append_change_extruder_menu_item (wxMenu*, bool switch_current_code = false);
void append_change_extruder_menu_item(wxMenu*, bool switch_current_code = false);
void append_add_color_change_menu_item(wxMenu*, bool switch_current_code = false);
bool is_osx { false };
bool m_render_as_disabled{ false };
bool is_osx{ false };
bool m_allow_editing{ true };
bool m_force_mode_apply = true;
bool m_enable_action_icon = true;
bool m_is_wipe_tower = false; //This flag indicates that there is multiple extruder print with wipe tower
DrawMode m_draw_mode = dmRegular;
DrawMode m_draw_mode { dmRegular };
Mode m_mode = SingleExtruder;
int m_only_extruder = -1;
@ -326,19 +416,18 @@ private:
bool m_show_estimated_times{ false };
std::vector<double> m_values;
TickCodeInfo m_ticks;
std::vector<double> m_layers_times;
std::vector<double> m_layers_values;
std::vector<std::string> m_extruder_colors;
std::string m_print_obj_idxs;
std::vector<double> m_alternate_values;
ExtrudersSequence m_extruders_sequence;
std::function<void()> m_cb_ticks_changed{ nullptr };
std::string m_print_obj_idxs;
// ImGuiDS
float m_scale{ 1.f };
bool m_can_change_color{ true };
void draw_colored_band(const ImRect& groove, const ImRect& slideable_region);
@ -346,8 +435,6 @@ private:
void render_menu();
bool render_button(const wchar_t btn_icon, const wchar_t btn_icon_hovered, const std::string& label_id, const ImVec2& pos, FocusedItem focus, int tick = -1);
void update_callbacks();
GUI::ImGuiControl imgui_ctrl;
};
} // DoubleSlider;

View File

@ -7,6 +7,7 @@
#include "GUI_Utils.hpp"
#include "DoubleSlider.hpp"
#include "wxExtensions.hpp"
class wxTextCtrl;
class wxFlexGridSizer;

View File

@ -77,7 +77,6 @@
#include <float.h>
#include <algorithm>
#include <cmath>
#include "DoubleSlider.hpp"
#include <imgui/imgui_internal.h>
#include <slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp>
@ -1019,9 +1018,7 @@ wxDEFINE_EVENT(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_UPDATE_BED_SHAPE, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_TAB, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_RESETGIZMOS, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_MOVE_SLIDERS, wxKeyEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_EDIT_COLOR_CHANGE, wxKeyEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_JUMP_TO, wxKeyEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_SLIDERS_MANIPULATION, wxKeyEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_UNDO, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_COLLAPSE_SIDEBAR, SimpleEvent);
@ -2828,14 +2825,14 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
case '6': { select_view("right"); break; }
case '+': {
if (dynamic_cast<Preview*>(m_canvas->GetParent()) != nullptr)
post_event(wxKeyEvent(EVT_GLCANVAS_EDIT_COLOR_CHANGE, evt));
post_event(wxKeyEvent(EVT_GLCANVAS_SLIDERS_MANIPULATION, evt));
else
post_event(Event<int>(EVT_GLCANVAS_INCREASE_INSTANCES, +1));
break;
}
case '-': {
if (dynamic_cast<Preview*>(m_canvas->GetParent()) != nullptr)
post_event(wxKeyEvent(EVT_GLCANVAS_EDIT_COLOR_CHANGE, evt));
post_event(wxKeyEvent(EVT_GLCANVAS_SLIDERS_MANIPULATION, evt));
else
post_event(Event<int>(EVT_GLCANVAS_INCREASE_INSTANCES, -1));
break;
@ -2853,7 +2850,7 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
case 'g': {
if ((evt.GetModifiers() & shiftMask) != 0) {
if (dynamic_cast<Preview*>(m_canvas->GetParent()) != nullptr)
post_event(wxKeyEvent(EVT_GLCANVAS_JUMP_TO, evt));
post_event(wxKeyEvent(EVT_GLCANVAS_SLIDERS_MANIPULATION, evt));
}
break;
}
@ -3138,7 +3135,7 @@ void GLCanvas3D::on_key(wxKeyEvent& evt)
keyCode == WXK_UP ||
keyCode == WXK_DOWN) {
if (dynamic_cast<Preview*>(m_canvas->GetParent()) != nullptr)
post_event(wxKeyEvent(EVT_GLCANVAS_MOVE_SLIDERS, evt));
post_event(wxKeyEvent(EVT_GLCANVAS_SLIDERS_MANIPULATION, evt));
}
}
}

View File

@ -176,9 +176,7 @@ wxDECLARE_EVENT(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_UPDATE_BED_SHAPE, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_TAB, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_RESETGIZMOS, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_MOVE_SLIDERS, wxKeyEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_EDIT_COLOR_CHANGE, wxKeyEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_JUMP_TO, wxKeyEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_SLIDERS_MANIPULATION, wxKeyEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_UNDO, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_COLLAPSE_SIDEBAR, SimpleEvent);

View File

@ -231,14 +231,11 @@ bool Preview::init(wxWindow* parent, Bed3D& bed, Model* model)
m_canvas->show_legend(true);
m_canvas->enable_dynamic_background(true);
create_layers_slider();
create_sliders();
m_left_sizer = new wxBoxSizer(wxVERTICAL);
m_left_sizer->Add(m_canvas_widget, 1, wxALL | wxEXPAND, 0);
m_moves_slider = new DoubleSlider::Control(this, 0, 0, 0, 100, wxSL_HORIZONTAL, "moves_slider");
m_moves_slider->SetDrawMode(DoubleSlider::dmSequentialGCodeView);
wxBoxSizer* main_sizer = new wxBoxSizer(wxHORIZONTAL);
main_sizer->Add(m_left_sizer, 1, wxALL | wxEXPAND, 0);
@ -260,6 +257,11 @@ Preview::~Preview()
if (m_canvas_widget != nullptr)
delete m_canvas_widget;
if (m_layers_slider)
delete m_layers_slider;
if (m_moves_slider)
delete m_moves_slider;
}
void Preview::set_as_dirty()
@ -321,42 +323,24 @@ void Preview::msw_rescale()
void Preview::render_sliders(GLCanvas3D& canvas, float extra_scale/* = 0.1f*/)
{
const Size cnv_size = canvas.get_canvas_size();
const int canvas_width = cnv_size.get_width();
const int canvas_height = cnv_size.get_height();
if (m_layers_slider)
m_layers_slider->imgui_render(canvas, extra_scale);
m_layers_slider->imgui_render(canvas_width, canvas_height, extra_scale);
if (m_moves_slider)
m_moves_slider->imgui_render(canvas, extra_scale);
}
void Preview::jump_layers_slider(wxKeyEvent& evt)
{
if (m_layers_slider) m_layers_slider->OnChar(evt);
}
void Preview::move_layers_slider(wxKeyEvent& evt)
{
if (m_layers_slider != nullptr) m_layers_slider->OnKeyDown(evt);
}
void Preview::edit_layers_slider(wxKeyEvent& evt)
{
if (m_layers_slider != nullptr) m_layers_slider->OnChar(evt);
m_moves_slider->imgui_render(canvas_width, canvas_height, extra_scale);
}
void Preview::bind_event_handlers()
{
Bind(wxEVT_SIZE, &Preview::on_size, this);
m_moves_slider->Bind(wxEVT_SCROLL_CHANGED, &Preview::on_moves_slider_scroll_changed, this);
}
void Preview::unbind_event_handlers()
{
Unbind(wxEVT_SIZE, &Preview::on_size, this);
m_moves_slider->Unbind(wxEVT_SCROLL_CHANGED, &Preview::on_moves_slider_scroll_changed, this);
}
void Preview::move_moves_slider(wxKeyEvent& evt)
{
if (m_moves_slider != nullptr) m_moves_slider->OnKeyDown(evt);
}
void Preview::hide_layers_slider()
@ -370,26 +354,20 @@ void Preview::on_size(wxSizeEvent& evt)
Refresh();
}
void Preview::create_layers_slider()
void Preview::create_sliders()
{
m_layers_slider = new DoubleSlider::Control(this,0, 0, 0, 100, wxVERTICAL, "layers_slider");
// Layers Slider
m_layers_slider = new DoubleSlider::DSManagerForLayers(0, 0, 0, 100, wxGetApp().is_editor());
m_layers_slider->SetDrawMode(wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA,
wxGetApp().preset_bundle->prints.get_edited_preset().config.opt_bool("complete_objects"));
wxGetApp().preset_bundle->prints.get_edited_preset().config.opt_bool("complete_objects"));
m_layers_slider->enable_action_icon(wxGetApp().is_editor());
// sizer, m_canvas_widget
m_canvas_widget->Bind(wxEVT_KEY_DOWN, &Preview::update_layers_slider_from_canvas, this);
m_canvas_widget->Bind(wxEVT_KEY_UP, [this](wxKeyEvent& event) {
if (event.GetKeyCode() == WXK_SHIFT)
m_layers_slider->UseDefaultColors(true);
event.Skip();
});
m_layers_slider->set_callback_on_thumb_move( [this]() -> void { Preview::on_layers_slider_scroll_changed(); } );
m_layers_slider->Bind(wxEVT_SCROLL_CHANGED, &Preview::on_layers_slider_scroll_changed, this);
Bind(DoubleSlider::wxCUSTOMEVT_TICKSCHANGED, [this](wxEvent&) {
m_layers_slider->set_callback_on_ticks_changed( [this]() -> void {
Model& model = wxGetApp().plater()->model();
model.custom_gcode_per_print_z = m_layers_slider->GetTicksValues();
m_schedule_background_process();
@ -397,6 +375,16 @@ void Preview::create_layers_slider()
m_keep_current_preview_type = false;
reload_print();
});
// Move Gcode Slider
m_moves_slider = new DoubleSlider::DSManagerForGcode(0, 0, 0, 100);
m_moves_slider->set_callback_on_thumb_move([this]() ->void { Preview::on_moves_slider_scroll_changed(); });
// m_canvas_widget
m_canvas_widget->Bind(wxEVT_KEY_DOWN, &Preview::update_sliders_from_canvas, this);
m_canvas_widget->Bind(EVT_GLCANVAS_SLIDERS_MANIPULATION, &Preview::update_sliders_from_canvas, this);
}
// Find an index of a value in a sorted vector, which is in <z-eps, z+eps>.
@ -510,10 +498,20 @@ void Preview::update_layers_slider(const std::vector<double>& layers_z, bool kee
break;
}
auto get_print_obj_idxs = [plater]() ->std::string {
if (plater->printer_technology() == ptSLA)
return "sla";
const Print& print = GUI::wxGetApp().plater()->fff_print();
std::string idxs;
for (auto object : print.objects())
idxs += std::to_string(object->id().id) + "_";
return idxs;
};
// Suggest the auto color change, if model looks like sign
if (!color_change_already_exists &&
wxGetApp().app_config->get_bool("allow_auto_color_change") &&
m_layers_slider->IsNewPrint())
m_layers_slider->IsNewPrint(get_print_obj_idxs()))
{
const Print& print = wxGetApp().plater()->fff_print();
@ -631,16 +629,39 @@ void Preview::reset_layers_slider()
m_layers_slider->SetLowerValue(0);
}
void Preview::update_layers_slider_from_canvas(wxKeyEvent& event)
void Preview::update_sliders_from_canvas(wxKeyEvent& event)
{
if (event.HasModifiers()) {
const auto key = event.GetKeyCode();
if (key == WXK_NUMPAD_ADD || key == '+')
m_layers_slider->add_current_tick(true);
else if (key == WXK_NUMPAD_SUBTRACT || key == WXK_DELETE || key == WXK_BACK || key == '-')
m_layers_slider->delete_current_tick();
else if (key == 'G' || key == 'g')
m_layers_slider->jump_to_value();
else if (key == WXK_LEFT || key == WXK_RIGHT || key == WXK_UP || key == WXK_DOWN) {
int delta = 1;
// accelerators
int accelerator = 0;
if (wxGetKeyState(WXK_SHIFT))
accelerator += 5;
if (wxGetKeyState(WXK_CONTROL))
accelerator += 5;
if (accelerator > 0)
delta *= accelerator;
if (key == WXK_LEFT || key == WXK_RIGHT)
m_moves_slider->move_current_thumb(delta * (key == WXK_LEFT ? 1 : -1));
else if (key == WXK_UP || key == WXK_DOWN)
m_layers_slider->move_current_thumb(delta * (key == WXK_DOWN ? 1 : -1));
}
else if (event.HasModifiers()) {
event.Skip();
return;
}
const auto key = event.GetKeyCode();
if (key == 'S' || key == 'W') {
else if (key == 'S' || key == 'W') {
const int new_pos = key == 'W' ? m_layers_slider->GetHigherValue() + 1 : m_layers_slider->GetHigherValue() - 1;
m_layers_slider->SetHigherValue(new_pos);
}
@ -650,8 +671,6 @@ void Preview::update_layers_slider_from_canvas(wxKeyEvent& event)
}
else if (key == 'X')
m_layers_slider->ChangeOneLayerLock();
else if (key == WXK_SHIFT)
m_layers_slider->UseDefaultColors(false);
else
event.Skip();
}
@ -669,9 +688,9 @@ void Preview::update_moves_slider(std::optional<int> visible_range_min, std::opt
std::optional<uint32_t>{ m_canvas->get_gcode_vertex_at(*visible_range_max).gcode_id } : std::nullopt;
const size_t range_size = range[1] - range[0] + 1;
std::vector<double> values;
std::vector<unsigned int> values;
values.reserve(range_size);
std::vector<double> alternate_values;
std::vector<unsigned int> alternate_values;
alternate_values.reserve(range_size);
std::optional<uint32_t> visible_range_min_id;
@ -684,7 +703,7 @@ void Preview::update_moves_slider(std::optional<int> visible_range_min, std::opt
if (i > range[0]) {
// skip consecutive moves with same gcode id (resulting from processing G2 and G3 lines)
if (last_gcode_id == gcode_id) {
values.back() = static_cast<double>(i + 1);
values.back() = i + 1;
skip = true;
}
else
@ -692,11 +711,11 @@ void Preview::update_moves_slider(std::optional<int> visible_range_min, std::opt
}
if (!skip) {
values.emplace_back(static_cast<double>(i + 1));
alternate_values.emplace_back(static_cast<double>(gcode_id));
if (gcode_id_min.has_value() && alternate_values.back() == static_cast<double>(*gcode_id_min))
values.emplace_back(i + 1);
alternate_values.emplace_back(gcode_id);
if (gcode_id_min.has_value() && alternate_values.back() == *gcode_id_min)
visible_range_min_id = counter;
else if (gcode_id_max.has_value() && alternate_values.back() == static_cast<double>(*gcode_id_max))
else if (gcode_id_max.has_value() && alternate_values.back() == *gcode_id_max)
visible_range_max_id = counter;
++counter;
}
@ -716,7 +735,6 @@ void Preview::enable_moves_slider(bool enable)
bool render_as_disabled = !enable;
if (m_moves_slider != nullptr && m_moves_slider->is_rendering_as_disabled() != render_as_disabled) {
m_moves_slider->set_render_as_disabled(render_as_disabled);
m_moves_slider->Refresh();
}
}
@ -865,7 +883,7 @@ void Preview::load_print_as_sla()
}
}
void Preview::on_layers_slider_scroll_changed(wxCommandEvent& event)
void Preview::on_layers_slider_scroll_changed()
{
if (IsShown()) {
PrinterTechnology tech = m_process->current_printer_technology();
@ -882,7 +900,7 @@ void Preview::on_layers_slider_scroll_changed(wxCommandEvent& event)
}
}
void Preview::on_moves_slider_scroll_changed(wxCommandEvent& event)
void Preview::on_moves_slider_scroll_changed()
{
m_canvas->update_gcode_sequential_view_current(static_cast<unsigned int>(m_moves_slider->GetLowerValueD() - 1.0), static_cast<unsigned int>(m_moves_slider->GetHigherValueD() - 1.0));
m_canvas->set_as_dirty();

View File

@ -28,7 +28,8 @@ class BackgroundSlicingProcess;
class Model;
namespace DoubleSlider {
class Control;
class DSManagerForGcode;
class DSManagerForLayers;
};
namespace GUI {
@ -95,8 +96,8 @@ class Preview : public wxPanel
bool m_loaded { false };
DoubleSlider::Control* m_layers_slider{ nullptr };
DoubleSlider::Control* m_moves_slider{ nullptr };
DoubleSlider::DSManagerForLayers* m_layers_slider{ nullptr };
DoubleSlider::DSManagerForGcode* m_moves_slider { nullptr };
public:
enum class OptionType : unsigned int
@ -133,9 +134,6 @@ public:
void reload_print();
void msw_rescale();
void jump_layers_slider(wxKeyEvent& evt);
void move_layers_slider(wxKeyEvent& evt);
void edit_layers_slider(wxKeyEvent& evt);
void render_sliders(GLCanvas3D& canvas, float extra_scale = 0.1f);
@ -143,7 +141,6 @@ public:
void update_moves_slider(std::optional<int> visible_range_min = std::nullopt, std::optional<int> visible_range_max = std::nullopt);
void enable_moves_slider(bool enable);
void move_moves_slider(wxKeyEvent& evt);
void hide_layers_slider();
void set_keep_current_preview_type(bool value) { m_keep_current_preview_type = value; }
@ -159,20 +156,20 @@ private:
void on_size(wxSizeEvent& evt);
// Create/Update/Reset double slider on 3dPreview
void create_layers_slider();
void create_sliders();
void check_layers_slider_values(std::vector<CustomGCode::Item>& ticks_from_model,
const std::vector<double>& layers_z);
void reset_layers_slider();
void update_layers_slider(const std::vector<double>& layers_z, bool keep_z_range = false);
void update_layers_slider_mode();
// update vertical DoubleSlider after keyDown in canvas
void update_layers_slider_from_canvas(wxKeyEvent& event);
void update_sliders_from_canvas(wxKeyEvent& event);
void load_print_as_fff(bool keep_z_range = false);
void load_print_as_sla();
void on_layers_slider_scroll_changed(wxCommandEvent& event);
void on_moves_slider_scroll_changed(wxCommandEvent& event);
void on_layers_slider_scroll_changed();
void on_moves_slider_scroll_changed();
};
} // namespace GUI

View File

@ -120,14 +120,10 @@ ImGuiControl::ImGuiControl( int lowerValue,
int higherValue,
int minValue,
int maxValue,
ImVec2 pos,
ImVec2 size,
ImGuiSliderFlags flags,
std::string name,
bool use_lower_thumb) :
m_selection(ssUndef),
m_pos(pos),
m_size(size),
m_name(name),
m_lower_value(lowerValue),
m_higher_value (higherValue),

View File

@ -32,13 +32,6 @@ enum SelectedSlider {
ssHigher
};
enum LabelType
{
ltHeightWithLayer,
ltHeight,
ltEstimatedTime,
};
class ImGuiControl
{
public:
@ -46,8 +39,6 @@ public:
int higherValue,
int minValue,
int maxValue,
ImVec2 pos,
ImVec2 size,
ImGuiSliderFlags flags = ImGuiSliderFlags_None,
std::string name = "d_slider",
bool use_lower_thumb = true);
@ -79,12 +70,12 @@ public:
m_draw_opts.scale = scale;
}
void Show(bool show) { m_is_shown = show; }
void Hide() { m_is_shown = false; }
bool IsShown() const { return m_is_shown; }
void MoveActiveThumb(int delta);
bool IsCombineThumbs() const { return m_combine_thumbs; }
bool IsActiveHigherThumb() const { return m_selection == ssHigher; }
void Show(bool show) { m_is_shown = show; }
void Hide() { m_is_shown = false; }
bool IsShown() const { return m_is_shown; }
bool IsCombineThumbs() const { return m_combine_thumbs; }
bool IsActiveHigherThumb() const { return m_selection == ssHigher; }
void MoveActiveThumb(int delta);
void ShowLabelOnMouseMove(bool show = true) { m_show_move_label = show; }
ImRect GetGrooveRect() const { return m_draw_opts.groove(m_pos, m_size, is_horizontal()); }
@ -95,11 +86,7 @@ public:
bool is_full_span() const { return this->is_lower_at_min() && this->is_higher_at_max(); }
bool is_rclick_on_thumb() const { return m_rclick_on_selected_thumb; }
void correct_lower_value();
void correct_higher_value();
bool render();
void draw_scroll_line(const ImRect& scroll_line, const ImRect& slideable_region);
std::string get_label(int pos) const;
@ -108,6 +95,8 @@ public:
void set_draw_scroll_line_cb(std::function<void(const ImRect&, const ImRect&)> cb) { m_cb_draw_scroll_line = cb; }
void set_extra_draw_cb(std::function<void(const ImRect&)> cb) { m_cb_extra_draw = cb; }
private:
struct DrawOptions {
float scale { 1.f }; // used for Retina on osx
@ -134,8 +123,6 @@ public:
ImRect lower_thumb;
};
private:
SelectedSlider m_selection;
ImVec2 m_pos;
ImVec2 m_size;
@ -143,31 +130,34 @@ private:
ImGuiSliderFlags m_flags{ ImGuiSliderFlags_None };
bool m_is_shown{ true };
int m_min_value;
int m_max_value;
int m_lower_value;
int m_higher_value;
int m_mouse_pos_value;
int m_min_value;
int m_max_value;
int m_lower_value;
int m_higher_value;
int m_mouse_pos_value;
bool m_rclick_on_selected_thumb{ false };
bool m_rclick_on_selected_thumb{ false };
bool m_draw_lower_thumb{ true };
bool m_combine_thumbs { false };
bool m_show_move_label{ false };
bool m_draw_lower_thumb{ true };
bool m_combine_thumbs { false };
bool m_show_move_label { false };
DrawOptions m_draw_opts;
Regions m_regions;
DrawOptions m_draw_opts;
Regions m_regions;
std::function<std::string(int)> m_cb_get_label { nullptr };
std::function<std::string(int)> m_cb_get_label_on_move { nullptr };
std::function<void(const ImRect&, const ImRect&)> m_cb_draw_scroll_line { nullptr };
std::function<void(const ImRect&)> m_cb_extra_draw { nullptr };
void apply_regions(int higher_value, int lower_value, const ImRect& draggable_region);
void correct_lower_value();
void correct_higher_value();
std::string get_label_on_move(int pos) const { return m_cb_get_label_on_move ? m_cb_get_label_on_move(pos) : get_label(pos); }
void apply_regions(int higher_value, int lower_value, const ImRect& draggable_region);
void check_and_correct_thumbs(int* higher_value, int* lower_value);
void draw_scroll_line(const ImRect& scroll_line, const ImRect& slideable_region);
void draw_background(const ImRect& slideable_region);
void draw_label(std::string label, const ImRect& thumb);
void draw_thumb(const ImVec2& center, bool mark = false);

View File

@ -736,12 +736,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_TAB, [this](SimpleEvent&) { select_next_view_3D(); });
preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_COLLAPSE_SIDEBAR, [this](SimpleEvent&) { this->q->collapse_sidebar(!this->q->is_sidebar_collapsed()); });
}
preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_JUMP_TO, [this](wxKeyEvent& evt) { preview->jump_layers_slider(evt); });
preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_MOVE_SLIDERS, [this](wxKeyEvent& evt) {
preview->move_layers_slider(evt);
preview->move_moves_slider(evt);
});
preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_EDIT_COLOR_CHANGE, [this](wxKeyEvent& evt) { preview->edit_layers_slider(evt); });
if (wxGetApp().is_gcode_viewer())
preview->Bind(EVT_GLCANVAS_RELOAD_FROM_DISK, [this](SimpleEvent&) { this->q->reload_gcode_from_disk(); });