mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 05:56:02 +08:00
DoubleSliderForLayers Improvements:
* Set "Show estimated print time on mouse moving" on true by default * Back ported Ruler * Fix for "Add" button * Show move line on ruler
This commit is contained in:
parent
102ff4a40e
commit
97d82a0d57
@ -218,6 +218,15 @@ void AppConfig::set_defaults()
|
||||
if (get("auth_login_dialog_confirmed").empty())
|
||||
set("auth_login_dialog_confirmed", "0");
|
||||
|
||||
if (get("show_estimated_times_in_dbl_slider").empty())
|
||||
set("show_estimated_times_in_dbl_slider", "1");
|
||||
|
||||
if (get("show_ruler_in_dbl_slider").empty())
|
||||
set("show_ruler_in_dbl_slider", "0");
|
||||
|
||||
if (get("show_ruler_bg_in_dbl_slider").empty())
|
||||
set("show_ruler_bg_in_dbl_slider", "1");
|
||||
|
||||
#ifdef _WIN32
|
||||
if (get("use_legacy_3DConnexion").empty())
|
||||
set("use_legacy_3DConnexion", "0");
|
||||
|
@ -262,6 +262,8 @@ set(SLIC3R_GUI_SOURCES
|
||||
GUI/DoubleSliderForLayers.hpp
|
||||
GUI/DoubleSliderForGcode.cpp
|
||||
GUI/DoubleSliderForGcode.hpp
|
||||
GUI/RulerForDoubleSlider.cpp
|
||||
GUI/RulerForDoubleSlider.hpp
|
||||
GUI/Notebook.cpp
|
||||
GUI/Notebook.hpp
|
||||
GUI/TopBar.cpp
|
||||
|
@ -27,7 +27,7 @@ using Slic3r::format;
|
||||
|
||||
namespace DoubleSlider {
|
||||
|
||||
static const float VERTICAL_SLIDER_WIDTH = 105.0f;
|
||||
//static const float VERTICAL_SLIDER_WIDTH = 105.0f;
|
||||
|
||||
DSForLayers::DSForLayers( int lowerValue,
|
||||
int higherValue,
|
||||
@ -42,7 +42,10 @@ DSForLayers::DSForLayers( int lowerValue,
|
||||
Init(lowerValue, higherValue, minValue, maxValue, "layers_slider", false);
|
||||
m_ctrl.ShowLabelOnMouseMove(true);
|
||||
|
||||
m_ctrl.set_get_label_on_move_cb([this](int pos) { return m_show_estimated_times ? get_label(pos, ltEstimatedTime) : ""; });
|
||||
m_ctrl.set_get_label_on_move_cb([this](int pos) {
|
||||
m_pos_on_move = pos;
|
||||
return m_show_estimated_times ? get_label(pos, ltEstimatedTime) : "";
|
||||
});
|
||||
m_ctrl.set_extra_draw_cb([this](const ImRect& draw_rc) {return draw_ticks(draw_rc); });
|
||||
|
||||
m_ticks.set_values(&m_values);
|
||||
@ -170,22 +173,25 @@ using namespace ImGui;
|
||||
|
||||
void DSForLayers::draw_ticks(const ImRect& slideable_region)
|
||||
{
|
||||
//if(m_draw_mode != dmRegular)
|
||||
// return;
|
||||
//if (m_ticks.empty() || m_mode == MultiExtruder)
|
||||
// return;
|
||||
if (m_show_ruler)
|
||||
draw_ruler(slideable_region);
|
||||
|
||||
if (m_ticks.empty() || m_draw_mode == dmSlaPrint)
|
||||
return;
|
||||
|
||||
// distance form center begin end
|
||||
const ImVec2 tick_border = ImVec2(23.0f, 2.0f) * m_scale;
|
||||
// distance form center begin end
|
||||
const ImVec2 tick_size = ImVec2(19.0f, 11.0f) * m_scale;
|
||||
const float tick_width = 1.0f * m_scale;
|
||||
const float icon_side = m_imgui->GetTextureCustomRect(ImGui::PausePrint)->Height;
|
||||
const float icon_offset = 0.5f * icon_side;;
|
||||
|
||||
const ImU32 tick_clr = ImGui::ColorConvertFloat4ToU32(ImGuiPureWrap::COL_ORANGE_DARK);
|
||||
const ImU32 tick_hovered_clr = ImGui::ColorConvertFloat4ToU32(ImGuiPureWrap::COL_WINDOW_BACKGROUND);
|
||||
const float inner_x = 11.f * m_scale;
|
||||
const float outer_x = 19.f * m_scale;
|
||||
const float x_center = slideable_region.GetCenter().x;
|
||||
|
||||
const float tick_width = float(int(1.0f * m_scale + 0.5f));
|
||||
const float icon_side = m_imgui->GetTextureCustomRect(ImGui::PausePrint)->Height;
|
||||
const float icon_offset = 0.5f * icon_side;;
|
||||
|
||||
const ImU32 tick_clr = ImGui::ColorConvertFloat4ToU32(m_show_ruler ? ImGuiPureWrap::COL_ORANGE_LIGHT : ImGuiPureWrap::COL_ORANGE_DARK);
|
||||
const ImU32 tick_hovered_clr = ImGui::ColorConvertFloat4ToU32(m_show_ruler ? ImGuiPureWrap::COL_ORANGE_DARK : ImGuiPureWrap::COL_WINDOW_BACKGROUND);
|
||||
|
||||
auto get_tick_pos = [this, slideable_region](int tick) {
|
||||
return m_ctrl.GetPositionInRect(tick, slideable_region);
|
||||
@ -197,8 +203,8 @@ void DSForLayers::draw_ticks(const ImRect& slideable_region)
|
||||
float tick_pos = get_tick_pos(tick_it->tick);
|
||||
|
||||
//draw tick hover box when hovered
|
||||
ImRect tick_hover_box = ImRect(slideable_region.GetCenter().x - tick_border.x, tick_pos - tick_border.y,
|
||||
slideable_region.GetCenter().x + tick_border.x, tick_pos + tick_border.y - tick_width);
|
||||
ImRect tick_hover_box = ImRect(x_center - tick_border.x, tick_pos - tick_border.y,
|
||||
x_center + tick_border.x, tick_pos + tick_border.y - tick_width);
|
||||
|
||||
if (ImGui::IsMouseHoveringRect(tick_hover_box.Min, tick_hover_box.Max)) {
|
||||
ImGui::RenderFrame(tick_hover_box.Min, tick_hover_box.Max, tick_hovered_clr, false);
|
||||
@ -219,12 +225,12 @@ void DSForLayers::draw_ticks(const ImRect& slideable_region)
|
||||
float tick_pos = get_tick_pos(tick_it->tick);
|
||||
|
||||
//draw ticks
|
||||
ImRect tick_left = ImRect(slideable_region.GetCenter().x - tick_size.x, tick_pos - tick_width, slideable_region.GetCenter().x - tick_size.y, tick_pos);
|
||||
ImRect tick_right = ImRect(slideable_region.GetCenter().x + tick_size.y, tick_pos - tick_width, slideable_region.GetCenter().x + tick_size.x, tick_pos);
|
||||
ImRect tick_left = ImRect(x_center - outer_x, tick_pos - tick_width, x_center - inner_x, tick_pos);
|
||||
ImRect tick_right = ImRect(x_center + inner_x, tick_pos - tick_width, x_center + outer_x, tick_pos);
|
||||
ImGui::RenderFrame(tick_left.Min, tick_left.Max, tick_clr, false);
|
||||
ImGui::RenderFrame(tick_right.Min, tick_right.Max, tick_clr, false);
|
||||
|
||||
ImVec2 icon_pos = ImVec2(tick_right.Max.x + 0.5f * icon_offset, tick_pos - icon_offset);
|
||||
ImVec2 icon_pos = ImVec2(m_ctrl.GetCtrlPos().x + GetWidth(), tick_pos - icon_offset);
|
||||
std::string btn_label = "tick " + std::to_string(tick_it->tick);
|
||||
|
||||
//draw tick icon-buttons
|
||||
@ -257,6 +263,174 @@ void DSForLayers::draw_ticks(const ImRect& slideable_region)
|
||||
}
|
||||
}
|
||||
|
||||
void DSForLayers::draw_ruler(const ImRect& slideable_region)
|
||||
{
|
||||
if (m_values.empty())
|
||||
return;
|
||||
|
||||
const double step = double(slideable_region.GetHeight()) / (m_ctrl.GetMaxPos() - m_ctrl.GetMinPos());
|
||||
|
||||
if (!m_ruler.valid())
|
||||
m_ruler.init(m_values, step);
|
||||
|
||||
const float inner_x = 11.f * m_scale;
|
||||
const float long_outer_x = 17.f * m_scale;
|
||||
const float short_outer_x = 14.f * m_scale;
|
||||
const float tick_width = float(int(1.0f * m_scale +0.5f));
|
||||
const float label_height = m_imgui->GetTextureCustomRect(ImGui::PausePrint)->Height;
|
||||
|
||||
const ImU32 tick_clr = IM_COL32(255, 255, 255, 255);
|
||||
|
||||
const float x_center = slideable_region.GetCenter().x;
|
||||
|
||||
double max_val = 0.;
|
||||
for (const auto& val : m_ruler.max_values)
|
||||
if (max_val < val)
|
||||
max_val = val;
|
||||
|
||||
if (m_show_ruler_bg) {
|
||||
// draw ruler BG
|
||||
ImRect bg_rect = slideable_region;
|
||||
bg_rect.Expand(ImVec2(0.f, long_outer_x));
|
||||
bg_rect.Min.x -= tick_width;
|
||||
bg_rect.Max.x = m_ctrl.GetCtrlPos().x + GetWidth();
|
||||
bg_rect.Min.y = m_ctrl.GetCtrlPos().y + label_height;
|
||||
bg_rect.Max.y = m_ctrl.GetCtrlPos().y + GetHeight() - label_height;
|
||||
const ImU32 bg_color = ImGui::ColorConvertFloat4ToU32(ImVec4(0.13f, 0.13f, 0.13f, 0.5f));
|
||||
|
||||
ImGui::RenderFrame(bg_rect.Min, bg_rect.Max, bg_color, false, 2.f * m_ctrl.rounding());
|
||||
}
|
||||
|
||||
auto get_tick_pos = [this, slideable_region](int tick) -> float {
|
||||
return m_ctrl.GetPositionInRect(tick, slideable_region);
|
||||
};
|
||||
|
||||
auto draw_text = [max_val, x_center, label_height, long_outer_x, this](const int tick, const float tick_pos)
|
||||
{
|
||||
ImVec2 start = ImVec2(x_center + long_outer_x + 1, tick_pos - (0.5f * label_height));
|
||||
std::string label = get_label(tick, ltHeight, max_val > 100.0 ? "%1$.1f" : "%1$.2f");
|
||||
ImGui::RenderText(start, label.c_str());
|
||||
};
|
||||
|
||||
auto draw_tick = [tick_clr, x_center, tick_width, inner_x](const float tick_pos, const float outer_x)
|
||||
{
|
||||
ImRect tick_right = ImRect(x_center + inner_x, tick_pos - tick_width, x_center + outer_x, tick_pos);
|
||||
ImGui::RenderFrame(tick_right.Min, tick_right.Max, tick_clr, false);
|
||||
};
|
||||
|
||||
auto draw_short_ticks = [this, short_outer_x, draw_tick, get_tick_pos](double& current_tick, int max_tick)
|
||||
{
|
||||
if (m_ruler.short_step <= 0.0)
|
||||
return;
|
||||
while (current_tick < max_tick) {
|
||||
float pos = get_tick_pos(lround(current_tick));
|
||||
draw_tick(pos, short_outer_x);
|
||||
current_tick += m_ruler.short_step;
|
||||
if (current_tick > m_ctrl.GetMaxPos())
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
double short_tick = NaNd;
|
||||
int tick = 0;
|
||||
double value = 0.0;
|
||||
size_t sequence = 0;
|
||||
int prev_y_pos = -1;
|
||||
int values_size = (int)m_values.size();
|
||||
|
||||
if (m_ruler.long_step < 0) {
|
||||
// sequential print when long_step wasn't detected because of a lot of printed objects
|
||||
if (m_ruler.max_values.size() > 1) {
|
||||
while (tick <= m_ctrl.GetMaxPos() && sequence < m_ruler.count()) {
|
||||
// draw just ticks with max value
|
||||
value = m_ruler.max_values[sequence];
|
||||
short_tick = tick;
|
||||
|
||||
for (; tick < values_size; tick++) {
|
||||
if (m_values[tick] == value)
|
||||
break;
|
||||
if (m_values[tick] > value) {
|
||||
if (tick > 0)
|
||||
tick--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (tick > m_ctrl.GetMaxPos())
|
||||
break;
|
||||
|
||||
float pos = get_tick_pos(tick);
|
||||
draw_tick(pos, long_outer_x);
|
||||
if (prev_y_pos < 0 || prev_y_pos - pos >= label_height) {
|
||||
draw_text(tick, pos);
|
||||
prev_y_pos = pos;
|
||||
}
|
||||
draw_short_ticks(short_tick, tick);
|
||||
|
||||
sequence++;
|
||||
tick++;
|
||||
}
|
||||
}
|
||||
// very short object or some non-trivial ruler with non-regular step (see https://github.com/prusa3d/PrusaSlicer/issues/7263)
|
||||
else {
|
||||
if (step < 1) // step less then 1 px indicates very tall object with non-regular laayer step (probably in vase mode)
|
||||
return;
|
||||
for (size_t tick = 1; tick < m_values.size(); tick++) {
|
||||
float pos = get_tick_pos(tick);
|
||||
draw_tick(pos, long_outer_x);
|
||||
draw_text(tick, pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
while (tick <= m_ctrl.GetMaxPos()) {
|
||||
value += m_ruler.long_step;
|
||||
|
||||
if (sequence < m_ruler.count() && value > m_ruler.max_values[sequence])
|
||||
value = m_ruler.max_values[sequence];
|
||||
|
||||
short_tick = tick;
|
||||
|
||||
for (; tick < values_size; tick++) {
|
||||
if (m_values[tick] == value)
|
||||
break;
|
||||
if (m_values[tick] > value) {
|
||||
if (tick > 0)
|
||||
tick--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (tick > m_ctrl.GetMaxPos())
|
||||
break;
|
||||
|
||||
float pos = get_tick_pos(tick);
|
||||
draw_tick(pos, long_outer_x);
|
||||
if (prev_y_pos < 0 || prev_y_pos - pos >= label_height) {
|
||||
draw_text(tick, pos);
|
||||
prev_y_pos = pos;
|
||||
}
|
||||
|
||||
draw_short_ticks(short_tick, tick);
|
||||
|
||||
if (sequence < m_ruler.count() && value == m_ruler.max_values[sequence]) {
|
||||
value = 0.0;
|
||||
sequence++;
|
||||
tick++;
|
||||
}
|
||||
}
|
||||
// short ticks from the last tick to the end
|
||||
draw_short_ticks(short_tick, m_ctrl.GetMaxPos());
|
||||
}
|
||||
|
||||
// draw mose move line
|
||||
if (m_pos_on_move > 0) {
|
||||
float line_pos = get_tick_pos(m_pos_on_move);
|
||||
|
||||
ImRect move_line = ImRect(x_center + 0.75f * inner_x, line_pos - tick_width, x_center + 1.5f * long_outer_x, line_pos);
|
||||
ImGui::RenderFrame(move_line.Min, move_line.Max, ImGui::ColorConvertFloat4ToU32(ImGuiPureWrap::COL_ORANGE_LIGHT), false);
|
||||
m_pos_on_move = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static std::array<float, 4> decode_color_to_float_array(const std::string color)
|
||||
{
|
||||
auto hex_digit_to_int = [](const char c) {
|
||||
@ -504,7 +678,7 @@ bool DSForLayers::render_multi_extruders_menu(bool switch_current_code/* = false
|
||||
void DSForLayers::render_color_picker()
|
||||
{
|
||||
ImGuiContext& context = *GImGui;
|
||||
const std::string title = _u8L("Select color for Color Change");
|
||||
const std::string title = ("Select color for Color Change");
|
||||
if (m_show_color_picker) {
|
||||
|
||||
ImGuiPureWrap::set_next_window_pos(1200, 200, ImGuiCond_Always, 0.5f, 0.0f);
|
||||
@ -534,12 +708,31 @@ void DSForLayers::render_cog_menu()
|
||||
}
|
||||
if (ImGuiPureWrap::menu_item_with_icon(_u8L("Show estimated print time on hover").c_str(), "", icon_sz, 0, m_show_estimated_times)) {
|
||||
m_show_estimated_times = !m_show_estimated_times;
|
||||
if (m_cb_change_app_config)
|
||||
m_cb_change_app_config("show_estimated_times_in_dbl_slider", m_show_estimated_times ? "1" : "0");
|
||||
}
|
||||
if (m_mode == MultiAsSingle && m_draw_mode == dmRegular &&
|
||||
ImGuiPureWrap::menu_item_with_icon(_u8L("Set extruder sequence for the entire print").c_str(), "")) {
|
||||
if (m_ticks.edit_extruder_sequence(m_ctrl.GetMaxPos(), m_mode))
|
||||
process_ticks_changed();
|
||||
}
|
||||
if (ImGuiPureWrap::begin_menu(_u8L("Ruler").c_str())) {
|
||||
if (ImGuiPureWrap::menu_item_with_icon(_u8L("Show").c_str(), "", icon_sz, 0, m_show_ruler)) {
|
||||
m_show_ruler = !m_show_ruler;
|
||||
if (m_show_ruler)
|
||||
m_imgui->set_requires_extra_frame();
|
||||
if (m_cb_change_app_config)
|
||||
m_cb_change_app_config("show_ruler_in_dbl_slider", m_show_ruler ? "1" : "0");
|
||||
}
|
||||
|
||||
if (ImGuiPureWrap::menu_item_with_icon(_u8L("Show backgroung").c_str(), "", icon_sz, 0, m_show_ruler_bg)) {
|
||||
m_show_ruler_bg = !m_show_ruler_bg;
|
||||
if (m_cb_change_app_config)
|
||||
m_cb_change_app_config("show_ruler_bg_in_dbl_slider", m_show_ruler_bg ? "1" : "0");
|
||||
}
|
||||
|
||||
ImGuiPureWrap::end_menu();
|
||||
}
|
||||
if (can_edit()) {
|
||||
if (ImGuiPureWrap::menu_item_with_icon(_u8L("Use default colors").c_str(), "", icon_sz, 0, m_ticks.used_default_colors())) {
|
||||
UseDefaultColors(!m_ticks.used_default_colors());
|
||||
@ -707,11 +900,15 @@ void DSForLayers::Render(const int canvas_width, const int canvas_height, float
|
||||
return;
|
||||
m_scale = extra_scale * 0.1f * m_em;
|
||||
|
||||
m_ruler.set_scale(m_scale);
|
||||
|
||||
const float action_btn_sz = m_imgui->GetTextureCustomRect(ImGui::DSRevert)->Height;
|
||||
const float tick_icon_side = m_imgui->GetTextureCustomRect(ImGui::PausePrint)->Height;
|
||||
|
||||
ImVec2 pos;
|
||||
|
||||
const float VERTICAL_SLIDER_WIDTH = m_show_ruler ? 125.f : 105.0f;
|
||||
|
||||
pos.x = canvas_width - VERTICAL_SLIDER_WIDTH * m_scale - tick_icon_side;
|
||||
pos.y = 1.5f * action_btn_sz + offset;
|
||||
if (m_allow_editing)
|
||||
@ -719,7 +916,7 @@ void DSForLayers::Render(const int canvas_width, const int canvas_height, float
|
||||
|
||||
ImVec2 size = ImVec2(VERTICAL_SLIDER_WIDTH * m_scale, canvas_height - 4.f * action_btn_sz - offset);
|
||||
|
||||
m_ctrl.Init(pos, size, m_scale);
|
||||
m_ctrl.Init(pos, size, m_scale, m_show_ruler);
|
||||
if (m_ctrl.render()) {
|
||||
// request one more frame if value was changes with mouse wheel
|
||||
if (GImGui->IO.MouseWheel != 0.0f)
|
||||
@ -770,6 +967,12 @@ void DSForLayers::Render(const int canvas_width, const int canvas_height, float
|
||||
render_color_picker();
|
||||
}
|
||||
|
||||
void DSForLayers::force_ruler_update()
|
||||
{
|
||||
if (m_show_ruler)
|
||||
m_ruler.invalidate();
|
||||
}
|
||||
|
||||
bool DSForLayers::is_wipe_tower_layer(int tick) const
|
||||
{
|
||||
if (!m_ticks.is_wipe_tower || tick >= (int)m_values.size())
|
||||
@ -824,7 +1027,7 @@ static std::string short_and_splitted_time(const std::string& time)
|
||||
return get_s();
|
||||
}
|
||||
|
||||
std::string DSForLayers::get_label(int pos, LabelType label_type) const
|
||||
std::string DSForLayers::get_label(int pos, LabelType label_type, const std::string& fmt/* = "%1$.2f"*/) const
|
||||
{
|
||||
const size_t value = pos;
|
||||
|
||||
@ -861,7 +1064,7 @@ std::string DSForLayers::get_label(int pos, LabelType label_type) const
|
||||
}
|
||||
return value < m_layers_times.size() ? short_and_splitted_time(get_time_dhms(m_layers_times[value])) : "";
|
||||
}
|
||||
std::string str = format("%1$.2f", m_values[value]);
|
||||
std::string str = format(fmt, m_values[value]);
|
||||
if (label_type == ltHeight)
|
||||
return str;
|
||||
if (label_type == ltHeightWithLayer) {
|
||||
|
@ -6,6 +6,7 @@
|
||||
#define slic3r_GUI_DoubleSliderForLayers_hpp_
|
||||
|
||||
#include "ImGuiDoubleSlider.hpp"
|
||||
#include "RulerForDoubleSlider.hpp"
|
||||
#include "TickCodesManager.hpp"
|
||||
|
||||
#include <vector>
|
||||
@ -72,6 +73,7 @@ public:
|
||||
void SetModeAndOnlyExtruder(const bool is_one_extruder_printed_model, const int only_extruder);
|
||||
|
||||
void Render(const int canvas_width, const int canvas_height, float extra_scale = 1.f, float offset = 0.f) override;
|
||||
void force_ruler_update();
|
||||
|
||||
// jump to selected layer
|
||||
void jump_to_value();
|
||||
@ -82,6 +84,8 @@ public:
|
||||
void UseDefaultColors(bool def_colors_on);
|
||||
bool is_new_print(const std::string& print_obj_idxs);
|
||||
void set_imgui_wrapper(Slic3r::GUI::ImGuiWrapper* imgui) { m_imgui = imgui; }
|
||||
void show_estimated_times(bool show) { m_show_estimated_times = show; }
|
||||
void show_ruler(bool show, bool show_bg) { m_show_ruler = show; m_show_ruler_bg = show_bg; }
|
||||
|
||||
// manipulation with slider from keyboard
|
||||
|
||||
@ -104,6 +108,9 @@ public:
|
||||
void set_callback_on_get_print (std::function<const Slic3r::Print& ()> cb)
|
||||
{ m_cb_get_print = cb; }
|
||||
|
||||
void set_callback_on_change_app_config (std::function<void(const std::string&, const std::string&)> cb)
|
||||
{ m_cb_change_app_config = cb; }
|
||||
|
||||
void set_callback_on_empty_auto_color_change(std::function<void()> cb)
|
||||
{ m_ticks.set_callback_on_empty_auto_color_change(cb); }
|
||||
|
||||
@ -134,14 +141,18 @@ private:
|
||||
|
||||
bool is_osx { false };
|
||||
bool m_allow_editing { true };
|
||||
bool m_show_estimated_times { false };
|
||||
bool m_show_estimated_times { true };
|
||||
bool m_show_ruler { false };
|
||||
bool m_show_ruler_bg { true };
|
||||
bool m_show_cog_menu { false };
|
||||
bool m_show_edit_menu { false };
|
||||
int m_pos_on_move { -1 };
|
||||
|
||||
DrawMode m_draw_mode { dmRegular };
|
||||
Mode m_mode { SingleExtruder };
|
||||
FocusedItem m_focus { fiNone };
|
||||
|
||||
Ruler m_ruler;
|
||||
TickCodeManager m_ticks;
|
||||
Slic3r::GUI::ImGuiWrapper* m_imgui { nullptr };
|
||||
|
||||
@ -150,7 +161,7 @@ private:
|
||||
|
||||
bool is_wipe_tower_layer(int tick) const;
|
||||
|
||||
std::string get_label(int tick, LabelType label_type) const;
|
||||
std::string get_label(int tick, LabelType label_type, const std::string& fmt = "%1$.2f") const;
|
||||
|
||||
std::string get_tooltip(int tick = -1);
|
||||
|
||||
@ -160,6 +171,7 @@ private:
|
||||
|
||||
void draw_colored_band(const ImRect& groove, const ImRect& slideable_region);
|
||||
void draw_ticks(const ImRect& slideable_region);
|
||||
void draw_ruler(const ImRect& slideable_region);
|
||||
void render_menu();
|
||||
void render_cog_menu();
|
||||
void render_edit_menu();
|
||||
@ -195,6 +207,7 @@ private:
|
||||
std::function<void()> m_cb_ticks_changed { nullptr };
|
||||
std::function<std::vector<std::string>()> m_cb_get_extruder_colors { nullptr };
|
||||
std::function<const Slic3r::Print&()> m_cb_get_print { nullptr };
|
||||
std::function<void(const std::string&, const std::string&)> m_cb_change_app_config { nullptr };
|
||||
};
|
||||
|
||||
} // DoubleSlider;
|
||||
|
@ -6008,7 +6008,7 @@ bool GLCanvas3D::check_toolbar_icon_size(float init_scale, float& new_scale_to_s
|
||||
const float top_tb_width = m_main_toolbar.get_width() + m_undoredo_toolbar.get_width() + collapse_toolbar.get_width();
|
||||
float items_cnt = float(m_main_toolbar.get_visible_items_cnt() + m_undoredo_toolbar.get_visible_items_cnt() + collapse_toolbar.get_visible_items_cnt());
|
||||
const float noitems_width = top_tb_width - float(size) * items_cnt; // width of separators and borders in top toolbars
|
||||
items_cnt += 1.6; // +1.6 means a place for some minimal margin between toolbars
|
||||
items_cnt += 1.6f; // +1.6 means a place for some minimal margin between toolbars
|
||||
|
||||
// calculate scale needed for items in all top toolbars
|
||||
// the std::max() is there because on some Linux dialects/virtual machines this code is called when the canvas has not been properly initialized yet,
|
||||
|
@ -360,6 +360,7 @@ void Preview::hide_layers_slider()
|
||||
void Preview::on_size(wxSizeEvent& evt)
|
||||
{
|
||||
evt.Skip();
|
||||
m_layers_slider->force_ruler_update();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
@ -393,12 +394,18 @@ void Preview::create_sliders()
|
||||
m_layers_slider = std::make_unique<DoubleSlider::DSForLayers>(0, 0, 0, 100, wxGetApp().is_editor());
|
||||
m_layers_slider->SetEmUnit(wxGetApp().em_unit());
|
||||
m_layers_slider->set_imgui_wrapper(wxGetApp().imgui());
|
||||
m_layers_slider->show_estimated_times(wxGetApp().app_config->get_bool("show_estimated_times_in_dbl_slider"));
|
||||
m_layers_slider->show_ruler(wxGetApp().app_config->get_bool("show_ruler_in_dbl_slider"), wxGetApp().app_config->get_bool("show_ruler_bg_in_dbl_slider"));
|
||||
|
||||
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"));
|
||||
|
||||
m_layers_slider->set_callback_on_thumb_move( [this]() -> void { Preview::on_layers_slider_scroll_changed(); } );
|
||||
|
||||
m_layers_slider->set_callback_on_change_app_config([this](const std::string& key, const std::string& val) -> void {
|
||||
wxGetApp().app_config->set(key, val);
|
||||
});
|
||||
|
||||
if (wxGetApp().is_editor()) {
|
||||
m_layers_slider->set_callback_on_ticks_changed([this]() -> void {
|
||||
Model& model = wxGetApp().plater()->model();
|
||||
@ -605,6 +612,7 @@ 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
|
||||
m_layers_slider->SetExtruderColors(plater->get_extruder_color_strings_from_plater_config(wxGetApp().is_editor() ? nullptr : m_gcode_result));
|
||||
m_layers_slider->SetSliderValues(layers_z);
|
||||
m_layers_slider->force_ruler_update();
|
||||
assert(m_layers_slider->GetMinPos() == 0);
|
||||
|
||||
m_layers_slider->Freeze();
|
||||
|
@ -80,6 +80,43 @@ static bool behavior(ImGuiID id, const ImRect& region,
|
||||
return value_changed;
|
||||
}
|
||||
|
||||
static bool lclicked_on_thumb(ImGuiID id, const ImRect& region,
|
||||
const ImS32 v_min, const ImS32 v_max,
|
||||
const ImRect& thumb, ImGuiSliderFlags flags = 0)
|
||||
{
|
||||
ImGuiContext& context = *GImGui;
|
||||
|
||||
if (context.ActiveId == id && context.ActiveIdSource == ImGuiInputSource_Mouse &&
|
||||
context.IO.MouseReleased[0])
|
||||
{
|
||||
const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X;
|
||||
|
||||
ImS32 v_range = (v_min < v_max ? v_max - v_min : v_min - v_max);
|
||||
const float region_usable_sz = (region.Max[axis] - region.Min[axis]);
|
||||
const float region_usable_pos_min = region.Min[axis];
|
||||
const float region_usable_pos_max = region.Max[axis];
|
||||
|
||||
const float mouse_abs_pos = context.IO.MousePos[axis];
|
||||
float mouse_pos_ratio = (region_usable_sz > 0.0f) ? ImClamp((mouse_abs_pos - region_usable_pos_min) / region_usable_sz, 0.0f, 1.0f) : 0.0f;
|
||||
if (axis == ImGuiAxis_Y)
|
||||
mouse_pos_ratio = 1.0f - mouse_pos_ratio;
|
||||
|
||||
ImS32 v_new = v_min + (ImS32)(v_range * mouse_pos_ratio + 0.5f);
|
||||
|
||||
// Output thumb position so it can be displayed by the caller
|
||||
const ImS32 v_clamped = (v_min < v_max) ? ImClamp(v_new, v_min, v_max) : ImClamp(v_new, v_max, v_min);
|
||||
float thumb_pos_ratio = v_range != 0 ? ((float)(v_clamped - v_min) / (float)v_range) : 0.0f;
|
||||
thumb_pos_ratio = axis == ImGuiAxis_Y ? 1.0f - thumb_pos_ratio : thumb_pos_ratio;
|
||||
const float thumb_pos = region_usable_pos_min + (region_usable_pos_max - region_usable_pos_min) * thumb_pos_ratio;
|
||||
|
||||
ImVec2 new_thumb_center = axis == ImGuiAxis_Y ? ImVec2(thumb.GetCenter().x, thumb_pos) : ImVec2(thumb_pos, thumb.GetCenter().y);
|
||||
if (thumb.Contains(new_thumb_center))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ImRect ImGuiControl::DrawOptions::groove(const ImVec2& pos, const ImVec2& size, bool is_horizontal) const
|
||||
{
|
||||
ImVec2 groove_start = is_horizontal ?
|
||||
@ -262,6 +299,7 @@ bool ImGuiControl::IsLClickOnThumb()
|
||||
if (m_lclick_on_selected_thumb) {
|
||||
// discard left mouse click at list its value is checked to avoud reuse it on next frame
|
||||
m_lclick_on_selected_thumb = false;
|
||||
m_suppress_process_behavior = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -493,29 +531,55 @@ bool ImGuiControl::draw_slider( int* higher_pos, int* lower_pos,
|
||||
ImGui::ItemHoverable(m_regions.lower_thumb, id) && context.IO.MouseClicked[0])
|
||||
m_selection = ssLower;
|
||||
|
||||
// detect left click on selected thumb
|
||||
{
|
||||
const ImRect& active_thumb = m_selection == ssHigher ? m_regions.higher_thumb : m_regions.lower_thumb;
|
||||
if (ImGui::ItemHoverable(active_thumb, id) && context.IO.MouseClicked[0]) {
|
||||
m_active_thumb = active_thumb;
|
||||
m_suppress_process_behavior = true;
|
||||
}
|
||||
else if (ImGui::ItemHoverable(active_thumb, id) && context.IO.MouseReleased[0]) {
|
||||
const ImRect& slideable_region = m_selection == ssHigher ? m_regions.higher_slideable_region : m_regions.lower_slideable_region;
|
||||
if (lclicked_on_thumb(id, slideable_region, m_min_pos, m_max_pos, m_active_thumb, m_flags)) {
|
||||
m_suppress_process_behavior = true;
|
||||
m_lclick_on_selected_thumb = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update thumb position
|
||||
bool pos_changed = false;
|
||||
if (m_selection == ssHigher) {
|
||||
pos_changed = behavior(id, m_regions.higher_slideable_region, m_min_pos, m_max_pos,
|
||||
higher_pos, &m_regions.higher_thumb, m_flags);
|
||||
}
|
||||
else if (m_draw_lower_thumb && !m_combine_thumbs) {
|
||||
pos_changed = behavior(id, m_regions.lower_slideable_region, m_min_pos, m_max_pos,
|
||||
lower_pos, &m_regions.lower_thumb, m_flags);
|
||||
}
|
||||
|
||||
// check thumbs poss and correct them if needed
|
||||
check_and_correct_thumbs(higher_pos, lower_pos);
|
||||
if (!m_suppress_process_behavior) {
|
||||
if (m_selection == ssHigher) {
|
||||
pos_changed = behavior(id, m_regions.higher_slideable_region, m_min_pos, m_max_pos,
|
||||
higher_pos, &m_regions.higher_thumb, m_flags);
|
||||
}
|
||||
else if (m_draw_lower_thumb && !m_combine_thumbs) {
|
||||
pos_changed = behavior(id, m_regions.lower_slideable_region, m_min_pos, m_max_pos,
|
||||
lower_pos, &m_regions.lower_thumb, m_flags);
|
||||
}
|
||||
|
||||
// check thumbs poss and correct them if needed
|
||||
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& active_thumb = m_selection == ssHigher ? m_regions.higher_thumb : m_regions.lower_thumb;
|
||||
|
||||
bool show_move_label = false;
|
||||
ImRect mouse_pos_rc = active_thumb;
|
||||
if (!pos_changed && ImGui::ItemHoverable(item_size, id) && !ImGui::IsMouseDragging(0)) {
|
||||
behavior(id, slideable_region, m_min_pos, m_max_pos,
|
||||
|
||||
std::string move_label = "";
|
||||
|
||||
auto move_size = item_size;
|
||||
move_size.Min.x += left_dummy_sz().x;
|
||||
if (!pos_changed && ImGui::ItemHoverable(move_size, id) && !ImGui::IsMouseDragging(0)) {
|
||||
auto sl_region = slideable_region;
|
||||
if (!is_horizontal() && m_draw_opts.has_ruler)
|
||||
sl_region.Max.x += m_draw_opts.dummy_sz().x;
|
||||
behavior(id, sl_region, m_min_pos, m_max_pos,
|
||||
&m_mouse_pos, &mouse_pos_rc, m_flags, true);
|
||||
show_move_label = true;
|
||||
move_label = get_label_on_move(m_mouse_pos);
|
||||
}
|
||||
|
||||
// detect right click on selected thumb
|
||||
@ -525,16 +589,8 @@ bool ImGuiControl::draw_slider( int* higher_pos, int* lower_pos,
|
||||
context.IO.MouseClicked[0])
|
||||
m_rclick_on_selected_thumb = false;
|
||||
|
||||
// detect left click on selected thumb
|
||||
if (ImGui::ItemHoverable(active_thumb, id) && !pos_changed) {
|
||||
ImVec2 active_thumb_center = active_thumb.GetCenter();
|
||||
if (context.IO.MouseClicked[0])
|
||||
m_active_thumb_center_on_lcklick = active_thumb_center;
|
||||
if (context.IO.MouseReleased[0] &&
|
||||
(m_active_thumb_center_on_lcklick.y == active_thumb_center.y) &&
|
||||
(m_active_thumb_center_on_lcklick.x == active_thumb_center.x) )
|
||||
m_lclick_on_selected_thumb = true;
|
||||
}
|
||||
if (m_suppress_process_behavior && ImGui::ItemHoverable(item_size, id) && ImGui::IsMouseDragging(0))
|
||||
m_suppress_process_behavior = false;
|
||||
|
||||
// render slider
|
||||
|
||||
@ -565,8 +621,7 @@ bool ImGuiControl::draw_slider( int* higher_pos, int* lower_pos,
|
||||
}
|
||||
|
||||
// draw label on mouse move
|
||||
if (show_move_label)
|
||||
draw_label(get_label_on_move(m_mouse_pos), mouse_pos_rc, false, true);
|
||||
draw_label(move_label, mouse_pos_rc, false, true);
|
||||
|
||||
return pos_changed;
|
||||
}
|
||||
|
@ -62,10 +62,11 @@ public:
|
||||
void SetCtrlPos(ImVec2 pos) { m_pos = pos; }
|
||||
void SetCtrlSize(ImVec2 size) { m_size = size; }
|
||||
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, bool has_ruler = false) {
|
||||
m_pos = pos;
|
||||
m_size = size;
|
||||
m_draw_opts.scale = scale;
|
||||
m_draw_opts.has_ruler = has_ruler;
|
||||
}
|
||||
ImVec2 GetCtrlSize() { return m_size; }
|
||||
ImVec2 GetCtrlPos() { return m_pos; }
|
||||
@ -90,6 +91,8 @@ public:
|
||||
bool render();
|
||||
|
||||
std::string get_label(int pos) const;
|
||||
float rounding() const { return m_draw_opts.rounding(); }
|
||||
ImVec2 left_dummy_sz() const { return m_draw_opts.text_dummy_sz() + m_draw_opts.text_padding(); }
|
||||
|
||||
void set_get_label_on_move_cb(std::function<std::string(int)> cb) { m_cb_get_label_on_move = cb; }
|
||||
void set_get_label_cb(std::function<std::string(int)> cb) { m_cb_get_label = cb; }
|
||||
@ -100,12 +103,13 @@ private:
|
||||
|
||||
struct DrawOptions {
|
||||
float scale { 1.f }; // used for Retina on osx
|
||||
bool has_ruler { false };
|
||||
|
||||
ImVec2 dummy_sz() const { return ImVec2(24.0f, 16.0f) * scale; }
|
||||
ImVec2 dummy_sz() const { return ImVec2(has_ruler ? 48.0f : 24.0f, 16.0f) * scale; }
|
||||
ImVec2 thumb_dummy_sz() const { return ImVec2(17.0f, 17.0f) * scale; }
|
||||
ImVec2 groove_sz() const { return ImVec2(4.0f, 4.0f) * scale; }
|
||||
ImVec2 draggable_region_sz()const { return ImVec2(20.0f, 19.0f) * scale; }
|
||||
ImVec2 text_dummy_sz() const { return ImVec2(50.0f, 34.0f) * scale; }
|
||||
ImVec2 text_dummy_sz() const { return ImVec2(60.0f, 34.0f) * scale; }
|
||||
ImVec2 text_padding() const { return ImVec2( 5.0f, 2.0f) * scale; }
|
||||
|
||||
float thumb_radius() const { return 10.0f * scale; }
|
||||
@ -140,7 +144,8 @@ private:
|
||||
|
||||
bool m_rclick_on_selected_thumb{ false };
|
||||
bool m_lclick_on_selected_thumb{ false };
|
||||
ImVec2 m_active_thumb_center_on_lcklick;
|
||||
bool m_suppress_process_behavior{ false };
|
||||
ImRect m_active_thumb;
|
||||
|
||||
bool m_draw_lower_thumb{ true };
|
||||
bool m_combine_thumbs { false };
|
||||
|
96
src/slic3r/GUI/RulerForDoubleSlider.cpp
Normal file
96
src/slic3r/GUI/RulerForDoubleSlider.cpp
Normal file
@ -0,0 +1,96 @@
|
||||
///|/ 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 "RulerForDoubleSlider.hpp"
|
||||
#include "libslic3r/CustomGCode.hpp"
|
||||
|
||||
using namespace Slic3r;
|
||||
using namespace CustomGCode;
|
||||
|
||||
namespace DoubleSlider {
|
||||
|
||||
static const double PIXELS_PER_SM_DEFAULT = 96./*DEFAULT_DPI*/ * 5. / 25.4;
|
||||
|
||||
void Ruler::init(const std::vector<double>& values, double scroll_step)
|
||||
{
|
||||
if (m_is_valid)
|
||||
return;
|
||||
max_values.clear();
|
||||
max_values.reserve(std::count(values.begin(), values.end(), values.front()));
|
||||
|
||||
auto it = std::find(values.begin() + 1, values.end(), values.front());
|
||||
while (it != values.end()) {
|
||||
max_values.push_back(*(it - 1));
|
||||
it = std::find(it + 1, values.end(), values.front());
|
||||
}
|
||||
max_values.push_back(*(it - 1));
|
||||
|
||||
m_is_valid = true;
|
||||
update(values, scroll_step);
|
||||
}
|
||||
|
||||
void Ruler::update(const std::vector<double>& values, double scroll_step)
|
||||
{
|
||||
if (!m_is_valid || values.empty() ||
|
||||
// check if need to update ruler in respect to input values
|
||||
(values.front() == m_min_val && values.back() == m_max_val && m_scroll_step == scroll_step && max_values.size() == m_max_values_cnt))
|
||||
return;
|
||||
|
||||
m_min_val = values.front();
|
||||
m_max_val = values.back();
|
||||
m_scroll_step = scroll_step;
|
||||
m_max_values_cnt = max_values.size();
|
||||
|
||||
int pixels_per_sm = lround(m_scale * PIXELS_PER_SM_DEFAULT);
|
||||
|
||||
if (lround(scroll_step) > pixels_per_sm) {
|
||||
long_step = -1.0;
|
||||
return;
|
||||
}
|
||||
|
||||
int pow = -2;
|
||||
int step = 0;
|
||||
auto end_it = std::find(values.begin() + 1, values.end(), values.front());
|
||||
|
||||
while (pow < 3) {
|
||||
for (int istep : {1, 2, 5}) {
|
||||
double val = (double)istep * std::pow(10, pow);
|
||||
auto val_it = std::lower_bound(values.begin(), end_it, val - epsilon());
|
||||
|
||||
if (val_it == values.end())
|
||||
break;
|
||||
int tick = val_it - values.begin();
|
||||
|
||||
// find next tick with istep
|
||||
val *= 2;
|
||||
val_it = std::lower_bound(values.begin(), end_it, val - epsilon());
|
||||
// count of short ticks between ticks
|
||||
int short_ticks_cnt = val_it == values.end() ? tick : val_it - values.begin() - tick;
|
||||
|
||||
if (lround(short_ticks_cnt * scroll_step) > pixels_per_sm) {
|
||||
step = istep;
|
||||
// there couldn't be more then 10 short ticks between ticks
|
||||
short_step = 0.1 * short_ticks_cnt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (step > 0)
|
||||
break;
|
||||
pow++;
|
||||
}
|
||||
|
||||
long_step = step == 0 ? -1.0 : (double)step * std::pow(10, pow);
|
||||
if (long_step < 0)
|
||||
short_step = long_step;
|
||||
}
|
||||
|
||||
void Ruler::set_scale(double scale)
|
||||
{
|
||||
if (!is_approx(m_scale, scale))
|
||||
m_scale = scale;
|
||||
}
|
||||
|
||||
} // DoubleSlider
|
||||
|
||||
|
42
src/slic3r/GUI/RulerForDoubleSlider.hpp
Normal file
42
src/slic3r/GUI/RulerForDoubleSlider.hpp
Normal 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_RulerForDoubleSlider_hpp_
|
||||
#define slic3r_GUI_RulerForDoubleSlider_hpp_
|
||||
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
namespace DoubleSlider {
|
||||
|
||||
class Ruler
|
||||
{
|
||||
bool m_is_valid { false };
|
||||
double m_scale { 1. };
|
||||
double m_min_val;
|
||||
double m_max_val;
|
||||
double m_scroll_step;
|
||||
size_t m_max_values_cnt;
|
||||
|
||||
public:
|
||||
|
||||
double long_step;
|
||||
double short_step;
|
||||
std::vector<double> max_values;// max value for each object/instance in sequence print
|
||||
// > 1 for sequential print
|
||||
|
||||
void init(const std::vector<double>& values, double scroll_step);
|
||||
void update(const std::vector<double>& values, double scroll_step);
|
||||
void set_scale(double scale);
|
||||
void invalidate() { m_is_valid = false; }
|
||||
bool is_ok() { return long_step > 0 && short_step > 0; }
|
||||
size_t count() { return max_values.size(); }
|
||||
bool valid() { return m_is_valid; }
|
||||
};
|
||||
|
||||
} // DoubleSlider;
|
||||
|
||||
|
||||
|
||||
#endif // slic3r_GUI_RulerForDoubleSlider_hpp_
|
Loading…
x
Reference in New Issue
Block a user