mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 10:45:55 +08:00
ImguiDoubleSlider: WIP: Implemented "pure" ImGuiControl
+ For ImGuiControl implemented adding of callbacks for get_label and draw_scroll_line
This commit is contained in:
parent
a26d17d689
commit
ab9923eee6
@ -254,6 +254,8 @@ set(SLIC3R_GUI_SOURCES
|
||||
GUI/Mouse3DController.hpp
|
||||
GUI/DoubleSlider.cpp
|
||||
GUI/DoubleSlider.hpp
|
||||
GUI/ImGuiDoubleSlider.cpp
|
||||
GUI/ImGuiDoubleSlider.hpp
|
||||
GUI/Notebook.cpp
|
||||
GUI/Notebook.hpp
|
||||
GUI/TopBar.cpp
|
||||
|
@ -44,11 +44,6 @@
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
using GUI::from_u8;
|
||||
using GUI::into_u8;
|
||||
using GUI::format_wxstr;
|
||||
using GUI::format;
|
||||
|
||||
using namespace GUI;
|
||||
|
||||
namespace DoubleSlider {
|
||||
@ -57,19 +52,10 @@ constexpr double min_delta_area = scale_(scale_(25)); // equal to 25 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 SLIDER_LENGTH = 680.0f;
|
||||
static const float TEXT_WIDTH_DUMMY = 63.0f;
|
||||
static const ImVec2 ONE_LAYER_OFFSET = ImVec2(41.0f, /*44*/33.0f);
|
||||
static const ImVec2 HORIZONTAL_SLIDER_SIZE = ImVec2(764.0f, 90.0f);//764 = 680 + handle_dummy_width * 2 + text_right_dummy
|
||||
static const ImVec2 VERTICAL_SLIDER_SIZE = ImVec2(105.0f, 748.0f);//748 = 680 + text_dummy_height * 2
|
||||
|
||||
const ImU32 tooltip_bg = ImGui::ColorConvertFloat4ToU32(ImGuiPureWrap::COL_GREY_LIGHT);
|
||||
const ImU32 handle_clr = ImGui::ColorConvertFloat4ToU32(ImGuiPureWrap::COL_ORANGE_LIGHT);
|
||||
const ImU32 handle_border_clr = IM_COL32(255, 255, 255, 255);//white_bg;
|
||||
|
||||
int m_tick_value = -1;
|
||||
ImVec4 m_tick_rect;
|
||||
|
||||
bool equivalent_areas(const double& bottom_area, const double& top_area)
|
||||
{
|
||||
return fabs(bottom_area - top_area) <= miscalculation;
|
||||
@ -97,7 +83,7 @@ Control::Control( wxWindow *parent,
|
||||
const wxPoint& pos,
|
||||
const wxSize& size,
|
||||
long style,
|
||||
const wxValidator& val,
|
||||
// const wxValidator& val,
|
||||
const wxString& name) :
|
||||
wxControl(parent, id, pos, size, wxWANTS_CHARS | wxBORDER_NONE),
|
||||
m_lower_value(lowerValue),
|
||||
@ -178,6 +164,16 @@ Control::Control( wxWindow *parent,
|
||||
|
||||
if (style == wxSL_VERTICAL)
|
||||
m_ruler.set_parent(this->GetParent());
|
||||
imgui_ctrl = ImGuiControl( lowerValue, higherValue,
|
||||
minValue, maxValue,
|
||||
ImVec2(0.f, 0.f), ImVec2(0.f, 0.f),
|
||||
style, into_u8(name), !is_horizontal());
|
||||
|
||||
imgui_ctrl.set_get_label_cb([this](int pos) {return into_u8(get_label(pos)); });
|
||||
|
||||
if (!is_horizontal())
|
||||
imgui_ctrl.set_get_label_on_move_cb([this](int pos) {return into_u8(get_label(pos, ltEstimatedTime)); });
|
||||
|
||||
}
|
||||
|
||||
void Control::msw_rescale()
|
||||
@ -249,6 +245,8 @@ void Control::SetLowerValue(const int lower_val)
|
||||
wxCommandEvent e(wxEVT_SCROLL_CHANGED);
|
||||
e.SetEventObject(this);
|
||||
ProcessWindowEvent(e);
|
||||
|
||||
imgui_ctrl.SetLowerValue(lower_val);
|
||||
}
|
||||
|
||||
void Control::SetHigherValue(const int higher_val)
|
||||
@ -262,6 +260,8 @@ void Control::SetHigherValue(const int higher_val)
|
||||
wxCommandEvent e(wxEVT_SCROLL_CHANGED);
|
||||
e.SetEventObject(this);
|
||||
ProcessWindowEvent(e);
|
||||
|
||||
imgui_ctrl.SetHigherValue(higher_val);
|
||||
}
|
||||
|
||||
void Control::SetSelectionSpan(const int lower_val, const int higher_val)
|
||||
@ -271,6 +271,9 @@ void Control::SetSelectionSpan(const int lower_val, const int higher_val)
|
||||
if (m_lower_value < m_higher_value)
|
||||
m_is_one_layer = false;
|
||||
|
||||
imgui_ctrl.CombineThumbs(m_is_one_layer);
|
||||
imgui_ctrl.SetSelectionSpan(lower_val, higher_val);
|
||||
|
||||
Refresh();
|
||||
Update();
|
||||
|
||||
@ -284,6 +287,8 @@ void Control::SetMaxValue(const int max_value)
|
||||
m_max_value = max_value;
|
||||
Refresh();
|
||||
Update();
|
||||
|
||||
imgui_ctrl.SetMaxValue(max_value);
|
||||
}
|
||||
|
||||
void Control::SetSliderValues(const std::vector<double>& values)
|
||||
@ -294,6 +299,8 @@ void Control::SetSliderValues(const std::vector<double>& values)
|
||||
// When "No sparce layer" is enabled, use m_layers_values for ruler update.
|
||||
// Because of m_values has duplicate values in this case.
|
||||
// m_ruler.update(this->GetParent(), m_layers_values.empty() ? m_values : m_layers_values, get_scroll_step());
|
||||
|
||||
imgui_ctrl.SetSliderValues(values);
|
||||
}
|
||||
|
||||
void Control::draw_scroll_line(wxDC& dc, const int lower_pos, const int higher_pos)
|
||||
@ -420,8 +427,12 @@ void Control::SetTicksValues(const Info& custom_gcode_per_print_z)
|
||||
post_ticks_changed_event();
|
||||
|
||||
// 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());
|
||||
imgui_ctrl.set_draw_scroll_line_cb(nullptr);
|
||||
}
|
||||
else
|
||||
imgui_ctrl.set_draw_scroll_line_cb([this](const ImRect& scroll_line, const ImRect& slideable_region) { draw_colored_band(scroll_line, slideable_region); });
|
||||
|
||||
if (custom_gcode_per_print_z.mode && !custom_gcode_per_print_z.gcodes.empty())
|
||||
m_ticks.mode = custom_gcode_per_print_z.mode;
|
||||
@ -585,6 +596,8 @@ void Control::render()
|
||||
}
|
||||
}
|
||||
|
||||
using namespace ImGui;
|
||||
|
||||
// ImGuiDS
|
||||
|
||||
float Control::get_pos_from_value(int v_min, int v_max, int value, const ImRect& rect) {
|
||||
@ -600,35 +613,6 @@ float Control::get_pos_from_value(int v_min, int v_max, int value, const ImRect&
|
||||
return handle_pos;
|
||||
}
|
||||
|
||||
void Control::draw_background(const ImRect& groove)
|
||||
{
|
||||
const ImU32 bg_rect_col = IM_COL32(255, 255, 255, 255);
|
||||
const ImU32 groove_col = ImGui::ColorConvertFloat4ToU32(ImGuiPureWrap::COL_WINDOW_BACKGROUND);
|
||||
|
||||
if (is_horizontal() || m_ticks.empty()) {
|
||||
ImVec2 groove_padding = ImVec2(2.0f, 2.0f) * m_scale;
|
||||
|
||||
ImRect bg_rect = groove;
|
||||
bg_rect.Expand(groove_padding);
|
||||
|
||||
// draw bg of slider
|
||||
ImGui::RenderFrame(bg_rect.Min, bg_rect.Max, bg_rect_col, false, 0.5 * bg_rect.GetWidth());
|
||||
// draw bg of scroll
|
||||
ImGui::RenderFrame(groove.Min, groove.Max, groove_col, false, 0.5 * groove.GetWidth());
|
||||
}
|
||||
else {
|
||||
ImVec2 groove_padding = ImVec2(3.0f, 4.0f) * m_scale;
|
||||
|
||||
ImRect bg_rect = groove;
|
||||
bg_rect.Expand(groove_padding);
|
||||
|
||||
// draw bg of slider
|
||||
ImGui::RenderFrame(bg_rect.Min, bg_rect.Max, bg_rect_col, false, bg_rect.GetWidth() * 0.5);
|
||||
// draw bg of scroll
|
||||
ImGui::RenderFrame(groove.Min, groove.Max, groove_col, false, 0.5 * groove.GetWidth());
|
||||
}
|
||||
}
|
||||
|
||||
void Control::draw_ticks(const ImRect& slideable_region) {
|
||||
//if(m_draw_mode != dmRegular)
|
||||
// return;
|
||||
@ -669,8 +653,6 @@ void Control::draw_ticks(const ImRect& slideable_region) {
|
||||
{
|
||||
ImGui::RenderFrame(tick_hover_box.Min, tick_hover_box.Max, tick_hover_box_clr, false);
|
||||
if (context.IO.MouseClicked[0]) {
|
||||
m_tick_value = tick_it->tick;
|
||||
m_tick_rect = ImVec4(tick_hover_box.Min.x, tick_hover_box.Min.y, tick_hover_box.Max.x, tick_hover_box.Max.y);
|
||||
}
|
||||
}
|
||||
++tick_it;
|
||||
@ -745,9 +727,7 @@ void Control::draw_colored_band(const ImRect& groove, const ImRect& slideable_re
|
||||
if (m_ticks.empty())
|
||||
return;
|
||||
|
||||
const ImU32 blank_col = IM_COL32(255, 255, 255, 255);
|
||||
|
||||
ImVec2 blank_padding = ImVec2(4.0f, 2.0f) * m_scale;
|
||||
ImVec2 blank_padding = ImVec2(5.0f, 2.0f) * m_scale;
|
||||
float blank_width = 1.0f * m_scale;
|
||||
|
||||
ImRect blank_rect = ImRect(groove.GetCenter().x - blank_width, groove.Min.y, groove.GetCenter().x + blank_width, groove.Max.y);
|
||||
@ -761,7 +741,7 @@ void Control::draw_colored_band(const ImRect& groove, const ImRect& slideable_re
|
||||
//cover round corner
|
||||
ImGui::RenderFrame(ImVec2(band_rc.Min.x, band_rc.Max.y - band_rc.GetWidth() * 0.5), band_rc.Max, clr, false);
|
||||
};
|
||||
auto draw_main_band = [&main_band, this](const ImU32& clr) {
|
||||
auto draw_main_band = [&main_band](const ImU32& clr) {
|
||||
ImGui::RenderFrame(main_band.Min, main_band.Max, clr, false, main_band.GetWidth() * 0.5);
|
||||
};
|
||||
//draw main colored band
|
||||
@ -811,286 +791,6 @@ void Control::draw_colored_band(const ImRect& groove, const ImRect& slideable_re
|
||||
}
|
||||
}
|
||||
|
||||
void Control::draw_label(std::string label, const ImRect& handle, const ImVec2& handle_center, bool is_horizontal /*= false*/)
|
||||
{
|
||||
ImVec2 text_padding = ImVec2(5.0f, 2.0f) * m_scale;
|
||||
float rounding = 2.0f * m_scale;
|
||||
ImVec2 triangle_offsets[3] = { ImVec2(2.0f, 0.0f) * m_scale, ImVec2(0.0f, 8.0f) * m_scale, ImVec2(9.0f, 0.0f) * m_scale };
|
||||
|
||||
ImVec2 text_content_size = ImGui::CalcTextSize(label.c_str());
|
||||
ImVec2 text_size = text_content_size + text_padding * 2;
|
||||
ImVec2 text_start = is_horizontal ?
|
||||
ImVec2(handle.Max.x + triangle_offsets[2].x, handle_center.y - text_size.y) :
|
||||
ImVec2(handle.Min.x - text_size.x - triangle_offsets[2].x, handle_center.y - text_size.y) ;
|
||||
ImRect text_rect(text_start, text_start + text_size);
|
||||
|
||||
ImVec2 pos_1 = is_horizontal ?
|
||||
ImVec2(text_rect.Min.x + triangle_offsets[0].x, text_rect.Max.y - triangle_offsets[0].y) :
|
||||
text_rect.Max - triangle_offsets[0];
|
||||
ImVec2 pos_2 = is_horizontal ? pos_1 - triangle_offsets[2] : pos_1 - triangle_offsets[1];
|
||||
ImVec2 pos_3 = is_horizontal ? pos_1 - triangle_offsets[1] : pos_1 + triangle_offsets[2];
|
||||
|
||||
ImGui::RenderFrame(text_rect.Min, text_rect.Max, tooltip_bg, true, rounding);
|
||||
ImGui::GetCurrentWindow()->DrawList->AddTriangleFilled(pos_1, pos_2, pos_3, tooltip_bg);
|
||||
ImGui::RenderText(text_start + text_padding, label.c_str());
|
||||
};
|
||||
|
||||
bool Control::horizontal_slider(const char* str_id, int* value, int v_min, int v_max, const ImVec2& pos, const ImVec2& size, float scale)
|
||||
{
|
||||
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
||||
if (window->SkipItems)
|
||||
return false;
|
||||
|
||||
ImGuiContext& context = *GImGui;
|
||||
const ImGuiID id = window->GetID(str_id);
|
||||
|
||||
const ImRect draw_region(pos, pos + size);
|
||||
ImGui::ItemSize(draw_region);
|
||||
|
||||
float bottom_dummy = 44.0f * m_scale;
|
||||
float handle_dummy_width = 17.0f * m_scale;
|
||||
float text_right_dummy = 50.0f * scale * m_scale;
|
||||
float groove_y = 8.0f * m_scale;
|
||||
float draggable_region_y = 19.0f * m_scale;
|
||||
float handle_radius = 14.0f * m_scale;
|
||||
float handle_border = 2.0f * m_scale;
|
||||
float rounding = 2.0f * m_scale;
|
||||
float text_start_offset = 8.0f * m_scale;
|
||||
ImVec2 text_padding = ImVec2(5.0f, 2.0f) * m_scale;
|
||||
float triangle_offsets[3] = { -3.5f * m_scale, 3.5f * m_scale, -6.06f * m_scale };
|
||||
|
||||
// calc groove size
|
||||
ImVec2 groove_start = ImVec2(pos.x + handle_dummy_width, pos.y + size.y - groove_y - bottom_dummy);
|
||||
ImVec2 groove_size = ImVec2(size.x - 2 * handle_dummy_width - text_right_dummy, groove_y);
|
||||
ImRect groove = ImRect(groove_start, groove_start + groove_size);
|
||||
|
||||
// set active(draggable) region.
|
||||
ImRect draggable_region = ImRect(groove.Min.x, groove.GetCenter().y, groove.Max.x, groove.GetCenter().y);
|
||||
draggable_region.Expand(ImVec2(handle_radius, draggable_region_y));
|
||||
float mid_y = draggable_region.GetCenter().y;
|
||||
bool hovered = ImGui::ItemHoverable(draggable_region, id);
|
||||
if (hovered && context.IO.MouseDown[0]) {
|
||||
ImGui::SetActiveID(id, window);
|
||||
ImGui::SetFocusID(id, window);
|
||||
ImGui::FocusWindow(window);
|
||||
}
|
||||
|
||||
// draw background
|
||||
draw_background(groove);
|
||||
|
||||
// set slideable region
|
||||
ImRect slideable_region = draggable_region;
|
||||
slideable_region.Expand(ImVec2(-handle_radius, 0));
|
||||
|
||||
// initialize the handle
|
||||
float handle_pos = get_pos_from_value(v_min, v_max, *value, groove);
|
||||
ImRect handle = ImRect(handle_pos - handle_radius, mid_y - handle_radius, handle_pos + handle_radius, mid_y + handle_radius);
|
||||
|
||||
// update handle position and value
|
||||
bool value_changed = GUI::slider_behavior(id, slideable_region, (const ImS32)v_min, (const ImS32)v_max, (ImS32*)value, &handle);
|
||||
ImVec2 handle_center = handle.GetCenter();
|
||||
|
||||
// draw scroll line
|
||||
ImRect scroll_line = ImRect(ImVec2(groove.Min.x, mid_y - groove_y / 2), ImVec2(handle_center.x, mid_y + groove_y / 2));
|
||||
window->DrawList->AddRectFilled(scroll_line.Min, scroll_line.Max, handle_clr, rounding);
|
||||
|
||||
// draw handle
|
||||
ImGuiPureWrap::draw_hexagon(handle_center, handle_radius, handle_border_clr);
|
||||
ImGuiPureWrap::draw_hexagon(handle_center, handle_radius - handle_border, handle_clr);
|
||||
|
||||
draw_label(std::to_string(*value), handle, handle_center, true);
|
||||
|
||||
return value_changed;
|
||||
}
|
||||
|
||||
bool Control::vertical_slider(const char* str_id, int* higher_value, int* lower_value, std::string& higher_label, std::string& lower_label, int v_min, int v_max, const ImVec2& pos, const ImVec2& size, SelectedSlider& selection, bool one_layer_flag, float scale)
|
||||
{
|
||||
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
||||
if (window->SkipItems)
|
||||
return false;
|
||||
|
||||
ImGuiContext& context = *GImGui;
|
||||
const ImGuiID id = window->GetID(str_id);
|
||||
|
||||
const ImRect draw_region(pos, pos + size);
|
||||
ImGui::ItemSize(draw_region);
|
||||
|
||||
float right_dummy = 24.0f * m_scale;
|
||||
float text_dummy_height = 34.0f * scale * m_scale;
|
||||
float groove_x = 10.0f * m_scale;
|
||||
float draggable_region_x = 40.0f * m_scale;
|
||||
float handle_radius = 14.0f * m_scale;
|
||||
float handle_border = 2.0f * m_scale;
|
||||
float line_width = 2.0f * m_scale;
|
||||
float line_offset = 9.0f * m_scale;
|
||||
float one_handle_offset = 26.0f * m_scale;
|
||||
float bar_width = 12.0f * m_scale;
|
||||
ImVec2 text_content_size;
|
||||
ImVec2 text_size;
|
||||
|
||||
const ImU32 delete_btn_clr = IM_COL32(144, 144, 144, 255);
|
||||
|
||||
// calc slider groove size
|
||||
ImVec2 groove_start = ImVec2(pos.x + size.x - groove_x - right_dummy, pos.y + text_dummy_height);
|
||||
ImVec2 groove_size = ImVec2(groove_x, size.y - /*2 * */text_dummy_height);
|
||||
ImRect groove = ImRect(groove_start, groove_start + groove_size);
|
||||
|
||||
// set active(draggable) region.
|
||||
ImRect draggable_region = ImRect(groove.GetCenter().x, groove.Min.y, groove.GetCenter().x, groove.Max.y);
|
||||
draggable_region.Expand(ImVec2(draggable_region_x, 0));
|
||||
float mid_x = draggable_region.GetCenter().x;
|
||||
bool hovered = ImGui::ItemHoverable(draggable_region, id) && !ImGui::ItemHoverable(m_tick_rect, id);
|
||||
if (hovered && context.IO.MouseDown[0]) {
|
||||
ImGui::SetActiveID(id, window);
|
||||
ImGui::SetFocusID(id, window);
|
||||
ImGui::FocusWindow(window);
|
||||
}
|
||||
|
||||
// Processing interacting
|
||||
// set slideable region
|
||||
ImRect higher_slideable_region = ImRect(draggable_region.Min, draggable_region.Max - ImVec2(0, handle_radius));
|
||||
ImRect lower_slideable_region = ImRect(draggable_region.Min + ImVec2(0, handle_radius), draggable_region.Max);
|
||||
ImRect one_slideable_region = draggable_region;
|
||||
|
||||
// initialize the handles.
|
||||
float higher_handle_pos = get_pos_from_value(v_min, v_max, *higher_value, higher_slideable_region);
|
||||
ImRect higher_handle = ImRect(mid_x - handle_radius, higher_handle_pos - handle_radius, mid_x + handle_radius, higher_handle_pos + handle_radius);
|
||||
|
||||
float lower_handle_pos = get_pos_from_value(v_min, v_max, *lower_value, lower_slideable_region);
|
||||
ImRect lower_handle = ImRect(mid_x - handle_radius, lower_handle_pos - handle_radius, mid_x + handle_radius, lower_handle_pos + handle_radius);
|
||||
|
||||
ImRect one_handle = ImRect(higher_handle.Min - ImVec2(one_handle_offset, 0), higher_handle.Max - ImVec2(one_handle_offset, 0));
|
||||
|
||||
//static bool become_del_handle = false;
|
||||
bool value_changed = false;
|
||||
const float hexagon_angle = IM_PI * 0.5;
|
||||
if (!one_layer_flag)
|
||||
{
|
||||
// select higher handle by default
|
||||
static bool h_selected = true;
|
||||
if (ImGui::ItemHoverable(higher_handle, id) && context.IO.MouseClicked[0]) {
|
||||
selection = ssHigher;
|
||||
h_selected = true;
|
||||
}
|
||||
if (ImGui::ItemHoverable(lower_handle, id) && context.IO.MouseClicked[0]) {
|
||||
selection = ssLower;
|
||||
h_selected = false;
|
||||
}
|
||||
|
||||
// update handle position and value
|
||||
if (h_selected)
|
||||
{
|
||||
value_changed = slider_behavior(id, higher_slideable_region, v_min, v_max,
|
||||
higher_value, &higher_handle, ImGuiSliderFlags_Vertical,
|
||||
m_tick_value, m_tick_rect);
|
||||
}
|
||||
if (!h_selected) {
|
||||
value_changed = slider_behavior(id, lower_slideable_region, v_min, v_max,
|
||||
lower_value, &lower_handle, ImGuiSliderFlags_Vertical,
|
||||
m_tick_value, m_tick_rect);
|
||||
}
|
||||
|
||||
ImVec2 higher_handle_center = higher_handle.GetCenter();
|
||||
ImVec2 lower_handle_center = lower_handle.GetCenter();
|
||||
if (higher_handle_center.y + handle_radius > lower_handle_center.y && h_selected)
|
||||
{
|
||||
lower_handle = higher_handle;
|
||||
lower_handle.TranslateY(handle_radius);
|
||||
lower_handle_center.y = higher_handle_center.y + handle_radius;
|
||||
*lower_value = *higher_value;
|
||||
}
|
||||
if (higher_handle_center.y + handle_radius > lower_handle_center.y && !h_selected)
|
||||
{
|
||||
higher_handle = lower_handle;
|
||||
higher_handle.TranslateY(-handle_radius);
|
||||
higher_handle_center.y = lower_handle_center.y - handle_radius;
|
||||
*higher_value = *lower_value;
|
||||
}
|
||||
|
||||
// judge whether to open menu
|
||||
if (ImGui::ItemHoverable(h_selected ? higher_handle : lower_handle, id) && context.IO.MouseClicked[1])
|
||||
m_show_menu = true;
|
||||
if ((!ImGui::ItemHoverable(h_selected ? higher_handle : lower_handle, id) && context.IO.MouseClicked[1]) ||
|
||||
context.IO.MouseClicked[0])
|
||||
m_show_menu = false;
|
||||
|
||||
ImRect scroll_line = ImRect(ImVec2(mid_x - groove_x / 2, higher_handle_center.y), ImVec2(mid_x + groove_x / 2, lower_handle_center.y));
|
||||
if (!m_ticks.empty()) {
|
||||
// draw ticks
|
||||
draw_ticks(h_selected ? higher_slideable_region : lower_slideable_region);
|
||||
// draw background
|
||||
draw_background(groove);
|
||||
// draw colored band
|
||||
draw_colored_band(scroll_line, h_selected ? higher_slideable_region : lower_slideable_region);
|
||||
}
|
||||
else {
|
||||
// draw background
|
||||
draw_background(groove);
|
||||
// draw scroll line
|
||||
window->DrawList->AddRectFilled(scroll_line.Min, scroll_line.Max, handle_clr, 2.0f * m_scale);
|
||||
}
|
||||
|
||||
// draw handles
|
||||
ImGuiPureWrap::draw_hexagon(higher_handle_center, handle_radius, handle_border_clr, hexagon_angle);
|
||||
ImGuiPureWrap::draw_hexagon(higher_handle_center, handle_radius - handle_border, handle_clr, hexagon_angle);
|
||||
ImGuiPureWrap::draw_hexagon(lower_handle_center, handle_radius, handle_border_clr, hexagon_angle);
|
||||
ImGuiPureWrap::draw_hexagon(lower_handle_center, handle_radius - handle_border, handle_clr, hexagon_angle);
|
||||
if (h_selected) {
|
||||
ImGuiPureWrap::draw_hexagon(higher_handle_center, handle_radius, handle_border_clr, hexagon_angle);
|
||||
ImGuiPureWrap::draw_hexagon(higher_handle_center, handle_radius - handle_border, handle_clr, hexagon_angle);
|
||||
window->DrawList->AddLine(higher_handle_center + ImVec2(-line_offset, 0.0f), higher_handle_center + ImVec2(line_offset, 0.0f), handle_border_clr, line_width);
|
||||
window->DrawList->AddLine(higher_handle_center + ImVec2(0.0f, -line_offset), higher_handle_center + ImVec2(0.0f, line_offset), handle_border_clr, line_width);
|
||||
}
|
||||
if (!h_selected) {
|
||||
window->DrawList->AddLine(lower_handle_center + ImVec2(-line_offset, 0.0f), lower_handle_center + ImVec2(line_offset, 0.0f), handle_border_clr, line_width);
|
||||
window->DrawList->AddLine(lower_handle_center + ImVec2(0.0f, -line_offset), lower_handle_center + ImVec2(0.0f, line_offset), handle_border_clr, line_width);
|
||||
}
|
||||
|
||||
// draw higher label
|
||||
draw_label(higher_label, higher_handle, higher_handle_center);
|
||||
// draw lower label
|
||||
draw_label(lower_label, lower_handle, lower_handle_center);
|
||||
}
|
||||
|
||||
if (one_layer_flag)
|
||||
{
|
||||
// update handle position
|
||||
value_changed = GUI::slider_behavior(id, one_slideable_region, v_min, v_max,
|
||||
higher_value, &one_handle, ImGuiSliderFlags_Vertical,
|
||||
m_tick_value, m_tick_rect);
|
||||
|
||||
ImVec2 handle_center = one_handle.GetCenter();
|
||||
|
||||
// judge whether to open menu
|
||||
if (ImGui::ItemHoverable(one_handle, id) && context.IO.MouseClicked[1])
|
||||
m_show_menu = true;
|
||||
if ((!ImGui::ItemHoverable(one_handle, id) && context.IO.MouseClicked[1]) ||
|
||||
context.IO.MouseClicked[0])
|
||||
m_show_menu = false;
|
||||
|
||||
ImVec2 bar_center = higher_handle.GetCenter();
|
||||
|
||||
if (!m_ticks.empty()) {
|
||||
// draw ticks
|
||||
draw_ticks(one_slideable_region);
|
||||
// draw colored band
|
||||
draw_colored_band(groove, one_slideable_region);
|
||||
}
|
||||
|
||||
// draw handle
|
||||
window->DrawList->AddLine(ImVec2(mid_x - bar_width, handle_center.y), ImVec2(mid_x + bar_width, handle_center.y), handle_clr, line_width);
|
||||
ImGuiPureWrap::draw_hexagon(handle_center, handle_radius, handle_border_clr, hexagon_angle);
|
||||
ImGuiPureWrap::draw_hexagon(handle_center, handle_radius - handle_border, handle_clr, hexagon_angle);
|
||||
window->DrawList->AddLine(handle_center + ImVec2(-line_offset, 0.0f), handle_center + ImVec2(line_offset, 0.0f), handle_border_clr, line_width);
|
||||
window->DrawList->AddLine(handle_center + ImVec2(0.0f, -line_offset), handle_center + ImVec2(0.0f, line_offset), handle_border_clr, line_width);
|
||||
|
||||
// draw label
|
||||
draw_label(higher_label, one_handle, handle_center);
|
||||
}
|
||||
|
||||
return value_changed;
|
||||
}
|
||||
|
||||
void Control::render_menu()
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(10.0f, 10.0f) * m_scale);
|
||||
@ -1154,9 +854,6 @@ void Control::render_menu()
|
||||
|
||||
bool Control::render_button(const wchar_t btn_icon, const std::string& label_id, FocusedItem focus)
|
||||
{
|
||||
float scale = (float)wxGetApp().em_unit() / 10.0f;
|
||||
ImGui::SameLine(66.f * scale * m_scale);
|
||||
|
||||
const ImGuiStyle& style = ImGui::GetStyle();
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, { 1, style.ItemSpacing.y });
|
||||
@ -1168,7 +865,7 @@ bool Control::render_button(const wchar_t btn_icon, const std::string& label_id,
|
||||
|
||||
std::string btn_label;
|
||||
btn_label += btn_icon;
|
||||
const bool ret = ImGui::Button((btn_label + "##" + label_id).c_str(), ImVec2(16*scale, 0));
|
||||
const bool ret = ImGui::Button((btn_label + "##" + label_id).c_str(), ImVec2(16*m_scale, 0));
|
||||
|
||||
ImGui::PopStyleColor(3);
|
||||
|
||||
@ -1192,81 +889,31 @@ bool Control::imgui_render(GUI::GLCanvas3D& canvas)
|
||||
int canvas_width = cnv_size.get_width();
|
||||
int canvas_height = cnv_size.get_height();
|
||||
|
||||
/* style and colors */
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_::ImGuiStyleVar_WindowBorderSize, 0);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_::ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_::ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_::ImGuiCol_WindowBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_Text));
|
||||
|
||||
int windows_flag = ImGuiWindowFlags_NoTitleBar
|
||||
| ImGuiWindowFlags_NoCollapse
|
||||
| ImGuiWindowFlags_NoMove
|
||||
| ImGuiWindowFlags_NoResize
|
||||
| ImGuiWindowFlags_NoScrollbar
|
||||
| ImGuiWindowFlags_NoScrollWithMouse;
|
||||
|
||||
// render_input_custom_gcode();
|
||||
|
||||
float scale = (float)wxGetApp().em_unit() / 10.0f;
|
||||
|
||||
scale *= m_scale;
|
||||
ImVec2 pos;
|
||||
ImVec2 size;
|
||||
|
||||
if (is_horizontal()) {
|
||||
float pos_x = std::max(LEFT_MARGIN, 0.2f * canvas_width);
|
||||
float pos_y = (canvas_height - HORIZONTAL_SLIDER_SIZE.y * m_scale);
|
||||
ImVec2 size = ImVec2(canvas_width - 2 * pos_x, HORIZONTAL_SLIDER_SIZE.y * m_scale);
|
||||
ImGuiPureWrap::set_next_window_pos(pos_x, pos_y, ImGuiCond_Always);
|
||||
ImGuiPureWrap::begin(std::string("moves_slider"), windows_flag);
|
||||
int value = GetHigherValue();
|
||||
if (horizontal_slider("moves_slider", &value, GetMinValue(), GetMaxValue(), ImVec2(pos_x, pos_y), size, scale)) {
|
||||
result = true;
|
||||
SetHigherValue(value);
|
||||
}
|
||||
ImGuiPureWrap::end();
|
||||
pos.x = std::max(LEFT_MARGIN, 0.2f * canvas_width);
|
||||
pos.y = canvas_height - HORIZONTAL_SLIDER_SIZE.y * scale;
|
||||
size = ImVec2(canvas_width - 2 * pos.x, HORIZONTAL_SLIDER_SIZE.y * scale);
|
||||
imgui_ctrl.ShowLabelOnMouseMove(false);
|
||||
}
|
||||
else {
|
||||
float pos_x = canvas_width - (VERTICAL_SLIDER_SIZE.x + TEXT_WIDTH_DUMMY * scale - TEXT_WIDTH_DUMMY) * m_scale;
|
||||
float pos_y = ONE_LAYER_OFFSET.y;
|
||||
ImVec2 size = ImVec2((VERTICAL_SLIDER_SIZE.x + TEXT_WIDTH_DUMMY * scale - TEXT_WIDTH_DUMMY) * m_scale, canvas_height - 4 * pos_y);
|
||||
|
||||
ImGuiPureWrap::set_next_window_pos(pos_x, pos_y, ImGuiCond_Always);
|
||||
ImGuiPureWrap::begin(std::string("laysers_slider"), windows_flag);
|
||||
|
||||
if (!m_ticks.empty() && /*m_draw_mode == dmRegular && */render_button(ImGui::RevertButton, "revert", fiRevertIcon))
|
||||
discard_all_thicks();
|
||||
else
|
||||
ImGui::NewLine();
|
||||
|
||||
render_menu();
|
||||
|
||||
int higher_value = GetHigherValue();
|
||||
int lower_value = GetLowerValue();
|
||||
std::string higher_label = into_u8(get_label(m_higher_value));
|
||||
std::string lower_label = into_u8(get_label(m_lower_value));
|
||||
int temp_higher_value = higher_value;
|
||||
int temp_lower_value = lower_value;
|
||||
|
||||
if (vertical_slider("laysers_slider", &higher_value, &lower_value, higher_label, lower_label, GetMinValue(), GetMaxValue(),
|
||||
ImVec2(pos_x, pos_y), size, m_selection, is_one_layer(), scale)) {
|
||||
if (temp_higher_value != higher_value)
|
||||
SetHigherValue(higher_value);
|
||||
if (temp_lower_value != lower_value)
|
||||
SetLowerValue(lower_value);
|
||||
result = true;
|
||||
pos.x = canvas_width - VERTICAL_SLIDER_SIZE.x * scale;
|
||||
pos.y = ONE_LAYER_OFFSET.y;
|
||||
size = ImVec2(VERTICAL_SLIDER_SIZE.x * scale, canvas_height - 4 * pos.y);
|
||||
imgui_ctrl.ShowLabelOnMouseMove(true);
|
||||
}
|
||||
|
||||
ImGui::NewLine();
|
||||
if (render_button(is_one_layer() ? ImGui::Lock : ImGui::Unlock, "one_layer", fiOneLayerIcon))
|
||||
switch_one_layer_mode();
|
||||
imgui_ctrl.SetPos(pos);
|
||||
imgui_ctrl.SetSize(size);
|
||||
imgui_ctrl.SetScale(scale);
|
||||
|
||||
ImGui::NewLine();
|
||||
if (m_draw_mode != dmSequentialGCodeView && render_button(ImGui::PrintIconMarker, "settings", fiCogIcon))
|
||||
show_cog_icon_context_menu();
|
||||
|
||||
ImGuiPureWrap::end();
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar(3);
|
||||
ImGui::PopStyleColor(2);
|
||||
if (imgui_ctrl.render(m_selection))
|
||||
SetSelectionSpan(m_is_one_layer ? imgui_ctrl.GetHigherValue() : imgui_ctrl.GetLowerValue(), imgui_ctrl.GetHigherValue());
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -2092,6 +1739,7 @@ int Control::get_tick_near_point(const wxPoint& pt)
|
||||
void Control::ChangeOneLayerLock()
|
||||
{
|
||||
m_is_one_layer = !m_is_one_layer;
|
||||
imgui_ctrl.CombineThumbs(m_is_one_layer);
|
||||
m_selection == ssLower ? correct_lower_value() : correct_higher_value();
|
||||
if (!m_selection) m_selection = ssHigher;
|
||||
|
||||
@ -2142,6 +1790,8 @@ void Control::correct_lower_value()
|
||||
|
||||
if ((m_lower_value >= m_higher_value && m_lower_value <= m_max_value) || m_is_one_layer)
|
||||
m_higher_value = m_lower_value;
|
||||
|
||||
imgui_ctrl.SetSelectionSpan(m_lower_value, m_higher_value);
|
||||
}
|
||||
|
||||
void Control::correct_higher_value()
|
||||
@ -2153,6 +1803,8 @@ void Control::correct_higher_value()
|
||||
|
||||
if ((m_higher_value <= m_lower_value && m_higher_value >= m_min_value) || m_is_one_layer)
|
||||
m_lower_value = m_higher_value;
|
||||
|
||||
imgui_ctrl.SetSelectionSpan(m_lower_value, m_higher_value);
|
||||
}
|
||||
|
||||
wxString Control::get_tooltip(int tick/*=-1*/)
|
||||
@ -2599,6 +2251,8 @@ void Control::OnKeyUp(wxKeyEvent &event)
|
||||
else if (event.GetKeyCode() == WXK_SHIFT)
|
||||
UseDefaultColors(true);
|
||||
|
||||
imgui_ctrl.CombineThumbs(m_is_one_layer);
|
||||
|
||||
Refresh();
|
||||
Update();
|
||||
event.Skip();
|
||||
@ -2649,8 +2303,8 @@ void Control::OnRightDown(wxMouseEvent& event)
|
||||
else
|
||||
m_lower_value = m_higher_value;
|
||||
|
||||
// set slider to "one layer" mode
|
||||
m_is_right_down = m_is_one_layer = true;
|
||||
// set slider to "one layer" mode // ysWhy???
|
||||
m_is_right_down = /*m_is_one_layer = */true;
|
||||
|
||||
Refresh();
|
||||
Update();
|
||||
@ -2909,8 +2563,12 @@ void Control::auto_color_change()
|
||||
});
|
||||
}
|
||||
|
||||
if (m_ticks.empty())
|
||||
if (m_ticks.empty()) {
|
||||
GUI::wxGetApp().plater()->get_notification_manager()->push_notification(GUI::NotificationType::EmptyAutoColorChange);
|
||||
imgui_ctrl.set_draw_scroll_line_cb(nullptr);
|
||||
}
|
||||
else
|
||||
imgui_ctrl.set_draw_scroll_line_cb([this](const ImRect& scroll_line, const ImRect& slideable_region) { draw_colored_band(scroll_line, slideable_region); });
|
||||
|
||||
post_ticks_changed_event();
|
||||
}
|
||||
@ -2920,7 +2578,7 @@ void Control::OnRightUp(wxMouseEvent& event)
|
||||
if (!HasCapture() || m_is_left_down)
|
||||
return;
|
||||
this->ReleaseMouse();
|
||||
m_is_right_down = m_is_one_layer = false;
|
||||
m_is_right_down = /*m_is_one_layer = */false;
|
||||
|
||||
if (m_mouse == maForceColorEdit) {
|
||||
wxPoint pos = event.GetLogicalPosition(wxClientDC(this));
|
||||
@ -3065,6 +2723,8 @@ void Control::add_code_as_tick(Type type, int selected_extruder/* = -1*/)
|
||||
const int extruder = selected_extruder > 0 ? selected_extruder : std::max<int>(1, m_only_extruder);
|
||||
const auto it = m_ticks.ticks.find(TickCode{ tick });
|
||||
|
||||
bool was_ticks = m_ticks.empty();
|
||||
|
||||
if ( it == m_ticks.ticks.end() ) {
|
||||
// try to add tick
|
||||
if (!m_ticks.add_tick(tick, type, extruder, m_values[tick]))
|
||||
@ -3078,6 +2738,13 @@ void Control::add_code_as_tick(Type type, int selected_extruder/* = -1*/)
|
||||
else
|
||||
return;
|
||||
|
||||
if (was_ticks != m_ticks.empty()) {
|
||||
if (m_ticks.empty())
|
||||
imgui_ctrl.set_draw_scroll_line_cb(nullptr);
|
||||
else
|
||||
imgui_ctrl.set_draw_scroll_line_cb([this](const ImRect& scroll_line, const ImRect& slideable_region) { draw_colored_band(scroll_line, slideable_region); });
|
||||
}
|
||||
|
||||
post_ticks_changed_event(type);
|
||||
}
|
||||
|
||||
@ -3157,6 +2824,7 @@ void Control::edit_tick(int tick/* = -1*/)
|
||||
void Control::switch_one_layer_mode()
|
||||
{
|
||||
m_is_one_layer = !m_is_one_layer;
|
||||
imgui_ctrl.CombineThumbs(m_is_one_layer);
|
||||
if (!m_is_one_layer) {
|
||||
SetLowerValue(m_min_value);
|
||||
SetHigherValue(m_max_value);
|
||||
@ -3175,6 +2843,7 @@ void Control::discard_all_thicks()
|
||||
if (m_selection == ssUndef) m_selection = ssHigher;
|
||||
|
||||
m_ticks.ticks.clear();
|
||||
imgui_ctrl.set_draw_scroll_line_cb(nullptr);
|
||||
post_ticks_changed_event();
|
||||
|
||||
}
|
||||
|
@ -9,6 +9,8 @@
|
||||
#include "wxExtensions.hpp"
|
||||
#include "GLCanvas3D.hpp"
|
||||
|
||||
#include "ImGuiDoubleSlider.hpp"
|
||||
|
||||
#include <wx/window.h>
|
||||
#include <wx/control.h>
|
||||
#include <wx/dc.h>
|
||||
@ -27,6 +29,8 @@ class Layer;
|
||||
|
||||
namespace DoubleSlider {
|
||||
|
||||
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.
|
||||
*/
|
||||
@ -43,13 +47,13 @@ bool check_color_change(const PrintObject* object, size_t frst_layer_id, size_t
|
||||
|
||||
// custom message the slider sends to its parent to notify a tick-change:
|
||||
wxDECLARE_EVENT(wxCUSTOMEVT_TICKSCHANGED, wxEvent);
|
||||
|
||||
/*
|
||||
enum SelectedSlider {
|
||||
ssUndef,
|
||||
ssLower,
|
||||
ssHigher
|
||||
};
|
||||
|
||||
*/
|
||||
enum FocusedItem {
|
||||
fiNone,
|
||||
fiRevertIcon,
|
||||
@ -218,7 +222,7 @@ public:
|
||||
const wxPoint& pos = wxDefaultPosition,
|
||||
const wxSize& size = wxDefaultSize,
|
||||
long style = wxSL_VERTICAL,
|
||||
const wxValidator& val = wxDefaultValidator,
|
||||
// const wxValidator& val = wxDefaultValidator,
|
||||
const wxString& name = wxEmptyString);
|
||||
~Control() {}
|
||||
|
||||
@ -483,17 +487,14 @@ private:
|
||||
bool m_show_menu{ false };
|
||||
float get_pos_from_value(int v_min, int v_max, int value, const ImRect& rect);
|
||||
|
||||
void draw_background(const ImRect& groove);
|
||||
void draw_colored_band(const ImRect& groove, const ImRect& slideable_region);
|
||||
void draw_label(std::string label, const ImRect& handle, const ImVec2& handle_center, bool is_horizontal = false);
|
||||
void draw_ticks(const ImRect& slideable_region);
|
||||
void render_menu();
|
||||
bool render_button(const wchar_t btn_icon, const std::string& label_id, FocusedItem focus);
|
||||
bool horizontal_slider(const char* str_id, int* v, int v_min, int v_max, const ImVec2& pos, const ImVec2& size, float scale = 1.0);
|
||||
bool vertical_slider(const char* str_id, int* higher_value, int* lower_value,
|
||||
std::string& higher_label, std::string& lower_label,
|
||||
int v_min, int v_max, const ImVec2& pos, const ImVec2& size,
|
||||
SelectedSlider& selection, bool one_layer_flag = false, float scale = 1.0f);
|
||||
|
||||
|
||||
|
||||
GUI::ImGuiControl imgui_ctrl;
|
||||
|
||||
};
|
||||
|
||||
|
@ -241,7 +241,7 @@ bool Preview::init(wxWindow* parent, Bed3D& bed, Model* model)
|
||||
wxBoxSizer* right_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
right_sizer->Add(m_layers_slider_sizer, 1, wxEXPAND, 0);
|
||||
|
||||
m_moves_slider = new DoubleSlider::Control(m_bottom_toolbar_panel, wxID_ANY, 0, 0, 0, 100, wxDefaultPosition, wxDefaultSize, wxSL_HORIZONTAL);
|
||||
m_moves_slider = new DoubleSlider::Control(m_bottom_toolbar_panel, wxID_ANY, 0, 0, 0, 100, wxDefaultPosition, wxDefaultSize, wxSL_HORIZONTAL, "moves_slider");
|
||||
m_moves_slider->SetDrawMode(DoubleSlider::dmSequentialGCodeView);
|
||||
|
||||
wxBoxSizer* bottom_toolbar_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
@ -352,7 +352,7 @@ void Preview::render_imgui_double_slider(GLCanvas3D& canvas)
|
||||
{
|
||||
if (m_layers_slider && m_layers_slider->IsShown())
|
||||
m_layers_slider->imgui_render(canvas);
|
||||
if (m_moves_slider && m_moves_slider->IsShown())
|
||||
if (m_moves_slider && m_moves_slider->IsShown() && m_bottom_toolbar_panel->IsShown())
|
||||
m_moves_slider->imgui_render(canvas);
|
||||
}
|
||||
|
||||
@ -403,7 +403,7 @@ void Preview::on_size(wxSizeEvent& evt)
|
||||
wxBoxSizer* Preview::create_layers_slider_sizer()
|
||||
{
|
||||
wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
m_layers_slider = new DoubleSlider::Control(this, wxID_ANY, 0, 0, 0, 100);
|
||||
m_layers_slider = new DoubleSlider::Control(this, wxID_ANY, 0, 0, 0, 100, wxDefaultPosition, wxDefaultSize, wxVERTICAL, "layers_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"));
|
||||
|
489
src/slic3r/GUI/ImGuiDoubleSlider.cpp
Normal file
489
src/slic3r/GUI/ImGuiDoubleSlider.cpp
Normal file
@ -0,0 +1,489 @@
|
||||
///|/ 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 "ImGuiDoubleSlider.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
const ImU32 tooltip_bg_clr = ImGui::ColorConvertFloat4ToU32(ImGuiPureWrap::COL_GREY_LIGHT);
|
||||
const ImU32 thumb_bg_clr = ImGui::ColorConvertFloat4ToU32(ImGuiPureWrap::COL_ORANGE_LIGHT);
|
||||
const ImU32 groove_bg_clr = ImGui::ColorConvertFloat4ToU32(ImGuiPureWrap::COL_WINDOW_BACKGROUND);
|
||||
const ImU32 border_clr = IM_COL32(255, 255, 255, 255);
|
||||
|
||||
static bool behavior(ImGuiID id, const ImRect& region,
|
||||
const ImS32 v_min, const ImS32 v_max,
|
||||
ImS32* out_value, ImRect* out_thumb,
|
||||
ImGuiSliderFlags flags = 0,
|
||||
bool change_on_mouse_move = false,
|
||||
const int fixed_value = -1,
|
||||
const ImVec4& fixed_rect = ImVec4())
|
||||
{
|
||||
ImGuiContext& context = *GImGui;
|
||||
|
||||
const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X;
|
||||
|
||||
const ImVec2 thumb_sz = out_thumb->GetSize();
|
||||
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;
|
||||
|
||||
// Process interacting with the slider
|
||||
ImS32 v_new = *out_value;
|
||||
bool value_changed = false;
|
||||
// wheel behavior
|
||||
ImRect mouse_wheel_responsive_region;
|
||||
if (axis == ImGuiAxis_X)
|
||||
mouse_wheel_responsive_region = ImRect(region.Min - ImVec2(thumb_sz.x / 2, 0), region.Max + ImVec2(thumb_sz.x / 2, 0));
|
||||
if (axis == ImGuiAxis_Y)
|
||||
mouse_wheel_responsive_region = ImRect(region.Min - ImVec2(0, thumb_sz.y), region.Max + ImVec2(0, thumb_sz.y));
|
||||
if (ImGui::ItemHoverable(mouse_wheel_responsive_region, id)) {
|
||||
if (change_on_mouse_move)
|
||||
v_new = v_min + (ImS32)(v_range * mouse_pos_ratio + 0.5f);
|
||||
else
|
||||
v_new = ImClamp(*out_value + (ImS32)(context.IO.MouseWheel/* * accer*/), v_min, v_max);
|
||||
}
|
||||
|
||||
// drag behavior
|
||||
if (context.ActiveId == id)
|
||||
{
|
||||
if (context.ActiveIdSource == ImGuiInputSource_Mouse)
|
||||
{
|
||||
if (context.IO.MouseReleased[0])
|
||||
ImGui::ClearActiveID();
|
||||
if (context.IO.MouseDown[0])
|
||||
v_new = v_min + (ImS32)(v_range * mouse_pos_ratio + 0.5f);
|
||||
}
|
||||
}
|
||||
// click in fixed_rect behavior
|
||||
if (ImGui::ItemHoverable(fixed_rect, id) && context.IO.MouseReleased[0])
|
||||
{
|
||||
v_new = fixed_value;
|
||||
}
|
||||
|
||||
// apply result, output value
|
||||
if (*out_value != v_new)
|
||||
{
|
||||
*out_value = v_new;
|
||||
value_changed = true;
|
||||
}
|
||||
|
||||
// Output thumb position so it can be displayed by the caller
|
||||
const ImS32 v_clamped = (v_min < v_max) ? ImClamp(*out_value, v_min, v_max) : ImClamp(*out_value, 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(out_thumb->GetCenter().x, thumb_pos) : ImVec2(thumb_pos, out_thumb->GetCenter().y);
|
||||
*out_thumb = ImRect(new_thumb_center - thumb_sz * 0.5f, new_thumb_center + thumb_sz * 0.5f);
|
||||
|
||||
return value_changed;
|
||||
}
|
||||
|
||||
ImRect ImGuiControl::DrawOptions::groove(const ImVec2& pos, const ImVec2& size, bool is_horizontal)
|
||||
{
|
||||
ImVec2 groove_start = is_horizontal ?
|
||||
ImVec2(pos.x + thumb_dummy_sz().x, pos.y + size.y - groove_sz().y - dummy_sz().y) :
|
||||
ImVec2(pos.x + size.x - groove_sz().x - dummy_sz().x, pos.y + text_dummy_sz().y);
|
||||
ImVec2 groove_size = is_horizontal ?
|
||||
ImVec2(size.x - 2 * thumb_dummy_sz().x - text_dummy_sz().x, groove_sz().y) :
|
||||
ImVec2(groove_sz().x, size.y - 2 * text_dummy_sz().y);
|
||||
|
||||
return ImRect(groove_start, groove_start + groove_size);
|
||||
}
|
||||
|
||||
ImRect ImGuiControl::DrawOptions::draggable_region(const ImRect& groove, bool is_horizontal)
|
||||
{
|
||||
ImRect draggable_region = is_horizontal ?
|
||||
ImRect(groove.Min.x, groove.GetCenter().y, groove.Max.x, groove.GetCenter().y) :
|
||||
ImRect(groove.GetCenter().x, groove.Min.y, groove.GetCenter().x, groove.Max.y);
|
||||
draggable_region.Expand(is_horizontal ?
|
||||
ImVec2(/*thumb_radius()*/0, draggable_region_sz().y) :
|
||||
ImVec2(draggable_region_sz().x, 0));
|
||||
|
||||
return draggable_region;
|
||||
}
|
||||
|
||||
ImRect ImGuiControl::DrawOptions::slider_line(const ImRect& draggable_region, const ImVec2& h_thumb_center, const ImVec2& l_thumb_center, bool is_horizontal)
|
||||
{
|
||||
ImVec2 mid = draggable_region.GetCenter();
|
||||
|
||||
ImRect scroll_line = is_horizontal ?
|
||||
ImRect(ImVec2(l_thumb_center.x, mid.y - groove_sz().y / 2), ImVec2(h_thumb_center.x, mid.y + groove_sz().y / 2)) :
|
||||
ImRect(ImVec2(mid.x - groove_sz().x / 2, h_thumb_center.y), ImVec2(mid.x + groove_sz().x / 2, l_thumb_center.y));
|
||||
|
||||
return scroll_line;
|
||||
}
|
||||
|
||||
ImGuiControl::ImGuiControl( int lowerValue,
|
||||
int higherValue,
|
||||
int minValue,
|
||||
int maxValue,
|
||||
ImVec2 pos,
|
||||
ImVec2 size,
|
||||
long style,
|
||||
std::string name,
|
||||
bool use_lower_thumb) :
|
||||
m_selection(ssUndef),
|
||||
m_pos(pos),
|
||||
m_size(size),
|
||||
m_name(name),
|
||||
m_lower_value(lowerValue),
|
||||
m_higher_value (higherValue),
|
||||
m_min_value(minValue),
|
||||
m_max_value(maxValue),
|
||||
m_style(style == wxSL_HORIZONTAL || style == wxSL_VERTICAL ? style: wxSL_HORIZONTAL),
|
||||
m_draw_lower_thumb(use_lower_thumb)
|
||||
//,m_extra_style(style == wxSL_VERTICAL ? wxSL_AUTOTICKS | wxSL_VALUE_LABEL : 0)
|
||||
{
|
||||
}
|
||||
|
||||
int ImGuiControl::GetActiveValue() const
|
||||
{
|
||||
return m_selection == ssLower ? m_lower_value :
|
||||
m_selection == ssHigher ? m_higher_value : -1;
|
||||
}
|
||||
|
||||
void ImGuiControl::SetLowerValue(const int lower_val)
|
||||
{
|
||||
m_selection = ssLower;
|
||||
m_lower_value = lower_val;
|
||||
}
|
||||
|
||||
void ImGuiControl::SetHigherValue(const int higher_val)
|
||||
{
|
||||
m_selection = ssHigher;
|
||||
m_higher_value = higher_val;
|
||||
}
|
||||
|
||||
void ImGuiControl::SetSelectionSpan(const int lower_val, const int higher_val)
|
||||
{
|
||||
m_lower_value = std::max(lower_val, m_min_value);
|
||||
m_higher_value = std::max(std::min(higher_val, m_max_value), m_lower_value);
|
||||
}
|
||||
|
||||
void ImGuiControl::SetMaxValue(const int max_value)
|
||||
{
|
||||
m_max_value = max_value;
|
||||
}
|
||||
|
||||
void ImGuiControl::SetSliderValues(const std::vector<double>& values)
|
||||
{
|
||||
m_values = values;
|
||||
}
|
||||
|
||||
std::string ImGuiControl::get_label(int pos) const
|
||||
{
|
||||
if (m_cb_get_label)
|
||||
return m_cb_get_label(pos);
|
||||
|
||||
const size_t value = pos;
|
||||
|
||||
if (m_label_koef == 1.0 && m_values.empty())
|
||||
return std::to_string(static_cast<unsigned long>(value));
|
||||
if (value >= m_values.size())
|
||||
return "ErrVal";
|
||||
|
||||
return m_values.empty() ?
|
||||
to_string_with_precision(m_label_koef * value) :
|
||||
to_string_with_precision(m_values[value]);
|
||||
}
|
||||
|
||||
float ImGuiControl::get_pos_from_value(int v_min, int v_max, int value, const ImRect& rect)
|
||||
{
|
||||
float pos_ratio = (v_max - v_min) != 0 ? ((float)(value - v_min) / (float)(v_max - v_min)) : 0.0f;
|
||||
float thumb_pos;
|
||||
if (is_horizontal()) {
|
||||
thumb_pos = rect.Min.x + (rect.Max.x - rect.Min.x) * pos_ratio;
|
||||
}
|
||||
else {
|
||||
pos_ratio = 1.0f - pos_ratio;
|
||||
thumb_pos = rect.Min.y + (rect.Max.y - rect.Min.y) * pos_ratio;
|
||||
}
|
||||
return thumb_pos;
|
||||
}
|
||||
|
||||
void ImGuiControl::draw_scroll_line(const ImRect& scroll_line, const ImRect& slideable_region)
|
||||
{
|
||||
if (m_cb_draw_scroll_line)
|
||||
m_cb_draw_scroll_line(scroll_line, slideable_region);
|
||||
else
|
||||
ImGui::RenderFrame(scroll_line.Min, scroll_line.Max, thumb_bg_clr, false, m_draw_opts.rounding());
|
||||
}
|
||||
|
||||
void ImGuiControl::draw_background(const ImRect& groove)
|
||||
{
|
||||
ImVec2 groove_padding = (is_horizontal() ? ImVec2(2.0f, 2.0f) : ImVec2(3.0f, 4.0f)) * m_draw_opts.scale;
|
||||
|
||||
ImRect bg_rect = groove;
|
||||
bg_rect.Expand(groove_padding);
|
||||
|
||||
// draw bg of slider
|
||||
ImGui::RenderFrame(bg_rect.Min, bg_rect.Max, border_clr, false, 0.5 * bg_rect.GetWidth());
|
||||
// draw bg of scroll
|
||||
ImGui::RenderFrame(groove.Min, groove.Max, groove_bg_clr, false, 0.5 * groove.GetWidth());
|
||||
}
|
||||
|
||||
void ImGuiControl::draw_label(std::string label, const ImRect& thumb)
|
||||
{
|
||||
const ImVec2 thumb_center = thumb.GetCenter();
|
||||
ImVec2 text_padding = m_draw_opts.text_padding();
|
||||
float rounding = m_draw_opts.rounding();
|
||||
ImVec2 triangle_offsets[3] = { ImVec2(2.0f, 0.0f) * m_draw_opts.scale, ImVec2(0.0f, 8.0f) * m_draw_opts.scale, ImVec2(9.0f, 0.0f) * m_draw_opts.scale };
|
||||
|
||||
ImVec2 text_content_size = ImGui::CalcTextSize(label.c_str());
|
||||
ImVec2 text_size = text_content_size + text_padding * 2;
|
||||
ImVec2 text_start = is_horizontal() ?
|
||||
ImVec2(thumb.Max.x + triangle_offsets[2].x, thumb_center.y - text_size.y) :
|
||||
ImVec2(thumb.Min.x - text_size.x - triangle_offsets[2].x, thumb_center.y - text_size.y) ;
|
||||
ImRect text_rect(text_start, text_start + text_size);
|
||||
|
||||
ImVec2 pos_1 = is_horizontal() ?
|
||||
ImVec2(text_rect.Min.x + triangle_offsets[0].x, text_rect.Max.y - triangle_offsets[0].y) :
|
||||
text_rect.Max - triangle_offsets[0];
|
||||
ImVec2 pos_2 = is_horizontal() ? pos_1 - triangle_offsets[2] : pos_1 - triangle_offsets[1];
|
||||
ImVec2 pos_3 = is_horizontal() ? pos_1 - triangle_offsets[1] : pos_1 + triangle_offsets[2];
|
||||
|
||||
ImGui::RenderFrame(text_rect.Min, text_rect.Max, tooltip_bg_clr, true, rounding);
|
||||
ImGui::GetCurrentWindow()->DrawList->AddTriangleFilled(pos_1, pos_2, pos_3, tooltip_bg_clr);
|
||||
ImGui::RenderText(text_start + text_padding, label.c_str());
|
||||
};
|
||||
|
||||
void ImGuiControl::draw_thumb(const ImVec2& center, bool mark/* = false*/)
|
||||
{
|
||||
const float line_width = 2.0f * m_draw_opts.scale;
|
||||
const float line_offset = 9.0f * m_draw_opts.scale;
|
||||
const float radius = m_draw_opts.thumb_radius();
|
||||
|
||||
const float hexagon_angle = is_horizontal() ? 0.f : IM_PI * 0.5f;
|
||||
|
||||
ImGuiPureWrap::draw_hexagon(center, radius, border_clr, hexagon_angle);
|
||||
ImGuiPureWrap::draw_hexagon(center, radius - line_width, thumb_bg_clr, hexagon_angle);
|
||||
|
||||
if (mark) {
|
||||
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
||||
window->DrawList->AddLine(center + ImVec2(-line_offset, 0.0f), center + ImVec2(line_offset, 0.0f), border_clr, line_width);
|
||||
window->DrawList->AddLine(center + ImVec2(0.0f, -line_offset), center + ImVec2(0.0f, line_offset), border_clr, line_width);
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiControl::apply_regions(int higher_value, int lower_value, const ImRect& draggable_region)
|
||||
{
|
||||
ImVec2 mid = draggable_region.GetCenter();
|
||||
float thumb_radius = m_draw_opts.thumb_radius();
|
||||
|
||||
// set slideable region
|
||||
m_regions.higher_slideable_region = is_horizontal() ?
|
||||
ImRect(draggable_region.Min + ImVec2(m_draw_lower_thumb ? thumb_radius : 0, 0), draggable_region.Max) :
|
||||
ImRect(draggable_region.Min, draggable_region.Max - ImVec2(0, m_combine_thumbs ? 0 : thumb_radius));
|
||||
m_regions.lower_slideable_region = is_horizontal() ?
|
||||
ImRect(draggable_region.Min, draggable_region.Max - ImVec2(thumb_radius, 0)) :
|
||||
ImRect(draggable_region.Min + ImVec2(0, thumb_radius), draggable_region.Max);
|
||||
|
||||
// initialize the thumbs.
|
||||
float higher_thumb_pos = get_pos_from_value(m_min_value, m_max_value, higher_value, m_regions.higher_slideable_region);
|
||||
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(mid.x - thumb_radius, higher_thumb_pos - thumb_radius, mid.x + thumb_radius, higher_thumb_pos + thumb_radius);
|
||||
|
||||
float lower_thumb_pos = get_pos_from_value(m_min_value, m_max_value, lower_value, m_regions.lower_slideable_region);
|
||||
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(mid.x - thumb_radius, lower_thumb_pos - thumb_radius, mid.x + thumb_radius, lower_thumb_pos + thumb_radius);
|
||||
}
|
||||
|
||||
void ImGuiControl::check_thumbs(int* higher_value, int* lower_value)
|
||||
{
|
||||
if (!m_draw_lower_thumb || m_combine_thumbs)
|
||||
return;
|
||||
|
||||
const ImVec2 higher_thumb_center = m_regions.higher_thumb.GetCenter();
|
||||
const ImVec2 lower_thumb_center = m_regions.lower_thumb.GetCenter();
|
||||
const float thumb_radius = m_draw_opts.thumb_radius();
|
||||
|
||||
const float higher_thumb_center_pos = is_horizontal() ? higher_thumb_center.x : higher_thumb_center.y;
|
||||
const float lower_thumb_center_pos = is_horizontal() ? lower_thumb_center.x : lower_thumb_center.y;
|
||||
|
||||
if (is_horizontal()) {
|
||||
if (lower_thumb_center_pos + thumb_radius > higher_thumb_center_pos) {
|
||||
if (m_selection == ssHigher) {
|
||||
m_regions.lower_thumb = m_regions.higher_thumb;
|
||||
m_regions.higher_thumb.TranslateX(thumb_radius);
|
||||
*lower_value = *higher_value;
|
||||
}
|
||||
else {
|
||||
m_regions.higher_thumb = m_regions.lower_thumb;
|
||||
m_regions.lower_thumb.TranslateX(-thumb_radius);
|
||||
*higher_value = *lower_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (higher_thumb_center_pos + thumb_radius > lower_thumb_center_pos) {
|
||||
if (m_selection == ssHigher) {
|
||||
m_regions.lower_thumb = m_regions.higher_thumb;
|
||||
m_regions.lower_thumb.TranslateY(thumb_radius);
|
||||
*lower_value = *higher_value;
|
||||
}
|
||||
else {
|
||||
m_regions.higher_thumb = m_regions.lower_thumb;
|
||||
m_regions.lower_thumb.TranslateY(-thumb_radius);
|
||||
*higher_value = *lower_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ImGuiControl::draw_slider( int* higher_value, int* lower_value,
|
||||
std::string& higher_label, std::string& lower_label,
|
||||
const ImVec2& pos, const ImVec2& size, float scale)
|
||||
{
|
||||
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
||||
if (window->SkipItems)
|
||||
return false;
|
||||
|
||||
ImGuiContext& context = *GImGui;
|
||||
const ImGuiID id = window->GetID(m_name.c_str());
|
||||
|
||||
const ImRect draw_region(pos, pos + size);
|
||||
ImGui::ItemSize(draw_region);
|
||||
|
||||
// calc slider groove size
|
||||
ImRect groove = m_draw_opts.groove(pos, size, is_horizontal());
|
||||
|
||||
// set active(draggable) region.
|
||||
ImRect draggable_region = m_draw_opts.draggable_region(groove, is_horizontal());
|
||||
|
||||
if (ImGui::ItemHoverable(draggable_region, id) && context.IO.MouseDown[0]) {
|
||||
ImGui::SetActiveID(id, window);
|
||||
ImGui::SetFocusID(id, window);
|
||||
ImGui::FocusWindow(window);
|
||||
}
|
||||
|
||||
// set slideable region and thumbs.
|
||||
apply_regions(*higher_value, *lower_value, draggable_region);
|
||||
|
||||
// Processing interacting
|
||||
|
||||
if (ImGui::ItemHoverable(m_regions.higher_thumb, id) && context.IO.MouseClicked[0])
|
||||
m_selection = ssHigher;
|
||||
|
||||
if (m_draw_lower_thumb && !m_combine_thumbs &&
|
||||
ImGui::ItemHoverable(m_regions.lower_thumb, id) && context.IO.MouseClicked[0])
|
||||
m_selection = ssLower;
|
||||
|
||||
// update thumb position and value
|
||||
bool value_changed = false;
|
||||
if (m_selection == ssHigher)
|
||||
value_changed = behavior(id, m_regions.higher_slideable_region, m_min_value, m_max_value,
|
||||
higher_value, &m_regions.higher_thumb, is_horizontal() ? 0: ImGuiSliderFlags_Vertical);
|
||||
else if (m_draw_lower_thumb && !m_combine_thumbs)
|
||||
value_changed = behavior(id, m_regions.lower_slideable_region, m_min_value, m_max_value,
|
||||
lower_value, &m_regions.lower_thumb, is_horizontal() ? 0: ImGuiSliderFlags_Vertical);
|
||||
|
||||
bool show_move_label = false;
|
||||
ImRect mouse_pos_rc = m_regions.higher_thumb;
|
||||
if (!value_changed && ImGui::ItemHoverable(draw_region, id)) {
|
||||
behavior(id, draggable_region, m_min_value, m_max_value,
|
||||
&m_mouse_pos_value, &mouse_pos_rc, is_horizontal() ? 0 : ImGuiSliderFlags_Vertical, true);
|
||||
show_move_label = true;
|
||||
}
|
||||
|
||||
// check thumbs values and correct them if needed
|
||||
check_thumbs(higher_value, lower_value);
|
||||
|
||||
// detect right click on thumb
|
||||
if (ImGui::ItemHoverable(m_selection == ssHigher ? m_regions.higher_thumb : m_regions.lower_thumb, id) && context.IO.MouseClicked[1])
|
||||
m_rclick_on_selected_thumb = true;
|
||||
if ((!ImGui::ItemHoverable(m_selection == ssHigher ? m_regions.higher_thumb : m_regions.lower_thumb, id) && context.IO.MouseClicked[1]) ||
|
||||
context.IO.MouseClicked[0])
|
||||
m_rclick_on_selected_thumb = false;
|
||||
|
||||
ImVec2 higher_thumb_center = m_regions.higher_thumb.GetCenter();
|
||||
ImVec2 lower_thumb_center = m_regions.lower_thumb.GetCenter();
|
||||
|
||||
ImRect scroll_line = m_draw_opts.slider_line(draggable_region, higher_thumb_center, lower_thumb_center, is_horizontal());
|
||||
|
||||
// draw background
|
||||
draw_background(groove);
|
||||
// draw scroll line
|
||||
draw_scroll_line(m_combine_thumbs ? groove : scroll_line, groove);
|
||||
|
||||
// draw thumbs with label
|
||||
// select and mark higher thumb by default
|
||||
draw_thumb(higher_thumb_center, m_selection != ssLower && m_draw_lower_thumb);
|
||||
draw_label(higher_label, m_regions.higher_thumb);
|
||||
|
||||
if (m_draw_lower_thumb && !m_combine_thumbs) {
|
||||
draw_thumb(lower_thumb_center, m_selection == ssLower);
|
||||
draw_label(lower_label, m_regions.lower_thumb);
|
||||
}
|
||||
|
||||
// draw label on mouse move
|
||||
if (show_move_label)
|
||||
draw_label(get_label_on_move(m_mouse_pos_value), mouse_pos_rc);
|
||||
|
||||
return value_changed;
|
||||
}
|
||||
|
||||
bool ImGuiControl::render(SelectedSlider& selection)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_::ImGuiStyleVar_WindowBorderSize, 0);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_::ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_::ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_::ImGuiCol_WindowBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_Text));
|
||||
|
||||
int windows_flag = ImGuiWindowFlags_NoTitleBar
|
||||
| ImGuiWindowFlags_NoCollapse
|
||||
| ImGuiWindowFlags_NoMove
|
||||
| ImGuiWindowFlags_NoResize
|
||||
| ImGuiWindowFlags_NoScrollbar
|
||||
| ImGuiWindowFlags_NoScrollWithMouse;
|
||||
|
||||
ImGuiPureWrap::set_next_window_pos(m_pos.x, m_pos.y, ImGuiCond_Always);
|
||||
ImGuiPureWrap::begin(m_name, windows_flag);
|
||||
|
||||
float scale = 1.f;
|
||||
|
||||
int higher_value = m_higher_value;
|
||||
int lower_value = m_lower_value;
|
||||
std::string higher_label = get_label(m_higher_value);
|
||||
std::string lower_label = get_label(m_lower_value);
|
||||
int temp_higher_value = m_higher_value;
|
||||
int temp_lower_value = m_lower_value;
|
||||
|
||||
if (draw_slider(&higher_value, &lower_value, higher_label, lower_label, m_pos, m_size, scale)) {
|
||||
if (temp_higher_value != higher_value)
|
||||
SetHigherValue(higher_value);
|
||||
if (temp_lower_value != lower_value)
|
||||
SetLowerValue(lower_value);
|
||||
result = true;
|
||||
}
|
||||
selection = m_selection;
|
||||
|
||||
ImGuiPureWrap::end();
|
||||
|
||||
ImGui::PopStyleColor(2);
|
||||
ImGui::PopStyleVar(3);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//} // DoubleSlider
|
||||
|
||||
} // GUI
|
||||
|
||||
} // Slic3r
|
||||
|
172
src/slic3r/GUI/ImGuiDoubleSlider.hpp
Normal file
172
src/slic3r/GUI/ImGuiDoubleSlider.hpp
Normal file
@ -0,0 +1,172 @@
|
||||
///|/ 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_ImGUI_DoubleSlider_hpp_
|
||||
#define slic3r_ImGUI_DoubleSlider_hpp_
|
||||
|
||||
#include "ImGuiPureWrap.hpp"
|
||||
#ifndef IMGUI_DEFINE_MATH_OPERATORS
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
#endif
|
||||
#include "imgui/imgui_internal.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
// this code is borrowed from https://stackoverflow.com/questions/16605967/set-precision-of-stdto-string-when-converting-floating-point-values
|
||||
template <typename T>
|
||||
std::string to_string_with_precision(const T a_value, const int n = 2)
|
||||
{
|
||||
std::ostringstream out;
|
||||
out.precision(n);
|
||||
out << std::fixed << a_value;
|
||||
return std::move(out).str();
|
||||
}
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
enum SelectedSlider {
|
||||
ssUndef,
|
||||
ssLower,
|
||||
ssHigher
|
||||
};
|
||||
|
||||
enum LabelType
|
||||
{
|
||||
ltHeightWithLayer,
|
||||
ltHeight,
|
||||
ltEstimatedTime,
|
||||
};
|
||||
|
||||
class ImGuiControl
|
||||
{
|
||||
public:
|
||||
ImGuiControl(int lowerValue,
|
||||
int higherValue,
|
||||
int minValue,
|
||||
int maxValue,
|
||||
ImVec2 pos,
|
||||
ImVec2 size,
|
||||
long style = wxSL_VERTICAL,
|
||||
std::string name = "d_slider",
|
||||
bool use_lower_thumb = true);
|
||||
ImGuiControl() {}
|
||||
~ImGuiControl() {}
|
||||
|
||||
int GetMinValue() const { return m_min_value; }
|
||||
int GetMaxValue() const { return m_max_value; }
|
||||
double GetMinValueD() { return m_values.empty() ? 0. : m_values[m_min_value]; }
|
||||
double GetMaxValueD() { return m_values.empty() ? 0. : m_values[m_max_value]; }
|
||||
int GetLowerValue() const { return m_lower_value; }
|
||||
int GetHigherValue() const { return m_higher_value; }
|
||||
int GetActiveValue() const;
|
||||
|
||||
// Set low and high slider position. If the span is non-empty, disable the "one layer" mode.
|
||||
void SetLowerValue (const int lower_val);
|
||||
void SetHigherValue(const int higher_val);
|
||||
void SetSelectionSpan(const int lower_val, const int higher_val);
|
||||
|
||||
void SetMaxValue(const int max_value);
|
||||
void SetSliderValues(const std::vector<double>& values);
|
||||
|
||||
void SetPos(ImVec2 pos) { m_pos = pos; }
|
||||
void SetSize(ImVec2 size) { m_size = size; }
|
||||
void SetScale(float scale) { m_draw_opts.scale = scale; }
|
||||
void ShowLabelOnMouseMove(bool show = true) { m_show_move_label = show; }
|
||||
void CombineThumbs(bool combine = true) { m_combine_thumbs = combine; }
|
||||
|
||||
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; }
|
||||
void set_draw_scroll_line_cb(std::function<void(const ImRect&, const ImRect&)> cb) { m_cb_draw_scroll_line = cb; }
|
||||
|
||||
bool is_horizontal() const { return m_style == wxSL_HORIZONTAL; }
|
||||
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 render(SelectedSlider& selection);
|
||||
void draw_scroll_line(const ImRect& scroll_line, const ImRect& slideable_region);
|
||||
|
||||
std::string get_label(int pos) const;
|
||||
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); }
|
||||
|
||||
struct DrawOptions {
|
||||
float scale { 1.f }; // used for Retina on osx
|
||||
|
||||
ImVec2 dummy_sz() { return ImVec2(24.0f, 44.0f) * scale; }
|
||||
ImVec2 thumb_dummy_sz() { return ImVec2(17.0f, 17.0f) * scale; }
|
||||
ImVec2 groove_sz() { return ImVec2(10.0f, 8.0f) * scale; }
|
||||
ImVec2 draggable_region_sz() { return ImVec2(40.0f, 19.0f) * scale; }
|
||||
ImVec2 text_dummy_sz() { return ImVec2(50.0f, 34.0f) * scale; }
|
||||
ImVec2 text_padding() { return ImVec2( 5.0f, 2.0f) * scale; }
|
||||
|
||||
float thumb_radius() { return 14.0f * scale; }
|
||||
float thumb_border() { return 2.0f * scale; }
|
||||
float rounding() { return 2.0f * scale; }
|
||||
|
||||
ImRect groove(const ImVec2& pos, const ImVec2& size, bool is_horizontal);
|
||||
ImRect draggable_region(const ImRect& groove, bool is_horizontal);
|
||||
ImRect slider_line(const ImRect& draggable_region, const ImVec2& h_thumb_center, const ImVec2& l_thumb_center, bool is_horizontal);
|
||||
};
|
||||
|
||||
struct Regions {
|
||||
ImRect higher_slideable_region;
|
||||
ImRect lower_slideable_region;
|
||||
ImRect higher_thumb;
|
||||
ImRect lower_thumb;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
SelectedSlider m_selection;
|
||||
ImVec2 m_pos;
|
||||
ImVec2 m_size;
|
||||
std::string m_name;
|
||||
|
||||
int m_min_value;
|
||||
int m_max_value;
|
||||
int m_lower_value;
|
||||
int m_higher_value;
|
||||
int m_mouse_pos_value;
|
||||
|
||||
long m_style;
|
||||
double m_label_koef{ 1. };
|
||||
|
||||
bool m_lclick_on_selected_thumb{ false };
|
||||
bool m_rclick_on_selected_thumb{ false };
|
||||
|
||||
bool m_draw_lower_thumb{ true };
|
||||
bool m_combine_thumbs { false };
|
||||
bool m_show_move_label{ false };
|
||||
|
||||
std::function<std::string(int)> m_cb_get_label { nullptr };
|
||||
std::function<std::string(int)> m_cb_get_label_on_move { nullptr };
|
||||
std::function<void(const ImRect&, const ImRect&)> m_cb_draw_scroll_line { nullptr };
|
||||
|
||||
void apply_regions(int higher_value, int lower_value, const ImRect& draggable_region);
|
||||
|
||||
float get_pos_from_value(int v_min, int v_max, int value, const ImRect& rect);
|
||||
void check_thumbs(int* higher_value, int* lower_value);
|
||||
|
||||
void draw_background(const ImRect& groove);
|
||||
void draw_label(std::string label, const ImRect& thumb);
|
||||
void draw_thumb(const ImVec2& center, bool mark = false);
|
||||
bool draw_slider(int* higher_value, int* lower_value,
|
||||
std::string& higher_label, std::string& lower_label,
|
||||
const ImVec2& pos, const ImVec2& size, float scale = 1.0f);
|
||||
|
||||
protected:
|
||||
|
||||
std::vector<double> m_values;
|
||||
|
||||
DrawOptions m_draw_opts;
|
||||
Regions m_regions;
|
||||
};
|
||||
|
||||
} // GUI
|
||||
|
||||
} // Slic3r
|
||||
|
||||
|
||||
#endif // slic3r_ImGUI_DoubleSlider_hpp_
|
@ -1523,79 +1523,6 @@ void ImGuiWrapper::clipboard_set(void* /* user_data */, const char* text)
|
||||
}
|
||||
}
|
||||
|
||||
static float accer = 1.f;
|
||||
|
||||
bool slider_behavior(ImGuiID id, const ImRect& region, const ImS32 v_min, const ImS32 v_max, ImS32* out_value, ImRect* out_handle, ImGuiSliderFlags flags/* = 0*/, const int fixed_value/* = -1*/, const ImVec4& fixed_rect/* = ImRect()*/)
|
||||
{
|
||||
ImGuiContext& context = *GImGui;
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X;
|
||||
|
||||
const ImVec2 handle_sz = out_handle->GetSize();
|
||||
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];
|
||||
|
||||
// Process interacting with the slider
|
||||
ImS32 v_new = *out_value;
|
||||
bool value_changed = false;
|
||||
// wheel behavior
|
||||
ImRect mouse_wheel_responsive_region;
|
||||
if (axis == ImGuiAxis_X)
|
||||
mouse_wheel_responsive_region = ImRect(region.Min - ImVec2(handle_sz.x / 2, 0), region.Max + ImVec2(handle_sz.x / 2, 0));
|
||||
if (axis == ImGuiAxis_Y)
|
||||
mouse_wheel_responsive_region = ImRect(region.Min - ImVec2(0, handle_sz.y), region.Max + ImVec2(0, handle_sz.y));
|
||||
if (ImGui::ItemHoverable(mouse_wheel_responsive_region, id)) {
|
||||
v_new = ImClamp(*out_value + (ImS32)(context.IO.MouseWheel * accer), v_min, v_max);
|
||||
}
|
||||
// drag behavior
|
||||
if (context.ActiveId == id)
|
||||
{
|
||||
float mouse_pos_ratio = 0.0f;
|
||||
if (context.ActiveIdSource == ImGuiInputSource_Mouse)
|
||||
{
|
||||
if (context.IO.MouseReleased[0])
|
||||
{
|
||||
ImGui::ClearActiveID();
|
||||
}
|
||||
if (context.IO.MouseDown[0])
|
||||
{
|
||||
const float mouse_abs_pos = context.IO.MousePos[axis];
|
||||
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;
|
||||
v_new = v_min + (ImS32)(v_range * mouse_pos_ratio + 0.5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
// click in fixed_rect behavior
|
||||
if (ImGui::ItemHoverable(fixed_rect, id) && context.IO.MouseReleased[0])
|
||||
{
|
||||
v_new = fixed_value;
|
||||
}
|
||||
|
||||
// apply result, output value
|
||||
if (*out_value != v_new)
|
||||
{
|
||||
*out_value = v_new;
|
||||
value_changed = true;
|
||||
}
|
||||
|
||||
// Output handle position so it can be displayed by the caller
|
||||
const ImS32 v_clamped = (v_min < v_max) ? ImClamp(*out_value, v_min, v_max) : ImClamp(*out_value, v_max, v_min);
|
||||
float handle_pos_ratio = v_range != 0 ? ((float)(v_clamped - v_min) / (float)v_range) : 0.0f;
|
||||
handle_pos_ratio = axis == ImGuiAxis_Y ? 1.0f - handle_pos_ratio : handle_pos_ratio;
|
||||
const float handle_pos = region_usable_pos_min + (region_usable_pos_max - region_usable_pos_min) * handle_pos_ratio;
|
||||
|
||||
ImVec2 new_handle_center = axis == ImGuiAxis_Y ? ImVec2(out_handle->GetCenter().x, handle_pos) : ImVec2(handle_pos, out_handle->GetCenter().y);
|
||||
*out_handle = ImRect(new_handle_center - handle_sz * 0.5f, new_handle_center + handle_sz * 0.5f);
|
||||
|
||||
return value_changed;
|
||||
}
|
||||
|
||||
|
||||
bool begin_menu(const char* label, bool enabled)
|
||||
{
|
||||
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
||||
|
@ -154,8 +154,6 @@ namespace ImGuiPSWrap
|
||||
ColorRGBA from_ImU32(const ImU32& color);
|
||||
ColorRGBA from_ImVec4(const ImVec4& color);
|
||||
}
|
||||
bool slider_behavior(ImGuiID id, const ImRect& region, const ImS32 v_min, const ImS32 v_max, ImS32* out_value, ImRect* out_handle, ImGuiSliderFlags flags = 0, const int fixed_value = -1, const ImVec4& fixed_rect = ImVec4());
|
||||
|
||||
bool begin_menu(const char* label, bool enabled = true);
|
||||
void end_menu();
|
||||
bool menu_item_with_icon(const char* label, const char* shortcut, ImVec2 icon_size = ImVec2(0, 0), ImU32 icon_color = 0, bool selected = false, bool enabled = true);
|
||||
|
Loading…
x
Reference in New Issue
Block a user