mirror of
				https://github.com/Drezil/imgui.git
				synced 2025-10-31 21:21:06 +01:00 
			
		
		
		
	ColorPicker: Hue wheel + SV triangle picker mode (mode selection flags still wip, missing context menu and persistent options). (#346)
This commit is contained in:
		
							
								
								
									
										113
									
								
								imgui.cpp
									
									
									
									
									
								
							
							
						
						
									
										113
									
								
								imgui.cpp
									
									
									
									
									
								
							| @@ -1013,7 +1013,6 @@ const char* ImStristr(const char* haystack, const char* haystack_end, const char | ||||
|     return NULL; | ||||
| } | ||||
|  | ||||
|  | ||||
| // MSVC version appears to return -1 on overflow, whereas glibc appears to return total count (which may be >= buf_size).  | ||||
| // Ideally we would test for only one of those limits at runtime depending on the behavior the vsnprintf(), but trying to deduct it at compile time sounds like a pandora can of worm. | ||||
| int ImFormatString(char* buf, int buf_size, const char* fmt, ...) | ||||
| @@ -9401,6 +9400,21 @@ static void RenderArrowsForVerticalBar(ImDrawList* draw_list, ImVec2 pos, ImVec2 | ||||
|     RenderArrow(draw_list, ImVec2(pos.x + bar_w - half_sz.x,     pos.y), half_sz,                              ImGuiDir_Left,  IM_COL32_WHITE); | ||||
| } | ||||
|  | ||||
| static void PaintVertsLinearGradientKeepAlpha(ImDrawVert* vert_start, ImDrawVert* vert_end, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1) | ||||
| { | ||||
|     ImVec2 gradient_extent = gradient_p1 - gradient_p0; | ||||
|     float gradient_inv_length = ImInvLength(gradient_extent, 0.0f); | ||||
|     for (ImDrawVert* vert = vert_start; vert < vert_end; vert++) | ||||
|     { | ||||
|         float d = ImDot(vert->pos - gradient_p0, gradient_extent); | ||||
|         float t = ImMin(sqrtf(ImMax(d, 0.0f)) * gradient_inv_length, 1.0f); | ||||
|         int r = ImLerp((int)(col0 >> IM_COL32_R_SHIFT) & 0xFF, (int)(col1 >> IM_COL32_R_SHIFT) & 0xFF, t); | ||||
|         int g = ImLerp((int)(col0 >> IM_COL32_G_SHIFT) & 0xFF, (int)(col1 >> IM_COL32_G_SHIFT) & 0xFF, t); | ||||
|         int b = ImLerp((int)(col0 >> IM_COL32_B_SHIFT) & 0xFF, (int)(col1 >> IM_COL32_B_SHIFT) & 0xFF, t); | ||||
|         vert->col = (r << IM_COL32_R_SHIFT) | (g << IM_COL32_G_SHIFT) | (b << IM_COL32_B_SHIFT) | (vert->col & IM_COL32_A_MASK); | ||||
|     } | ||||
| } | ||||
|  | ||||
| // ColorPicker | ||||
| // Note: only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set. | ||||
| // FIXME: we adjust the big color square height based on item width, which may cause a flickering feedback loop (if automatic height makes a vertical scrollbar appears, affecting automatic width..)  | ||||
| @@ -9428,13 +9442,63 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl | ||||
|     float bar1_pos_x = bar0_pos_x + bars_width + style.ItemInnerSpacing.x; | ||||
|     float bars_triangles_half_sz = (float)(int)(bars_width * 0.20f); | ||||
|  | ||||
|     float wheel_thickness = sv_picker_size * 0.08f; | ||||
|     float wheel_r_outer = sv_picker_size * 0.50f; | ||||
|     float wheel_r_inner = wheel_r_outer - wheel_thickness; | ||||
|     ImVec2 wheel_center(picker_pos.x + (sv_picker_size + bars_width)*0.5f, picker_pos.y + sv_picker_size*0.5f); | ||||
|      | ||||
|     // Note: the triangle is displayed rotated with triangle_pa pointing to Hue, but most coordinates stays unrotated for logic. | ||||
|     float triangle_r = wheel_r_inner - (int)(sv_picker_size * 0.027f); | ||||
|     ImVec2 triangle_pa = ImVec2(triangle_r, 0.0f); // Hue point. | ||||
|     ImVec2 triangle_pb = ImVec2(triangle_r * -0.5f, triangle_r * -0.866025f); // Black point. | ||||
|     ImVec2 triangle_pc = ImVec2(triangle_r * -0.5f, triangle_r * +0.866025f); // White point. | ||||
|  | ||||
|     float H,S,V; | ||||
|     ColorConvertRGBtoHSV(col[0], col[1], col[2], H, S, V); | ||||
|  | ||||
|     // Color matrix logic | ||||
|     // Defaults to Hue bar + SV rectangle // FIXME-WIP | ||||
|     if ((flags & ImGuiColorEditFlags_PickerModeMask_) == 0) | ||||
|         flags |= ImGuiColorEditFlags_PickerHueBar; | ||||
|     IM_ASSERT(ImIsPowerOfTwo((int)(flags & ImGuiColorEditFlags_PickerModeMask_))); // Check that only 1 is selected | ||||
|  | ||||
|     bool value_changed = false, value_changed_h = false, value_changed_sv = false; | ||||
|  | ||||
|     if (flags & ImGuiColorEditFlags_PickerHueWheel) | ||||
|     { | ||||
|         // Hue wheel + SV triangle logic | ||||
|         InvisibleButton("hsv", ImVec2(sv_picker_size + style.ItemInnerSpacing.x + bars_width, sv_picker_size)); | ||||
|         if (IsItemActive()) | ||||
|         { | ||||
|             ImVec2 initial_off = g.IO.MouseClickedPos[0] - wheel_center; | ||||
|             ImVec2 current_off = g.IO.MousePos - wheel_center; | ||||
|             float initial_dist2 = ImLengthSqr(initial_off); | ||||
|             if (initial_dist2 >= (wheel_r_inner-1)*(wheel_r_inner-1) && initial_dist2 <= (wheel_r_outer+1)*(wheel_r_outer+1)) | ||||
|             { | ||||
|                 // Interactive with Hue wheel | ||||
|                 H = atan2f(current_off.y, current_off.x) / IM_PI*0.5f; | ||||
|                 if (H < 0.0f) | ||||
|                     H += 1.0f; | ||||
|                 value_changed = value_changed_h = true; | ||||
|             } | ||||
|             float cos_hue_angle = cosf(-H * 2.0f * IM_PI); | ||||
|             float sin_hue_angle = sinf(-H * 2.0f * IM_PI); | ||||
|             if (ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_pc, ImRotate(initial_off, cos_hue_angle, sin_hue_angle))) | ||||
|             { | ||||
|                 // Interacting with SV triangle | ||||
|                 ImVec2 current_off_unrotated = ImRotate(current_off, cos_hue_angle, sin_hue_angle); | ||||
|                 if (!ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated)) | ||||
|                     current_off_unrotated = ImTriangleClosestPoint(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated); | ||||
|                 float uu, vv, ww; | ||||
|                 ImTriangleBarycentricCoords(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated, uu, vv, ww); | ||||
|                 V = ImClamp(1.0f - vv, 0.0001f, 1.0f); | ||||
|                 S = ImClamp(uu / V, 0.0001f, 1.0f); | ||||
|                 value_changed = value_changed_sv = true; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     else if (flags & ImGuiColorEditFlags_PickerHueBar) | ||||
|     { | ||||
|         // SV rectangle logic | ||||
|         InvisibleButton("sv", ImVec2(sv_picker_size, sv_picker_size)); | ||||
|         if (IsItemActive()) | ||||
|         { | ||||
| @@ -9546,6 +9610,51 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl | ||||
|     const ImU32 hue_colors[6+1] = { 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) }; | ||||
|     ImVec2 sv_cursor_pos; | ||||
|      | ||||
|     if (flags & ImGuiColorEditFlags_PickerHueWheel) | ||||
|     { | ||||
|         // Render Hue Wheel | ||||
|         const float aeps = 1.5f / wheel_r_outer; // Half a pixel arc length in radians (2pi cancels out). | ||||
|         const int segment_per_arc = ImMax(4, (int)wheel_r_outer / 12); | ||||
|         for (int n = 0; n < 6; n++) | ||||
|         { | ||||
|             const float a0 = (n)     /6.0f * 2.0f * IM_PI - aeps; | ||||
|             const float a1 = (n+1.0f)/6.0f * 2.0f * IM_PI + aeps; | ||||
|             int vert_start_idx = draw_list->_VtxCurrentIdx; | ||||
|             draw_list->PathArcTo(wheel_center, (wheel_r_inner + wheel_r_outer)*0.5f, a0, a1, segment_per_arc); | ||||
|             draw_list->PathStroke(IM_COL32_WHITE, false, wheel_thickness); | ||||
|  | ||||
|             // Paint colors over existing vertices | ||||
|             ImVec2 gradient_p0(wheel_center.x + cosf(a0) * wheel_r_inner, wheel_center.y + sinf(a0) * wheel_r_inner); | ||||
|             ImVec2 gradient_p1(wheel_center.x + cosf(a1) * wheel_r_inner, wheel_center.y + sinf(a1) * wheel_r_inner); | ||||
|             PaintVertsLinearGradientKeepAlpha(draw_list->_VtxWritePtr - (draw_list->_VtxCurrentIdx - vert_start_idx), draw_list->_VtxWritePtr, gradient_p0, gradient_p1, hue_colors[n], hue_colors[n+1]); | ||||
|         } | ||||
|  | ||||
|         // Render Cursor + preview on Hue Wheel | ||||
|         float cos_hue_angle = cosf(H * 2.0f * IM_PI); | ||||
|         float sin_hue_angle = sinf(H * 2.0f * IM_PI); | ||||
|         ImVec2 hue_cursor_pos(wheel_center.x + cos_hue_angle * (wheel_r_inner+wheel_r_outer)*0.5f, wheel_center.y + sin_hue_angle * (wheel_r_inner+wheel_r_outer)*0.5f); | ||||
|         float hue_cursor_rad = value_changed_h ? wheel_thickness * 0.65f : wheel_thickness * 0.55f; | ||||
|         int hue_cursor_segments = ImClamp((int)(hue_cursor_rad / 1.4f), 9, 32); | ||||
|         draw_list->AddCircleFilled(hue_cursor_pos, hue_cursor_rad, hue_color32, hue_cursor_segments); | ||||
|         draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad+1, IM_COL32(128,128,128,255), hue_cursor_segments); | ||||
|         draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad, IM_COL32_WHITE, hue_cursor_segments); | ||||
|  | ||||
|         // Render SV triangle (rotated according to hue) | ||||
|         ImVec2 tra = wheel_center + ImRotate(triangle_pa, cos_hue_angle, sin_hue_angle); | ||||
|         ImVec2 trb = wheel_center + ImRotate(triangle_pb, cos_hue_angle, sin_hue_angle); | ||||
|         ImVec2 trc = wheel_center + ImRotate(triangle_pc, cos_hue_angle, sin_hue_angle); | ||||
|         ImVec2 uv_white = g.FontTexUvWhitePixel; | ||||
|         draw_list->PrimReserve(6, 6); | ||||
|         draw_list->PrimVtx(tra, uv_white, hue_color32); | ||||
|         draw_list->PrimVtx(trb, uv_white, hue_color32); | ||||
|         draw_list->PrimVtx(trc, uv_white, IM_COL32_WHITE); | ||||
|         draw_list->PrimVtx(tra, uv_white, IM_COL32_BLACK_TRANS); | ||||
|         draw_list->PrimVtx(trb, uv_white, IM_COL32_BLACK); | ||||
|         draw_list->PrimVtx(trc, uv_white, IM_COL32_BLACK_TRANS); | ||||
|         draw_list->AddTriangle(tra, trb, trc, IM_COL32(128,128,128,255), 1.5f); | ||||
|         sv_cursor_pos = ImLerp(ImLerp(trc, tra, ImSaturate(S)), trb, ImSaturate(1 - V)); | ||||
|     } | ||||
|     else if (flags & ImGuiColorEditFlags_PickerHueBar) | ||||
|     { | ||||
|         // Render SV Square | ||||
|         draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size,sv_picker_size), IM_COL32_WHITE, hue_color32, hue_color32, IM_COL32_WHITE); | ||||
|   | ||||
							
								
								
									
										5
									
								
								imgui.h
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								imgui.h
									
									
									
									
									
								
							| @@ -673,14 +673,17 @@ enum ImGuiColorEditFlags_ | ||||
|     ImGuiColorEditFlags_AlphaPreview    = 1 << 7,   // ColorEdit, ColorPicker, ColorButton: display preview as a transparent color over a checkerboard, instead of opaque. | ||||
|     ImGuiColorEditFlags_AlphaPreviewHalf= 1 << 8,   // ColorEdit, ColorPicker, ColorButton: display half opaque / half checkerboard, instead of opaque. | ||||
|     ImGuiColorEditFlags_NoAlpha         = 1 << 9,   // ColorEdit, ColorPicker, ColorButton: completely ignore Alpha component (read 3 components from the input pointer). | ||||
|     ImGuiColorEditFlags_NoPicker        = 1 << 10,   // ColorEdit: disable picker when clicking on colored square. | ||||
|     ImGuiColorEditFlags_NoPicker        = 1 << 10,  // ColorEdit: disable picker when clicking on colored square. | ||||
|     ImGuiColorEditFlags_NoOptions       = 1 << 11,  // ColorEdit: disable toggling options menu when right-clicking on inputs/small preview. | ||||
|     ImGuiColorEditFlags_NoSmallPreview  = 1 << 12,  // ColorEdit, ColorPicker: disable colored square preview next to the inputs. (e.g. to show only the inputs) | ||||
|     ImGuiColorEditFlags_NoInputs        = 1 << 13,  // ColorEdit, ColorPicker: disable inputs sliders/text widgets (e.g. to show only the small preview colored square). | ||||
|     ImGuiColorEditFlags_NoTooltip       = 1 << 14,  // ColorEdit, ColorPicker, ColorButton: disable tooltip when hovering the preview. | ||||
|     ImGuiColorEditFlags_NoLabel         = 1 << 15,  // ColorEdit, ColorPicker: disable display of inline text label (the label is still forwarded to the tooltip and picker). | ||||
|     ImGuiColorEditFlags_NoSidePreview   = 1 << 16,  // ColorPicker: disable bigger color preview on right side of the picker, use small colored square preview instead. | ||||
|     ImGuiColorEditFlags_PickerHueWheel  = 1 << 17,  // [WIP] ColorPicker: wheel for Hue, triangle for SV | ||||
|     ImGuiColorEditFlags_PickerHueBar    = 1 << 18,  // [WIP] ColorPicker: bar for Hue, rectangle for SV | ||||
|     ImGuiColorEditFlags_InputsModeMask_ = ImGuiColorEditFlags_RGB|ImGuiColorEditFlags_HSV|ImGuiColorEditFlags_HEX, | ||||
|     ImGuiColorEditFlags_PickerModeMask_ = ImGuiColorEditFlags_PickerHueWheel|ImGuiColorEditFlags_PickerHueBar, | ||||
|     ImGuiColorEditFlags_StoredMask_     = ImGuiColorEditFlags_RGB|ImGuiColorEditFlags_HSV|ImGuiColorEditFlags_HEX|ImGuiColorEditFlags_Float | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -737,7 +737,7 @@ void ImGui::ShowTestWindow(bool* p_open) | ||||
|             static bool ref_color = false; | ||||
|             static ImVec4 ref_color_v(1.0f,0.0f,1.0f,0.5f); | ||||
|             static int inputs_mode = 2; | ||||
|             static float width = 200.0f; | ||||
|             static int picker_mode = 0; | ||||
|             ImGui::Checkbox("With Alpha", &alpha); | ||||
|             ImGui::Checkbox("With Alpha Bar", &alpha_bar); | ||||
|             ImGui::Checkbox("With Side Preview", &side_preview); | ||||
| @@ -750,20 +750,20 @@ void ImGui::ShowTestWindow(bool* p_open) | ||||
|                     ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | misc_flags); | ||||
|                 } | ||||
|             } | ||||
|             ImGui::Combo("Mode", &inputs_mode, "All Inputs\0No Inputs\0RGB Input\0HSV Input\0HEX Input\0"); | ||||
|             ImGui::Combo("Inputs Mode", &inputs_mode, "All Inputs\0No Inputs\0RGB Input\0HSV Input\0HEX Input\0"); | ||||
|             ImGui::Combo("Picker Mode", &picker_mode, "Hue bar + SV rect\0Hue wheel + SV triangle\0"); | ||||
|             ImGui::SameLine(); ShowHelpMarker("User can right-click the inputs and override edit mode."); | ||||
|             //ImGui::DragFloat("Width", &width, 1.0f, 1.0f, 999.0f); | ||||
|             //ImGui::PushItemWidth(width); | ||||
|             ImGuiColorEditFlags flags = misc_flags; | ||||
|             if (!alpha) flags |= ImGuiColorEditFlags_NoAlpha; // This is by default if you call ColorPicker3() instead of ColorPicker4() | ||||
|             if (alpha_bar) flags |= ImGuiColorEditFlags_AlphaBar; | ||||
|             if (!side_preview) flags |= ImGuiColorEditFlags_NoSidePreview; | ||||
|             if (picker_mode == 0) flags |= ImGuiColorEditFlags_PickerHueBar; | ||||
|             if (picker_mode == 1) flags |= ImGuiColorEditFlags_PickerHueWheel; | ||||
|             if (inputs_mode == 1) flags |= ImGuiColorEditFlags_NoInputs; | ||||
|             if (inputs_mode == 2) flags |= ImGuiColorEditFlags_RGB; | ||||
|             if (inputs_mode == 3) flags |= ImGuiColorEditFlags_HSV; | ||||
|             if (inputs_mode == 4) flags |= ImGuiColorEditFlags_HEX; | ||||
|             ImGui::ColorPicker4("MyColor##4", (float*)&color, flags, ref_color ? &ref_color_v.x : NULL); | ||||
|             //ImGui::PopItemWidth(); | ||||
|  | ||||
|             ImGui::TreePop(); | ||||
|         } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user