1// https://github.com/ocornut/imgui/issues/346#issuecomment-171961296 2// [src] https://github.com/ocornut/imgui/issues/346 3 4namespace ImGui 5{ 6 bool ColorPicker4(float* col, bool show_alpha) 7 { 8 ImGuiIO& io = ImGui::GetIO(); 9 ImGuiStyle& style = ImGui::GetStyle(); 10 ImDrawList* draw_list = ImGui::GetWindowDrawList(); 11 12 // Setup 13 ImVec2 picker_pos = ImGui::GetCursorScreenPos(); 14 ImVec2 sv_picker_size = ImVec2(256.0f, 256.0f); // Saturation/Value picking box 15 float bars_width = ImGui::GetFontSize() + style.FramePadding.y*2.0f; // Width of Hue/Alpha picking bars (using Framepadding.y to match the ColorButton sides) 16 float bar0_pos_x = picker_pos.x + sv_picker_size.x + style.ItemInnerSpacing.x; 17 float bar1_pos_x = bar0_pos_x + bars_width + style.ItemInnerSpacing.x; 18 19 float H,S,V; 20 ImGui::ColorConvertRGBtoHSV(col[0], col[1], col[2], H, S, V); 21 22 // Color matrix logic 23 bool value_changed = false, hsv_changed = false; 24 ImGui::BeginGroup(); 25 ImGui::InvisibleButton("sv", sv_picker_size); 26 if (ImGui::IsItemActive()) 27 { 28 S = ImSaturate((io.MousePos.x - picker_pos.x) / (sv_picker_size.x-1)); 29 V = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size.y-1)); 30 value_changed = hsv_changed = true; 31 } 32 33 // Hue bar logic 34 ImGui::SetCursorScreenPos(ImVec2(bar0_pos_x, picker_pos.y)); 35 ImGui::InvisibleButton("hue", ImVec2(bars_width, sv_picker_size.y)); 36 if (ImGui::IsItemActive()) 37 { 38 H = ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size.y-1)); 39 value_changed = hsv_changed = true; 40 } 41 42 // Alpha bar logic 43 if (show_alpha) 44 { 45 ImGui::SetCursorScreenPos(ImVec2(bar1_pos_x, picker_pos.y)); 46 ImGui::InvisibleButton("alpha", ImVec2(bars_width, sv_picker_size.y)); 47 if (ImGui::IsItemActive()) 48 { 49 col[3] = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size.y-1)); 50 value_changed = true; 51 } 52 } 53 54 // Convert back to RGB 55 if (hsv_changed) 56 ImGui::ColorConvertHSVtoRGB(H >= 1.0f ? H - 10 * 1e-6f : H, S > 0.0f ? S : 10*1e-6f, V > 0.0f ? V : 1e-6f, col[0], col[1], col[2]); 57 58 // R,G,B or H,S,V color editor 59 ImGui::PushItemWidth((show_alpha ? bar1_pos_x : bar0_pos_x) + bars_width - picker_pos.x); 60 value_changed |= show_alpha ? ImGui::ColorEdit4("##edit", col) : ImGui::ColorEdit3("##edit", col); 61 ImGui::PopItemWidth(); 62 63 // Try to cancel hue wrap (after ColorEdit), if any 64 if (value_changed) 65 { 66 float new_H, new_S, new_V; 67 ImGui::ColorConvertRGBtoHSV(col[0], col[1], col[2], new_H, new_S, new_V); 68 if (new_H <= 0 && H > 0) 69 { 70 if (new_V <= 0 && V != new_V) 71 ImGui::ColorConvertHSVtoRGB(H, S, new_V <= 0 ? V * 0.5f : new_V, col[0], col[1], col[2]); 72 else if (new_S <= 0) 73 ImGui::ColorConvertHSVtoRGB(H, new_S <= 0 ? S * 0.5f : new_S, new_V, col[0], col[1], col[2]); 74 } 75 } 76 77 // Render hue bar 78 ImU32 hue_colors[] = { IM_COL32(255,0,0,255), IM_COL32(255,255,0,255), IM_COL32(0,255,0,255), IM_COL32(0,255,255,255), IM_COL32(0,0,255,255), IM_COL32(255,0,255,255), IM_COL32(255,0,0,255) }; 79 for (int i = 0; i < 6; ++i) 80 { 81 draw_list->AddRectFilledMultiColor( 82 ImVec2(bar0_pos_x, picker_pos.y + i * (sv_picker_size.y / 6)), 83 ImVec2(bar0_pos_x + bars_width, picker_pos.y + (i + 1) * (sv_picker_size.y / 6)), 84 hue_colors[i], hue_colors[i], hue_colors[i + 1], hue_colors[i + 1]); 85 } 86 float bar0_line_y = (float)(int)(picker_pos.y + H * sv_picker_size.y + 0.5f); 87 draw_list->AddLine(ImVec2(bar0_pos_x - 1, bar0_line_y), ImVec2(bar0_pos_x + bars_width + 1, bar0_line_y), IM_COL32_WHITE); 88 89 // Render alpha bar 90 if (show_alpha) 91 { 92 float alpha = ImSaturate(col[3]); 93 float bar1_line_y = (float)(int)(picker_pos.y + (1.0f-alpha) * sv_picker_size.y + 0.5f); 94 draw_list->AddRectFilledMultiColor(ImVec2(bar1_pos_x, picker_pos.y), ImVec2(bar1_pos_x + bars_width, picker_pos.y + sv_picker_size.y), IM_COL32_WHITE, IM_COL32_WHITE, IM_COL32_BLACK, IM_COL32_BLACK); 95 draw_list->AddLine(ImVec2(bar1_pos_x - 1, bar1_line_y), ImVec2(bar1_pos_x + bars_width + 1, bar1_line_y), IM_COL32_WHITE); 96 } 97 98 // Render color matrix 99 ImVec4 hue_color_f(1, 1, 1, 1); 100 ImGui::ColorConvertHSVtoRGB(H, 1, 1, hue_color_f.x, hue_color_f.y, hue_color_f.z); 101 ImU32 hue_color32 = ImGui::ColorConvertFloat4ToU32(hue_color_f); 102 draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + sv_picker_size, IM_COL32_WHITE, hue_color32, hue_color32, IM_COL32_WHITE); 103 draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + sv_picker_size, IM_COL32_BLACK_TRANS, IM_COL32_BLACK_TRANS, IM_COL32_BLACK, IM_COL32_BLACK); 104 105 // Render cross-hair 106 const float CROSSHAIR_SIZE = 7.0f; 107 ImVec2 p((float)(int)(picker_pos.x + S * sv_picker_size.x + 0.5f), (float)(int)(picker_pos.y + (1 - V) * sv_picker_size.y + 0.5f)); 108 draw_list->AddLine(ImVec2(p.x - CROSSHAIR_SIZE, p.y), ImVec2(p.x - 2, p.y), IM_COL32_WHITE); 109 draw_list->AddLine(ImVec2(p.x + CROSSHAIR_SIZE, p.y), ImVec2(p.x + 2, p.y), IM_COL32_WHITE); 110 draw_list->AddLine(ImVec2(p.x, p.y + CROSSHAIR_SIZE), ImVec2(p.x, p.y + 2), IM_COL32_WHITE); 111 draw_list->AddLine(ImVec2(p.x, p.y - CROSSHAIR_SIZE), ImVec2(p.x, p.y - 2), IM_COL32_WHITE); 112 ImGui::EndGroup(); 113 114 return value_changed; 115 } 116 117 bool ColorPicker3(float col[3]) 118 { 119 return ColorPicker4(col, false); 120 } 121 122} // namespace ImGui 123