09 高级绘制

09 高级绘制

choosing box(选中框)

ImVec2 start{0,0};
ImVec2 end{0,0};
bool isMouseRelease = true;

// into loop
// ...
if (isMouseRelease)
if (ImGui::IsMouseDown(0) && IsWindowFocused()) // record start pos
{
isMouseRelease = false;
start = ImGui::GetMousePos();
}

if (ImGui::IsMouseDown(0) && IsWindowFocused())
{
end = ImGui::GetMousePos(); // record end pos
auto leftup = ImGui::GetWindowPos(); // avoid out of window range
auto size = ImGui::GetWindowSize();
if (end.x > leftup.x + size.x)end.x = leftup.x + size.x;
if (end.x < leftup.x)end.x = leftup.x;
if (end.y > leftup.y + size.y)end.y = leftup.y + size.y;
if (end.x < leftup.y)end.y = leftup.y;
ImVec2 startR{start}, endR{end}; // set leftTop and rightDown Point
if (start.x > end.x) { startR.x = end.x; endR.x = start.x; }
if (start.y > end.y) { startR.y = end.y; endR.y = start.y; }
ImDrawList* drawList = ImGui::GetForegroundDrawList();
drawList->AddRectFilled(startR, endR, ImColor(224, 247, 224),5,ImDrawFlags_::ImDrawFlags_RoundCornersAll);
}

if (ImGui::IsMouseReleased(0))
{
isMouseRelease = true;
}

loading bar(加载条)

Progress Indicators (spinner + loading bar) · Issue #1901 · ocornut/imgui (github.com)

1号

namespace ImGui {

bool BufferingBar(const char* label, float value, const ImVec2& size_arg, const ImU32& bg_col, const ImU32& fg_col) {
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
return false;

ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label);

ImVec2 pos = window->DC.CursorPos;
ImVec2 size = size_arg;
size.x -= style.FramePadding.x * 2;

const ImRect bb(pos, ImVec2(pos.x + size.x, pos.y + size.y));
ItemSize(bb, style.FramePadding.y);
if (!ItemAdd(bb, id))
return false;

// Render
const float circleStart = size.x * 0.7f;
const float circleEnd = size.x;
const float circleWidth = circleEnd - circleStart;

window->DrawList->AddRectFilled(bb.Min, ImVec2(pos.x + circleStart, bb.Max.y), bg_col);
window->DrawList->AddRectFilled(bb.Min, ImVec2(pos.x + circleStart*value, bb.Max.y), fg_col);

const float t = g.Time;
const float r = size.y / 2;
const float speed = 1.5f;

const float a = speed*0;
const float b = speed*0.333f;
const float c = speed*0.666f;

const float o1 = (circleWidth+r) * (t+a - speed * (int)((t+a) / speed)) / speed;
const float o2 = (circleWidth+r) * (t+b - speed * (int)((t+b) / speed)) / speed;
const float o3 = (circleWidth+r) * (t+c - speed * (int)((t+c) / speed)) / speed;

window->DrawList->AddCircleFilled(ImVec2(pos.x + circleEnd - o1, bb.Min.y + r), r, bg_col);
window->DrawList->AddCircleFilled(ImVec2(pos.x + circleEnd - o2, bb.Min.y + r), r, bg_col);
window->DrawList->AddCircleFilled(ImVec2(pos.x + circleEnd - o3, bb.Min.y + r), r, bg_col);
}

bool Spinner(const char* label, float radius, int thickness, const ImU32& color) {
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
return false;

ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label);

ImVec2 pos = window->DC.CursorPos;
ImVec2 size((radius )*2, (radius + style.FramePadding.y)*2);

const ImRect bb(pos, ImVec2(pos.x + size.x, pos.y + size.y));
ItemSize(bb, style.FramePadding.y);
if (!ItemAdd(bb, id))
return false;

// Render
window->DrawList->PathClear();

int num_segments = 30;
int start = abs(ImSin(g.Time*1.8f)*(num_segments-5));

const float a_min = IM_PI*2.0f * ((float)start) / (float)num_segments;
const float a_max = IM_PI*2.0f * ((float)num_segments-3) / (float)num_segments;

const ImVec2 centre = ImVec2(pos.x+radius, pos.y+radius+style.FramePadding.y);

for (int i = 0; i < num_segments; i++) {
const float a = a_min + ((float)i / (float)num_segments) * (a_max - a_min);
window->DrawList->PathLineTo(ImVec2(centre.x + ImCos(a+g.Time*8) * radius,
centre.y + ImSin(a+g.Time*8) * radius));
}

window->DrawList->PathStroke(color, false, thickness);
}

}

2号

#include "cubic_bezier.h"
#include "imgui.h"
#include "imgui_internal.h"
#include <functional>

static gfx::CubicBezier fast_out_slow_in(0.4, 0.0, 0.2, 1.0);

static float bezier(float t) {
return fast_out_slow_in.Solve(t);
}

namespace ImGui {
constexpr
static auto lerp(float x0, float x1) {
return [=](float t){
return (1-t) * x0 + t * x1;
};
}

constexpr
static float lerp(float x0, float x1, float t) {
return lerp(x0, x1)(t);
}

static auto interval(float T0, float T1, std::function<float(float)> tween = lerp(0.0, 1.0)) {
return [=](float t){
return t < T0 ? 0.0f : t > T1 ? 1.0f : tween((t-T0) / (T1-T0));
};
}

template <int T>
float sawtooth(float t) {
return ImFmod(((float)T)*t, 1.0f);
}

bool Spinner(const char* label, float radius, int thickness, const ImU32& color) {
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
return false;

ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label);

ImVec2 pos = window->DC.CursorPos;
ImVec2 size((radius )*2, (radius + style.FramePadding.y)*2);

const ImRect bb(pos, ImVec2(pos.x + size.x, pos.y + size.y));
ItemSize(bb, style.FramePadding.y);
if (!ItemAdd(bb, id))
return false;

// Render
const ImVec2 center = ImVec2(pos.x+radius, pos.y+radius+thickness+style.FramePadding.y);

const float start_angle = -IM_PI / 2.0f; // Start at the top
const int num_detents = 5; // how many rotations we want before a repeat
const int skip_detents = 3; // how many steps we skip each rotation
const float period = 5.0f; // in seconds
const float t = ImFmod(g.Time, period) / period; // map period into [0, 1]

// Tweening functions for each part of the spinner
auto stroke_head_tween = [](float t){
t = sawtooth<num_detents>(t);
return interval(0.0, 0.5, bezier)(t);
};

auto stroke_tail_tween = [](float t){
t = sawtooth<num_detents>(t);
return interval(0.5, 1.0, bezier)(t);
};

auto step_tween = [=](float t){
return floor(lerp(0.0, (float)num_detents, t));
};

auto rotation_tween = sawtooth<num_detents>;

const float head_value = stroke_head_tween(t);
const float tail_value = stroke_tail_tween(t);
const float step_value = step_tween(t);
const float rotation_value = rotation_tween(t);

const float min_arc = 30.0f / 360.0f * 2.0f * IM_PI;
const float max_arc = 270.0f / 360.0f * 2.0f * IM_PI;
const float step_offset = skip_detents * 2.0f * IM_PI / num_detents;
const float rotation_compensation = ImFmod(4.0*IM_PI - step_offset - max_arc, 2*IM_PI);

const float a_min = start_angle + tail_value * max_arc + rotation_value * rotation_compensation - step_value * step_offset;
const float a_max = a_min + (head_value - tail_value) * max_arc + min_arc;

window->DrawList->PathClear();

int num_segments = 24;
for (int i = 0; i < num_segments; i++) {
const float a = a_min + ((float)i / (float)num_segments) * (a_max - a_min);
window->DrawList->PathLineTo(ImVec2(center.x + ImCos(a) * radius,
center.y + ImSin(a) * radius));
}

window->DrawList->PathStroke(color, false, thickness);

return true;
}

}