ImguiDoubleSlider: WIP: Slider Manager is moved to ImGuiDoubleSlider and some values and methods are renamed

+ "DoubleSlider: file is split to DoubleSliderForGcode and DoubleSliderForLayers in separate files
 + Suppress to add/delete ticks on update layers_slider from canvas when an application is a GCodeViewer
 + epsilon() is moved from DoubleSlider name space to CustomGCode
This commit is contained in:
YuSanka 2024-03-25 14:49:30 +01:00 committed by Lukas Matena
parent 56a3740fe4
commit 6b83f135c9
13 changed files with 637 additions and 601 deletions

View File

@ -30,7 +30,7 @@ src/slic3r/GUI/ConfigManipulation.cpp
src/slic3r/GUI/ConfigSnapshotDialog.cpp src/slic3r/GUI/ConfigSnapshotDialog.cpp
src/slic3r/GUI/ConfigWizard.cpp src/slic3r/GUI/ConfigWizard.cpp
src/slic3r/GUI/DesktopIntegrationDialog.cpp src/slic3r/GUI/DesktopIntegrationDialog.cpp
src/slic3r/GUI/DoubleSlider.cpp src/slic3r/GUI/DoubleSliderForLayers.cpp
src/slic3r/GUI/Downloader.cpp src/slic3r/GUI/Downloader.cpp
src/slic3r/GUI/DownloaderFileGet.cpp src/slic3r/GUI/DownloaderFileGet.cpp
src/slic3r/GUI/EditGCodeDialog.cpp src/slic3r/GUI/EditGCodeDialog.cpp

View File

@ -14,6 +14,11 @@ class DynamicPrintConfig;
namespace CustomGCode { namespace CustomGCode {
/* For exporting GCode in GCodeWriter is used XYZF_NUM(val) = PRECISION(val, 3) for XYZ values.
* So, let use same value as a permissible error for layer height.
*/
constexpr double epsilon() { return 0.0011; }
enum Type enum Type
{ {
ColorChange, ColorChange,

View File

@ -252,10 +252,12 @@ set(SLIC3R_GUI_SOURCES
GUI/ProgressStatusBar.cpp GUI/ProgressStatusBar.cpp
GUI/Mouse3DController.cpp GUI/Mouse3DController.cpp
GUI/Mouse3DController.hpp GUI/Mouse3DController.hpp
GUI/DoubleSlider.cpp
GUI/DoubleSlider.hpp
GUI/ImGuiDoubleSlider.cpp GUI/ImGuiDoubleSlider.cpp
GUI/ImGuiDoubleSlider.hpp GUI/ImGuiDoubleSlider.hpp
GUI/DoubleSliderForLayers.cpp
GUI/DoubleSliderForLayers.hpp
GUI/DoubleSliderForGcode.cpp
GUI/DoubleSliderForGcode.hpp
GUI/Notebook.cpp GUI/Notebook.cpp
GUI/Notebook.hpp GUI/Notebook.hpp
GUI/TopBar.cpp GUI/TopBar.cpp

View File

@ -0,0 +1,33 @@
///|/ Copyright (c) Prusa Research 2020 - 2023 Oleksandra Iushchenko @YuSanka, Vojtěch Bubník @bubnikv, Tomáš Mészáros @tamasmeszaros, Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966
///|/
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
///|/
#include "DoubleSliderForGcode.hpp"
namespace Slic3r {
namespace DoubleSlider {
static const float LEFT_MARGIN = 13.0f + 100.0f; // avoid thumbnail toolbar
static const float HORIZONTAL_SLIDER_HEIGHT = 90.0f;
void DSForGcode::Render(const int canvas_width, const int canvas_height, float extra_scale/* = 0.1f*/)
{
if (!m_ctrl.IsShown())
return;
m_scale = extra_scale * 0.1f * m_em;
ImVec2 pos = ImVec2{std::max(LEFT_MARGIN, 0.2f * canvas_width), canvas_height - HORIZONTAL_SLIDER_HEIGHT * m_scale};
ImVec2 size = ImVec2(canvas_width - 2 * pos.x, HORIZONTAL_SLIDER_HEIGHT * m_scale);
m_ctrl.Init(pos, size, m_scale);
if (m_ctrl.render())
process_thumb_move();
}
} // DoubleSlider
} // Slic3r

View File

@ -0,0 +1,42 @@
///|/ Copyright (c) Prusa Research 2020 - 2022 Vojtěch Bubník @bubnikv, Oleksandra Iushchenko @YuSanka, Enrico Turri @enricoturri1966, Lukáš Matěna @lukasmatena
///|/
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
///|/
#ifndef slic3r_GUI_DoubleSliderForGcode_hpp_
#define slic3r_GUI_DoubleSliderForGcode_hpp_
#include "ImGuiDoubleSlider.hpp"
namespace Slic3r {
namespace DoubleSlider {
class DSForGcode : public Manager<unsigned int>
{
public:
DSForGcode() : Manager<unsigned int>() {}
DSForGcode( int lowerPos,
int higherPos,
int minPos,
int maxPos)
{
Init(lowerPos, higherPos, minPos, maxPos, "moves_slider", true);
}
~DSForGcode() {}
void 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 };
};
} // DoubleSlider;
} // Slic3r
#endif // slic3r_GUI_DoubleSliderForGcode_hpp_

View File

@ -2,8 +2,9 @@
///|/ ///|/
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher ///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
///|/ ///|/
#include "DoubleSliderForLayers.hpp"
#include "libslic3r/libslic3r.h" #include "libslic3r/libslic3r.h"
#include "DoubleSlider.hpp"
#include "libslic3r/GCode.hpp" #include "libslic3r/GCode.hpp"
#include "GUI.hpp" #include "GUI.hpp"
#include "GUI_App.hpp" #include "GUI_App.hpp"
@ -14,8 +15,6 @@
#include "libslic3r/AppConfig.hpp" #include "libslic3r/AppConfig.hpp"
#include "GUI_Utils.hpp" #include "GUI_Utils.hpp"
#include "MsgDialog.hpp" #include "MsgDialog.hpp"
#include "Tab.hpp"
#include "GUI_ObjectList.hpp"
#include <wx/dialog.h> #include <wx/dialog.h>
#include <wx/menu.h> #include <wx/menu.h>
@ -24,7 +23,7 @@
#include <cmath> #include <cmath>
#include <boost/algorithm/string/replace.hpp> #include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/split.hpp> #include <boost/algorithm/string/split.hpp>
#include "Field.hpp"
#include "format.hpp" #include "format.hpp"
#include "NotificationManager.hpp" #include "NotificationManager.hpp"
@ -44,9 +43,7 @@ namespace DoubleSlider {
constexpr double min_delta_area = scale_(scale_(25)); // equal to 25 mm2 constexpr double min_delta_area = scale_(scale_(25)); // equal to 25 mm2
constexpr double miscalculation = scale_(scale_(1)); // equal to 1 mm2 constexpr double miscalculation = scale_(scale_(1)); // equal to 1 mm2
static const float LEFT_MARGIN = 13.0f + 100.0f; // avoid thumbnail toolbar static const float VERTICAL_SLIDER_WIDTH = 105.0f;
static const float HORIZONTAL_SLIDER_WIDTH = 90.0f;
static const float VERTICAL_SLIDER_HEIGHT = 105.0f;
bool equivalent_areas(const double& bottom_area, const double& top_area) bool equivalent_areas(const double& bottom_area, const double& top_area)
{ {
@ -55,7 +52,7 @@ bool equivalent_areas(const double& bottom_area, const double& top_area)
static std::string gcode(Type type) static std::string gcode(Type type)
{ {
const PrintConfig& config = GUI::wxGetApp().plater()->fff_print().config(); const PrintConfig& config = GUI::wxGetApp().plater()->fff_print().config(); // ! ys_FIXME
switch (type) { switch (type) {
case ColorChange: return config.color_change_gcode; case ColorChange: return config.color_change_gcode;
case PausePrint: return config.pause_print_gcode; case PausePrint: return config.pause_print_gcode;
@ -64,7 +61,26 @@ static std::string gcode(Type type)
} }
} }
int DSManagerForLayers::get_tick_from_value(double value, bool force_lower_bound/* = false*/) DSForLayers::DSForLayers( int lowerValue,
int higherValue,
int minValue,
int maxValue,
bool allow_editing) :
m_allow_editing(allow_editing)
{
#ifdef __WXOSX__
is_osx = true;
#endif //__WXOSX__
Init(lowerValue, higherValue, minValue, maxValue, "layers_slider", false);
m_ctrl.set_get_label_on_move_cb([this](int pos) { return m_show_estimated_times ? into_u8(get_label(pos, ltEstimatedTime)) : ""; });
m_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);
}
int DSForLayers::get_tick_from_value(double value, bool force_lower_bound/* = false*/)
{ {
std::vector<double>::iterator it; std::vector<double>::iterator it;
if (m_is_wipe_tower && !force_lower_bound) if (m_is_wipe_tower && !force_lower_bound)
@ -78,7 +94,7 @@ int DSManagerForLayers::get_tick_from_value(double value, bool force_lower_bound
return int(it - m_values.begin()); return int(it - m_values.begin());
} }
Info DSManagerForLayers::GetTicksValues() const Info DSForLayers::GetTicksValues() const
{ {
Info custom_gcode_per_print_z; Info custom_gcode_per_print_z;
std::vector<CustomGCode::Item>& values = custom_gcode_per_print_z.gcodes; std::vector<CustomGCode::Item>& values = custom_gcode_per_print_z.gcodes;
@ -91,13 +107,12 @@ Info DSManagerForLayers::GetTicksValues() const
values.emplace_back(CustomGCode::Item{ m_values[tick.tick], tick.type, tick.extruder, tick.color, tick.extra }); values.emplace_back(CustomGCode::Item{ m_values[tick.tick], tick.type, tick.extruder, tick.color, tick.extra });
} }
if (m_force_mode_apply) custom_gcode_per_print_z.mode = m_mode;
custom_gcode_per_print_z.mode = m_mode;
return custom_gcode_per_print_z; return custom_gcode_per_print_z;
} }
void DSManagerForLayers::SetTicksValues(const Info& custom_gcode_per_print_z) void DSForLayers::SetTicksValues(const Info& custom_gcode_per_print_z)
{ {
if (m_values.empty()) { if (m_values.empty()) {
m_ticks.mode = m_mode; m_ticks.mode = m_mode;
@ -116,18 +131,18 @@ void DSManagerForLayers::SetTicksValues(const Info& custom_gcode_per_print_z)
if (!was_empty && m_ticks.empty()) if (!was_empty && m_ticks.empty())
// Switch to the "Feature type"/"Tool" from the very beginning of a new object slicing after deleting of the old one // Switch to the "Feature type"/"Tool" from the very beginning of a new object slicing after deleting of the old one
post_ticks_changed_event(); process_ticks_changed();
// init extruder sequence in respect to the extruders count // init extruder sequence in respect to the extruders count
if (m_ticks.empty()) if (m_ticks.empty())
m_extruders_sequence.init(m_extruder_colors.size()); m_extruders_sequence.init(m_extruder_colors.size());
update_callbacks(); update_draw_scroll_line_cb();
if (custom_gcode_per_print_z.mode && !custom_gcode_per_print_z.gcodes.empty()) if (custom_gcode_per_print_z.mode && !custom_gcode_per_print_z.gcodes.empty())
m_ticks.mode = custom_gcode_per_print_z.mode; m_ticks.mode = custom_gcode_per_print_z.mode;
} }
void DSManagerForLayers::SetLayersTimes(const std::vector<float>& layers_times, float total_time) void DSForLayers::SetLayersTimes(const std::vector<float>& layers_times, float total_time)
{ {
m_layers_times.clear(); m_layers_times.clear();
if (layers_times.empty()) if (layers_times.empty())
@ -153,7 +168,7 @@ void DSManagerForLayers::SetLayersTimes(const std::vector<float>& layers_times,
} }
} }
void DSManagerForLayers::SetLayersTimes(const std::vector<double>& layers_times) void DSForLayers::SetLayersTimes(const std::vector<double>& layers_times)
{ {
m_is_wipe_tower = false; m_is_wipe_tower = false;
m_layers_times = layers_times; m_layers_times = layers_times;
@ -161,16 +176,16 @@ void DSManagerForLayers::SetLayersTimes(const std::vector<double>& layers_times)
m_layers_times[i] += m_layers_times[i - 1]; m_layers_times[i] += m_layers_times[i - 1];
} }
void DSManagerForLayers::SetDrawMode(bool is_sla_print, bool is_sequential_print) void DSForLayers::SetDrawMode(bool is_sla_print, bool is_sequential_print)
{ {
m_draw_mode = is_sla_print ? dmSlaPrint : m_draw_mode = is_sla_print ? dmSlaPrint :
is_sequential_print ? dmSequentialFffPrint : is_sequential_print ? dmSequentialFffPrint :
dmRegular; dmRegular;
update_callbacks(); update_draw_scroll_line_cb();
} }
void DSManagerForLayers::SetModeAndOnlyExtruder(const bool is_one_extruder_printed_model, const int only_extruder) void DSForLayers::SetModeAndOnlyExtruder(const bool is_one_extruder_printed_model, const int only_extruder)
{ {
m_mode = !is_one_extruder_printed_model ? MultiExtruder : m_mode = !is_one_extruder_printed_model ? MultiExtruder :
only_extruder < 0 ? SingleExtruder : only_extruder < 0 ? SingleExtruder :
@ -185,12 +200,12 @@ void DSManagerForLayers::SetModeAndOnlyExtruder(const bool is_one_extruder_print
m_is_wipe_tower = m_mode != SingleExtruder; m_is_wipe_tower = m_mode != SingleExtruder;
} }
void DSManagerForLayers::SetExtruderColors( const std::vector<std::string>& extruder_colors) void DSForLayers::SetExtruderColors( const std::vector<std::string>& extruder_colors)
{ {
m_extruder_colors = extruder_colors; m_extruder_colors = extruder_colors;
} }
bool DSManagerForLayers::IsNewPrint(const std::string& idxs) bool DSForLayers::IsNewPrint(const std::string& idxs)
{ {
if (idxs == "sla" || idxs == m_print_obj_idxs) if (idxs == "sla" || idxs == m_print_obj_idxs)
return false; return false;
@ -199,17 +214,17 @@ bool DSManagerForLayers::IsNewPrint(const std::string& idxs)
return true; return true;
} }
void DSManagerForLayers::update_callbacks() void DSForLayers::update_draw_scroll_line_cb()
{ {
if (m_ticks.empty() || m_draw_mode == dmSequentialFffPrint) if (m_ticks.empty() || m_draw_mode == dmSequentialFffPrint || m_draw_mode == dmSlaPrint)
imgui_ctrl.set_draw_scroll_line_cb(nullptr); m_ctrl.set_draw_scroll_line_cb(nullptr);
else else
imgui_ctrl.set_draw_scroll_line_cb([this](const ImRect& scroll_line, const ImRect& slideable_region) { draw_colored_band(scroll_line, slideable_region); }); m_ctrl.set_draw_scroll_line_cb([this](const ImRect& scroll_line, const ImRect& slideable_region) { draw_colored_band(scroll_line, slideable_region); });
} }
using namespace ImGui; using namespace ImGui;
void DSManagerForLayers::draw_ticks(const ImRect& slideable_region) void DSForLayers::draw_ticks(const ImRect& slideable_region)
{ {
//if(m_draw_mode != dmRegular) //if(m_draw_mode != dmRegular)
// return; // return;
@ -231,7 +246,7 @@ void DSManagerForLayers::draw_ticks(const ImRect& slideable_region)
const ImU32 tick_hovered_clr = ImGui::ColorConvertFloat4ToU32(ImGuiPureWrap::COL_WINDOW_BACKGROUND); const ImU32 tick_hovered_clr = ImGui::ColorConvertFloat4ToU32(ImGuiPureWrap::COL_WINDOW_BACKGROUND);
auto get_tick_pos = [this, slideable_region](int tick) { auto get_tick_pos = [this, slideable_region](int tick) {
return imgui_ctrl.GetPositionFromValue(tick, slideable_region); return m_ctrl.GetPositionInRect(tick, slideable_region);
}; };
std::set<TickCode>::const_iterator tick_it = m_ticks.ticks.begin(); std::set<TickCode>::const_iterator tick_it = m_ticks.ticks.begin();
@ -250,7 +265,7 @@ void DSManagerForLayers::draw_ticks(const ImRect& slideable_region)
++tick_it; ++tick_it;
} }
auto active_tick_it = m_ticks.ticks.find(TickCode{ imgui_ctrl.GetActiveValue() }); auto active_tick_it = m_ticks.ticks.find(TickCode{ m_ctrl.GetActivePos() });
tick_it = m_ticks.ticks.begin(); tick_it = m_ticks.ticks.begin();
while (tick_it != m_ticks.ticks.end()) while (tick_it != m_ticks.ticks.end())
@ -270,10 +285,10 @@ void DSManagerForLayers::draw_ticks(const ImRect& slideable_region)
bool activate_this_tick = false; bool activate_this_tick = false;
if (tick_it == active_tick_it && m_allow_editing) { if (tick_it == active_tick_it && m_allow_editing) {
// delete tick // delete tick
if (render_button(ImGui::RemoveTick, ImGui::RemoveTickHovered, btn_label, icon_pos, imgui_ctrl.IsActiveHigherThumb() ? fiHigherThumb : fiLowerThumb, tick_it->tick)) { if (render_button(ImGui::RemoveTick, ImGui::RemoveTickHovered, btn_label, icon_pos, m_ctrl.IsActiveHigherThumb() ? fiHigherThumb : fiLowerThumb, tick_it->tick)) {
Type type = tick_it->type; Type type = tick_it->type;
m_ticks.ticks.erase(tick_it); m_ticks.ticks.erase(tick_it);
post_ticks_changed_event(type); process_ticks_changed();
break; break;
} }
} }
@ -289,7 +304,7 @@ void DSManagerForLayers::draw_ticks(const ImRect& slideable_region)
activate_this_tick = render_button(ImGui::EditGCode, ImGui::EditGCodeHovered, btn_label, icon_pos, fiActionIcon, tick_it->tick); activate_this_tick = render_button(ImGui::EditGCode, ImGui::EditGCodeHovered, btn_label, icon_pos, fiActionIcon, tick_it->tick);
if (activate_this_tick) { if (activate_this_tick) {
imgui_ctrl.IsActiveHigherThumb() ? SetHigherValue(tick_it->tick) : SetLowerValue(tick_it->tick); m_ctrl.IsActiveHigherThumb() ? SetHigherPos(tick_it->tick) : SetLowerPos(tick_it->tick);
break; break;
} }
@ -318,7 +333,7 @@ static std::array<float, 4> decode_color_to_float_array(const std::string color)
return ret; return ret;
} }
void DSManagerForLayers::draw_colored_band(const ImRect& groove, const ImRect& slideable_region) void DSForLayers::draw_colored_band(const ImRect& groove, const ImRect& slideable_region)
{ {
if (m_ticks.empty() || m_draw_mode == dmSequentialFffPrint) if (m_ticks.empty() || m_draw_mode == dmSequentialFffPrint)
return; return;
@ -352,7 +367,7 @@ void DSManagerForLayers::draw_colored_band(const ImRect& groove, const ImRect& s
while (tick_it != m_ticks.ticks.end()) while (tick_it != m_ticks.ticks.end())
{ {
//get position from tick //get position from tick
tick_pos = imgui_ctrl.GetPositionFromValue(tick_it->tick, slideable_region); tick_pos = m_ctrl.GetPositionInRect(tick_it->tick, slideable_region);
ImRect band_rect = ImRect(ImVec2(main_band.Min.x, std::min(tick_pos, main_band.Min.y)), ImRect band_rect = ImRect(ImVec2(main_band.Min.x, std::min(tick_pos, main_band.Min.y)),
ImVec2(main_band.Max.x, std::min(tick_pos, main_band.Max.y))); ImVec2(main_band.Max.x, std::min(tick_pos, main_band.Max.y)));
@ -380,7 +395,7 @@ void DSManagerForLayers::draw_colored_band(const ImRect& groove, const ImRect& s
} }
} }
void DSManagerForLayers::render_menu() void DSForLayers::render_menu()
{ {
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(10.0f, 10.0f) * m_scale); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(10.0f, 10.0f) * m_scale);
ImGui::PushStyleVar(ImGuiStyleVar_PopupRounding, 4.0f * m_scale); ImGui::PushStyleVar(ImGuiStyleVar_PopupRounding, 4.0f * m_scale);
@ -391,14 +406,14 @@ void DSManagerForLayers::render_menu()
std::vector<std::string> colors = wxGetApp().plater()->get_extruder_colors_from_plater_config(); std::vector<std::string> colors = wxGetApp().plater()->get_extruder_colors_from_plater_config();
int extruder_num = colors.size(); int extruder_num = colors.size();
if (imgui_ctrl.is_rclick_on_thumb()) { if (m_ctrl.IsRClickOnThumb()) {
ImGui::OpenPopup("slider_menu_popup"); ImGui::OpenPopup("slider_menu_popup");
} }
ImGui::PushStyleVar(ImGuiStyleVar_::ImGuiStyleVar_ChildRounding, 4.0f * m_scale); ImGui::PushStyleVar(ImGuiStyleVar_::ImGuiStyleVar_ChildRounding, 4.0f * m_scale);
if (ImGui::BeginPopup("slider_menu_popup")) { if (ImGui::BeginPopup("slider_menu_popup")) {
if ((!imgui_ctrl.IsActiveHigherThumb() && GetLowerValueD() == 0.0) || if ((!m_ctrl.IsActiveHigherThumb() && GetLowerValue() == 0.0) ||
(imgui_ctrl.IsActiveHigherThumb() && GetHigherValueD() == 0.0)) (m_ctrl.IsActiveHigherThumb() && GetHigherValue() == 0.0))
{ {
menu_item_with_icon(_u8L("Add Pause").c_str(), "", ImVec2(0, 0), 0, false, false); menu_item_with_icon(_u8L("Add Pause").c_str(), "", ImVec2(0, 0), 0, false, false);
} }
@ -442,7 +457,7 @@ void DSManagerForLayers::render_menu()
ImGui::PopStyleVar(3); ImGui::PopStyleVar(3);
} }
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*/) bool DSForLayers::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; float scale = (float)wxGetApp().em_unit() / 10.0f;
@ -468,7 +483,7 @@ bool DSManagerForLayers::render_button(const wchar_t btn_icon, const wchar_t btn
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
m_focus = focus; m_focus = focus;
std::string tooltip = m_allow_editing ? into_u8(get_tooltip(tick)) : ""; std::string tooltip = m_allow_editing ? get_tooltip(tick) : "";
ImGui::SetCursorPos(ImVec2(0, 0)); ImGui::SetCursorPos(ImVec2(0, 0));
const bool ret = m_imgui->image_button(g.HoveredWindow == g.CurrentWindow ? btn_icon_hovered : btn_icon, tooltip, false); const bool ret = m_imgui->image_button(g.HoveredWindow == g.CurrentWindow ? btn_icon_hovered : btn_icon, tooltip, false);
@ -480,25 +495,11 @@ bool DSManagerForLayers::render_button(const wchar_t btn_icon, const wchar_t btn
return ret; return ret;
} }
void DSManagerForGcode::imgui_render(const int canvas_width, const int canvas_height, float extra_scale/* = 0.1f*/) void DSForLayers::Render(const int canvas_width, const int canvas_height, float extra_scale/* = 0.1f*/)
{ {
if (!imgui_ctrl.IsShown()) if (!m_ctrl.IsShown())
return; return;
m_scale = extra_scale * 0.1f * wxGetApp().em_unit(); m_scale = extra_scale * 0.1f * m_em;
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 action_btn_sz = wxGetApp().imgui()->GetTextureCustomRect(ImGui::DSRevert)->Height;
const float tick_icon_side = wxGetApp().imgui()->GetTextureCustomRect(ImGui::PausePrint)->Height; const float tick_icon_side = wxGetApp().imgui()->GetTextureCustomRect(ImGui::PausePrint)->Height;
@ -506,15 +507,15 @@ void DSManagerForLayers::imgui_render(const int canvas_width, const int canvas_h
ImVec2 pos; ImVec2 pos;
ImVec2 size; ImVec2 size;
pos.x = canvas_width - VERTICAL_SLIDER_HEIGHT * m_scale - tick_icon_side; pos.x = canvas_width - VERTICAL_SLIDER_WIDTH * m_scale - tick_icon_side;
pos.y = 1.f * action_btn_sz; pos.y = 1.f * action_btn_sz;
if (m_allow_editing) if (m_allow_editing)
pos.y += 2.f; pos.y += 2.f;
size = ImVec2(VERTICAL_SLIDER_HEIGHT * m_scale, canvas_height - 4.f * action_btn_sz); size = ImVec2(VERTICAL_SLIDER_WIDTH * m_scale, canvas_height - 4.f * action_btn_sz);
imgui_ctrl.ShowLabelOnMouseMove(true); m_ctrl.ShowLabelOnMouseMove(true);
imgui_ctrl.Init(pos, size, m_scale); m_ctrl.Init(pos, size, m_scale);
if (imgui_ctrl.render()) { if (m_ctrl.render()) {
// request one more frame if value was changes with mouse wheel // request one more frame if value was changes with mouse wheel
if (GImGui->IO.MouseWheel != 0.0f) if (GImGui->IO.MouseWheel != 0.0f)
wxGetApp().imgui()->set_requires_extra_frame(); wxGetApp().imgui()->set_requires_extra_frame();
@ -523,7 +524,7 @@ void DSManagerForLayers::imgui_render(const int canvas_width, const int canvas_h
// draw action buttons // draw action buttons
const float groove_center_x = imgui_ctrl.GetGrooveRect().GetCenter().x; const float groove_center_x = m_ctrl.GetGrooveRect().GetCenter().x;
ImVec2 btn_pos = ImVec2(groove_center_x - 0.5f * action_btn_sz, pos.y - 0.25f * action_btn_sz); ImVec2 btn_pos = ImVec2(groove_center_x - 0.5f * action_btn_sz, pos.y - 0.25f * action_btn_sz);
@ -532,7 +533,7 @@ void DSManagerForLayers::imgui_render(const int canvas_width, const int canvas_h
discard_all_thicks(); discard_all_thicks();
btn_pos.y += 0.1f * action_btn_sz + size.y; btn_pos.y += 0.1f * action_btn_sz + size.y;
const bool is_one_layer = imgui_ctrl.IsCombineThumbs(); const bool is_one_layer = m_ctrl.IsCombineThumbs();
if (render_button(is_one_layer ? ImGui::Lock : ImGui::Unlock, is_one_layer ? ImGui::LockHovered : ImGui::UnlockHovered, "one_layer", btn_pos, fiOneLayerIcon)) if (render_button(is_one_layer ? ImGui::Lock : ImGui::Unlock, is_one_layer ? ImGui::LockHovered : ImGui::UnlockHovered, "one_layer", btn_pos, fiOneLayerIcon))
ChangeOneLayerLock(); ChangeOneLayerLock();
@ -540,7 +541,7 @@ void DSManagerForLayers::imgui_render(const int canvas_width, const int canvas_h
if (render_button(ImGui::DSSettings, ImGui::DSSettingsHovered, "settings", btn_pos, fiCogIcon)) if (render_button(ImGui::DSSettings, ImGui::DSSettingsHovered, "settings", btn_pos, fiCogIcon))
show_cog_icon_context_menu(); show_cog_icon_context_menu();
if (m_draw_mode == dmSequentialFffPrint && imgui_ctrl.is_rclick_on_thumb()) { if (m_draw_mode == dmSequentialFffPrint && m_ctrl.IsRClickOnThumb()) {
std::string tooltip = _u8L("The sequential print is on.\n" std::string tooltip = _u8L("The sequential print is on.\n"
"It's impossible to apply any custom G-code for objects printing sequentually."); "It's impossible to apply any custom G-code for objects printing sequentually.");
ImGuiPureWrap::tooltip(tooltip, ImGui::GetFontSize() * 20.0f); ImGuiPureWrap::tooltip(tooltip, ImGui::GetFontSize() * 20.0f);
@ -549,7 +550,7 @@ void DSManagerForLayers::imgui_render(const int canvas_width, const int canvas_h
render_menu(); render_menu();
} }
bool DSManagerForLayers::is_wipe_tower_layer(int tick) const bool DSForLayers::is_wipe_tower_layer(int tick) const
{ {
if (!m_is_wipe_tower || tick >= (int)m_values.size()) if (!m_is_wipe_tower || tick >= (int)m_values.size())
return false; return false;
@ -603,7 +604,7 @@ static std::string short_and_splitted_time(const std::string& time)
return get_s(); return get_s();
} }
std::string DSManagerForLayers::get_label(int pos, LabelType label_type/* = ltHeightWithLayer*/) const std::string DSForLayers::get_label(int pos, LabelType label_type/* = ltHeightWithLayer*/) const
{ {
const size_t value = pos; const size_t value = pos;
@ -651,7 +652,7 @@ std::string DSManagerForLayers::get_label(int pos, LabelType label_type/* = ltHe
return ""; return "";
} }
std::string DSManagerForLayers::get_color_for_tool_change_tick(std::set<TickCode>::const_iterator it) const std::string DSForLayers::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; const int current_extruder = it->extruder == 0 ? std::max<int>(m_only_extruder, 1) : it->extruder;
@ -665,7 +666,7 @@ std::string DSManagerForLayers::get_color_for_tool_change_tick(std::set<TickCode
return m_extruder_colors[current_extruder-1]; // return a color for a specific extruder from the colors list return m_extruder_colors[current_extruder-1]; // return a color for a specific extruder from the colors list
} }
std::string DSManagerForLayers::get_color_for_color_change_tick(std::set<TickCode>::const_iterator it) const std::string DSForLayers::get_color_for_color_change_tick(std::set<TickCode>::const_iterator it) const
{ {
const int def_extruder = std::max<int>(1, m_only_extruder); const int def_extruder = std::max<int>(1, m_only_extruder);
auto it_n = it; auto it_n = it;
@ -687,48 +688,48 @@ std::string DSManagerForLayers::get_color_for_color_change_tick(std::set<TickCod
return ""; return "";
} }
void DSManagerForLayers::ChangeOneLayerLock() void DSForLayers::ChangeOneLayerLock()
{ {
imgui_ctrl.CombineThumbs(!imgui_ctrl.IsCombineThumbs()); m_ctrl.CombineThumbs(!m_ctrl.IsCombineThumbs());
process_thumb_move(); process_thumb_move();
} }
wxString DSManagerForLayers::get_tooltip(int tick/*=-1*/) std::string DSForLayers::get_tooltip(int tick/*=-1*/)
{ {
if (m_focus == fiNone) if (m_focus == fiNone)
return ""; return "";
if (m_focus == fiOneLayerIcon) if (m_focus == fiOneLayerIcon)
return _L("One layer mode"); return _u8L("One layer mode");
if (m_focus == fiRevertIcon) if (m_focus == fiRevertIcon)
return _L("Discard all custom changes"); return _u8L("Discard all custom changes");
if (m_focus == fiCogIcon) if (m_focus == fiCogIcon)
{ {
return m_mode == MultiAsSingle ? return m_mode == MultiAsSingle ?
GUI::from_u8((boost::format(_u8L("Jump to height %s\n" (boost::format(_u8L("Jump to height %s\n"
"Set ruler mode\n" "Set ruler mode\n"
"or Set extruder sequence for the entire print")) % "(Shift + G)").str()) : "or Set extruder sequence for the entire print")) % "(Shift + G)").str() :
GUI::from_u8((boost::format(_u8L("Jump to height %s\n" (boost::format(_u8L("Jump to height %s\n"
"or Set ruler mode")) % "(Shift + G)").str()); "or Set ruler mode")) % "(Shift + G)").str();
} }
if (m_focus == fiColorBand) if (m_focus == fiColorBand)
return m_mode != SingleExtruder ? "" : return m_mode != SingleExtruder ? "" :
_L("Edit current color - Right click the colored slider segment"); _u8L("Edit current color - Right click the colored slider segment");
if (m_focus == fiSmartWipeTower) if (m_focus == fiSmartWipeTower)
return _L("This is wipe tower layer"); return _u8L("This is wipe tower layer");
if (m_draw_mode == dmSlaPrint) if (m_draw_mode == dmSlaPrint)
return ""; // no drawn ticks and no tooltips for them in SlaPrinting mode return ""; // no drawn ticks and no tooltips for them in SlaPrinting mode
wxString tooltip; std::string tooltip;
const auto tick_code_it = m_ticks.ticks.find(TickCode{tick}); const auto tick_code_it = m_ticks.ticks.find(TickCode{tick});
if (tick_code_it == m_ticks.ticks.end() && m_focus == fiActionIcon) // tick doesn't exist if (tick_code_it == m_ticks.ticks.end() && m_focus == fiActionIcon) // tick doesn't exist
{ {
if (m_draw_mode == dmSequentialFffPrint) if (m_draw_mode == dmSequentialFffPrint)
return (_L("The sequential print is on.\n" return (_u8L("The sequential print is on.\n"
"It's impossible to apply any custom G-code for objects printing sequentually.") + "\n"); "It's impossible to apply any custom G-code for objects printing sequentually.") + "\n");
// Show mode as a first string of tooltop // Show mode as a first string of tooltop
tooltip = " " + _L("Print mode") + ": "; tooltip = " " + _u8L("Print mode") + ": ";
tooltip += (m_mode == SingleExtruder ? SingleExtruderMode : tooltip += (m_mode == SingleExtruder ? SingleExtruderMode :
m_mode == MultiAsSingle ? MultiAsSingleMode : m_mode == MultiAsSingle ? MultiAsSingleMode :
MultiExtruderMode ); MultiExtruderMode );
@ -742,28 +743,28 @@ wxString DSManagerForLayers::get_tooltip(int tick/*=-1*/)
// Show list of actions with new tick // Show list of actions with new tick
tooltip += ( m_mode == MultiAsSingle ? tooltip += ( m_mode == MultiAsSingle ?
_L("Add extruder change - Left click") : _u8L("Add extruder change - Left click") :
m_mode == SingleExtruder ? m_mode == SingleExtruder ?
_L("Add color change - Left click for predefined color or " _u8L("Add color change - Left click for predefined color or "
"Shift + Left click for custom color selection") : "Shift + Left click for custom color selection") :
_L("Add color change - Left click") ) + " " + _u8L("Add color change - Left click") ) + " " +
_L("or press \"+\" key") + "\n" + ( _u8L("or press \"+\" key") + "\n" + (
is_osx ? is_osx ?
_L("Add another code - Ctrl + Left click") : _u8L("Add another code - Ctrl + Left click") :
_L("Add another code - Right click") ); _u8L("Add another code - Right click") );
} }
if (tick_code_it != m_ticks.ticks.end()) // tick exists if (tick_code_it != m_ticks.ticks.end()) // tick exists
{ {
if (m_draw_mode == dmSequentialFffPrint) if (m_draw_mode == dmSequentialFffPrint)
return _L("The sequential print is on.\n" return _u8L("The sequential print is on.\n"
"It's impossible to apply any custom G-code for objects printing sequentually.\n" "It's impossible to apply any custom G-code for objects printing sequentually.\n"
"This code won't be processed during G-code generation."); "This code won't be processed during G-code generation.");
// Show custom Gcode as a first string of tooltop // Show custom Gcode as a first string of tooltop
std::string space = " "; std::string space = " ";
tooltip = space; tooltip = space;
auto format_gcode = [space](std::string gcode) { auto format_gcode = [space](std::string gcode) -> std::string {
// when the tooltip is too long, it starts to flicker, see: https://github.com/prusa3d/PrusaSlicer/issues/7368 // when the tooltip is too long, it starts to flicker, see: https://github.com/prusa3d/PrusaSlicer/issues/7368
// so we limit the number of lines shown // so we limit the number of lines shown
std::vector<std::string> lines; std::vector<std::string> lines;
@ -782,50 +783,50 @@ wxString DSManagerForLayers::get_tooltip(int tick/*=-1*/)
tooltip += tooltip +=
tick_code_it->type == ColorChange ? tick_code_it->type == ColorChange ?
(m_mode == SingleExtruder ? (m_mode == SingleExtruder ?
format_wxstr(_L("Color change (\"%1%\")"), gcode(ColorChange)) : GUI::format(_L("Color change (\"%1%\")"), gcode(ColorChange)) :
format_wxstr(_L("Color change (\"%1%\") for Extruder %2%"), gcode(ColorChange), tick_code_it->extruder)) : GUI::format(_L("Color change (\"%1%\") for Extruder %2%"), gcode(ColorChange), tick_code_it->extruder)) :
tick_code_it->type == PausePrint ? tick_code_it->type == PausePrint ?
format_wxstr(_L("Pause print (\"%1%\")"), gcode(PausePrint)) : GUI::format(_L("Pause print (\"%1%\")"), gcode(PausePrint)) :
tick_code_it->type == Template ? tick_code_it->type == Template ?
format_wxstr(_L("Custom template (\"%1%\")"), gcode(Template)) : GUI::format(_L("Custom template (\"%1%\")"), gcode(Template)) :
tick_code_it->type == ToolChange ? tick_code_it->type == ToolChange ?
format_wxstr(_L("Extruder (tool) is changed to Extruder \"%1%\""), tick_code_it->extruder) : GUI::format(_L("Extruder (tool) is changed to Extruder \"%1%\""), tick_code_it->extruder) :
from_u8(format_gcode(tick_code_it->extra));// tick_code_it->type == Custom format_gcode(tick_code_it->extra);// tick_code_it->type == Custom
// If tick is marked as a conflict (exclamation icon), // If tick is marked as a conflict (exclamation icon),
// we should to explain why // we should to explain why
ConflictType conflict = m_ticks.is_conflict_tick(*tick_code_it, m_mode, m_only_extruder, m_values[tick]); ConflictType conflict = m_ticks.is_conflict_tick(*tick_code_it, m_mode, m_only_extruder, m_values[tick]);
if (conflict != ctNone) if (conflict != ctNone)
tooltip += "\n\n" + _L("Note") + "! "; tooltip += "\n\n" + _u8L("Note") + "! ";
if (conflict == ctModeConflict) if (conflict == ctModeConflict)
tooltip += _L("G-code associated to this tick mark is in a conflict with print mode.\n" tooltip += _u8L("G-code associated to this tick mark is in a conflict with print mode.\n"
"Editing it will cause changes of Slider data."); "Editing it will cause changes of Slider data.");
else if (conflict == ctMeaninglessColorChange) else if (conflict == ctMeaninglessColorChange)
tooltip += _L("There is a color change for extruder that won't be used till the end of print job.\n" tooltip += _u8L("There is a color change for extruder that won't be used till the end of print job.\n"
"This code won't be processed during G-code generation."); "This code won't be processed during G-code generation.");
else if (conflict == ctMeaninglessToolChange) else if (conflict == ctMeaninglessToolChange)
tooltip += _L("There is an extruder change set to the same extruder.\n" tooltip += _u8L("There is an extruder change set to the same extruder.\n"
"This code won't be processed during G-code generation."); "This code won't be processed during G-code generation.");
else if (conflict == ctRedundant) else if (conflict == ctRedundant)
tooltip += _L("There is a color change for extruder that has not been used before.\n" tooltip += _u8L("There is a color change for extruder that has not been used before.\n"
"Check your settings to avoid redundant color changes."); "Check your settings to avoid redundant color changes.");
// Show list of actions with existing tick // Show list of actions with existing tick
if (m_focus == fiActionIcon) if (m_focus == fiActionIcon)
tooltip += "\n\n" + _L("Delete tick mark - Left click or press \"-\" key") + "\n" + ( tooltip += "\n\n" + _u8L("Delete tick mark - Left click or press \"-\" key") + "\n" + (
is_osx ? is_osx ?
_L("Edit tick mark - Ctrl + Left click") : _u8L("Edit tick mark - Ctrl + Left click") :
_L("Edit tick mark - Right click") ); _u8L("Edit tick mark - Right click") );
} }
return tooltip;
return tooltip;
} }
void DSManagerForLayers::append_change_extruder_menu_item(wxMenu* menu, bool switch_current_code/* = false*/) void DSForLayers::append_change_extruder_menu_item(wxMenu* menu, bool switch_current_code/* = false*/)
{ {
const int extruders_cnt = GUI::wxGetApp().extruders_edited_cnt(); const int extruders_cnt = GUI::wxGetApp().extruders_edited_cnt();
if (extruders_cnt > 1) { if (extruders_cnt > 1) {
std::array<int, 2> active_extruders = get_active_extruders_for_tick(imgui_ctrl.GetActiveValue()); std::array<int, 2> active_extruders = get_active_extruders_for_tick(m_ctrl.GetActivePos());
std::vector<wxBitmapBundle*> icons = get_extruder_color_icons(true); std::vector<wxBitmapBundle*> icons = get_extruder_color_icons(true);
@ -848,15 +849,15 @@ void DSManagerForLayers::append_change_extruder_menu_item(wxMenu* menu, bool swi
append_submenu(menu, change_extruder_menu, wxID_ANY, change_extruder_menu_name, _L("Use another extruder"), append_submenu(menu, change_extruder_menu, wxID_ANY, change_extruder_menu_name, _L("Use another extruder"),
active_extruders[1] > 0 ? "edit_uni" : "change_extruder", active_extruders[1] > 0 ? "edit_uni" : "change_extruder",
[this]() {return m_mode == MultiAsSingle && !GUI::wxGetApp().obj_list()->has_paint_on_segmentation(); }, GUI::wxGetApp().plater()); [this]() {return m_mode == MultiAsSingle /*&& !GUI::wxGetApp().obj_list()->has_paint_on_segmentation()*/; }, GUI::wxGetApp().plater()); // !ysFIXME has_paint_on_segmentation
} }
} }
void DSManagerForLayers::append_add_color_change_menu_item(wxMenu* menu, bool switch_current_code/* = false*/) void DSForLayers::append_add_color_change_menu_item(wxMenu* menu, bool switch_current_code/* = false*/)
{ {
const int extruders_cnt = GUI::wxGetApp().extruders_edited_cnt(); const int extruders_cnt = GUI::wxGetApp().extruders_edited_cnt();
if (extruders_cnt > 1) { if (extruders_cnt > 1) {
int tick = imgui_ctrl.GetActiveValue(); int tick = m_ctrl.GetActivePos();
std::set<int> used_extruders_for_tick = m_ticks.get_used_extruders_for_tick(tick, m_only_extruder, m_values[tick]); std::set<int> used_extruders_for_tick = m_ticks.get_used_extruders_for_tick(tick, m_only_extruder, m_values[tick]);
wxMenu* add_color_change_menu = new wxMenu(); wxMenu* add_color_change_menu = new wxMenu();
@ -880,7 +881,7 @@ void DSManagerForLayers::append_add_color_change_menu_item(wxMenu* menu, bool sw
} }
} }
void DSManagerForLayers::UseDefaultColors(bool def_colors_on) void DSForLayers::UseDefaultColors(bool def_colors_on)
{ {
m_ticks.set_default_colors(def_colors_on); m_ticks.set_default_colors(def_colors_on);
} }
@ -889,7 +890,7 @@ void DSManagerForLayers::UseDefaultColors(bool def_colors_on)
// Means one current extruder for not existing tick OR // Means one current extruder for not existing tick OR
// 2 extruders - for existing tick (extruder before ToolChange and extruder of current existing tick) // 2 extruders - for existing tick (extruder before ToolChange and extruder of current existing tick)
// Use those values to disable selection of active extruders // Use those values to disable selection of active extruders
std::array<int, 2> DSManagerForLayers::get_active_extruders_for_tick(int tick) const std::array<int, 2> DSForLayers::get_active_extruders_for_tick(int tick) const
{ {
int default_initial_extruder = m_mode == MultiAsSingle ? std::max<int>(1, m_only_extruder) : 1; int default_initial_extruder = m_mode == MultiAsSingle ? std::max<int>(1, m_only_extruder) : 1;
std::array<int, 2> extruders = { default_initial_extruder, -1 }; std::array<int, 2> extruders = { default_initial_extruder, -1 };
@ -912,73 +913,14 @@ std::array<int, 2> DSManagerForLayers::get_active_extruders_for_tick(int tick) c
return extruders; return extruders;
} }
// Get used extruders for tick. void DSForLayers::show_cog_icon_context_menu()
// Means all extruders(tools) which will be used during printing from current tick to the end
std::set<int> TickCodeInfo::get_used_extruders_for_tick(int tick, int only_extruder, double print_z, Mode force_mode/* = Undef*/) const
{
Mode e_mode = !force_mode ? mode : force_mode;
if (e_mode == MultiExtruder) {
// #ys_FIXME: get tool ordering from _correct_ place
const ToolOrdering& tool_ordering = GUI::wxGetApp().plater()->fff_print().get_tool_ordering();
if (tool_ordering.empty())
return {};
std::set<int> used_extruders;
auto it_layer_tools = std::lower_bound(tool_ordering.begin(), tool_ordering.end(), print_z, [](const LayerTools &lhs, double rhs){ return lhs.print_z < rhs; });
for (; it_layer_tools != tool_ordering.end(); ++it_layer_tools) {
const std::vector<unsigned>& extruders = it_layer_tools->extruders;
for (const auto& extruder : extruders)
used_extruders.emplace(extruder+1);
}
return used_extruders;
}
const int default_initial_extruder = e_mode == MultiAsSingle ? std::max(only_extruder, 1) : 1;
if (ticks.empty() || e_mode == SingleExtruder)
return {default_initial_extruder};
std::set<int> used_extruders;
auto it_start = ticks.lower_bound(TickCode{tick});
auto it = it_start;
if (it == ticks.begin() && it->type == ToolChange &&
tick != it->tick ) // In case of switch of ToolChange to ColorChange, when tick exists,
// we shouldn't change color for extruder, which will be deleted
{
used_extruders.emplace(it->extruder);
if (tick < it->tick)
used_extruders.emplace(default_initial_extruder);
}
while (it != ticks.begin()) {
--it;
if (it->type == ToolChange && tick != it->tick) {
used_extruders.emplace(it->extruder);
break;
}
}
if (it == ticks.begin() && used_extruders.empty())
used_extruders.emplace(default_initial_extruder);
for (it = it_start; it != ticks.end(); ++it)
if (it->type == ToolChange && tick != it->tick)
used_extruders.emplace(it->extruder);
return used_extruders;
}
void DSManagerForLayers::show_cog_icon_context_menu()
{ {
wxMenu menu; wxMenu menu;
append_menu_item(&menu, wxID_ANY, _L("Jump to height") + " (Shift+G)", "", append_menu_item(&menu, wxID_ANY, _L("Jump to height") + " (Shift+G)", "",
[this](wxCommandEvent&) { jump_to_value(); }, "", & menu); [this](wxCommandEvent&) { jump_to_value(); }, "", & menu);
if (m_allow_editing)
append_menu_check_item(&menu, wxID_ANY, _L("Use default colors"), _L("Use default colors on color change"), append_menu_check_item(&menu, wxID_ANY, _L("Use default colors"), _L("Use default colors on color change"),
[this](wxCommandEvent&) { [this](wxCommandEvent&) {
UseDefaultColors(!m_ticks.used_default_colors()); }, &menu, UseDefaultColors(!m_ticks.used_default_colors()); }, &menu,
@ -1025,7 +967,7 @@ bool check_color_change(const PrintObject* object, size_t frst_layer_id, size_t
return detected; return detected;
} }
void DSManagerForLayers::auto_color_change() void DSForLayers::auto_color_change()
{ {
if (!m_ticks.empty()) { if (!m_ticks.empty()) {
wxString msg_text = _L("This action will cause deletion of all ticks on vertical slider.") + "\n\n" + wxString msg_text = _L("This action will cause deletion of all ticks on vertical slider.") + "\n\n" +
@ -1072,9 +1014,9 @@ void DSManagerForLayers::auto_color_change()
if (m_ticks.empty()) if (m_ticks.empty())
GUI::wxGetApp().plater()->get_notification_manager()->push_notification(GUI::NotificationType::EmptyAutoColorChange); GUI::wxGetApp().plater()->get_notification_manager()->push_notification(GUI::NotificationType::EmptyAutoColorChange);
update_callbacks(); update_draw_scroll_line_cb();
post_ticks_changed_event(); process_ticks_changed();
} }
static std::string get_new_color(const std::string& color) static std::string get_new_color(const std::string& color)
@ -1149,7 +1091,7 @@ static std::string get_custom_code(const std::string& code_in, double height)
return ""; return "";
value = into_u8(dlg.GetValue()); value = into_u8(dlg.GetValue());
valid = GUI::Tab::validate_custom_gcode("Custom G-code", value); valid = true;// GUI::Tab::validate_custom_gcode("Custom G-code", value); // !ysFIXME validate_custom_gcode
} while (!valid); } while (!valid);
return value; return value;
} }
@ -1170,11 +1112,12 @@ static std::string get_pause_print_msg(const std::string& msg_in, double height)
return into_u8(dlg.GetValue()); return into_u8(dlg.GetValue());
} }
// draw with imgui
static double get_value_to_jump(double active_value, double min_z, double max_z, DrawMode mode) static double get_value_to_jump(double active_value, double min_z, double max_z, DrawMode mode)
{ {
wxString msg_text = _L("Enter the height you want to jump to") + ":"; wxString msg_text = _L("Enter the height you want to jump to") + ":";
wxString msg_header = _L("Jump to height"); wxString msg_header = _L("Jump to height");
wxString msg_in = GUI::double_to_string(active_value); wxString msg_in = "";// GUI::double_to_string(active_value);
// get custom gcode // get custom gcode
wxTextEntryDialog dlg(nullptr, msg_text, msg_header, msg_in, wxTextEntryDialogStyle); wxTextEntryDialog dlg(nullptr, msg_text, msg_header, msg_in, wxTextEntryDialogStyle);
@ -1187,9 +1130,9 @@ static double get_value_to_jump(double active_value, double min_z, double max_z,
return dlg.GetValue().ToDouble(&value) ? value : -1.0; return dlg.GetValue().ToDouble(&value) ? value : -1.0;
} }
void DSManagerForLayers::add_code_as_tick(Type type, int selected_extruder/* = -1*/) void DSForLayers::add_code_as_tick(Type type, int selected_extruder/* = -1*/)
{ {
const int tick = imgui_ctrl.GetActiveValue(); const int tick = m_ctrl.GetActivePos();
if ( !check_ticks_changed_event(type) ) if ( !check_ticks_changed_event(type) )
return; return;
@ -1216,14 +1159,17 @@ void DSManagerForLayers::add_code_as_tick(Type type, int selected_extruder/* = -
return; return;
if (was_ticks != m_ticks.empty()) if (was_ticks != m_ticks.empty())
update_callbacks(); update_draw_scroll_line_cb();
post_ticks_changed_event(type); process_ticks_changed();
} }
void DSManagerForLayers::add_current_tick(bool call_from_keyboard /*= false*/) void DSForLayers::add_current_tick()
{ {
const int tick = imgui_ctrl.GetActiveValue(); if (!m_allow_editing)
return;
const int tick = m_ctrl.GetActivePos();
auto it = m_ticks.ticks.find(TickCode{ tick }); auto it = m_ticks.ticks.find(TickCode{ tick });
if (it != m_ticks.ticks.end() || // this tick is already exist if (it != m_ticks.ticks.end() || // this tick is already exist
@ -1232,8 +1178,9 @@ void DSManagerForLayers::add_current_tick(bool call_from_keyboard /*= false*/)
if (m_mode == SingleExtruder) if (m_mode == SingleExtruder)
add_code_as_tick(ColorChange); add_code_as_tick(ColorChange);
/*
else else
render_menu();
/*
{ {
wxMenu menu; wxMenu menu;
@ -1263,43 +1210,42 @@ void DSManagerForLayers::add_current_tick(bool call_from_keyboard /*= false*/)
*/ */
} }
void DSManagerForLayers::delete_current_tick() void DSForLayers::delete_current_tick()
{ {
auto it = m_ticks.ticks.find(TickCode{ imgui_ctrl.GetActiveValue()}); auto it = m_ticks.ticks.find(TickCode{ m_ctrl.GetActivePos()});
if (it == m_ticks.ticks.end() || if (it == m_ticks.ticks.end() ||
!check_ticks_changed_event(it->type)) !check_ticks_changed_event(it->type))
return; return;
Type type = it->type; Type type = it->type;
m_ticks.ticks.erase(it); m_ticks.ticks.erase(it);
post_ticks_changed_event(type); process_ticks_changed();
} }
void DSManagerForLayers::edit_tick(int tick/* = -1*/) void DSForLayers::edit_tick(int tick/* = -1*/)
{ {
if (tick < 0) if (tick < 0)
tick = imgui_ctrl.GetActiveValue(); tick = m_ctrl.GetActivePos();
const std::set<TickCode>::iterator it = m_ticks.ticks.find(TickCode{ tick }); const std::set<TickCode>::iterator it = m_ticks.ticks.find(TickCode{ tick });
if (it == m_ticks.ticks.end() || if (it == m_ticks.ticks.end() ||
!check_ticks_changed_event(it->type)) !check_ticks_changed_event(it->type))
return; return;
Type type = it->type;
if (m_ticks.edit_tick(it, m_values[it->tick])) if (m_ticks.edit_tick(it, m_values[it->tick]))
post_ticks_changed_event(type); process_ticks_changed();
} }
// discard all custom changes on DoubleSlider // discard all custom changes on DoubleSlider
void DSManagerForLayers::discard_all_thicks() void DSForLayers::discard_all_thicks()
{ {
m_ticks.ticks.clear(); m_ticks.ticks.clear();
imgui_ctrl.ResetValues(); m_ctrl.ResetPositions();
update_callbacks(); update_draw_scroll_line_cb();
post_ticks_changed_event(); process_ticks_changed();
} }
void DSManagerForLayers::edit_extruder_sequence() void DSForLayers::edit_extruder_sequence()
{ {
if (!check_ticks_changed_event(ToolChange)) if (!check_ticks_changed_event(ToolChange))
return; return;
@ -1323,7 +1269,7 @@ void DSManagerForLayers::edit_extruder_sequence()
std::mt19937 gen(rd()); //Standard mersenne_twister_engine seeded with rd() std::mt19937 gen(rd()); //Standard mersenne_twister_engine seeded with rd()
std::uniform_int_distribution<> distrib(0, extr_cnt-1); std::uniform_int_distribution<> distrib(0, extr_cnt-1);
while (tick <= imgui_ctrl.GetMaxValue()) while (tick <= m_ctrl.GetMaxPos())
{ {
bool color_repetition = false; bool color_repetition = false;
if (m_extruders_sequence.random_sequence) { if (m_extruders_sequence.random_sequence) {
@ -1357,31 +1303,25 @@ void DSManagerForLayers::edit_extruder_sequence()
tick += m_extruders_sequence.interval_by_layers; tick += m_extruders_sequence.interval_by_layers;
} }
post_ticks_changed_event(ToolChange); process_ticks_changed();
} }
void DSManagerForLayers::jump_to_value() void DSForLayers::jump_to_value()
{ {
double value = get_value_to_jump(m_values[imgui_ctrl.GetActiveValue()], double value = get_value_to_jump(m_values[m_ctrl.GetActivePos()],
m_values[imgui_ctrl.GetMinValue()], m_values[imgui_ctrl.GetMaxValue()], m_draw_mode); m_values[m_ctrl.GetMinPos()], m_values[m_ctrl.GetMaxPos()], m_draw_mode);
if (value < 0.0) if (value < 0.0)
return; return;
int tick_value = get_tick_from_value(value); int tick_value = get_tick_from_value(value);
if (imgui_ctrl.IsActiveHigherThumb()) if (m_ctrl.IsActiveHigherThumb())
SetHigherValue(tick_value); SetHigherPos(tick_value);
else else
SetLowerValue(tick_value); SetLowerPos(tick_value);
} }
void DSManagerForLayers::post_ticks_changed_event(Type type /*= Custom*/) bool DSForLayers::check_ticks_changed_event(Type type)
{
// m_force_mode_apply = type != ToolChange; // It looks like this condition is no needed now. Leave it for the testing
process_ticks_changed();
}
bool DSManagerForLayers::check_ticks_changed_event(Type type)
{ {
if ( m_ticks.mode == m_mode || if ( m_ticks.mode == m_mode ||
(type != ColorChange && type != ToolChange) || (type != ColorChange && type != ToolChange) ||
@ -1406,7 +1346,7 @@ bool DSManagerForLayers::check_ticks_changed_event(Type type)
GUI::MessageDialog msg(nullptr, message, _L("Notice"), wxYES_NO); GUI::MessageDialog msg(nullptr, message, _L("Notice"), wxYES_NO);
if (msg.ShowModal() == wxID_YES) { if (msg.ShowModal() == wxID_YES) {
m_ticks.erase_all_ticks_with_code(ColorChange); m_ticks.erase_all_ticks_with_code(ColorChange);
post_ticks_changed_event(ColorChange); process_ticks_changed();
} }
return false; return false;
} }
@ -1427,11 +1367,11 @@ bool DSManagerForLayers::check_ticks_changed_event(Type type)
const int answer = msg.ShowModal(); const int answer = msg.ShowModal();
if (answer == wxID_YES) { if (answer == wxID_YES) {
m_ticks.erase_all_ticks_with_code(ToolChange); m_ticks.erase_all_ticks_with_code(ToolChange);
post_ticks_changed_event(ToolChange); process_ticks_changed();
} }
else if (m_mode == SingleExtruder && answer == wxID_NO) { else if (m_mode == SingleExtruder && answer == wxID_NO) {
m_ticks.switch_code(ToolChange, ColorChange); m_ticks.switch_code(ToolChange, ColorChange);
post_ticks_changed_event(ColorChange); process_ticks_changed();
} }
return false; return false;
} }
@ -1439,23 +1379,67 @@ bool DSManagerForLayers::check_ticks_changed_event(Type type)
return true; return true;
} }
DSManagerForLayers::DSManagerForLayers( int lowerValue,
int higherValue,
int minValue,
int maxValue, // Get used extruders for tick.
bool allow_editing/* = true*/) : // Means all extruders(tools) which will be used during printing from current tick to the end
m_allow_editing(allow_editing) std::set<int> TickCodeInfo::get_used_extruders_for_tick(int tick, int only_extruder, double print_z, Mode force_mode/* = Undef*/) const
{ {
#ifdef __WXOSX__ Mode e_mode = !force_mode ? mode : force_mode;
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)) : ""; }); if (e_mode == MultiExtruder) {
imgui_ctrl.set_extra_draw_cb([this](const ImRect& draw_rc) {return draw_ticks(draw_rc); }); // #ys_FIXME: get tool ordering from _correct_ place
const ToolOrdering& tool_ordering = GUI::wxGetApp().plater()->fff_print().get_tool_ordering();
m_ticks.set_pause_print_msg(_u8L("Place bearings in slots and resume printing")); if (tool_ordering.empty())
m_ticks.set_extruder_colors(&m_extruder_colors); return {};
std::set<int> used_extruders;
auto it_layer_tools = std::lower_bound(tool_ordering.begin(), tool_ordering.end(), print_z, [](const LayerTools& lhs, double rhs) { return lhs.print_z < rhs; });
for (; it_layer_tools != tool_ordering.end(); ++it_layer_tools) {
const std::vector<unsigned>& extruders = it_layer_tools->extruders;
for (const auto& extruder : extruders)
used_extruders.emplace(extruder + 1);
}
return used_extruders;
}
const int default_initial_extruder = e_mode == MultiAsSingle ? std::max(only_extruder, 1) : 1;
if (ticks.empty() || e_mode == SingleExtruder)
return { default_initial_extruder };
std::set<int> used_extruders;
auto it_start = ticks.lower_bound(TickCode{ tick });
auto it = it_start;
if (it == ticks.begin() && it->type == ToolChange &&
tick != it->tick) // In case of switch of ToolChange to ColorChange, when tick exists,
// we shouldn't change color for extruder, which will be deleted
{
used_extruders.emplace(it->extruder);
if (tick < it->tick)
used_extruders.emplace(default_initial_extruder);
}
while (it != ticks.begin()) {
--it;
if (it->type == ToolChange && tick != it->tick) {
used_extruders.emplace(it->extruder);
break;
}
}
if (it == ticks.begin() && used_extruders.empty())
used_extruders.emplace(default_initial_extruder);
for (it = it_start; it != ticks.end(); ++it)
if (it->type == ToolChange && tick != it->tick)
used_extruders.emplace(it->extruder);
return used_extruders;
} }
std::string TickCodeInfo::get_color_for_tick(TickCode tick, Type type, const int extruder) std::string TickCodeInfo::get_color_for_tick(TickCode tick, Type type, const int extruder)

View File

@ -2,8 +2,8 @@
///|/ ///|/
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher ///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
///|/ ///|/
#ifndef slic3r_GUI_DoubleSlider_hpp_ #ifndef slic3r_GUI_DoubleSliderForLayers_hpp_
#define slic3r_GUI_DoubleSlider_hpp_ #define slic3r_GUI_DoubleSliderForLayers_hpp_
#include "libslic3r/CustomGCode.hpp" #include "libslic3r/CustomGCode.hpp"
#include "ImGuiDoubleSlider.hpp" #include "ImGuiDoubleSlider.hpp"
@ -23,11 +23,6 @@ namespace DoubleSlider {
using namespace GUI; using namespace GUI;
/* For exporting GCode in GCodeWriter is used XYZF_NUM(val) = PRECISION(val, 3) for XYZ values.
* So, let use same value as a permissible error for layer height.
*/
constexpr double epsilon() { return 0.0011; }
// return true when areas are mostly equivalent // return true when areas are mostly equivalent
bool equivalent_areas(const double& bottom_area, const double& top_area); bool equivalent_areas(const double& bottom_area, const double& top_area);
@ -60,20 +55,6 @@ enum ConflictType
ctRedundant ctRedundant
}; };
enum MouseAction
{
maNone,
maAddMenu, // show "Add" context menu for NOTexist active tick
maEditMenu, // show "Edit" context menu for exist active tick
maCogIconMenu, // show context for "cog" icon
maForceColorEdit, // force color editing from colored band
maAddTick, // force tick adding
maDeleteTick, // force tick deleting
maCogIconClick, // LeftMouseClick on "cog" icon
maOneLayerIconClick, // LeftMouseClick on "one_layer" icon
maRevertIconClick, // LeftMouseClick on "revert" icon
};
enum DrawMode enum DrawMode
{ {
dmRegular, dmRegular,
@ -192,148 +173,17 @@ struct ExtrudersSequence
} }
}; };
template<typename ValType>
class DSManager_t class DSForLayers : public Manager<double>
{ {
public: public:
DSForLayers() : Manager<double>() {}
void Init( int lowerValue, DSForLayers(int lowerValue,
int higherValue, int higherValue,
int minValue, int minValue,
int maxValue, int maxValue,
const std::string& name, bool allow_editing);
bool is_horizontal) ~DSForLayers() {}
{
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(); }
int GetLowerValue() const { return imgui_ctrl.GetLowerValue(); }
int GetHigherValue()const { return imgui_ctrl.GetHigherValue(); }
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) {
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 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 Show(bool show = true) { imgui_ctrl.Show(show); }
void Hide() { 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(); void ChangeOneLayerLock();
@ -349,35 +199,38 @@ public:
void SetModeAndOnlyExtruder(const bool is_one_extruder_printed_model, const int only_extruder); void SetModeAndOnlyExtruder(const bool is_one_extruder_printed_model, const int only_extruder);
void SetExtruderColors(const std::vector<std::string>& extruder_colors); void SetExtruderColors(const std::vector<std::string>& extruder_colors);
void UseDefaultColors(bool def_colors_on); void UseDefaultColors(bool def_colors_on);
void add_code_as_tick(Type type, int selected_extruder = -1);
// add default action for tick, when press "+"
void add_current_tick(bool call_from_keyboard = false);
// delete current tick, when press "-"
void delete_current_tick();
void edit_tick(int tick = -1);
void discard_all_thicks();
void edit_extruder_sequence();
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 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); bool IsNewPrint(const std::string& print_obj_idxs);
void Render(const int canvas_width, const int canvas_height, float extra_scale = 1.f) override;
void set_callback_on_ticks_changed(std::function<void()> cb) { m_cb_ticks_changed = cb; };
// manipulation with slider from keyboard
// add default action for tick, when press "+"
void add_current_tick();
// delete current tick, when press "-"
void delete_current_tick();
// process adding of auto color change
void auto_color_change();
// jump to selected layer
void jump_to_value();
private: private:
void add_code_as_tick(Type type, int selected_extruder = -1);
void edit_tick(int tick = -1);
void discard_all_thicks();
void edit_extruder_sequence();
void show_cog_icon_context_menu();
bool is_wipe_tower_layer(int tick) const; bool is_wipe_tower_layer(int tick) const;
std::string get_label(int tick, LabelType label_type = ltHeightWithLayer) const; std::string get_label(int tick, LabelType label_type = ltHeightWithLayer) const;
int get_tick_from_value(double value, bool force_lower_bound = false); int get_tick_from_value(double value, bool force_lower_bound = false);
wxString get_tooltip(int tick = -1); std::string 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_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; std::string get_color_for_color_change_tick(std::set<TickCode>::const_iterator it) const;
@ -393,48 +246,44 @@ private:
// Use those values to disable selection of active extruders // Use those values to disable selection of active extruders
std::array<int, 2> get_active_extruders_for_tick(int tick) const; std::array<int, 2> get_active_extruders_for_tick(int tick) const;
void post_ticks_changed_event(Type type = Custom);
bool check_ticks_changed_event(Type type); 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); // ysFIXME !
void append_add_color_change_menu_item(wxMenu*, bool switch_current_code = false); void append_add_color_change_menu_item(wxMenu*, bool switch_current_code = false); // ysFIXME !
bool is_osx{ false }; bool is_osx { false };
bool m_allow_editing{ true }; bool m_allow_editing { true };
bool m_is_wipe_tower { false }; //This flag indicates that there is multiple extruder print with wipe tower
bool m_show_estimated_times { false };
bool m_force_mode_apply = true; DrawMode m_draw_mode { dmRegular };
bool m_enable_action_icon = true; Mode m_mode { SingleExtruder };
bool m_is_wipe_tower = false; //This flag indicates that there is multiple extruder print with wipe tower FocusedItem m_focus { fiNone };
DrawMode m_draw_mode { dmRegular }; int m_only_extruder { -1 };
Mode m_mode = SingleExtruder;
int m_only_extruder = -1;
MouseAction m_mouse = maNone;
FocusedItem m_focus = fiNone;
bool m_show_estimated_times{ false };
TickCodeInfo m_ticks;
std::vector<double> m_layers_times;
std::vector<double> m_layers_values;
std::vector<std::string> m_extruder_colors;
ExtrudersSequence m_extruders_sequence;
std::function<void()> m_cb_ticks_changed{ nullptr };
std::string m_print_obj_idxs; std::string m_print_obj_idxs;
// ImGuiDS std::vector<double> m_layers_times;
std::vector<double> m_layers_values;
std::vector<std::string> m_extruder_colors;
TickCodeInfo m_ticks;
ExtrudersSequence m_extruders_sequence;
std::function<void()> m_cb_ticks_changed{ nullptr };
bool m_can_change_color{ true }; bool m_can_change_color{ true };
// functions for extend rendering of m_ctrl
void draw_colored_band(const ImRect& groove, const ImRect& slideable_region); void draw_colored_band(const ImRect& groove, const ImRect& slideable_region);
void draw_ticks(const ImRect& slideable_region); void draw_ticks(const ImRect& slideable_region);
void render_menu(); 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); 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();
void update_draw_scroll_line_cb();
}; };
} // DoubleSlider; } // DoubleSlider;
@ -443,4 +292,4 @@ private:
#endif // slic3r_GUI_DoubleSlider_hpp_ #endif // slic3r_GUI_DoubleSliderForLayers_hpp_

View File

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

View File

@ -14,6 +14,7 @@
#include "libslic3r/Utils.hpp" #include "libslic3r/Utils.hpp"
#include "libslic3r/LocalesUtils.hpp" #include "libslic3r/LocalesUtils.hpp"
#include "libslic3r/PresetBundle.hpp" #include "libslic3r/PresetBundle.hpp"
#include "libslic3r/CustomGCode.hpp"
#include "slic3r/GUI/format.hpp" #include "slic3r/GUI/format.hpp"
@ -24,7 +25,6 @@
#include "I18N.hpp" #include "I18N.hpp"
#include "GUI_Utils.hpp" #include "GUI_Utils.hpp"
#include "GUI.hpp" #include "GUI.hpp"
#include "DoubleSlider.hpp"
#include "GLCanvas3D.hpp" #include "GLCanvas3D.hpp"
#include "GLToolbar.hpp" #include "GLToolbar.hpp"
#include "GUI_Preview.hpp" #include "GUI_Preview.hpp"
@ -2120,12 +2120,12 @@ void GCodeViewer::render_legend(float& legend_height)
if (extruder_id + 1 != static_cast<unsigned char>(item.extruder)) if (extruder_id + 1 != static_cast<unsigned char>(item.extruder))
continue; continue;
if (item.type != ColorChange) if (item.type != CustomGCode::ColorChange)
continue; continue;
const std::vector<float> zs = m_viewer.get_layers_zs(); const std::vector<float> zs = m_viewer.get_layers_zs();
auto lower_b = std::lower_bound(zs.begin(), zs.end(), auto lower_b = std::lower_bound(zs.begin(), zs.end(),
static_cast<float>(item.print_z - Slic3r::DoubleSlider::epsilon())); static_cast<float>(item.print_z - Slic3r::CustomGCode::epsilon()));
if (lower_b == zs.end()) if (lower_b == zs.end())
continue; continue;

View File

@ -19,7 +19,8 @@
#include "OpenGLManager.hpp" #include "OpenGLManager.hpp"
#include "GLCanvas3D.hpp" #include "GLCanvas3D.hpp"
#include "libslic3r/PresetBundle.hpp" #include "libslic3r/PresetBundle.hpp"
#include "DoubleSlider.hpp" #include "DoubleSliderForGcode.hpp"
#include "DoubleSliderForLayers.hpp"
#include "Plater.hpp" #include "Plater.hpp"
#include "MainFrame.hpp" #include "MainFrame.hpp"
#include "format.hpp" #include "format.hpp"
@ -197,8 +198,8 @@ Preview::Preview(
void Preview::set_layers_slider_values_range(int bottom, int top) void Preview::set_layers_slider_values_range(int bottom, int top)
{ {
m_layers_slider->SetHigherValue(std::min(top, m_layers_slider->GetMaxValue())); m_layers_slider->SetHigherPos(std::min(top, m_layers_slider->GetMaxPos()));
m_layers_slider->SetLowerValue(std::max(bottom, m_layers_slider->GetMinValue())); m_layers_slider->SetLowerPos(std::max(bottom, m_layers_slider->GetMinPos()));
} }
bool Preview::init(wxWindow* parent, Bed3D& bed, Model* model) bool Preview::init(wxWindow* parent, Bed3D& bed, Model* model)
@ -314,6 +315,8 @@ void Preview::reload_print()
void Preview::msw_rescale() void Preview::msw_rescale()
{ {
m_layers_slider->SetEmUnit(wxGetApp().em_unit());
m_moves_slider->SetEmUnit(wxGetApp().em_unit());
// rescale warning legend on the canvas // rescale warning legend on the canvas
get_canvas3d()->msw_rescale(); get_canvas3d()->msw_rescale();
@ -328,9 +331,9 @@ void Preview::render_sliders(GLCanvas3D& canvas, float extra_scale/* = 0.1f*/)
const int canvas_height = cnv_size.get_height(); const int canvas_height = cnv_size.get_height();
if (m_layers_slider) if (m_layers_slider)
m_layers_slider->imgui_render(canvas_width, canvas_height, extra_scale); m_layers_slider->Render(canvas_width, canvas_height, extra_scale);
if (m_moves_slider) if (m_moves_slider)
m_moves_slider->imgui_render(canvas_width, canvas_height, extra_scale); m_moves_slider->Render(canvas_width, canvas_height, extra_scale);
} }
void Preview::bind_event_handlers() void Preview::bind_event_handlers()
@ -358,13 +361,12 @@ void Preview::create_sliders()
{ {
// Layers Slider // Layers Slider
m_layers_slider = new DoubleSlider::DSManagerForLayers(0, 0, 0, 100, wxGetApp().is_editor()); m_layers_slider = new DoubleSlider::DSForLayers(0, 0, 0, 100, wxGetApp().is_editor());
m_layers_slider->SetEmUnit(wxGetApp().em_unit());
m_layers_slider->SetDrawMode(wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA, 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());
m_layers_slider->set_callback_on_thumb_move( [this]() -> void { Preview::on_layers_slider_scroll_changed(); } ); m_layers_slider->set_callback_on_thumb_move( [this]() -> void { Preview::on_layers_slider_scroll_changed(); } );
m_layers_slider->set_callback_on_ticks_changed( [this]() -> void { m_layers_slider->set_callback_on_ticks_changed( [this]() -> void {
@ -378,7 +380,8 @@ void Preview::create_sliders()
// Move Gcode Slider // Move Gcode Slider
m_moves_slider = new DoubleSlider::DSManagerForGcode(0, 0, 0, 100); m_moves_slider = new DoubleSlider::DSForGcode(0, 0, 0, 100);
m_moves_slider->SetEmUnit(wxGetApp().em_unit());
m_moves_slider->set_callback_on_thumb_move([this]() ->void { Preview::on_moves_slider_scroll_changed(); }); m_moves_slider->set_callback_on_thumb_move([this]() ->void { Preview::on_moves_slider_scroll_changed(); });
@ -423,7 +426,7 @@ void Preview::check_layers_slider_values(std::vector<CustomGCode::Item>& ticks_f
ticks_from_model.erase(std::remove_if(ticks_from_model.begin(), ticks_from_model.end(), ticks_from_model.erase(std::remove_if(ticks_from_model.begin(), ticks_from_model.end(),
[layers_z](CustomGCode::Item val) [layers_z](CustomGCode::Item val)
{ {
auto it = std::lower_bound(layers_z.begin(), layers_z.end(), val.print_z - DoubleSlider::epsilon()); auto it = std::lower_bound(layers_z.begin(), layers_z.end(), val.print_z - CustomGCode::epsilon());
return it == layers_z.end(); return it == layers_z.end();
}), }),
ticks_from_model.end()); ticks_from_model.end());
@ -434,17 +437,17 @@ void Preview::check_layers_slider_values(std::vector<CustomGCode::Item>& ticks_f
void Preview::update_layers_slider(const std::vector<double>& layers_z, bool keep_z_range) void Preview::update_layers_slider(const std::vector<double>& layers_z, bool keep_z_range)
{ {
// Save the initial slider span. // Save the initial slider span.
double z_low = m_layers_slider->GetLowerValueD(); double z_low = m_layers_slider->GetLowerValue();
double z_high = m_layers_slider->GetHigherValueD(); double z_high = m_layers_slider->GetHigherValue();
bool was_empty = m_layers_slider->GetMaxValue() == 0; bool was_empty = m_layers_slider->GetMaxPos() == 0;
bool force_sliders_full_range = was_empty; bool force_sliders_full_range = was_empty;
if (!keep_z_range) { if (!keep_z_range) {
bool span_changed = layers_z.empty() || std::abs(layers_z.back() - m_layers_slider->GetMaxValueD()) > DoubleSlider::epsilon()/*1e-6*/; bool span_changed = layers_z.empty() || std::abs(layers_z.back() - m_layers_slider->GetMaxValue()) > CustomGCode::epsilon()/*1e-6*/;
force_sliders_full_range |= span_changed; force_sliders_full_range |= span_changed;
} }
bool snap_to_min = force_sliders_full_range || m_layers_slider->is_lower_at_min(); bool snap_to_min = force_sliders_full_range || m_layers_slider->IsLowerAtMin();
bool snap_to_max = force_sliders_full_range || m_layers_slider->is_higher_at_max(); bool snap_to_max = force_sliders_full_range || m_layers_slider->IsHigherAtMax();
// Detect and set manipulation mode for double slider // Detect and set manipulation mode for double slider
update_layers_slider_mode(); update_layers_slider_mode();
@ -462,19 +465,19 @@ void Preview::update_layers_slider(const std::vector<double>& layers_z, bool kee
//first of all update extruder colors to avoid crash, when we are switching printer preset from MM to SM //first of all update extruder colors to avoid crash, when we are switching printer preset from MM to SM
m_layers_slider->SetExtruderColors(plater->get_extruder_colors_from_plater_config(wxGetApp().is_editor() ? nullptr : m_gcode_result)); m_layers_slider->SetExtruderColors(plater->get_extruder_colors_from_plater_config(wxGetApp().is_editor() ? nullptr : m_gcode_result));
m_layers_slider->SetSliderValues(layers_z); m_layers_slider->SetSliderValues(layers_z);
assert(m_layers_slider->GetMinValue() == 0); assert(m_layers_slider->GetMinPos() == 0);
m_layers_slider->SetMaxValue(layers_z.empty() ? 0 : layers_z.size() - 1); m_layers_slider->SetMaxPos(layers_z.empty() ? 0 : layers_z.size() - 1);
int idx_low = 0; int idx_low = 0;
int idx_high = m_layers_slider->GetMaxValue(); int idx_high = m_layers_slider->GetMaxPos();
if (!layers_z.empty()) { if (!layers_z.empty()) {
if (!snap_to_min) { if (!snap_to_min) {
int idx_new = find_close_layer_idx(layers_z, z_low, DoubleSlider::epsilon()/*1e-6*/); int idx_new = find_close_layer_idx(layers_z, z_low, CustomGCode::epsilon()/*1e-6*/);
if (idx_new != -1) if (idx_new != -1)
idx_low = idx_new; idx_low = idx_new;
} }
if (!snap_to_max) { if (!snap_to_max) {
int idx_new = find_close_layer_idx(layers_z, z_high, DoubleSlider::epsilon()/*1e-6*/); int idx_new = find_close_layer_idx(layers_z, z_high, CustomGCode::epsilon()/*1e-6*/);
if (idx_new != -1) if (idx_new != -1)
idx_high = idx_new; idx_high = idx_new;
} }
@ -625,17 +628,19 @@ void Preview::update_layers_slider_mode()
void Preview::reset_layers_slider() void Preview::reset_layers_slider()
{ {
m_layers_slider->SetHigherValue(0); m_layers_slider->SetHigherPos(0);
m_layers_slider->SetLowerValue(0); m_layers_slider->SetLowerPos(0);
} }
void Preview::update_sliders_from_canvas(wxKeyEvent& event) void Preview::update_sliders_from_canvas(wxKeyEvent& event)
{ {
const auto key = event.GetKeyCode(); const auto key = event.GetKeyCode();
if (key == WXK_NUMPAD_ADD || key == '+') const bool can_edit = wxGetApp().is_editor();
m_layers_slider->add_current_tick(true);
else if (key == WXK_NUMPAD_SUBTRACT || key == WXK_DELETE || key == WXK_BACK || key == '-') if (can_edit && (key == WXK_NUMPAD_ADD || key == '+'))
m_layers_slider->add_current_tick();
else if (can_edit && (key == WXK_NUMPAD_SUBTRACT || key == WXK_DELETE || key == WXK_BACK || key == '-'))
m_layers_slider->delete_current_tick(); m_layers_slider->delete_current_tick();
else if (key == 'G' || key == 'g') else if (key == 'G' || key == 'g')
m_layers_slider->jump_to_value(); m_layers_slider->jump_to_value();
@ -662,12 +667,12 @@ void Preview::update_sliders_from_canvas(wxKeyEvent& event)
} }
else 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; const int new_pos = key == 'W' ? m_layers_slider->GetHigherPos() + 1 : m_layers_slider->GetHigherPos() - 1;
m_layers_slider->SetHigherValue(new_pos); m_layers_slider->SetHigherPos(new_pos);
} }
else if (key == 'A' || key == 'D') { else if (key == 'A' || key == 'D') {
const int new_pos = key == 'D' ? m_moves_slider->GetHigherValue() + 1 : m_moves_slider->GetHigherValue() - 1; const int new_pos = key == 'D' ? m_moves_slider->GetHigherPos() + 1 : m_moves_slider->GetHigherPos() - 1;
m_moves_slider->SetHigherValue(new_pos); m_moves_slider->SetHigherPos(new_pos);
} }
else if (key == 'X') else if (key == 'X')
m_layers_slider->ChangeOneLayerLock(); m_layers_slider->ChangeOneLayerLock();
@ -726,8 +731,10 @@ void Preview::update_moves_slider(std::optional<int> visible_range_min, std::opt
m_moves_slider->SetSliderValues(values); m_moves_slider->SetSliderValues(values);
m_moves_slider->SetSliderAlternateValues(alternate_values); m_moves_slider->SetSliderAlternateValues(alternate_values);
m_moves_slider->SetMaxValue(static_cast<int>(values.size()) - 1); m_moves_slider->SetMaxPos(static_cast<int>(values.size()) - 1);
m_moves_slider->SetSelectionSpan(span_min_id, span_max_id); m_moves_slider->SetSelectionSpan(span_min_id, span_max_id);
m_moves_slider->ShowLowerThumb(get_app_config()->get("seq_top_layer_only") == "0");
} }
void Preview::enable_moves_slider(bool enable) void Preview::enable_moves_slider(bool enable)
@ -888,13 +895,13 @@ void Preview::on_layers_slider_scroll_changed()
if (IsShown()) { if (IsShown()) {
PrinterTechnology tech = m_process->current_printer_technology(); PrinterTechnology tech = m_process->current_printer_technology();
if (tech == ptFFF) { if (tech == ptFFF) {
m_canvas->set_volumes_z_range({ m_layers_slider->GetLowerValueD(), m_layers_slider->GetHigherValueD() }); m_canvas->set_volumes_z_range({ m_layers_slider->GetLowerValue(), m_layers_slider->GetHigherValue() });
m_canvas->set_toolpaths_z_range({ static_cast<unsigned int>(m_layers_slider->GetLowerValue()), static_cast<unsigned int>(m_layers_slider->GetHigherValue()) }); m_canvas->set_toolpaths_z_range({ static_cast<unsigned int>(m_layers_slider->GetLowerPos()), static_cast<unsigned int>(m_layers_slider->GetHigherPos()) });
m_canvas->set_as_dirty(); m_canvas->set_as_dirty();
} }
else if (tech == ptSLA) { else if (tech == ptSLA) {
m_canvas->set_clipping_plane(0, ClippingPlane(Vec3d::UnitZ(), -m_layers_slider->GetLowerValueD())); m_canvas->set_clipping_plane(0, ClippingPlane(Vec3d::UnitZ(), -m_layers_slider->GetLowerValue()));
m_canvas->set_clipping_plane(1, ClippingPlane(-Vec3d::UnitZ(), m_layers_slider->GetHigherValueD())); m_canvas->set_clipping_plane(1, ClippingPlane(-Vec3d::UnitZ(), m_layers_slider->GetHigherValue()));
m_canvas->render(); m_canvas->render();
} }
} }
@ -902,7 +909,7 @@ void Preview::on_layers_slider_scroll_changed()
void Preview::on_moves_slider_scroll_changed() 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->update_gcode_sequential_view_current(static_cast<unsigned int>(m_moves_slider->GetLowerValue() - 1), static_cast<unsigned int>(m_moves_slider->GetHigherValue() - 1));
m_canvas->set_as_dirty(); m_canvas->set_as_dirty();
m_canvas->request_extra_frame(); m_canvas->request_extra_frame();
} }

View File

@ -28,8 +28,8 @@ class BackgroundSlicingProcess;
class Model; class Model;
namespace DoubleSlider { namespace DoubleSlider {
class DSManagerForGcode; class DSForGcode;
class DSManagerForLayers; class DSForLayers;
}; };
namespace GUI { namespace GUI {
@ -96,8 +96,8 @@ class Preview : public wxPanel
bool m_loaded { false }; bool m_loaded { false };
DoubleSlider::DSManagerForLayers* m_layers_slider{ nullptr }; DoubleSlider::DSForLayers* m_layers_slider{ nullptr };
DoubleSlider::DSManagerForGcode* m_moves_slider { nullptr }; DoubleSlider::DSForGcode* m_moves_slider { nullptr };
public: public:
enum class OptionType : unsigned int enum class OptionType : unsigned int

View File

@ -6,7 +6,9 @@
#include "ImGuiDoubleSlider.hpp" #include "ImGuiDoubleSlider.hpp"
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace DoubleSlider {
using namespace GUI;
const ImU32 tooltip_bg_clr = ImGui::ColorConvertFloat4ToU32(ImGuiPureWrap::COL_GREY_LIGHT); const ImU32 tooltip_bg_clr = ImGui::ColorConvertFloat4ToU32(ImGuiPureWrap::COL_GREY_LIGHT);
const ImU32 thumb_bg_clr = ImGui::ColorConvertFloat4ToU32(ImGuiPureWrap::COL_ORANGE_LIGHT); const ImU32 thumb_bg_clr = ImGui::ColorConvertFloat4ToU32(ImGuiPureWrap::COL_ORANGE_LIGHT);
@ -125,46 +127,47 @@ ImGuiControl::ImGuiControl( int lowerValue,
bool use_lower_thumb) : bool use_lower_thumb) :
m_selection(ssUndef), m_selection(ssUndef),
m_name(name), m_name(name),
m_lower_value(lowerValue), m_lower_pos(lowerValue),
m_higher_value (higherValue), m_higher_pos (higherValue),
m_min_value(minValue), m_min_pos(minValue),
m_max_value(maxValue), m_max_pos(maxValue),
m_flags(flags), m_flags(flags),
m_draw_lower_thumb(use_lower_thumb) m_draw_lower_thumb(use_lower_thumb)
{ {
} }
int ImGuiControl::GetActiveValue() const int ImGuiControl::GetActivePos() const
{ {
return m_selection == ssLower ? m_lower_value : return m_selection == ssLower ? m_lower_pos :
m_selection == ssHigher ? m_higher_value : -1; m_selection == ssHigher ? m_higher_pos : -1;
} }
void ImGuiControl::SetLowerValue(const int lower_val) void ImGuiControl::SetLowerPos(const int lower_pos)
{ {
m_selection = ssLower; m_selection = ssLower;
m_lower_value = lower_val; m_lower_pos = lower_pos;
correct_lower_value(); correct_lower_pos();
} }
void ImGuiControl::SetHigherValue(const int higher_val) void ImGuiControl::SetHigherPos(const int higher_pos)
{ {
m_selection = ssHigher; m_selection = ssHigher;
m_higher_value = higher_val; m_higher_pos = higher_pos;
correct_higher_value(); correct_higher_pos();
} }
void ImGuiControl::SetSelectionSpan(const int lower_val, const int higher_val) void ImGuiControl::SetSelectionSpan(const int lower_pos, const int higher_pos)
{ {
m_lower_value = std::max(lower_val, m_min_value); m_lower_pos = std::max(lower_pos, m_min_pos);
m_higher_value = std::max(std::min(higher_val, m_max_value), m_lower_value); m_higher_pos = std::max(std::min(higher_pos, m_max_pos), m_lower_pos);
if (m_lower_value < m_higher_value) if (m_lower_pos < m_higher_pos)
m_combine_thumbs = false; m_combine_thumbs = false;
} }
void ImGuiControl::SetMaxValue(const int max_value) void ImGuiControl::SetMaxPos(const int max_pos)
{ {
m_max_value = max_value; m_max_pos = max_pos;
correct_higher_pos();
} }
void ImGuiControl::MoveActiveThumb(int delta) void ImGuiControl::MoveActiveThumb(int delta)
@ -173,36 +176,36 @@ void ImGuiControl::MoveActiveThumb(int delta)
m_selection = ssHigher; m_selection = ssHigher;
if (m_selection == ssLower) { if (m_selection == ssLower) {
m_lower_value -= delta; m_lower_pos -= delta;
correct_lower_value(); correct_lower_pos();
} }
else if (m_selection == ssHigher) { else if (m_selection == ssHigher) {
m_higher_value -= delta; m_higher_pos -= delta;
correct_higher_value(); correct_higher_pos();
} }
} }
void ImGuiControl::correct_lower_value() void ImGuiControl::correct_lower_pos()
{ {
if (m_lower_value < m_min_value) if (m_lower_pos < m_min_pos)
m_lower_value = m_min_value; m_lower_pos = m_min_pos;
else if (m_lower_value > m_max_value) else if (m_lower_pos > m_max_pos)
m_lower_value = m_max_value; m_lower_pos = m_max_pos;
if ((m_lower_value >= m_higher_value && m_lower_value <= m_max_value) || m_combine_thumbs) { if ((m_lower_pos >= m_higher_pos && m_lower_pos <= m_max_pos) || m_combine_thumbs) {
m_higher_value = m_lower_value; m_higher_pos = m_lower_pos;
} }
} }
void ImGuiControl::correct_higher_value() void ImGuiControl::correct_higher_pos()
{ {
if (m_higher_value > m_max_value) if (m_higher_pos > m_max_pos)
m_higher_value = m_max_value; m_higher_pos = m_max_pos;
else if (m_higher_value < m_min_value) else if (m_higher_pos < m_min_pos)
m_higher_value = m_min_value; m_higher_pos = m_min_pos;
if ((m_higher_value <= m_lower_value && m_higher_value >= m_min_value) || m_combine_thumbs) { if ((m_higher_pos <= m_lower_pos && m_higher_pos >= m_min_pos) || m_combine_thumbs) {
m_lower_value = m_higher_value; m_lower_pos = m_higher_pos;
} }
} }
@ -211,17 +214,17 @@ void ImGuiControl::CombineThumbs(bool combine)
m_combine_thumbs = combine; m_combine_thumbs = combine;
if (combine) { if (combine) {
m_selection = ssHigher; m_selection = ssHigher;
correct_higher_value(); correct_higher_pos();
} }
else else
ResetValues(); ResetPositions();
} }
void ImGuiControl::ResetValues() void ImGuiControl::ResetPositions()
{ {
SetLowerValue(m_min_value); SetLowerPos(m_min_pos);
SetHigherValue(m_max_value); SetHigherPos(m_max_pos);
m_selection == ssLower ? correct_lower_value() : correct_higher_value(); m_selection == ssLower ? correct_lower_pos() : correct_higher_pos();
} }
std::string ImGuiControl::get_label(int pos) const std::string ImGuiControl::get_label(int pos) const
@ -229,18 +232,18 @@ std::string ImGuiControl::get_label(int pos) const
if (m_cb_get_label) if (m_cb_get_label)
return m_cb_get_label(pos); return m_cb_get_label(pos);
if (pos >= m_max_value || pos < m_min_value) if (pos >= m_max_pos || pos < m_min_pos)
return "ErrVal"; return "ErrVal";
return std::to_string(pos); return std::to_string(pos);
} }
float ImGuiControl::GetPositionFromValue(int value, const ImRect& rect) const float ImGuiControl::GetPositionInRect(int pos, const ImRect& rect) const
{ {
int v_min = m_min_value; int v_min = m_min_pos;
int v_max = m_max_value; int v_max = m_max_pos;
float pos_ratio = (v_max - v_min) != 0 ? ((float)(value - v_min) / (float)(v_max - v_min)) : 0.0f; float pos_ratio = (v_max - v_min) != 0 ? ((float)(pos - v_min) / (float)(v_max - v_min)) : 0.0f;
float thumb_pos; float thumb_pos;
if (is_horizontal()) { if (is_horizontal()) {
thumb_pos = rect.Min.x + (rect.Max.x - rect.Min.x) * pos_ratio; thumb_pos = rect.Min.x + (rect.Max.x - rect.Min.x) * pos_ratio;
@ -324,7 +327,7 @@ void ImGuiControl::draw_thumb(const ImVec2& center, bool mark/* = false*/)
} }
} }
void ImGuiControl::apply_regions(int higher_value, int lower_value, const ImRect& draggable_region) void ImGuiControl::apply_regions(int higher_pos, int lower_pos, const ImRect& draggable_region)
{ {
ImVec2 mid = draggable_region.GetCenter(); ImVec2 mid = draggable_region.GetCenter();
float thumb_radius = m_draw_opts.thumb_radius(); float thumb_radius = m_draw_opts.thumb_radius();
@ -338,18 +341,18 @@ void ImGuiControl::apply_regions(int higher_value, int lower_value, const ImRect
ImRect(draggable_region.Min + ImVec2(0, thumb_radius), draggable_region.Max); ImRect(draggable_region.Min + ImVec2(0, thumb_radius), draggable_region.Max);
// initialize the thumbs. // initialize the thumbs.
float higher_thumb_pos = GetPositionFromValue(higher_value, m_regions.higher_slideable_region); float higher_thumb_pos = GetPositionInRect(higher_pos, m_regions.higher_slideable_region);
m_regions.higher_thumb = is_horizontal() ? m_regions.higher_thumb = is_horizontal() ?
ImRect(higher_thumb_pos - thumb_radius, mid.y - thumb_radius, higher_thumb_pos + thumb_radius, mid.y + thumb_radius) : ImRect(higher_thumb_pos - thumb_radius, mid.y - thumb_radius, higher_thumb_pos + thumb_radius, mid.y + thumb_radius) :
ImRect(mid.x - thumb_radius, higher_thumb_pos - thumb_radius, mid.x + thumb_radius, higher_thumb_pos + thumb_radius); ImRect(mid.x - thumb_radius, higher_thumb_pos - thumb_radius, mid.x + thumb_radius, higher_thumb_pos + thumb_radius);
float lower_thumb_pos = GetPositionFromValue(lower_value, m_regions.lower_slideable_region); float lower_thumb_pos = GetPositionInRect(lower_pos, m_regions.lower_slideable_region);
m_regions.lower_thumb = is_horizontal() ? m_regions.lower_thumb = is_horizontal() ?
ImRect(lower_thumb_pos - thumb_radius, mid.y - thumb_radius, lower_thumb_pos + thumb_radius, mid.y + thumb_radius) : ImRect(lower_thumb_pos - thumb_radius, mid.y - thumb_radius, lower_thumb_pos + thumb_radius, mid.y + thumb_radius) :
ImRect(mid.x - thumb_radius, lower_thumb_pos - thumb_radius, mid.x + thumb_radius, lower_thumb_pos + thumb_radius); ImRect(mid.x - thumb_radius, lower_thumb_pos - thumb_radius, mid.x + thumb_radius, lower_thumb_pos + thumb_radius);
} }
void ImGuiControl::check_and_correct_thumbs(int* higher_value, int* lower_value) void ImGuiControl::check_and_correct_thumbs(int* higher_pos, int* lower_pos)
{ {
if (!m_draw_lower_thumb || m_combine_thumbs) if (!m_draw_lower_thumb || m_combine_thumbs)
return; return;
@ -366,12 +369,12 @@ void ImGuiControl::check_and_correct_thumbs(int* higher_value, int* lower_value)
if (m_selection == ssHigher) { if (m_selection == ssHigher) {
m_regions.lower_thumb = m_regions.higher_thumb; m_regions.lower_thumb = m_regions.higher_thumb;
m_regions.higher_thumb.TranslateX(thumb_radius); m_regions.higher_thumb.TranslateX(thumb_radius);
*lower_value = *higher_value; *lower_pos = *higher_pos;
} }
else { else {
m_regions.higher_thumb = m_regions.lower_thumb; m_regions.higher_thumb = m_regions.lower_thumb;
m_regions.lower_thumb.TranslateX(-thumb_radius); m_regions.lower_thumb.TranslateX(-thumb_radius);
*higher_value = *lower_value; *higher_pos = *lower_pos;
} }
} }
} }
@ -380,18 +383,18 @@ void ImGuiControl::check_and_correct_thumbs(int* higher_value, int* lower_value)
if (m_selection == ssHigher) { if (m_selection == ssHigher) {
m_regions.lower_thumb = m_regions.higher_thumb; m_regions.lower_thumb = m_regions.higher_thumb;
m_regions.lower_thumb.TranslateY(thumb_radius); m_regions.lower_thumb.TranslateY(thumb_radius);
*lower_value = *higher_value; *lower_pos = *higher_pos;
} }
else { else {
m_regions.higher_thumb = m_regions.lower_thumb; m_regions.higher_thumb = m_regions.lower_thumb;
m_regions.lower_thumb.TranslateY(-thumb_radius); m_regions.lower_thumb.TranslateY(-thumb_radius);
*higher_value = *lower_value; *higher_pos = *lower_pos;
} }
} }
} }
} }
bool ImGuiControl::draw_slider( int* higher_value, int* lower_value, bool ImGuiControl::draw_slider( int* higher_pos, int* lower_pos,
std::string& higher_label, std::string& lower_label, std::string& higher_label, std::string& lower_label,
const ImVec2& pos, const ImVec2& size, float scale) const ImVec2& pos, const ImVec2& size, float scale)
{ {
@ -418,7 +421,7 @@ bool ImGuiControl::draw_slider( int* higher_value, int* lower_value,
} }
// set slideable regions and thumbs. // set slideable regions and thumbs.
apply_regions(*higher_value, *lower_value, draggable_region); apply_regions(*higher_pos, *lower_pos, draggable_region);
// select and mark higher thumb by default // select and mark higher thumb by default
if (m_selection == ssUndef) if (m_selection == ssUndef)
@ -433,28 +436,28 @@ bool ImGuiControl::draw_slider( int* higher_value, int* lower_value,
ImGui::ItemHoverable(m_regions.lower_thumb, id) && context.IO.MouseClicked[0]) ImGui::ItemHoverable(m_regions.lower_thumb, id) && context.IO.MouseClicked[0])
m_selection = ssLower; m_selection = ssLower;
// update thumb position and value // update thumb position
bool value_changed = false; bool pos_changed = false;
if (m_selection == ssHigher) { if (m_selection == ssHigher) {
value_changed = behavior(id, m_regions.higher_slideable_region, m_min_value, m_max_value, pos_changed = behavior(id, m_regions.higher_slideable_region, m_min_pos, m_max_pos,
higher_value, &m_regions.higher_thumb, m_flags); higher_pos, &m_regions.higher_thumb, m_flags);
} }
else if (m_draw_lower_thumb && !m_combine_thumbs) { else if (m_draw_lower_thumb && !m_combine_thumbs) {
value_changed = behavior(id, m_regions.lower_slideable_region, m_min_value, m_max_value, pos_changed = behavior(id, m_regions.lower_slideable_region, m_min_pos, m_max_pos,
lower_value, &m_regions.lower_thumb, m_flags); lower_pos, &m_regions.lower_thumb, m_flags);
} }
// check thumbs values and correct them if needed // check thumbs poss and correct them if needed
check_and_correct_thumbs(higher_value, lower_value); check_and_correct_thumbs(higher_pos, lower_pos);
const ImRect& slideable_region = m_selection == ssHigher ? m_regions.higher_slideable_region : m_regions.lower_slideable_region; const ImRect& slideable_region = m_selection == ssHigher ? m_regions.higher_slideable_region : m_regions.lower_slideable_region;
const ImRect& active_thumb = m_selection == ssHigher ? m_regions.higher_thumb : m_regions.lower_thumb; const ImRect& active_thumb = m_selection == ssHigher ? m_regions.higher_thumb : m_regions.lower_thumb;
bool show_move_label = false; bool show_move_label = false;
ImRect mouse_pos_rc = active_thumb; ImRect mouse_pos_rc = active_thumb;
if (!value_changed && ImGui::ItemHoverable(item_size, id) && !ImGui::IsMouseDragging(0)) { if (!pos_changed && ImGui::ItemHoverable(item_size, id) && !ImGui::IsMouseDragging(0)) {
behavior(id, slideable_region, m_min_value, m_max_value, behavior(id, slideable_region, m_min_pos, m_max_pos,
&m_mouse_pos_value, &mouse_pos_rc, m_flags, true); &m_mouse_pos, &mouse_pos_rc, m_flags, true);
show_move_label = true; show_move_label = true;
} }
@ -491,9 +494,9 @@ bool ImGuiControl::draw_slider( int* higher_value, int* lower_value,
// draw label on mouse move // draw label on mouse move
if (show_move_label) if (show_move_label)
draw_label(get_label_on_move(m_mouse_pos_value), mouse_pos_rc); draw_label(get_label_on_move(m_mouse_pos), mouse_pos_rc);
return value_changed; return pos_changed;
} }
bool ImGuiControl::render() bool ImGuiControl::render()
@ -519,21 +522,21 @@ bool ImGuiControl::render()
float scale = 1.f; float scale = 1.f;
int higher_value = m_higher_value; int higher_pos = m_higher_pos;
int lower_value = m_lower_value; int lower_pos = m_lower_pos;
std::string higher_label = get_label(m_higher_value); std::string higher_label = get_label(m_higher_pos);
std::string lower_label = get_label(m_lower_value); std::string lower_label = get_label(m_lower_pos);
int temp_higher_value = m_higher_value; int temp_higher_pos = m_higher_pos;
int temp_lower_value = m_lower_value; int temp_lower_pos = m_lower_pos;
if (draw_slider(&higher_value, &lower_value, higher_label, lower_label, m_pos, m_size, scale)) { if (draw_slider(&higher_pos, &lower_pos, higher_label, lower_label, m_pos, m_size, scale)) {
if (temp_higher_value != higher_value) { if (temp_higher_pos != higher_pos) {
m_higher_value = higher_value; m_higher_pos = higher_pos;
if (m_combine_thumbs) if (m_combine_thumbs)
m_lower_value = m_higher_value; m_lower_pos = m_higher_pos;
} }
if (temp_lower_value != lower_value) if (temp_lower_pos != lower_pos)
m_lower_value = lower_value; m_lower_pos = lower_pos;
result = true; result = true;
} }

View File

@ -24,7 +24,7 @@ std::string to_string_with_precision(const T a_value, const int n = 2)
} }
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace DoubleSlider {
enum SelectedSlider { enum SelectedSlider {
ssUndef, ssUndef,
@ -45,25 +45,24 @@ public:
ImGuiControl() {} ImGuiControl() {}
~ImGuiControl() {} ~ImGuiControl() {}
int GetMinValue() const { return m_min_value; } int GetMinPos() const { return m_min_pos; }
int GetMaxValue() const { return m_max_value; } int GetMaxPos() const { return m_max_pos; }
int GetLowerValue() const { return m_lower_value; } int GetLowerPos() const { return m_lower_pos; }
int GetHigherValue() const { return m_higher_value; } int GetHigherPos() const { return m_higher_pos; }
int GetActiveValue() const; int GetActivePos() const;
float GetPositionFromValue(int value, const ImRect& rect) const;
// Set low and high slider position. If the span is non-empty, disable the "one layer" mode. // Set low and high slider position. If the span is non-empty, disable the "one layer" mode.
void SetLowerValue (const int lower_val); void SetLowerPos (const int lower_pos);
void SetHigherValue(const int higher_val); void SetHigherPos(const int higher_pos);
void SetSelectionSpan(const int lower_val, const int higher_val); void SetSelectionSpan(const int lower_pos, const int higher_pos);
void SetMaxValue(const int max_value); void SetMaxPos(const int max_pos);
void CombineThumbs(bool combine); void CombineThumbs(bool combine);
void ResetValues(); void ResetPositions();
void SetPos(ImVec2 pos) { m_pos = pos; } void SetCtrlPos(ImVec2 pos) { m_pos = pos; }
void SetSize(ImVec2 size) { m_size = size; } void SetCtrlSize(ImVec2 size) { m_size = size; }
void SetScale(float scale) { m_draw_opts.scale = scale; } void SetCtrlScale(float scale) { m_draw_opts.scale = scale; }
void Init(const ImVec2& pos, const ImVec2& size, float scale) { void Init(const ImVec2& pos, const ImVec2& size, float scale) {
m_pos = pos; m_pos = pos;
m_size = size; m_size = size;
@ -76,16 +75,15 @@ public:
bool IsCombineThumbs() const { return m_combine_thumbs; } bool IsCombineThumbs() const { return m_combine_thumbs; }
bool IsActiveHigherThumb() const { return m_selection == ssHigher; } bool IsActiveHigherThumb() const { return m_selection == ssHigher; }
void MoveActiveThumb(int delta); void MoveActiveThumb(int delta);
void ShowLowerThumb(bool show) { m_draw_lower_thumb = show; }
void ShowLabelOnMouseMove(bool show = true) { m_show_move_label = show; } void ShowLabelOnMouseMove(bool show = true) { m_show_move_label = show; }
ImRect GetGrooveRect() const { return m_draw_opts.groove(m_pos, m_size, is_horizontal()); } ImRect GetGrooveRect() const { return m_draw_opts.groove(m_pos, m_size, is_horizontal()); }
float GetPositionInRect(int pos, const ImRect& rect) const;
bool IsRClickOnThumb() const { return m_rclick_on_selected_thumb; }
bool is_horizontal() const { return !(m_flags & ImGuiSliderFlags_Vertical); } bool is_horizontal() const { return !(m_flags & ImGuiSliderFlags_Vertical); }
bool is_lower_at_min() const { return m_lower_value == m_min_value; }
bool is_higher_at_max() const { return m_higher_value == m_max_value; }
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; }
bool render(); bool render();
std::string get_label(int pos) const; std::string get_label(int pos) const;
@ -130,11 +128,12 @@ private:
ImGuiSliderFlags m_flags{ ImGuiSliderFlags_None }; ImGuiSliderFlags m_flags{ ImGuiSliderFlags_None };
bool m_is_shown{ true }; bool m_is_shown{ true };
int m_min_value; int m_min_pos;
int m_max_value; int m_max_pos;
int m_lower_value; int m_lower_pos;
int m_higher_value; int m_higher_pos;
int m_mouse_pos_value; // slider's position of the mouse cursor
int m_mouse_pos;
bool m_rclick_on_selected_thumb{ false }; bool m_rclick_on_selected_thumb{ false };
@ -150,24 +149,136 @@ private:
std::function<void(const ImRect&, const ImRect&)> m_cb_draw_scroll_line { nullptr }; std::function<void(const ImRect&, const ImRect&)> m_cb_draw_scroll_line { nullptr };
std::function<void(const ImRect&)> m_cb_extra_draw { nullptr }; std::function<void(const ImRect&)> m_cb_extra_draw { nullptr };
void correct_lower_value(); void correct_lower_pos();
void correct_higher_value(); void correct_higher_pos();
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); } 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 apply_regions(int higher_pos, int lower_pos, const ImRect& draggable_region);
void check_and_correct_thumbs(int* higher_value, int* lower_value); void check_and_correct_thumbs(int* higher_pos, int* lower_pos);
void draw_scroll_line(const ImRect& scroll_line, const ImRect& slideable_region); void draw_scroll_line(const ImRect& scroll_line, const ImRect& slideable_region);
void draw_background(const ImRect& slideable_region); void draw_background(const ImRect& slideable_region);
void draw_label(std::string label, const ImRect& thumb); void draw_label(std::string label, const ImRect& thumb);
void draw_thumb(const ImVec2& center, bool mark = false); void draw_thumb(const ImVec2& center, bool mark = false);
bool draw_slider(int* higher_value, int* lower_value, bool draw_slider(int* higher_pos, int* lower_pos,
std::string& higher_label, std::string& lower_label, std::string& higher_label, std::string& lower_label,
const ImVec2& pos, const ImVec2& size, float scale = 1.0f); const ImVec2& pos, const ImVec2& size, float scale = 1.0f);
}; };
} // GUI // VatType = a typ of values, related to the each position in slider
template<typename ValType>
class Manager
{
public:
void Init( int lowerPos,
int higherPos,
int minPos,
int maxPos,
const std::string& name,
bool is_horizontal)
{
m_ctrl = ImGuiControl( lowerPos, higherPos,
minPos, maxPos,
is_horizontal ? 0 : ImGuiSliderFlags_Vertical,
name, !is_horizontal);
m_ctrl.set_get_label_cb([this](int pos) {return get_label(pos); });
};
Manager() {}
Manager(int lowerPos,
int higherPos,
int minPos,
int maxPos,
const std::string& name,
bool is_horizontal)
{
Init (lowerPos, higherPos, minPos, maxPos, name, is_horizontal);
}
~Manager() {}
int GetMinPos() const { return m_ctrl.GetMinPos(); }
int GetMaxPos() const { return m_ctrl.GetMaxPos(); }
int GetLowerPos() const { return m_ctrl.GetLowerPos(); }
int GetHigherPos()const { return m_ctrl.GetHigherPos(); }
ValType GetMinValue() { return m_values.empty() ? static_cast<ValType>(0) : m_values[GetMinPos()]; }
ValType GetMaxValue() { return m_values.empty() ? static_cast<ValType>(0) : m_values[GetMaxPos()]; }
ValType GetLowerValue() { return m_values.empty() ? static_cast<ValType>(0) : m_values[GetLowerPos()];}
ValType GetHigherValue() { return m_values.empty() ? static_cast<ValType>(0) : m_values[GetHigherPos()]; }
// Set low and high slider position. If the span is non-empty, disable the "one layer" mode.
void SetLowerPos(const int lower_pos) {
m_ctrl.SetLowerPos(lower_pos);
process_thumb_move();
}
void SetHigherPos(const int higher_pos) {
m_ctrl.SetHigherPos(higher_pos);
process_thumb_move();
}
void SetSelectionSpan(const int lower_pos, const int higher_pos) {
m_ctrl.SetSelectionSpan(lower_pos, higher_pos);
process_thumb_move();
}
void SetMaxPos(const int max_pos) {
m_ctrl.SetMaxPos(max_pos);
process_thumb_move();
}
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 IsLowerAtMin() const { return m_ctrl.GetLowerPos() == m_ctrl.GetMinPos(); }
bool IsHigherAtMax() const { return m_ctrl.GetHigherPos() == m_ctrl.GetMaxPos(); }
void Show(bool show = true) { m_ctrl.Show(show); }
void Hide() { m_ctrl.Show(false); }
void SetEmUnit(int em_unit) { m_em = em_unit; }
void ShowLowerThumb(bool show) { m_ctrl.ShowLowerThumb(show); }
virtual void 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)
{
m_ctrl.MoveActiveThumb(delta);
process_thumb_move();
}
protected:
std::vector<ValType> m_values;
std::vector<ValType> m_alternate_values;
ImGuiControl m_ctrl;
int m_em{ 10 };
float m_scale{ 1.f };
std::string get_label(int pos) const {
if (m_values.empty())
return std::to_string(pos);
if (pos >= m_values.size())
return "ErrVal";
return to_string_with_precision(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 };
};
} // GUI
} // Slic3r } // Slic3r