Open mrduda opened 4 years ago
Hello @mrduda,
Thanks for submitting this. You should be able to achieve a similar look by altering border color, frame color, checkmark colors:
(the checkmark shape is a little different, and sorry for blurry upscaled capture)
The aim of styling v2 will be to provide finer control per-widget style so this would be easier to alter the look of this while keeping a different look for other widgets.
Suggestions of things in your code in your widgets can could improved:
#
is incorrect and unnecessary. You can call ImGui::RenderText() which will call FindRenderedTextEnd()
to do the same in a more correct way.IsItemXXX()
function won't be honored on your custom Checkbox.Modelling your code after Checkbox()
would be preferable and will fix all those issues.
Thank you for feedback!
The main reason behind this custom checkbox implementation was the size of original checkbox, which can't be decreased in any known way. The rest (color and border) is just a minor issue.
You can modify checkbox size by adjusting style (ItemInnerSpacing
, FramePadding
) and font size. See https://github.com/ocornut/imgui/blob/ab4ef822f0e85a6dd65723db9e0e632a1e1a45d8/imgui_widgets.cpp#L1044
Here's another approach, this time I took existing Checkbox() code and modified it only in size, style/color and checkmark parts:
bool CheckboxEx(const char* label, bool* v)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
return false;
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const float square_sz = GetFrameHeight();
const ImVec2 pos = window->DC.CursorPos;
const ImRect total_bb(pos, pos + ImVec2(square_sz + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), label_size.y + style.FramePadding.y * 1.5f));
ItemSize(total_bb, style.FramePadding.y);
if (!ItemAdd(total_bb, id))
return false;
bool hovered, held;
bool pressed = ButtonBehavior(total_bb, id, &hovered, &held);
if (pressed)
{
*v = !(*v);
MarkItemEdited(id);
}
const float boxSize = IM_FLOOR(square_sz * 0.65f);
const float boxOffsetHorz = IM_FLOOR(style.ItemSpacing.x * 1.2f);
const float boxOffsetVert = IM_FLOOR(std::floor(0.5f * (square_sz - boxSize)));
ImRect check_bb(pos + ImVec2(boxOffsetHorz, boxOffsetVert), pos + ImVec2(boxOffsetHorz + boxSize, boxOffsetVert + boxSize));
ImU32 check_col = GetColorU32((window->DC.ItemFlags & ImGuiItemFlags_Disabled) ? ImGuiCol_FrameBg : ImGuiCol_Text);
RenderNavHighlight(total_bb, id);
ImVec4 border_col = style.Colors[hovered ? ImGuiCol_Text : ImGuiCol_CheckMark];
border_col.w *= 0.5f;
ImGui::PushStyleColor(ImGuiCol_Border, border_col);
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
RenderFrame(check_bb.Min, check_bb.Max, ImColor(0, 0, 0, 0), true, 0.0f);
ImGui::PopStyleVar();
ImGui::PopStyleColor();
if (window->DC.ItemFlags & ImGuiItemFlags_MixedValue)
{
// Undocumented tristate/mixed/indeterminate checkbox (#2644)
ImVec2 pad(ImMax(1.0f, IM_FLOOR(square_sz / 7.0f)), ImMax(1.0f, IM_FLOOR(square_sz / 7.0f)));
window->DrawList->AddRectFilled(check_bb.Min + pad, check_bb.Max - pad, check_col, 0.0f);
}
else if (*v)
{
const float pad = ImMax(1.0f, IM_FLOOR(square_sz / 6.0f));
ImVec2 checkMarkPts[3] = {
check_bb.Min + ImVec2(pad, pad + boxSize * 0.3f),
check_bb.Min + ImVec2(boxSize * 0.45f, boxSize - pad),
check_bb.Min + ImVec2(boxSize - pad, pad),
};
window->DrawList->AddPolyline(checkMarkPts, 3, ImColor(check_col), false, 2.5f);
}
check_bb = ImRect(pos, pos + ImVec2(square_sz, square_sz));
if (g.LogEnabled)
LogRenderedText(&total_bb.Min, *v ? "[x]" : "[ ]");
if (label_size.x > 0.0f)
RenderText(ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y), label);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0));
return pressed;
}
As for ItemInnerSpacing, FramePadding and font size suggestion: have you tried this and it worked, or is it only a guess? I'm not sure it will work as expected because changing font size may result in the incorrect text size calculation for checkbox label.
You should be using PushStyleVar()
/PopStyleVar()
or PushStyleColor()
/PopStyleColor()
instead of copying entire widget code and modifying those values.
You should be using
PushStyleVar()
/PopStyleVar()
orPushStyleColor()
/PopStyleColor()
instead of copying entire widget code and modifying those values.
As I said before, wrapping ImGui::Checkbox() into Push/PopStyleVar/Color doesn't help to achieve desired checkbox size. The method you have shown (by changing font size and other) does not work. Also, checkmark is custom and the color for checkbox border when mouse is over cannot be changed by Push/Pop calls. Anyway, thanks for attention.
Version/Branch of Dear ImGui:
Version: 1.78 WIP Branch: master
Back-end/Renderer/Compiler/OS
Back-ends: imgui_impl_dx11.cpp Compiler: MSVC 2019 Operating System: Win10
My Issue/Question: This is my replacement for built-in checkbox widget. Tri-state is supported. Color is taken from ImGuiCol_Text, with border alpha dimmed down when not hovered.
Screenshots/Video
Standalone, minimal, complete and verifiable example: