From 8e749734ff4a58bb36fc76736258e7bb623a1e1a Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 18 Mar 2024 00:49:00 +0100 Subject: [PATCH] ImguiDoubleSlider: WIP: For vertical slider are added : * actions buttons and theirs process * rendering of ticks and theirs info buttons * show label with estimated time on mouse moving + ImGuiWrapper::image_button is extended for highlight_on_hover parameter to enable/disable highlighting on the hover + Show and process some icon/buttons in respect to the application mode (if is Editor or Viewer) --- resources/icons/cog_f.svg | 17 +++ resources/icons/undo_f.svg | 12 ++ src/imgui/imconfig.h | 21 ++- src/slic3r/GUI/DoubleSlider.cpp | 186 +++++++++++++++++---------- src/slic3r/GUI/DoubleSlider.hpp | 3 +- src/slic3r/GUI/ImGuiDoubleSlider.cpp | 75 +++++++---- src/slic3r/GUI/ImGuiDoubleSlider.hpp | 18 +-- src/slic3r/GUI/ImGuiWrapper.cpp | 37 +++++- src/slic3r/GUI/ImGuiWrapper.hpp | 3 +- 9 files changed, 259 insertions(+), 113 deletions(-) create mode 100644 resources/icons/cog_f.svg create mode 100644 resources/icons/undo_f.svg diff --git a/resources/icons/cog_f.svg b/resources/icons/cog_f.svg new file mode 100644 index 0000000000..28267ddb4b --- /dev/null +++ b/resources/icons/cog_f.svg @@ -0,0 +1,17 @@ + + + + + + + + diff --git a/resources/icons/undo_f.svg b/resources/icons/undo_f.svg new file mode 100644 index 0000000000..c2db835498 --- /dev/null +++ b/resources/icons/undo_f.svg @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/src/imgui/imconfig.h b/src/imgui/imconfig.h index ba3cd1c368..172db0ec95 100644 --- a/src/imgui/imconfig.h +++ b/src/imgui/imconfig.h @@ -153,8 +153,6 @@ namespace ImGui const wchar_t PlugMarker = 0x1C; const wchar_t DowelMarker = 0x1D; const wchar_t SnapMarker = 0x1E; - const wchar_t Lock = 0x1F; - const wchar_t Unlock = 0x17; const wchar_t HorizontalHide = 0xB1; const wchar_t HorizontalShow = 0xB2; // Do not forget use following letters only in wstring @@ -191,6 +189,25 @@ namespace ImGui const wchar_t InfoMarkerSmall = 0x2716; const wchar_t CollapseBtn = 0x2715; + // icons for double slider (middle size icons) + const wchar_t Lock = 0x2801; + const wchar_t LockHovered = 0x2802; + const wchar_t Unlock = 0x2803; + const wchar_t UnlockHovered = 0x2804; + const wchar_t DSRevert = 0x2805; + const wchar_t DSRevertHovered = 0x2806; + const wchar_t DSSettings = 0x2807; + const wchar_t DSSettingsHovered = 0x2808; + // icons for double slider (small size icons) + const wchar_t ErrorTick = 0x2809; + const wchar_t ErrorTickHovered = 0x280A; + const wchar_t PausePrint = 0x280B; + const wchar_t PausePrintHovered = 0x280C; + const wchar_t EditGCode = 0x280D; + const wchar_t EditGCodeHovered = 0x280E; + const wchar_t RemoveTick = 0x280F; + const wchar_t RemoveTickHovered = 0x2810; + // void MyFunction(const char* name, const MyMatrix44& v); } diff --git a/src/slic3r/GUI/DoubleSlider.cpp b/src/slic3r/GUI/DoubleSlider.cpp index 11673d7799..55e3eafe0e 100644 --- a/src/slic3r/GUI/DoubleSlider.cpp +++ b/src/slic3r/GUI/DoubleSlider.cpp @@ -52,6 +52,8 @@ 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 BTN_SZ = 24.f; + 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 @@ -91,6 +93,7 @@ Control::Control( wxWindow *parent, m_min_value(minValue), m_max_value(maxValue), m_style(style == wxSL_HORIZONTAL || style == wxSL_VERTICAL ? style: wxSL_HORIZONTAL), + m_allow_editing(wxGetApp().is_editor()), m_extra_style(style == wxSL_VERTICAL ? wxSL_AUTOTICKS | wxSL_VALUE_LABEL : 0) { #ifdef __WXOSX__ @@ -171,8 +174,10 @@ Control::Control( wxWindow *parent, imgui_ctrl.set_get_label_cb([this](int pos) {return into_u8(get_label(pos)); }); - if (!is_horizontal()) + if (!is_horizontal()) { imgui_ctrl.set_get_label_on_move_cb([this](int pos) {return into_u8(get_label(pos, ltEstimatedTime)); }); + imgui_ctrl.set_extra_draw_cb([this](const ImRect& draw_rc) {return draw_ticks(draw_rc); }); + } } @@ -613,7 +618,8 @@ float Control::get_pos_from_value(int v_min, int v_max, int value, const ImRect& return handle_pos; } -void Control::draw_ticks(const ImRect& slideable_region) { +void Control::draw_ticks(const ImRect& slideable_region) +{ //if(m_draw_mode != dmRegular) // return; //if (m_ticks.empty() || m_mode == MultiExtruder) @@ -623,22 +629,22 @@ void Control::draw_ticks(const ImRect& slideable_region) { ImGuiContext& context = *GImGui; - ImVec2 tick_box = ImVec2(46.0f, 16.0f) * m_scale; - ImVec2 tick_offset = ImVec2(19.0f, 11.0f) * m_scale; - float tick_width = 1.0f * m_scale; - ImVec2 icon_offset = ImVec2(13.0f, 7.0f) * m_scale; - ImVec2 icon_size = ImVec2(14.0f, 14.0f) * m_scale; + 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 = wxGetApp().imgui()->GetTextureCustomRect(ImGui::PausePrint)->Height; + const float icon_offset = 0.5f * icon_side;; - const ImU32 tick_clr = ImGui::ColorConvertFloat4ToU32(ImGuiPureWrap::COL_ORANGE_DARK); //IM_COL32(144, 144, 144, 255); - const ImU32 tick_hover_box_clr = ImGui::ColorConvertFloat4ToU32(ImGuiPureWrap::COL_WINDOW_BACKGROUND); //IM_COL32(219, 253, 231, 255); - const ImU32 delete_btn_clr = IM_COL32(144, 144, 144, 255); + const ImU32 tick_clr = ImGui::ColorConvertFloat4ToU32(ImGuiPureWrap::COL_ORANGE_DARK); + const ImU32 tick_hovered_clr = ImGui::ColorConvertFloat4ToU32(ImGuiPureWrap::COL_WINDOW_BACKGROUND); auto get_tick_pos = [this, slideable_region](int tick) - { - int v_min = GetMinValue(); - int v_max = GetMaxValue(); - return get_pos_from_value(v_min, v_max, tick, slideable_region); - }; + { + int v_min = GetMinValue(); + int v_max = GetMaxValue(); + return get_pos_from_value(v_min, v_max, tick, slideable_region); + }; std::set::const_iterator tick_it = m_ticks.ticks.begin(); while (tick_it != m_ticks.ticks.end()) @@ -646,17 +652,19 @@ void Control::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_box.x / 2, tick_pos - tick_box.y / 2, slideable_region.GetCenter().x + tick_box.x / 2, - tick_pos + tick_box.y / 2); + 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); - if (ImGui::IsMouseHoveringRect(tick_hover_box.Min, tick_hover_box.Max)) - { - ImGui::RenderFrame(tick_hover_box.Min, tick_hover_box.Max, tick_hover_box_clr, false); - if (context.IO.MouseClicked[0]) { - } + 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); + break; } ++tick_it; } + + auto active_tick_it = m_selection == ssHigher ? m_ticks.ticks.find(TickCode{ this->GetHigherValue() }) : + m_selection == ssLower ? m_ticks.ticks.find(TickCode{ this->GetLowerValue() }) : + m_ticks.ticks.end(); tick_it = m_ticks.ticks.begin(); while (tick_it != m_ticks.ticks.end()) @@ -664,42 +672,43 @@ void Control::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_offset.x, tick_pos - tick_width, slideable_region.GetCenter().x - tick_offset.y, tick_pos); - ImRect tick_right = ImRect(slideable_region.GetCenter().x + tick_offset.y, tick_pos - tick_width, slideable_region.GetCenter().x + tick_offset.x, tick_pos); + 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); ImGui::RenderFrame(tick_left.Min, tick_left.Max, tick_clr, false); ImGui::RenderFrame(tick_right.Min, tick_right.Max, tick_clr, false); - //draw pause icon - if (tick_it->type == PausePrint) { - //ImTextureID pause_icon_id = m_pause_icon_id; - ImVec2 icon_pos = ImVec2(slideable_region.GetCenter().x + icon_offset.x, tick_pos - icon_offset.y); - //button_with_pos(pause_icon_id, icon_size, icon_pos); - if (ImGui::IsMouseHoveringRect(icon_pos, icon_pos + icon_size)) { - if (context.IO.MouseClicked[0]) - int a = 0; - } - } - ++tick_it; - } + ImVec2 icon_pos = ImVec2(tick_right.Max.x + icon_offset, tick_pos - icon_offset); + std::string btn_label = "tick " + std::to_string(tick_it->tick); - tick_it = m_selection == ssHigher ? m_ticks.ticks.find(TickCode{ this->GetHigherValue() }) : - m_selection == ssLower ? m_ticks.ticks.find(TickCode{ this->GetLowerValue() }) : - m_ticks.ticks.end(); - if (tick_it != m_ticks.ticks.end()) { - // draw delete icon - //ImTextureID delete_icon_id = m_delete_icon_id; - ImVec2 icon_pos = ImVec2(slideable_region.GetCenter().x + icon_offset.x, get_tick_pos(tick_it->tick) - icon_offset.y); - //! button_with_pos(m_delete_icon_id, icon_size, icon_pos); - if (ImGui::IsMouseHoveringRect(icon_pos, icon_pos + icon_size)) { - if (context.IO.MouseClicked[0]) { - // delete tick + //draw tick icon-buttons + bool activate_this_tick = false; + if (tick_it == active_tick_it && m_allow_editing) { + // delete tick + if (render_button(ImGui::RemoveTick, ImGui::RemoveTickHovered, btn_label, icon_pos, m_selection == ssHigher ? fiHigherThumb : fiLowerThumb, tick_it->tick)) { Type type = tick_it->type; m_ticks.ticks.erase(tick_it); post_ticks_changed_event(type); + break; } + } + else if (m_draw_mode != dmRegular)// if we have non-regular draw mode, all ticks should be marked with error icon + activate_this_tick = render_button(ImGui::ErrorTick, ImGui::ErrorTickHovered, btn_label, icon_pos, fiActionIcon, tick_it->tick); + else if (tick_it->type == ColorChange || tick_it->type == ToolChange) { + if (m_ticks.is_conflict_tick(*tick_it, m_mode, m_only_extruder, m_values[tick_it->tick])) + activate_this_tick = render_button(ImGui::ErrorTick, ImGui::ErrorTickHovered, btn_label, icon_pos, fiActionIcon, tick_it->tick); } - } + else if (tick_it->type == PausePrint) + activate_this_tick = render_button(ImGui::PausePrint, ImGui::PausePrintHovered, btn_label, icon_pos, fiActionIcon, tick_it->tick); + else + activate_this_tick = render_button(ImGui::EditGCode, ImGui::EditGCodeHovered, btn_label, icon_pos, fiActionIcon, tick_it->tick); + if (activate_this_tick) { + m_selection == ssHigher ? SetHigherValue(tick_it->tick) : SetLowerValue(tick_it->tick); + break; + } + + ++tick_it; + } } inline int hex_to_int(const char c) @@ -802,7 +811,7 @@ void Control::render_menu() std::vector colors = wxGetApp().plater()->get_extruder_colors_from_plater_config(); int extruder_num = colors.size(); - if (m_show_menu) { + if (imgui_ctrl.is_rclick_on_thumb()) { ImGui::OpenPopup("slider_menu_popup"); } @@ -815,13 +824,14 @@ void Control::render_menu() else { if (menu_item_with_icon(_u8L("Add Color Change").c_str(), "")) { + UseDefaultColors(false); add_code_as_tick(ColorChange); } if (menu_item_with_icon(_u8L("Add Pause").c_str(), "")) { add_code_as_tick(PausePrint); } if (menu_item_with_icon(_u8L("Add Custom G-code").c_str(), "")) { - + add_code_as_tick(Custom); } if (!gcode(Template).empty()) { if (menu_item_with_icon(_u8L("Add Custom Template").c_str(), "")) { @@ -852,30 +862,39 @@ void Control::render_menu() ImGui::PopStyleVar(3); } -bool Control::render_button(const wchar_t btn_icon, const std::string& label_id, FocusedItem focus) +bool Control::render_button(const wchar_t btn_icon, const wchar_t btn_icon_hovered, const std::string& label_id, const ImVec2& pos, FocusedItem focus, int tick /*= -1*/) { - const ImGuiStyle& style = ImGui::GetStyle(); + float scale = (float)wxGetApp().em_unit() / 10.0f; - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, { 1, style.ItemSpacing.y }); + 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)); - const ImVec4 col = { 0.25f, 0.25f, 0.25f, 0.0f }; - ImGui::PushStyleColor(ImGuiCol_Button, col); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, col); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, col); + ImGui::PushStyleColor(ImGuiCol_::ImGuiCol_WindowBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f)); + ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_Text)); - std::string btn_label; - btn_label += btn_icon; - const bool ret = ImGui::Button((btn_label + "##" + label_id).c_str(), ImVec2(16*m_scale, 0)); + int windows_flag = ImGuiWindowFlags_NoTitleBar + | ImGuiWindowFlags_NoCollapse + | ImGuiWindowFlags_NoMove + | ImGuiWindowFlags_NoResize + | ImGuiWindowFlags_NoScrollbar + | ImGuiWindowFlags_NoScrollWithMouse; - ImGui::PopStyleColor(3); + auto m_imgui = wxGetApp().imgui(); + ImGuiPureWrap::set_next_window_pos(pos.x, pos.y, ImGuiCond_Always); + std::string win_name = label_id + "##btn_win"; + ImGuiPureWrap::begin(win_name, windows_flag); - if (ImGui::IsItemHovered()) { - m_focus = focus; - std::string tooltip = into_u8(get_tooltip()); - ImGuiPureWrap::tooltip(tooltip.c_str(), ImGui::GetFontSize() * 20.0f); - } + ImGuiContext& g = *GImGui; - ImGui::PopStyleVar(); + std::string tooltip = m_allow_editing ? into_u8(get_tooltip(tick)) : ""; + ImGui::SetCursorPos(ImVec2(0, 0)); + const bool ret = m_imgui->image_button(g.HoveredWindow == g.CurrentWindow ? btn_icon_hovered : btn_icon, tooltip, false); + + ImGuiPureWrap::end(); + + ImGui::PopStyleColor(2); + ImGui::PopStyleVar(3); return ret; } @@ -902,7 +921,9 @@ bool Control::imgui_render(GUI::GLCanvas3D& canvas) imgui_ctrl.ShowLabelOnMouseMove(false); } else { - pos.x = canvas_width - VERTICAL_SLIDER_SIZE.x * scale; + const float tick_icon_side = wxGetApp().imgui()->GetTextureCustomRect(ImGui::PausePrint)->Height; + + pos.x = canvas_width - VERTICAL_SLIDER_SIZE.x * scale - tick_icon_side; pos.y = ONE_LAYER_OFFSET.y; size = ImVec2(VERTICAL_SLIDER_SIZE.x * scale, canvas_height - 4 * pos.y); imgui_ctrl.ShowLabelOnMouseMove(true); @@ -912,9 +933,28 @@ bool Control::imgui_render(GUI::GLCanvas3D& canvas) imgui_ctrl.SetSize(size); imgui_ctrl.SetScale(scale); + const float btn_sz = BTN_SZ*scale; + ImVec2 btn_pos = ImVec2(pos.x + 2.7 * btn_sz, pos.y - 0.5 * btn_sz); + + if (!is_horizontal() && !m_ticks.empty() && m_allow_editing && + render_button(ImGui::DSRevert, ImGui::DSRevertHovered, "revert", btn_pos, fiRevertIcon)) + discard_all_thicks(); + if (imgui_ctrl.render(m_selection)) SetSelectionSpan(m_is_one_layer ? imgui_ctrl.GetHigherValue() : imgui_ctrl.GetLowerValue(), imgui_ctrl.GetHigherValue()); + if (!is_horizontal()) { + btn_pos.y += 0.5 * btn_sz + size.y; + if (render_button(is_one_layer() ? ImGui::Lock : ImGui::Unlock, is_one_layer() ? ImGui::LockHovered : ImGui::UnlockHovered, "one_layer", btn_pos, fiOneLayerIcon)) + switch_one_layer_mode(); + + btn_pos.y += btn_sz; + if (render_button(ImGui::DSSettings, ImGui::DSSettingsHovered, "settings", btn_pos, fiCogIcon)) + show_cog_icon_context_menu(); + + if (m_allow_editing) + render_menu(); + } return result; } @@ -1739,9 +1779,11 @@ 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); + imgui_ctrl.CombineThumbs(m_is_one_layer); + if (!m_selection || m_is_one_layer) + m_selection = ssHigher; m_selection == ssLower ? correct_lower_value() : correct_higher_value(); - if (!m_selection) m_selection = ssHigher; + // if (!m_selection) m_selection = ssHigher; Refresh(); Update(); @@ -2829,8 +2871,10 @@ void Control::switch_one_layer_mode() SetLowerValue(m_min_value); SetHigherValue(m_max_value); } + if (!m_selection || m_is_one_layer) + m_selection = ssHigher; m_selection == ssLower ? correct_lower_value() : correct_higher_value(); - if (m_selection == ssUndef) m_selection = ssHigher; +// if (m_selection == ssUndef) m_selection = ssHigher; } // discard all custom changes on DoubleSlider diff --git a/src/slic3r/GUI/DoubleSlider.hpp b/src/slic3r/GUI/DoubleSlider.hpp index f5e57808f2..b021c774f9 100644 --- a/src/slic3r/GUI/DoubleSlider.hpp +++ b/src/slic3r/GUI/DoubleSlider.hpp @@ -381,6 +381,7 @@ private: int m_higher_value; bool m_render_as_disabled{ false }; + bool m_allow_editing{ true }; ScalableBitmap m_bmp_thumb_higher; ScalableBitmap m_bmp_thumb_lower; @@ -490,7 +491,7 @@ private: void draw_colored_band(const ImRect& groove, const ImRect& slideable_region); 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 render_button(const wchar_t btn_icon, const wchar_t btn_icon_hovered, const std::string& label_id, const ImVec2& pos, FocusedItem focus, int tick = -1); diff --git a/src/slic3r/GUI/ImGuiDoubleSlider.cpp b/src/slic3r/GUI/ImGuiDoubleSlider.cpp index 57bbd5d6c5..f06ab7eb98 100644 --- a/src/slic3r/GUI/ImGuiDoubleSlider.cpp +++ b/src/slic3r/GUI/ImGuiDoubleSlider.cpp @@ -95,7 +95,7 @@ ImRect ImGuiControl::DrawOptions::groove(const ImVec2& pos, const ImVec2& size, 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); + ImVec2(groove_sz().x, size.y - 1.6 * text_dummy_sz().y); return ImRect(groove_start, groove_start + groove_size); } @@ -180,6 +180,13 @@ void ImGuiControl::SetSliderValues(const std::vector& values) m_values = values; } +void ImGuiControl::CombineThumbs(bool combine) +{ + m_combine_thumbs = combine; + if (combine) + m_selection = ssHigher; +} + std::string ImGuiControl::get_label(int pos) const { if (m_cb_get_label) @@ -219,9 +226,14 @@ void ImGuiControl::draw_scroll_line(const ImRect& scroll_line, const ImRect& sli ImGui::RenderFrame(scroll_line.Min, scroll_line.Max, thumb_bg_clr, false, m_draw_opts.rounding()); } -void ImGuiControl::draw_background(const ImRect& groove) +void ImGuiControl::draw_background(const ImRect& slideable_region) { - ImVec2 groove_padding = (is_horizontal() ? ImVec2(2.0f, 2.0f) : ImVec2(3.0f, 4.0f)) * m_draw_opts.scale; + ImVec2 groove_sz = m_draw_opts.groove_sz() * 0.55f; + auto groove_center = slideable_region.GetCenter(); + ImRect groove = is_horizontal() ? + ImRect(slideable_region.Min.x, groove_center.y - groove_sz.y, slideable_region.Max.x, groove_center.y + groove_sz.y) : + ImRect(groove_center.x - groove_sz.x, slideable_region.Min.y, groove_center.x + groove_sz.x, slideable_region.Max.y); + 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); @@ -300,7 +312,7 @@ void ImGuiControl::apply_regions(int higher_value, int lower_value, const ImRect 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) +void ImGuiControl::check_and_correct_thumbs(int* higher_value, int* lower_value) { if (!m_draw_lower_thumb || m_combine_thumbs) return; @@ -353,13 +365,13 @@ bool ImGuiControl::draw_slider( int* higher_value, int* lower_value, ImGuiContext& context = *GImGui; const ImGuiID id = window->GetID(m_name.c_str()); - const ImRect draw_region(pos, pos + size); - ImGui::ItemSize(draw_region); + const ImRect item_size(pos, pos + size); + ImGui::ItemSize(item_size); - // calc slider groove size + // get slider groove size ImRect groove = m_draw_opts.groove(pos, size, is_horizontal()); - // set active(draggable) region. + // get active(draggable) region. ImRect draggable_region = m_draw_opts.draggable_region(groove, is_horizontal()); if (ImGui::ItemHoverable(draggable_region, id) && context.IO.MouseDown[0]) { @@ -368,9 +380,13 @@ bool ImGuiControl::draw_slider( int* higher_value, int* lower_value, ImGui::FocusWindow(window); } - // set slideable region and thumbs. + // set slideable regions and thumbs. apply_regions(*higher_value, *lower_value, draggable_region); + // select and mark higher thumb by default + if (m_selection == ssUndef) + m_selection = ssHigher; + // Processing interacting if (ImGui::ItemHoverable(m_regions.higher_thumb, id) && context.IO.MouseClicked[0]) @@ -382,44 +398,53 @@ bool ImGuiControl::draw_slider( int* higher_value, int* lower_value, // update thumb position and value bool value_changed = false; - if (m_selection == ssHigher) + if (m_selection == ssHigher) { value_changed = behavior(id, m_regions.higher_slideable_region, m_min_value, m_max_value, higher_value, &m_regions.higher_thumb, is_horizontal() ? 0: ImGuiSliderFlags_Vertical); - else if (m_draw_lower_thumb && !m_combine_thumbs) + } + else if (m_draw_lower_thumb && !m_combine_thumbs) { value_changed = behavior(id, m_regions.lower_slideable_region, m_min_value, m_max_value, lower_value, &m_regions.lower_thumb, is_horizontal() ? 0: ImGuiSliderFlags_Vertical); + } + + // check thumbs values and correct them if needed + check_and_correct_thumbs(higher_value, lower_value); + + 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 = m_regions.higher_thumb; - if (!value_changed && ImGui::ItemHoverable(draw_region, id)) { - behavior(id, draggable_region, m_min_value, m_max_value, + ImRect mouse_pos_rc = active_thumb; + if (!value_changed && ImGui::ItemHoverable(item_size, id) && !ImGui::IsMouseDragging(0)) { + behavior(id, slideable_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]) + // detect right click on selected thumb + if (ImGui::ItemHoverable(active_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]) || + if ((!ImGui::ItemHoverable(active_thumb, id) && context.IO.MouseClicked[1]) || context.IO.MouseClicked[0]) m_rclick_on_selected_thumb = false; + // render slider + 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()); + ImRect scroll_line = m_draw_opts.slider_line(slideable_region, higher_thumb_center, lower_thumb_center, is_horizontal()); + + if (m_cb_extra_draw) + m_cb_extra_draw(slideable_region); // draw background - draw_background(groove); + draw_background(slideable_region); // draw scroll line - draw_scroll_line(m_combine_thumbs ? groove : scroll_line, groove); + draw_scroll_line(m_combine_thumbs ? groove : scroll_line, slideable_region); // draw thumbs with label - // select and mark higher thumb by default - draw_thumb(higher_thumb_center, m_selection != ssLower && m_draw_lower_thumb); + draw_thumb(higher_thumb_center, m_selection == ssHigher && m_draw_lower_thumb); draw_label(higher_label, m_regions.higher_thumb); if (m_draw_lower_thumb && !m_combine_thumbs) { diff --git a/src/slic3r/GUI/ImGuiDoubleSlider.hpp b/src/slic3r/GUI/ImGuiDoubleSlider.hpp index 732ceff57d..406cb51a6e 100644 --- a/src/slic3r/GUI/ImGuiDoubleSlider.hpp +++ b/src/slic3r/GUI/ImGuiDoubleSlider.hpp @@ -69,21 +69,18 @@ public: void SetMaxValue(const int max_value); void SetSliderValues(const std::vector& values); + void CombineThumbs(bool combine); 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 cb) { m_cb_get_label_on_move = cb; } - void set_get_label_cb(std::function cb) { m_cb_get_label = cb; } - void set_draw_scroll_line_cb(std::function 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 is_rclick_on_thumb() const { return m_rclick_on_selected_thumb; } bool render(SelectedSlider& selection); void draw_scroll_line(const ImRect& scroll_line, const ImRect& slideable_region); @@ -91,6 +88,11 @@ public: 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); } + void set_get_label_on_move_cb(std::function cb) { m_cb_get_label_on_move = cb; } + void set_get_label_cb(std::function cb) { m_cb_get_label = cb; } + void set_draw_scroll_line_cb(std::function cb) { m_cb_draw_scroll_line = cb; } + void set_extra_draw_cb(std::function cb) { m_cb_extra_draw = cb; } + struct DrawOptions { float scale { 1.f }; // used for Retina on osx @@ -133,7 +135,6 @@ private: 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 }; @@ -143,13 +144,14 @@ private: std::function m_cb_get_label { nullptr }; std::function m_cb_get_label_on_move { nullptr }; std::function m_cb_draw_scroll_line { nullptr }; + std::function m_cb_extra_draw { 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 check_and_correct_thumbs(int* higher_value, int* lower_value); - void draw_background(const ImRect& groove); + void draw_background(const ImRect& slideable_region); void draw_label(std::string label, const ImRect& thumb); void draw_thumb(const ImVec2& center, bool mark = false); bool draw_slider(int* higher_value, int* lower_value, diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 455e961c00..b776dd5bbe 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -75,6 +75,15 @@ static const std::map font_icons = { {ImGui::SnapMarker , "snap" }, {ImGui::HorizontalHide , "horizontal_hide" }, {ImGui::HorizontalShow , "horizontal_show" }, + + {ImGui::ErrorTick , "error_tick" }, + {ImGui::ErrorTickHovered , "error_tick_f" }, + {ImGui::PausePrint , "pause_print" }, + {ImGui::PausePrintHovered , "pause_print_f" }, + {ImGui::EditGCode , "edit_gcode" }, + {ImGui::EditGCodeHovered , "edit_gcode_f" }, + {ImGui::RemoveTick , "colorchange_del" }, + {ImGui::RemoveTickHovered , "colorchange_del_f" }, }; static const std::map font_icons_large = { @@ -116,6 +125,17 @@ static const std::map font_icons_large = { {ImGui::SlaViewProcessed , "sla_view_processed" }, }; +static const std::map font_icons_medium = { + {ImGui::Lock , "lock_closed" }, + {ImGui::LockHovered , "lock_closed_f" }, + {ImGui::Unlock , "lock_open" }, + {ImGui::UnlockHovered , "lock_open_f" }, + {ImGui::DSRevert , "undo" }, + {ImGui::DSRevertHovered , "undo_f" }, + {ImGui::DSSettings , "cog" }, + {ImGui::DSSettingsHovered , "cog_f" }, +}; + static const std::map font_icons_extra_large = { {ImGui::ClippyMarker , "notification_clippy" }, }; @@ -470,7 +490,7 @@ bool ImGuiWrapper::slider_float(const wxString& label, float* v, float v_min, fl return this->slider_float(label_utf8.c_str(), v, v_min, v_max, format, power, clamp, tooltip, show_edit_btn); } -bool ImGuiWrapper::image_button(const wchar_t icon, const std::string& tooltip) +bool ImGuiWrapper::image_button(const wchar_t icon, const std::string& tooltip, bool highlight_on_hover/* = true*/) { const ImGuiIO& io = ImGui::GetIO(); const ImTextureID tex_id = io.Fonts->TexID; @@ -481,9 +501,9 @@ bool ImGuiWrapper::image_button(const wchar_t icon, const std::string& tooltip) const ImVec2 size = { float(rect->Width), float(rect->Height) }; const ImVec2 uv0 = ImVec2(float(rect->X) * inv_tex_w, float(rect->Y) * inv_tex_h); const ImVec2 uv1 = ImVec2(float(rect->X + rect->Width) * inv_tex_w, float(rect->Y + rect->Height) * inv_tex_h); - ImGui::PushStyleColor(ImGuiCol_Button, { 0.25f, 0.25f, 0.25f, 0.0f }); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, { 0.4f, 0.4f, 0.4f, 1.0f }); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, { 0.25f, 0.25f, 0.25f, 1.0f }); + ImGui::PushStyleColor(ImGuiCol_Button, { 0.25f, 0.25f, 0.25f, 0.0f }); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, { 0.4f, 0.4f, 0.4f, highlight_on_hover ? 1.0f : 0.0f }); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, { 0.25f, 0.25f, 0.25f, highlight_on_hover ? 1.0f : 0.0f }); const bool res = ImGuiPureWrap::image_button(tex_id, size, uv0, uv1); ImGui::PopStyleColor(3); @@ -1125,6 +1145,10 @@ void ImGuiWrapper::init_font(bool compress) m_custom_glyph_rects_ids[icon.first] = io.Fonts->AddCustomRectFontGlyph(font, icon.first, icon_sz, icon_sz, 3.0 * font_scale + icon_sz); } + for (auto& icon : font_icons_medium) { + m_custom_glyph_rects_ids[icon.first] = + io.Fonts->AddCustomRectFontGlyph(font, icon.first, 1.5 * icon_sz, 1.5 * icon_sz, 3.0 * font_scale + 1.5 * icon_sz); + } for (auto& icon : font_icons_large) { m_custom_glyph_rects_ids[icon.first] = io.Fonts->AddCustomRectFontGlyph(font, icon.first, icon_sz * 2, icon_sz * 2, 3.0 * font_scale + icon_sz * 2); @@ -1161,6 +1185,11 @@ void ImGuiWrapper::init_font(bool compress) load_icon_from_svg(icon, icon_sz); } + const int icon_sz_m = int(1.5 * icon_sz); // default size of medium icon is 24 px + for (auto icon : font_icons_medium) { + load_icon_from_svg(icon, icon_sz_m); + } + icon_sz *= 2; // default size of large icon is 32 px for (auto icon : font_icons_large) { load_icon_from_svg(icon, icon_sz); diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index 56797f7e3a..8cbec8b390 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -86,8 +86,7 @@ public: bool slider_float(const std::string& label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f, bool clamp = true, const wxString& tooltip = {}, bool show_edit_btn = true); bool slider_float(const wxString& label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f, bool clamp = true, const wxString& tooltip = {}, bool show_edit_btn = true); - bool image_button(const wchar_t icon, const std::string& tooltip = {}); - + bool image_button(const wchar_t icon, const std::string& tooltip = {}, bool highlight_on_hover = true); void search_list(const ImVec2& size, bool (*items_getter)(int, const char** label, const char** tooltip), char* search_str, Search::OptionViewParameters& view_params, int& selected, bool& edited, int& mouse_wheel, bool is_localized);