-
-
Notifications
You must be signed in to change notification settings - Fork 10.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Range Slider #76
Comments
These already exist:
|
I think he means a slider with two handles, used to specify a range of values? |
Could you specifi exactly what you need and how it would work? |
Sorry that wasn't clear. I mean a slider with two handles that allows you to set a range of values, a left handle sets the min and a right handle sets the max. For example you might have a random int generator, but you want the values to be in the range 5 - 25 this function could use such a slider control. |
Yup – I could definitely use that too, and in fact I would like both integer and floating point ranges. :) Thanks! A= Andrea Pessino (not female, just Italian) Cofounder/Chief Technology Officer From: davivid [mailto:[email protected]] Sorry that wasn't clear. I mean a slider with two handles that allows you to set a range of values, a left handle sets the min and a right handle sets the max. For example you might have a random int generator, but you want the values to be in the range 5 - 25 this function could use such a slider control. — |
OK. Sliders currently always sets their value given the position of the click, so they'd have to be changed in this case to require clicking on the slider grab and handling mouse movement in a relative manner. This is already a desired feature for sliders when clicking close to the current value. Currently when clicking close to the current value you are pretty much guarantee to modify the value, but it should goes "relative movement mode" and wait for horizontal dragging. So this has to be supported first then we can rather easily add a "range / double slider" over it. NB: Right now using SliderFloat2() + code that clamp values manually would be a reasonable workaround. |
Sorry this is still unresolved, such an old request! For now I have added helpers using DragFloat / DragInt which don't have the same issues to solve as SliderFloat / SliderInt. So you don't visualize two boxes into the same frame but they are separate frame. Limits are enforced when you drag either sides (but as always you can always bypass limits using ctrl+click to input values). DragFloatRange2()
DragIntRange2()
static float begin = 10, end = 90;
ImGui::DragFloatRange2("range", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%");
static int begin_i = 100, end_i = 1000;
ImGui::DragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %.0f units", "Max: %.0f units");
It's not "hard" do it for slider but right now it would require duplicating a bunch of code (100+ lines) which I'm not very happy with doing especially as the slider code is still in flux. In order to handle large int I first need to re-organize sliders and drags to that integer doesn't pass through a path that does int > float > int casting during edition. |
I've started to do a custom range but it is far from being finished. What would be the best way to handle the logic/rendering for a couple of sliders/grabbers together in a same group? I am right now creating a group with a couple of dummies, a scrollbar, and rendering two sliders on top of it. I am wondering if this is the best way to achieve it. edit: [Omar:Added attachment so that the data doesn't disappear in the future] |
Perhaps post the code. You'd probably want to create new code based on a combination of what Slider_, Drag_ and Scrollbar* do. |
Almost done ;) It looks better ( no overlapping shapes ) and allows to drag closest grab to mouse position. There is bug in selecting closest grab - it should lock to currently dragged and do not change to other while moving. Additionally same rule could change color for only one of them. You can look into https://github.com/wasikuss/imgui/tree/feature/range-slider or test it in https://github.com/wasikuss/imgui (soon emscripten playground will be added). |
@wasikuss I extracted your range slider into separate .inl/.h files and using ImGui's user includes for building it together with ImGui. This way it's easier to get integrated to other code before it's officially accepted. Code is here: One improvement could be that moving middle bar moves min/max values together. |
Another improvement that allows to shift a grabber while dragging the other one: // Put this section while dragging is active. Notes:
// - assumes left is range[0] and right is range[1]
// - assumes left <= right always
if(right < left) right = left;
if(left > right) left = right; |
ocornut/imgui#76 Taken from: wasikuss/imgui@a50515a needed SliderBehaviorCalcRatioFromValue() added to imgui.cpp to compile added timeline and curveeditor widgets from imgui_user files from here: https://github.com/nem0/LumixEngine/tree/master/external/imgui
hey @nem0, i just integrated your timeline with a few minor modifs :) awesome work! thanks! :) |
@r-lyeh: Are the few minor modifications publicly available ? [Edit:] These are the ones I've just made (but they're not very user-friendly as far as I can see): namespace ImGui {
// Definitions (header file)
// Timeline (from: https://github.com/nem0/LumixEngine/blob/timeline_gui/external/imgui/imgui_user.h)=
/* Possible enhancements:
* Add some kind of "snap to grid" epsilon
* Add zooming with CTRL+MouseWheel, and a horizontal scrollbar
* Add different types of TimelineEvent (e.g. multiple ranges in a single line, dot-like markers, etc.)
*/
IMGUI_API bool BeginTimeline(const char* str_id, float max_value=0.f, int num_visible_rows=5,int opt_exact_num_rows=0); // last arg, when !=0, enables item culling
IMGUI_API bool TimelineEvent(const char* str_id, float* values, bool keep_range_constant=false);
IMGUI_API void EndTimeline(int num_vertical_grid_lines=5.f,float current_time=0.f,ImU32 timeline_running_color=IM_COL32(0,128,0,200));
} // namespace ImGui
namespace ImGui {
// Timeline implementation (cpp file) from: https://github.com/nem0/LumixEngine/blob/timeline_gui/external/imgui/imgui_user.inl
static float s_max_timeline_value=0.f;
static int s_timeline_num_rows = 0;
static int s_timeline_display_start = 0;
static int s_timeline_display_end = 0;
static int s_timeline_display_index = 0;
bool BeginTimeline(const char* str_id, float max_value, int num_visible_rows,int opt_exact_num_rows)
{
// reset global variables
s_max_timeline_value=0.f;
s_timeline_num_rows = s_timeline_display_start = s_timeline_display_end = 0;
s_timeline_display_index = -1;
if (num_visible_rows<=0) num_visible_rows=5;
const float row_height = ImGui::GetTextLineHeightWithSpacing();
const bool rv = BeginChild(str_id,ImVec2(0,num_visible_rows>=0 ? (row_height*num_visible_rows) : -1.f),false);
ImGui::PushStyleColor(ImGuiCol_Column,GImGui->Style.Colors[ImGuiCol_Border]);
ImGui::Columns(2,str_id);
const float contentRegionWidth = ImGui::GetWindowContentRegionWidth();
if (ImGui::GetColumnOffset(1)>=contentRegionWidth*0.48f)ImGui::SetColumnOffset(1,contentRegionWidth*0.15f);
s_max_timeline_value = max_value>=0 ? max_value : (contentRegionWidth*0.85f);
if (opt_exact_num_rows>0) {
// Item culling
s_timeline_num_rows = opt_exact_num_rows;
ImGui::CalcListClipping(s_timeline_num_rows, row_height, &s_timeline_display_start, &s_timeline_display_end);
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + (s_timeline_display_start * row_height));
}
return rv;
}
static const float TIMELINE_RADIUS = 6;
bool TimelineEvent(const char* str_id, float* values,bool keep_range_constant)
{
++s_timeline_display_index;
if (s_timeline_num_rows>0 &&
(s_timeline_display_index<s_timeline_display_start || s_timeline_display_index>=s_timeline_display_end)) return false; // item culling
ImGuiWindow* win = GetCurrentWindow();
const ImU32 inactive_color = ColorConvertFloat4ToU32(GImGui->Style.Colors[ImGuiCol_Button]);
const ImU32 active_color = ColorConvertFloat4ToU32(GImGui->Style.Colors[ImGuiCol_ButtonHovered]);
const ImU32 line_color = ColorConvertFloat4ToU32(GImGui->Style.Colors[ImGuiCol_ColumnActive]);
bool changed = false;
bool hovered = false;
bool active = false;
ImGui::Text("%s",str_id);
ImGui::NextColumn();
const float columnOffset = ImGui::GetColumnOffset(1);
const float columnWidth = ImGui::GetColumnWidth(1)-GImGui->Style.ScrollbarSize;
ImVec2 cursor_pos(GetWindowContentRegionMin().x + win->Pos.x+columnOffset-TIMELINE_RADIUS,win->DC.CursorPos.y);
bool mustMoveBothEnds=false;
const bool isMouseDraggingZero = IsMouseDragging(0);
for (int i = 0; i < 2; ++i)
{
ImVec2 pos = cursor_pos;
pos.x += columnWidth * values[i] / s_max_timeline_value + TIMELINE_RADIUS;
pos.y += TIMELINE_RADIUS;
SetCursorScreenPos(pos - ImVec2(TIMELINE_RADIUS, TIMELINE_RADIUS));
PushID(i);
InvisibleButton(str_id, ImVec2(2 * TIMELINE_RADIUS, 2 * TIMELINE_RADIUS));
active = IsItemActive();
if (active || IsItemHovered())
{
ImGui::SetTooltip("%f", values[i]);
if (!keep_range_constant) {
// @meshula:The item hovered line needs to be compensated for vertical scrolling. Thx!
ImVec2 a(pos.x, GetWindowContentRegionMin().y + win->Pos.y + win->Scroll.y);
ImVec2 b(pos.x, GetWindowContentRegionMax().y + win->Pos.y + win->Scroll.y);
// possible aternative:
//ImVec2 a(pos.x, win->Pos.y);
//ImVec2 b(pos.x, win->Pos.y+win->Size.y);
win->DrawList->AddLine(a, b, line_color);
}
hovered = true;
}
if (active && isMouseDraggingZero)
{
if (!keep_range_constant) values[i] += GetIO().MouseDelta.x / columnWidth * s_max_timeline_value;
else mustMoveBothEnds = true;
changed = hovered = true;
}
PopID();
win->DrawList->AddCircleFilled(
pos, TIMELINE_RADIUS, IsItemActive() || IsItemHovered() ? active_color : inactive_color);
}
ImVec2 start = cursor_pos;
start.x += columnWidth * values[0] / s_max_timeline_value + 2 * TIMELINE_RADIUS;
start.y += TIMELINE_RADIUS * 0.5f;
ImVec2 end = start + ImVec2(columnWidth * (values[1] - values[0]) / s_max_timeline_value - 2 * TIMELINE_RADIUS,
TIMELINE_RADIUS);
PushID(-1);
SetCursorScreenPos(start);
InvisibleButton(str_id, end - start);
if ((IsItemActive() && isMouseDraggingZero) || mustMoveBothEnds)
{
const float deltaX = GetIO().MouseDelta.x / columnWidth * s_max_timeline_value;
values[0] += deltaX;
values[1] += deltaX;
changed = hovered = true;
}
else if (IsItemHovered()) hovered = true;
PopID();
SetCursorScreenPos(cursor_pos + ImVec2(0, GetTextLineHeightWithSpacing()));
win->DrawList->AddRectFilled(start, end, IsItemActive() || IsItemHovered() ? active_color : inactive_color);
if (values[0]>values[1]) {float tmp=values[0];values[0]=values[1];values[1]=tmp;}
if (values[1]>s_max_timeline_value) {values[0]-=values[1]-s_max_timeline_value;values[1]=s_max_timeline_value;}
if (values[0]<0) {values[1]-=values[0];values[0]=0;}
if (hovered) ImGui::SetMouseCursor(ImGuiMouseCursor_Move);
ImGui::NextColumn();
return changed;
}
void EndTimeline(int num_vertical_grid_lines,float current_time,ImU32 timeline_running_color) {
const float row_height = ImGui::GetTextLineHeightWithSpacing();
if (s_timeline_num_rows>0) ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ((s_timeline_num_rows - s_timeline_display_end) * row_height));
ImGui::NextColumn();
ImGuiWindow* win = GetCurrentWindow();
const float columnOffset = ImGui::GetColumnOffset(1);
const float columnWidth = ImGui::GetColumnWidth(1)-GImGui->Style.ScrollbarSize;
const float horizontal_interval = columnWidth / num_vertical_grid_lines;
ImU32 color = ColorConvertFloat4ToU32(GImGui->Style.Colors[ImGuiCol_Button]);
ImU32 line_color = ColorConvertFloat4ToU32(GImGui->Style.Colors[ImGuiCol_Border]);
ImU32 text_color = ColorConvertFloat4ToU32(GImGui->Style.Colors[ImGuiCol_Text]);
ImU32 moving_line_color = ColorConvertFloat4ToU32(GImGui->Style.Colors[ImGuiCol_ColumnActive]);
const float rounding = GImGui->Style.ScrollbarRounding;
const float startY = ImGui::GetWindowHeight() + win->Pos.y;
// Draw black vertical lines (inside scrolling area)
for (int i = 1; i <= num_vertical_grid_lines; ++i)
{
ImVec2 a = GetWindowContentRegionMin() + win->Pos;
a.x += i * horizontal_interval + columnOffset;
win->DrawList->AddLine(a, ImVec2(a.x,startY), line_color);
}
// Draw moving vertical line
if (current_time>0.f && current_time<s_max_timeline_value) {
ImVec2 a = GetWindowContentRegionMin() + win->Pos;
a.x += columnWidth*(current_time/s_max_timeline_value) + columnOffset;
win->DrawList->AddLine(a, ImVec2(a.x,startY), moving_line_color);
}
ImGui::Columns(1);
ImGui::PopStyleColor();
EndChild();
// Draw bottom axis ribbon (outside scrolling region)
win = GetCurrentWindow();
ImVec2 start(ImGui::GetCursorScreenPos().x+columnOffset,ImGui::GetCursorScreenPos().y);
ImVec2 end(start.x+columnWidth,start.y+row_height);
if (current_time<=0) win->DrawList->AddRectFilled(start, end, color, rounding);
else if (current_time>s_max_timeline_value) win->DrawList->AddRectFilled(start, end, timeline_running_color, rounding);
else {
ImVec2 median(start.x+columnWidth*(current_time/s_max_timeline_value),end.y);
win->DrawList->AddRectFilled(start, median, timeline_running_color, rounding,1|8);
median.y=start.y;
win->DrawList->AddRectFilled(median, end, color, rounding,2|4);
win->DrawList->AddLine(median, ImVec2(median.x,end.y), moving_line_color);
}
char tmp[256]="";
for (int i = 0; i < num_vertical_grid_lines; ++i)
{
ImVec2 a = start;
a.x += i * horizontal_interval;
a.y = start.y;
ImFormatString(tmp, sizeof(tmp), "%.2f", i * s_max_timeline_value / num_vertical_grid_lines);
win->DrawList->AddText(a, text_color, tmp);
}
ImGui::SetCursorPosY(ImGui::GetCursorPosY()+row_height);
}
// End Timeline
} // namespace ImGui And I can use it this way: if (ImGui::BeginTimeline("MyTimeline",50.f,4,6)) // label, max_value, num_visible_rows, opt_exact_num_rows (for item culling)
{
static float events[12]={10.f,20.f,0.5f,30.f,40.f,50.f,20.f,40.f,15.f,22.5f,35.f,45.f};
if (ImGui::TimelineEvent("Event1",&events[0])) {/*events[0] and/or events[1] modified*/}
ImGui::TimelineEvent("Event2",&events[2]);
ImGui::TimelineEvent("Event3",&events[4],true); // Event3 can only be shifted
ImGui::TimelineEvent("Event4",&events[6]);
ImGui::TimelineEvent("Event5",&events[8]);
ImGui::TimelineEvent("Event6",&events[10]);
}
const float elapsedTime = (float)(((unsigned)(ImGui::GetTime()*1000))%50000)/1000.f; // So that it's always in [0,50]
ImGui::EndTimeline(5,elapsedTime); // num_vertical_grid_lines, current_time (optional), timeline_running_color (optional)
|
@Flix01 sure edit: I havent played with columns here but I guess this is the way to go for the track labels. // https://github.com/ocornut/imgui/issues/76
// h
namespace ImGui {
bool BeginTimeline(const char* str_id, float max_time);
bool TimelineEvent(const char* str_id, float times[2]);
void EndTimeline(float current_time = -1);
}
// cpp
// https://github.com/ocornut/imgui/issues/76
namespace ImGui {
static float s_max_timeline_value;
bool BeginTimeline(const char* str_id, float max_time)
{
s_max_timeline_value = max_time;
return BeginChild(str_id);
}
static const float TIMELINE_RADIUS = 6;
bool TimelineEvent(const char* str_id, float values[2])
{
ImGuiWindow* win = GetCurrentWindow();
const ImU32 inactive_color = ColorConvertFloat4ToU32(GImGui->Style.Colors[ImGuiCol_Button]);
const ImU32 active_color = ColorConvertFloat4ToU32(GImGui->Style.Colors[ImGuiCol_ButtonHovered]);
const ImU32 line_color = ColorConvertFloat4ToU32(GImGui->Style.Colors[ImGuiCol_ColumnActive]);
bool changed = false;
ImVec2 cursor_pos = win->DC.CursorPos;
// @r-lyeh {
Button(str_id, ImVec2(120,0)); // @todo: enable/disable track channel here
SameLine();
cursor_pos += ImVec2(0, GetTextLineHeightWithSpacing() / 3);
// }
for (int i = 0; i < 2; ++i)
{
ImVec2 pos = cursor_pos;
pos.x += win->Size.x * values[i] / s_max_timeline_value + TIMELINE_RADIUS;
pos.y += TIMELINE_RADIUS;
SetCursorScreenPos(pos - ImVec2(TIMELINE_RADIUS, TIMELINE_RADIUS));
PushID(i);
InvisibleButton(str_id, ImVec2(2 * TIMELINE_RADIUS, 2 * TIMELINE_RADIUS));
if (IsItemActive() || IsItemHovered())
{
ImGui::SetTooltip("%f", values[i]);
ImVec2 a(pos.x, GetWindowContentRegionMin().y + win->Pos.y + win->Scroll.y);
ImVec2 b(pos.x, GetWindowContentRegionMax().y + win->Pos.y + win->Scroll.y);
win->DrawList->AddLine(a, b, line_color);
}
if (IsItemActive() && IsMouseDragging(0))
{
values[i] += GetIO().MouseDelta.x / win->Size.x * s_max_timeline_value;
changed = true;
}
PopID();
win->DrawList->AddCircleFilled(
pos, TIMELINE_RADIUS, IsItemActive() || IsItemHovered() ? active_color : inactive_color);
}
ImVec2 start = cursor_pos;
start.x += win->Size.x * values[0] / s_max_timeline_value + 2 * TIMELINE_RADIUS;
start.y += TIMELINE_RADIUS * 0.5f;
ImVec2 end = start + ImVec2(win->Size.x * (values[1] - values[0]) / s_max_timeline_value - 2 * TIMELINE_RADIUS,
TIMELINE_RADIUS);
PushID(-1);
SetCursorScreenPos(start);
InvisibleButton(str_id, end - start);
if (IsItemActive() && IsMouseDragging(0))
{
values[0] += GetIO().MouseDelta.x / win->Size.x * s_max_timeline_value;
values[1] += GetIO().MouseDelta.x / win->Size.x * s_max_timeline_value;
changed = true;
}
PopID();
SetCursorScreenPos(cursor_pos + ImVec2(0, GetTextLineHeightWithSpacing()));
win->DrawList->AddRectFilled(start, end, IsItemActive() || IsItemHovered() ? active_color : inactive_color);
if (values[0] > values[1])
{
float tmp = values[0];
values[0] = values[1];
values[1] = tmp;
}
if (values[1] > s_max_timeline_value) values[1] = s_max_timeline_value;
if (values[0] < 0) values[0] = 0;
return changed;
}
void EndTimeline( float t )
{
ImGuiWindow* win = GetCurrentWindow();
// @r-lyeh {
if( t >= 0 ) {
if( t > s_max_timeline_value ) t = s_max_timeline_value; t /= s_max_timeline_value;
const ImU32 line_color = ColorConvertFloat4ToU32(GImGui->Style.Colors[ImGuiCol_ColumnActive]);
ImVec2 a(win->Pos.x + GetWindowContentRegionMin().x + t * GetWindowContentRegionWidth(), GetWindowContentRegionMin().y + win->Pos.y + win->Scroll.y);
ImVec2 b(win->Pos.x + GetWindowContentRegionMin().x + t * GetWindowContentRegionWidth(), GetWindowContentRegionMax().y + win->Pos.y + win->Scroll.y);
win->DrawList->AddLine(a, b, line_color);
}
// }
ImU32 color = ColorConvertFloat4ToU32(GImGui->Style.Colors[ImGuiCol_Button]);
ImU32 line_color = ColorConvertFloat4ToU32(GImGui->Style.Colors[ImGuiCol_Border]);
ImU32 text_color = ColorConvertFloat4ToU32(GImGui->Style.Colors[ImGuiCol_Text]);
float rounding = GImGui->Style.ScrollbarRounding;
ImVec2 start(GetWindowContentRegionMin().x + win->Pos.x,
GetWindowContentRegionMax().y - GetTextLineHeightWithSpacing() + win->Pos.y + win->Scroll.y);
ImVec2 end = GetWindowContentRegionMax() + win->Pos + ImVec2(0,win->Scroll.y);
win->DrawList->AddRectFilled(start, end, color, rounding);
const int LINE_COUNT = 5;
const ImVec2 text_offset(0, GetTextLineHeightWithSpacing());
for (int i = 0; i <= LINE_COUNT; ++i)
{
ImVec2 a = GetWindowContentRegionMin() + win->Pos; // @r-lyeh: - ImVec2(TIMELINE_RADIUS, 0);
a.x += i * (GetWindowContentRegionWidth() - 1) / LINE_COUNT; // @r-lyeh: -1
ImVec2 b = a;
b.y = start.y;
win->DrawList->AddLine(a, b, line_color);
char tmp[256];
ImFormatString(tmp, sizeof(tmp), "%.2f", i * s_max_timeline_value / LINE_COUNT);
win->DrawList->AddText(b, text_color, tmp);
}
EndChild();
}
} |
Thanks @r-lyeh !
Yes, that's what I was thinking. However the current code relies heavily on the cursor position, that is completely messed up when we use columns! So I guess it's not as easy as it seems... |
I'm making some progress with the column API. I'll update the code when it's ready (I'm currently trying to make scrolling work: and it takes time, especially if I'll try to add line culling...) |
I've updated my modifications in the post above. |
Could you elaborate? |
@Flix01 The item hovered line needs to be compensated for vertical scrolling,
|
Now we need a "set first" flag for column offset so that if the user drags the column separator, it "sticks" instead of snapping back :) There's a number of open issues on columns, maybe it's premature to try to fix this? |
@meshula: yes, although in my code it snaps back only when the column is pulled to the half right side of the window. const float contentRegionWidth = ImGui::GetWindowContentRegionWidth();
if (ImGui::GetColumnOffset(1)>=contentRegionWidth*0.48f) ImGui::SetColumnOffset(1,contentRegionWidth*0.15f);
// The if branch is executed the first time and when the user drags
// the column to the right more than contentRegionWidth*0.48f |
Ah, that's clever. Not quite the behavior I would like, but I can cook up "something" with that solution in mind. |
Here's a version that allows you to pan and zoom the timeline, via a little stretchable bar that appears under the number line. It's use of static variables is super clumsy because it restricts to only one active timeline, but it's fine for a proof of concept.
|
@meshula: Looks interesting and useful! Thanks for posting! |
@meshula: cool! took me a while to figure out the input args but it finally worked :) mouse wheel now! :D |
@bkaradzic Did you added this feature? There's also some strange bounding box problems... Layout broke when using SameLine( |
@wasikuss |
@bkaradzic |
@bkaradzic |
Solved taken code from imgui_widgets.cpp from your repo // extern float RoundScalarWithFormatFloat(const char* format, ImGuiDataType data_type, float v);
float RoundScalarWithFormatFloat(const char* format, ImGuiDataType data_type, float v)
{
return ImGui::RoundScalarWithFormatT<float, float>(format, data_type, v);
}
// extern float SliderCalcRatioFromValueFloat(ImGuiDataType data_type, float v, float v_min, float v_max, float power, float linear_zero_pos);
float SliderCalcRatioFromValueFloat(ImGuiDataType data_type, float v, float v_min, float v_max, float power, float linear_zero_pos)
{
return ImGui::ScaleRatioFromValueT<float, float, float>(data_type, v, v_min, v_max, false, power, linear_zero_pos);
} |
@ocornut, is there any news about implementation of this feature in ImGui by default? For now I have found no way to add @bkaradzic implementation without problems with linking. Why is it still not implemented, while the sollution exists for 5 years? |
I get an error "no operator "+" matches these operands" on line 170 & 171 |
@Zejzz what version of imgui are you using? Write the full stacktrace of an error |
You need to use #define IMGUI_DEFINE_MATH_OPERATORS in order to access operators, unless your own math class was setup in imconfig.h |
I would find a range slider very handy. Any plans to implement one?
The text was updated successfully, but these errors were encountered: