916{
917 ImGuiWindow* window = ImGui::GetCurrentWindow();
918 if (window->SkipItems)
919 return false;
920
921 ImGuiContext& context = *GImGui;
922 const ImGuiID id = window->GetID(str_id);
923
924 const ImVec2
pos = window->DC.CursorPos;
925 const ImRect draw_region(pos, pos + size);
926 ImGui::ItemSize(draw_region);
927
928 const float text_dummy_height = 60.0f *
scale *
m_scale;
929
930 const float handle_radius = 12.0f *
m_scale;
931 const float handle_border = 2.0f *
m_scale;
932 const float line_width = 1.0f *
m_scale;
933 const float line_length = 12.0f *
m_scale;
934
935 const ImVec2 text_padding = ImVec2(5.0f, 2.0f) *
m_scale;
936 ImVec2 text_size;
937
946 const ImU32 label_bg_clr = IM_COL32(label_bg.Red(), label_bg.Green(), label_bg.Blue(), 238);
947 const ImU32 label_bg_active_clr = IM_COL32(label_bg_active.Red(), label_bg_active.Green(), label_bg_active.Blue(), 246);
948 const ImU32 label_border_clr = IM_COL32(label_border.Red(), label_border.Green(), label_border.Blue(), 255);
949 const ImU32 label_shadow_clr =
m_is_dark ? IM_COL32(0, 0, 0, 84) : IM_COL32(0, 0, 0, 38);
950 ImVec4 range_fill = ImGui::ColorConvertU32ToFloat4(
BRAND_COLOR);
951 range_fill.w = (
m_is_dark ? 210.0f : 190.0f) / 255.0f;
952 const ImU32 range_fill_clr = ImGui::GetColorU32(range_fill);
953 const ImU32 rail_inner_clr = IM_COL32(rail_inner_bg.Red(), rail_inner_bg.Green(), rail_inner_bg.Blue(), 255);
954 const ImU32 rail_border_clr = IM_COL32(rail_border.Red(), rail_border.Green(), rail_border.Blue(), 190);
955
958 const ImRect groove =
ImRect(groove_start, groove_start + groove_size);
960 const float mid_x = groove.GetCenter().x;
961
962 const float label_width_margin = 10.0f *
m_scale;
963 const float max_label_width = std::max(0.0f,
964 groove.Min.x - draw_region.Min.x - label_width_margin * 2.0f - text_padding.x * 2.0f);
965
966
967
968 const ImRect region =
ImRect(bg_rect.Min + ImVec2(0.0f, handle_radius), bg_rect.Max - ImVec2(0.0f, handle_radius));
969 const ImRect higher_slideable_region =
ImRect(region.Min, region.Max - ImVec2(0, handle_radius));
970 const ImRect lower_slideable_region =
ImRect(region.Min + ImVec2(0, handle_radius), region.Max);
971 const ImRect one_slideable_region = region;
972
973
974 float higher_handle_pos =
get_pos_from_value(v_min, v_max, *higher_value, higher_slideable_region);
975 ImRect higher_handle =
ImRect(mid_x - handle_radius, higher_handle_pos - handle_radius, mid_x + handle_radius, higher_handle_pos + handle_radius);
976
977 float lower_handle_pos =
get_pos_from_value(v_min, v_max, *lower_value, lower_slideable_region);
978 ImRect lower_handle =
ImRect(mid_x - handle_radius, lower_handle_pos - handle_radius, mid_x + handle_radius, lower_handle_pos + handle_radius);
979
980 auto one_layer_handle = [&](int value) {
981 const float handle_pos =
get_pos_from_value(v_min, v_max, value, one_slideable_region);
982 return ImRect(mid_x - handle_radius, handle_pos - handle_radius,
983 mid_x + handle_radius, handle_pos + handle_radius);
984 };
986 if (one_layer_flag)
987 one_handle = one_layer_handle(*higher_value);
988
989
991 const bool menu_open = ImGui::IsPopupOpen("slider_add_menu_popup") || ImGui::IsPopupOpen("slider_edit_menu_popup");
992 const ImVec2 higher_text_content_size = ImGui::CalcTextSize(
into_u8(higher_label).c_str());
993 const ImVec2 lower_text_content_size = one_layer_flag ? ImVec2() : ImGui::CalcTextSize(
into_u8(lower_label).c_str());
995 if (!label_rect.Contains(context.IO.MousePos))
996 return;
997 hovered_label = selection_value;
998 };
999 auto range_label_rect = [&](
const ImRect& handle,
const ImVec2& content_size,
bool top_label) {
1000 const ImVec2 text_size = ImVec2(max_label_width, content_size.y) + text_padding * 2.0f;
1001 const ImVec2 text_start = ImVec2(handle.Min.x - text_size.x - label_width_margin,
1002 top_label ? handle.GetCenter().y - text_size.y : handle.GetCenter().y);
1003 return ImRect(text_start, text_start + text_size + ImVec2(label_width_margin, 0.0f));
1004 };
1005 auto one_layer_label_rect = [&](
const ImRect& handle) {
1006 const ImVec2 text_size = ImVec2(max_label_width, higher_text_content_size.y) + text_padding * 2.0f;
1007 const ImVec2 text_start = ImVec2(handle.Min.x - text_size.x - label_width_margin,
1008 handle.GetCenter().y - 0.5f * text_size.y);
1009 return ImRect(text_start, text_start + text_size);
1010 };
1011 auto draw_label = [&](
const ImRect& rect,
const ImVec2& content_size,
const std::string& label,
bool hovered,
bool active) {
1012 const float rounding = 5.0f *
m_scale;
1013 const ImU32 bg_clr = active ? label_bg_active_clr : label_bg_clr;
1014 const ImVec2 shadow_offset = ImVec2(2.0f, 2.0f) *
m_scale;
1015 window->DrawList->AddRectFilled(rect.Min + shadow_offset, rect.Max + shadow_offset, label_shadow_clr, rounding);
1016 ImGui::RenderFrame(rect.Min, rect.Max, bg_clr, false, rounding);
1017 window->DrawList->AddRect(rect.Min, rect.Max, hovered ? handle_clr : label_border_clr, rounding, 0, hovered ? 1.5f *
m_scale : 1.0f *
m_scale);
1018 const ImVec2 rect_size = rect.GetSize();
1019 ImGui::RenderText(rect.Min + ImVec2((rect_size.x - content_size.x) * 0.5f,
1020 (rect_size.y - content_size.y) * 0.5f), label.c_str());
1021 };
1022 auto draw_handle = [&](
const ImVec2&
center) {
1023 window->DrawList->AddCircleFilled(
center, handle_radius, handle_border_clr);
1024 window->DrawList->AddCircleFilled(
center, handle_radius - handle_border, handle_clr);
1025 };
1026 auto draw_active_handle = [&](
const ImVec2&
center) {
1027 window->DrawList->AddCircleFilled(
center, handle_radius + 2.0f *
m_scale, handle_border_clr);
1029 window->DrawList->AddCircle(
center, handle_radius + 3.0f *
m_scale, handle_clr, 0, 2.0f *
m_scale);
1030 window->DrawList->AddLine(
center + ImVec2(-0.5f * line_length, 0.0f),
center + ImVec2(0.5f * line_length, 0.0f), white_bg, line_width);
1031 window->DrawList->AddLine(
center + ImVec2(0.0f, -0.5f * line_length),
center + ImVec2(0.0f, 0.5f * line_length), white_bg, line_width);
1032 };
1033
1034
1035
1036 if (!menu_open && (!context.IO.MouseDown[0] || context.IO.MouseClicked[0])) {
1037 if (!one_layer_flag) {
1038 label_hit(range_label_rect(higher_handle, higher_text_content_size, true), ssHigher);
1039 label_hit(range_label_rect(lower_handle, lower_text_content_size, false), ssLower);
1040 } else {
1041 label_hit(one_layer_label_rect(one_handle), ssHigher);
1042 }
1043 }
1044
1045
1046 const ImRect slider_active_region =
ImRect(ImVec2(draw_region.Min.x + 35.0f *
m_scale, draw_region.Min.y), draw_region.Max);
1047 bool slider_hovered = !menu_open && ImGui::ItemHoverable(slider_active_region,
id) && !ImGui::ItemHoverable(
m_tick_rect,
id) && hovered_label ==
ssUndef;
1048 struct LabelDragState
1049 {
1050 ImGuiID id = 0;
1052 ImVec2 start_mouse;
1053 int start_value = 0;
1054 };
1055
1056 static LabelDragState label_drag;
1057
1058 if (hovered_label !=
ssUndef && context.IO.MouseClicked[0]) {
1059 selection = hovered_label;
1060 label_drag.id = id;
1061 label_drag.selection = hovered_label;
1062 label_drag.start_mouse = context.IO.MousePos;
1063 label_drag.start_value = hovered_label ==
ssHigher ? *higher_value : *lower_value;
1064 ImGui::SetActiveID(id, window);
1065 ImGui::SetFocusID(id, window);
1066 ImGui::FocusWindow(window);
1067 }
1068 if (slider_hovered && context.IO.MouseDown[0]) {
1069 ImGui::SetActiveID(id, window);
1070 ImGui::SetFocusID(id, window);
1071 ImGui::FocusWindow(window);
1072 }
1073
1074
1076 window->DrawList->AddRect(groove.Min, groove.Max, rail_border_clr, 0.5f * groove.GetWidth(), 0, 1.0f *
m_scale);
1077 const ImRect rail_inner(groove.Min + ImVec2(2.0f, 2.0f) *
m_scale, groove.Max - ImVec2(2.0f, 2.0f) *
m_scale);
1078 window->DrawList->AddRectFilled(rail_inner.Min, rail_inner.Max, rail_inner_clr, 0.5f * rail_inner.GetWidth());
1079
1080 bool value_changed = false;
1081 if (!one_layer_flag)
1082 {
1083 const SelectedSlider dragged_label = label_drag.id ==
id && context.IO.MouseDown[0] ? label_drag.selection :
ssUndef;
1084 if (dragged_label ==
ssUndef && !menu_open) {
1085 if (ImGui::ItemHoverable(higher_handle, id) && context.IO.MouseClicked[0]) {
1087 }
1088 if (ImGui::ItemHoverable(lower_handle, id) && context.IO.MouseClicked[0]) {
1090 }
1091 }
1092 bool h_selected = selection !=
ssLower;
1093
1094
1095 if (dragged_label !=
ssUndef) {
1096 const ImRect& drag_region = dragged_label ==
ssHigher ? higher_slideable_region : lower_slideable_region;
1097 const float region_height = drag_region.GetHeight();
1098 if (region_height > 0.0f) {
1099 const float delta = context.IO.MousePos.y - label_drag.start_mouse.y;
1100 const float value_delta = delta * (float)(v_max - v_min) / region_height;
1101 const int new_value = (int)ImClamp((float)label_drag.start_value - value_delta, (float)v_min, (float)v_max);
1103 value_changed = *higher_value != new_value;
1104 *higher_value = new_value;
1105 } else {
1106 value_changed = *lower_value != new_value;
1107 *lower_value = new_value;
1108 }
1109 }
1110 h_selected = dragged_label ==
ssHigher;
1112 higher_handle_pos =
get_pos_from_value(v_min, v_max, *higher_value, higher_slideable_region);
1113 higher_handle =
ImRect(mid_x - handle_radius, higher_handle_pos - handle_radius, mid_x + handle_radius, higher_handle_pos + handle_radius);
1114 } else {
1115 lower_handle_pos =
get_pos_from_value(v_min, v_max, *lower_value, lower_slideable_region);
1116 lower_handle =
ImRect(mid_x - handle_radius, lower_handle_pos - handle_radius, mid_x + handle_radius, lower_handle_pos + handle_radius);
1117 }
1118 } else {
1119 if (h_selected)
1120 {
1121 value_changed =
slider_behavior(
id, higher_slideable_region, v_min, v_max,
1122 higher_value, &higher_handle, ImGuiSliderFlags_Vertical,
1124 }
1125 if (!h_selected) {
1126 value_changed =
slider_behavior(
id, lower_slideable_region, v_min, v_max,
1127 lower_value, &lower_handle, ImGuiSliderFlags_Vertical,
1129 }
1130 }
1133 active_label = dragged_label;
1134 else if (context.ActiveId == id && context.IO.MouseDown[0])
1136
1137 ImVec2 higher_handle_center = higher_handle.GetCenter();
1138 ImVec2 lower_handle_center = lower_handle.GetCenter();
1139 if (higher_handle_center.y + handle_radius > lower_handle_center.y && h_selected)
1140 {
1141 lower_handle = higher_handle;
1142 lower_handle.TranslateY(handle_radius);
1143 lower_handle_center.y = higher_handle_center.y + handle_radius;
1144 *lower_value = *higher_value;
1145 }
1146 if (higher_handle_center.y + handle_radius > lower_handle_center.y && !h_selected)
1147 {
1148 higher_handle = lower_handle;
1149 higher_handle.TranslateY(-handle_radius);
1150 higher_handle_center.y = lower_handle_center.y - handle_radius;
1151 *higher_value = *lower_value;
1152 }
1153
1154
1155 if (!menu_open && ImGui::ItemHoverable(h_selected ? higher_handle : lower_handle, id) && context.IO.MouseClicked[1])
1157 if (!menu_open && ((!ImGui::ItemHoverable(h_selected ? higher_handle : lower_handle, id) && context.IO.MouseClicked[1]) ||
1158 context.IO.MouseClicked[0]))
1160
1161
1162 draw_ticks(h_selected ? higher_slideable_region : lower_slideable_region);
1163
1164 draw_colored_band(groove, h_selected ? higher_slideable_region : lower_slideable_region);
1165
1167
1168 ImRect scroll_line =
ImRect(ImVec2(groove.Min.x - 2.0f *
m_scale, higher_handle_center.y),
1169 ImVec2(groove.Max.x + 2.0f *
m_scale, lower_handle_center.y));
1170 window->DrawList->AddRectFilled(scroll_line.Min, scroll_line.Max, range_fill_clr, 0.5f * scroll_line.GetWidth());
1171 }
1172
1173
1174 draw_handle(higher_handle_center);
1175 draw_handle(lower_handle_center);
1176 draw_active_handle(h_selected ? higher_handle_center : lower_handle_center);
1177
1178
1179
1180 text_size = ImVec2(max_label_width, higher_text_content_size.y) + text_padding * 2;
1181 ImVec2 text_start = ImVec2(higher_handle.Min.x - text_size.x - label_width_margin, higher_handle_center.y - text_size.y);
1182 ImRect text_rect(text_start, text_start + text_size);
1183 const bool higher_label_active = active_label ==
ssHigher;
1184 draw_label(text_rect, higher_text_content_size, higher_label,
1185 hovered_label ==
ssHigher || higher_label_active, higher_label_active);
1186
1187 text_size = ImVec2(max_label_width, lower_text_content_size.y) + text_padding * 2;
1188 text_start = ImVec2(lower_handle.Min.x - text_size.x - label_width_margin, lower_handle_center.y);
1189 text_rect =
ImRect(text_start, text_start + text_size);
1190 const bool lower_label_active = active_label ==
ssLower;
1191 draw_label(text_rect, lower_text_content_size, lower_label,
1192 hovered_label ==
ssLower || lower_label_active, lower_label_active);
1193
1194
1195 if (slider_hovered && !context.IO.MouseDown[0]) {
1197 }
1198 }
1199 if (one_layer_flag)
1200 {
1201
1202 const SelectedSlider dragged_label = label_drag.id ==
id && context.IO.MouseDown[0] ? label_drag.selection :
ssUndef;
1204 const float region_height = one_slideable_region.GetHeight();
1205 if (region_height > 0.0f) {
1206 const float delta = context.IO.MousePos.y - label_drag.start_mouse.y;
1207 const float value_delta = delta * (float)(v_max - v_min) / region_height;
1208 const int new_value = (int)ImClamp((float)label_drag.start_value - value_delta, (float)v_min, (float)v_max);
1209 value_changed = *higher_value != new_value;
1210 *higher_value = new_value;
1211 }
1212 one_handle = one_layer_handle(*higher_value);
1213 } else {
1214 value_changed =
slider_behavior(
id, one_slideable_region, v_min, v_max,
1215 higher_value, &one_handle, ImGuiSliderFlags_Vertical,
1217 }
1218
1219 ImVec2 handle_center = one_handle.GetCenter();
1220
1221
1222 if (!menu_open && ImGui::ItemHoverable(one_handle, id) && context.IO.MouseClicked[1])
1224 if (!menu_open && ((!ImGui::ItemHoverable(one_handle, id) && context.IO.MouseClicked[1]) ||
1225 context.IO.MouseClicked[0]))
1227
1228
1230
1232
1233
1234 draw_active_handle(handle_center);
1235
1236
1237 text_size = ImVec2(max_label_width, higher_text_content_size.y) + text_padding * 2;
1238 ImVec2 text_start = ImVec2(one_handle.Min.x - text_size.x - label_width_margin, handle_center.y - 0.5 * text_size.y);
1239 ImRect text_rect =
ImRect(text_start, text_start + text_size);
1240 const bool label_active = context.ActiveId == id && context.IO.MouseDown[0];
1241 draw_label(text_rect, higher_text_content_size, higher_label, hovered_label ==
ssHigher || label_active, label_active);
1242
1243
1244 if (slider_hovered && !context.IO.MouseDown[0]) {
1246 }
1247 }
1248
1249 if (!context.IO.MouseDown[0] && label_drag.id == id) {
1250 label_drag.id = 0;
1251 label_drag.selection =
ssUndef;
1252 if (context.ActiveId == id)
1253 ImGui::ClearActiveID();
1254 }
1255
1256 return value_changed;
1257}
void draw_colored_band(const ImRect &groove, const ImRect &slideable_region)
Definition IMSlider.cpp:619
void draw_ticks(const ImRect &slideable_region)
Definition IMSlider.cpp:728
void draw_tick_on_mouse_position(const ImRect &slideable_region)
Definition IMSlider.cpp:891
static ImVec4 m_tick_rect
Definition IMSlider.cpp:73
SelectedSlider
Definition IMSlider.hpp:41
static int m_tick_value
Definition IMSlider.cpp:72