imgui_widgets.cpp (imgui-1.86) | : | imgui_widgets.cpp (imgui-1.87) | ||
---|---|---|---|---|
// dear imgui, v1.86 | // dear imgui, v1.87 | |||
// (widgets code) | // (widgets code) | |||
/* | /* | |||
Index of this file: | Index of this file: | |||
// [SECTION] Forward Declarations | // [SECTION] Forward Declarations | |||
// [SECTION] Widgets: Text, etc. | // [SECTION] Widgets: Text, etc. | |||
// [SECTION] Widgets: Main (Button, Image, Checkbox, RadioButton, ProgressBar, B ullet, etc.) | // [SECTION] Widgets: Main (Button, Image, Checkbox, RadioButton, ProgressBar, B ullet, etc.) | |||
// [SECTION] Widgets: Low-level Layout helpers (Spacing, Dummy, NewLine, Separat or, etc.) | // [SECTION] Widgets: Low-level Layout helpers (Spacing, Dummy, NewLine, Separat or, etc.) | |||
skipping to change at line 734 | skipping to change at line 734 | |||
g.Style.FramePadding.y = 0.0f; | g.Style.FramePadding.y = 0.0f; | |||
bool pressed = ButtonEx(label, ImVec2(0, 0), ImGuiButtonFlags_AlignTextBaseL ine); | bool pressed = ButtonEx(label, ImVec2(0, 0), ImGuiButtonFlags_AlignTextBaseL ine); | |||
g.Style.FramePadding.y = backup_padding_y; | g.Style.FramePadding.y = backup_padding_y; | |||
return pressed; | return pressed; | |||
} | } | |||
// Tip: use ImGui::PushID()/PopID() to push indices or pointers in the ID stack. | // Tip: use ImGui::PushID()/PopID() to push indices or pointers in the ID stack. | |||
// Then you can keep 'str_id' empty or the same for all your buttons (instead of creating a string based on a non-string id) | // Then you can keep 'str_id' empty or the same for all your buttons (instead of creating a string based on a non-string id) | |||
bool ImGui::InvisibleButton(const char* str_id, const ImVec2& size_arg, ImGuiBut tonFlags flags) | bool ImGui::InvisibleButton(const char* str_id, const ImVec2& size_arg, ImGuiBut tonFlags flags) | |||
{ | { | |||
ImGuiContext& g = *GImGui; | ||||
ImGuiWindow* window = GetCurrentWindow(); | ImGuiWindow* window = GetCurrentWindow(); | |||
if (window->SkipItems) | if (window->SkipItems) | |||
return false; | return false; | |||
// Cannot use zero-size for InvisibleButton(). Unlike Button() there is not way to fallback using the label size. | // Cannot use zero-size for InvisibleButton(). Unlike Button() there is not way to fallback using the label size. | |||
IM_ASSERT(size_arg.x != 0.0f && size_arg.y != 0.0f); | IM_ASSERT(size_arg.x != 0.0f && size_arg.y != 0.0f); | |||
const ImGuiID id = window->GetID(str_id); | const ImGuiID id = window->GetID(str_id); | |||
ImVec2 size = CalcItemSize(size_arg, 0.0f, 0.0f); | ImVec2 size = CalcItemSize(size_arg, 0.0f, 0.0f); | |||
const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); | const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); | |||
ItemSize(size); | ItemSize(size); | |||
if (!ItemAdd(bb, id)) | if (!ItemAdd(bb, id)) | |||
return false; | return false; | |||
bool hovered, held; | bool hovered, held; | |||
bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); | bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); | |||
IMGUI_TEST_ENGINE_ITEM_INFO(id, str_id, g.LastItemData.StatusFlags); | ||||
return pressed; | return pressed; | |||
} | } | |||
bool ImGui::ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size, ImGuiBu ttonFlags flags) | bool ImGui::ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size, ImGuiBu ttonFlags flags) | |||
{ | { | |||
ImGuiContext& g = *GImGui; | ||||
ImGuiWindow* window = GetCurrentWindow(); | ImGuiWindow* window = GetCurrentWindow(); | |||
if (window->SkipItems) | if (window->SkipItems) | |||
return false; | return false; | |||
ImGuiContext& g = *GImGui; | ||||
const ImGuiID id = window->GetID(str_id); | const ImGuiID id = window->GetID(str_id); | |||
const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); | const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); | |||
const float default_size = GetFrameHeight(); | const float default_size = GetFrameHeight(); | |||
ItemSize(size, (size.y >= default_size) ? g.Style.FramePadding.y : -1.0f); | ItemSize(size, (size.y >= default_size) ? g.Style.FramePadding.y : -1.0f); | |||
if (!ItemAdd(bb, id)) | if (!ItemAdd(bb, id)) | |||
return false; | return false; | |||
if (g.LastItemData.InFlags & ImGuiItemFlags_ButtonRepeat) | if (g.LastItemData.InFlags & ImGuiItemFlags_ButtonRepeat) | |||
flags |= ImGuiButtonFlags_Repeat; | flags |= ImGuiButtonFlags_Repeat; | |||
bool hovered, held; | bool hovered, held; | |||
bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); | bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); | |||
// Render | // Render | |||
const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); | const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); | |||
const ImU32 text_col = GetColorU32(ImGuiCol_Text); | const ImU32 text_col = GetColorU32(ImGuiCol_Text); | |||
RenderNavHighlight(bb, id); | RenderNavHighlight(bb, id); | |||
RenderFrame(bb.Min, bb.Max, bg_col, true, g.Style.FrameRounding); | RenderFrame(bb.Min, bb.Max, bg_col, true, g.Style.FrameRounding); | |||
RenderArrow(window->DrawList, bb.Min + ImVec2(ImMax(0.0f, (size.x - g.FontSi ze) * 0.5f), ImMax(0.0f, (size.y - g.FontSize) * 0.5f)), text_col, dir); | RenderArrow(window->DrawList, bb.Min + ImVec2(ImMax(0.0f, (size.x - g.FontSi ze) * 0.5f), ImMax(0.0f, (size.y - g.FontSize) * 0.5f)), text_col, dir); | |||
IMGUI_TEST_ENGINE_ITEM_INFO(id, str_id, g.LastItemData.StatusFlags); | ||||
return pressed; | return pressed; | |||
} | } | |||
bool ImGui::ArrowButton(const char* str_id, ImGuiDir dir) | bool ImGui::ArrowButton(const char* str_id, ImGuiDir dir) | |||
{ | { | |||
float sz = GetFrameHeight(); | float sz = GetFrameHeight(); | |||
return ArrowButtonEx(str_id, dir, ImVec2(sz, sz), ImGuiButtonFlags_None); | return ArrowButtonEx(str_id, dir, ImVec2(sz, sz), ImGuiButtonFlags_None); | |||
} | } | |||
// Button to close a window | // Button to close a window | |||
skipping to change at line 1995 | skipping to change at line 1998 | |||
if (op == '+') { *(double*)output = *(const double*)arg1 + *(const d ouble*)arg2; } | if (op == '+') { *(double*)output = *(const double*)arg1 + *(const d ouble*)arg2; } | |||
if (op == '-') { *(double*)output = *(const double*)arg1 - *(const d ouble*)arg2; } | if (op == '-') { *(double*)output = *(const double*)arg1 - *(const d ouble*)arg2; } | |||
return; | return; | |||
case ImGuiDataType_COUNT: break; | case ImGuiDataType_COUNT: break; | |||
} | } | |||
IM_ASSERT(0); | IM_ASSERT(0); | |||
} | } | |||
// User can input math operators (e.g. +100) to edit a numerical values. | // User can input math operators (e.g. +100) to edit a numerical values. | |||
// NB: This is _not_ a full expression evaluator. We should probably add one and replace this dumb mess.. | // NB: This is _not_ a full expression evaluator. We should probably add one and replace this dumb mess.. | |||
bool ImGui::DataTypeApplyOpFromText(const char* buf, const char* initial_value_b uf, ImGuiDataType data_type, void* p_data, const char* format) | bool ImGui::DataTypeApplyFromText(const char* buf, ImGuiDataType data_type, void * p_data, const char* format) | |||
{ | { | |||
while (ImCharIsBlankA(*buf)) | while (ImCharIsBlankA(*buf)) | |||
buf++; | buf++; | |||
// We don't support '-' op because it would conflict with inputing negative | ||||
value. | ||||
// Instead you can use +-100 to subtract from an existing value | ||||
char op = buf[0]; | ||||
if (op == '+' || op == '*' || op == '/') | ||||
{ | ||||
buf++; | ||||
while (ImCharIsBlankA(*buf)) | ||||
buf++; | ||||
} | ||||
else | ||||
{ | ||||
op = 0; | ||||
} | ||||
if (!buf[0]) | if (!buf[0]) | |||
return false; | return false; | |||
// Copy the value in an opaque buffer so we can compare at the end of the fu nction if it changed at all. | // Copy the value in an opaque buffer so we can compare at the end of the fu nction if it changed at all. | |||
const ImGuiDataTypeInfo* type_info = DataTypeGetInfo(data_type); | const ImGuiDataTypeInfo* type_info = DataTypeGetInfo(data_type); | |||
ImGuiDataTypeTempStorage data_backup; | ImGuiDataTypeTempStorage data_backup; | |||
memcpy(&data_backup, p_data, type_info->Size); | memcpy(&data_backup, p_data, type_info->Size); | |||
if (format == NULL) | if (format == NULL) | |||
format = type_info->ScanFmt; | format = type_info->ScanFmt; | |||
// FIXME-LEGACY: The aim is to remove those operators and write a proper exp | if (data_type == ImGuiDataType_S32 || data_type == ImGuiDataType_U32 || data | |||
ression evaluator at some point.. | _type == ImGuiDataType_S64 || data_type == ImGuiDataType_U64 || data_type == ImG | |||
int arg1i = 0; | uiDataType_Float || data_type == ImGuiDataType_Double) | |||
if (data_type == ImGuiDataType_S32) | ||||
{ | ||||
int* v = (int*)p_data; | ||||
int arg0i = *v; | ||||
float arg1f = 0.0f; | ||||
if (op && sscanf(initial_value_buf, format, &arg0i) < 1) | ||||
return false; | ||||
// Store operand in a float so we can use fractional value for multiplie | ||||
rs (*1.1), but constant always parsed as integer so we can fit big integers (e.g | ||||
. 2000000003) past float precision | ||||
if (op == '+') { if (sscanf(buf, "%d", &arg1i)) *v = (int)(arg0i + | ||||
arg1i); } // Add (use "+-" to subtract) | ||||
else if (op == '*') { if (sscanf(buf, "%f", &arg1f)) *v = (int)(arg0i * | ||||
arg1f); } // Multiply | ||||
else if (op == '/') { if (sscanf(buf, "%f", &arg1f) && arg1f != 0.0f) *v | ||||
= (int)(arg0i / arg1f); } // Divide | ||||
else { if (sscanf(buf, format, &arg1i) == 1) *v = arg1i; | ||||
} // Assign constant | ||||
} | ||||
else if (data_type == ImGuiDataType_Float) | ||||
{ | ||||
// For floats we have to ignore format with precision (e.g. "%.2f") beca | ||||
use sscanf doesn't take them in | ||||
format = "%f"; | ||||
float* v = (float*)p_data; | ||||
float arg0f = *v, arg1f = 0.0f; | ||||
if (op && sscanf(initial_value_buf, format, &arg0f) < 1) | ||||
return false; | ||||
if (sscanf(buf, format, &arg1f) < 1) | ||||
return false; | ||||
if (op == '+') { *v = arg0f + arg1f; } // Add (u | ||||
se "+-" to subtract) | ||||
else if (op == '*') { *v = arg0f * arg1f; } // Multip | ||||
ly | ||||
else if (op == '/') { if (arg1f != 0.0f) *v = arg0f / arg1f; } // Divide | ||||
else { *v = arg1f; } // Assign | ||||
constant | ||||
} | ||||
else if (data_type == ImGuiDataType_Double) | ||||
{ | ||||
format = "%lf"; // scanf differentiate float/double unlike printf which | ||||
forces everything to double because of ellipsis | ||||
double* v = (double*)p_data; | ||||
double arg0f = *v, arg1f = 0.0; | ||||
if (op && sscanf(initial_value_buf, format, &arg0f) < 1) | ||||
return false; | ||||
if (sscanf(buf, format, &arg1f) < 1) | ||||
return false; | ||||
if (op == '+') { *v = arg0f + arg1f; } // Add (u | ||||
se "+-" to subtract) | ||||
else if (op == '*') { *v = arg0f * arg1f; } // Multip | ||||
ly | ||||
else if (op == '/') { if (arg1f != 0.0f) *v = arg0f / arg1f; } // Divide | ||||
else { *v = arg1f; } // Assign | ||||
constant | ||||
} | ||||
else if (data_type == ImGuiDataType_U32 || data_type == ImGuiDataType_S64 || | ||||
data_type == ImGuiDataType_U64) | ||||
{ | { | |||
// All other types assign constant | // For float/double we have to ignore format with precision (e.g. "%.2f" | |||
// We don't bother handling support for legacy operators since they are | ) because sscanf doesn't take them in, so force them into %f and %lf | |||
a little too crappy. Instead we will later implement a proper expression evaluat | if (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Doubl | |||
or in the future. | e) | |||
format = type_info->ScanFmt; | ||||
if (sscanf(buf, format, p_data) < 1) | if (sscanf(buf, format, p_data) < 1) | |||
return false; | return false; | |||
} | } | |||
else | else | |||
{ | { | |||
// Small types need a 32-bit buffer to receive the result from scanf() | // Small types need a 32-bit buffer to receive the result from scanf() | |||
int v32; | int v32; | |||
if (sscanf(buf, format, &v32) < 1) | if (sscanf(buf, format, &v32) < 1) | |||
return false; | return false; | |||
if (data_type == ImGuiDataType_S8) | if (data_type == ImGuiDataType_S8) | |||
skipping to change at line 3390 | skipping to change at line 3336 | |||
g.TempInputId = g.ActiveId; | g.TempInputId = g.ActiveId; | |||
} | } | |||
return value_changed; | return value_changed; | |||
} | } | |||
// Note that Drag/Slider functions are only forwarding the min/max values clampi ng values if the ImGuiSliderFlags_AlwaysClamp flag is set! | // Note that Drag/Slider functions are only forwarding the min/max values clampi ng values if the ImGuiSliderFlags_AlwaysClamp flag is set! | |||
// This is intended: this way we allow CTRL+Click manual input to set a value ou t of bounds, for maximum flexibility. | // This is intended: this way we allow CTRL+Click manual input to set a value ou t of bounds, for maximum flexibility. | |||
// However this may not be ideal for all uses, as some user code may break on ou t of bound values. | // However this may not be ideal for all uses, as some user code may break on ou t of bound values. | |||
bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImG uiDataType data_type, void* p_data, const char* format, const void* p_clamp_min, const void* p_clamp_max) | bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImG uiDataType data_type, void* p_data, const char* format, const void* p_clamp_min, const void* p_clamp_max) | |||
{ | { | |||
ImGuiContext& g = *GImGui; | ||||
char fmt_buf[32]; | char fmt_buf[32]; | |||
char data_buf[32]; | char data_buf[32]; | |||
format = ImParseFormatTrimDecorations(format, fmt_buf, IM_ARRAYSIZE(fmt_buf) ); | format = ImParseFormatTrimDecorations(format, fmt_buf, IM_ARRAYSIZE(fmt_buf) ); | |||
DataTypeFormatString(data_buf, IM_ARRAYSIZE(data_buf), data_type, p_data, fo rmat); | DataTypeFormatString(data_buf, IM_ARRAYSIZE(data_buf), data_type, p_data, fo rmat); | |||
ImStrTrimBlanks(data_buf); | ImStrTrimBlanks(data_buf); | |||
ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTe xtFlags_NoMarkEdited; | ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTe xtFlags_NoMarkEdited; | |||
flags |= ((data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Do uble) ? ImGuiInputTextFlags_CharsScientific : ImGuiInputTextFlags_CharsDecimal); | flags |= ((data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Do uble) ? ImGuiInputTextFlags_CharsScientific : ImGuiInputTextFlags_CharsDecimal); | |||
bool value_changed = false; | bool value_changed = false; | |||
if (TempInputText(bb, id, label, data_buf, IM_ARRAYSIZE(data_buf), flags)) | if (TempInputText(bb, id, label, data_buf, IM_ARRAYSIZE(data_buf), flags)) | |||
{ | { | |||
// Backup old value | // Backup old value | |||
size_t data_type_size = DataTypeGetInfo(data_type)->Size; | size_t data_type_size = DataTypeGetInfo(data_type)->Size; | |||
ImGuiDataTypeTempStorage data_backup; | ImGuiDataTypeTempStorage data_backup; | |||
memcpy(&data_backup, p_data, data_type_size); | memcpy(&data_backup, p_data, data_type_size); | |||
// Apply new value (or operations) then clamp | // Apply new value (or operations) then clamp | |||
DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialTextA.Data, da ta_type, p_data, NULL); | DataTypeApplyFromText(data_buf, data_type, p_data, NULL); | |||
if (p_clamp_min || p_clamp_max) | if (p_clamp_min || p_clamp_max) | |||
{ | { | |||
if (p_clamp_min && p_clamp_max && DataTypeCompare(data_type, p_clamp _min, p_clamp_max) > 0) | if (p_clamp_min && p_clamp_max && DataTypeCompare(data_type, p_clamp _min, p_clamp_max) > 0) | |||
ImSwap(p_clamp_min, p_clamp_max); | ImSwap(p_clamp_min, p_clamp_max); | |||
DataTypeClamp(data_type, p_data, p_clamp_min, p_clamp_max); | DataTypeClamp(data_type, p_data, p_clamp_min, p_clamp_max); | |||
} | } | |||
// Only mark as edited if new value is different | // Only mark as edited if new value is different | |||
value_changed = memcmp(&data_backup, p_data, data_type_size) != 0; | value_changed = memcmp(&data_backup, p_data, data_type_size) != 0; | |||
if (value_changed) | if (value_changed) | |||
skipping to change at line 3456 | skipping to change at line 3400 | |||
flags |= ImGuiInputTextFlags_NoMarkEdited; // We call MarkItemEdited() ours elves by comparing the actual data rather than the string. | flags |= ImGuiInputTextFlags_NoMarkEdited; // We call MarkItemEdited() ours elves by comparing the actual data rather than the string. | |||
if (p_step != NULL) | if (p_step != NULL) | |||
{ | { | |||
const float button_size = GetFrameHeight(); | const float button_size = GetFrameHeight(); | |||
BeginGroup(); // The only purpose of the group here is to allow the call er to query item data e.g. IsItemActive() | BeginGroup(); // The only purpose of the group here is to allow the call er to query item data e.g. IsItemActive() | |||
PushID(label); | PushID(label); | |||
SetNextItemWidth(ImMax(1.0f, CalcItemWidth() - (button_size + style.Item InnerSpacing.x) * 2)); | SetNextItemWidth(ImMax(1.0f, CalcItemWidth() - (button_size + style.Item InnerSpacing.x) * 2)); | |||
if (InputText("", buf, IM_ARRAYSIZE(buf), flags)) // PushId(label) + "" gives us the expected ID from outside point of view | if (InputText("", buf, IM_ARRAYSIZE(buf), flags)) // PushId(label) + "" gives us the expected ID from outside point of view | |||
value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.Initia lTextA.Data, data_type, p_data, format); | value_changed = DataTypeApplyFromText(buf, data_type, p_data, format ); | |||
// Step buttons | // Step buttons | |||
const ImVec2 backup_frame_padding = style.FramePadding; | const ImVec2 backup_frame_padding = style.FramePadding; | |||
style.FramePadding.x = style.FramePadding.y; | style.FramePadding.x = style.FramePadding.y; | |||
ImGuiButtonFlags button_flags = ImGuiButtonFlags_Repeat | ImGuiButtonFla gs_DontClosePopups; | ImGuiButtonFlags button_flags = ImGuiButtonFlags_Repeat | ImGuiButtonFla gs_DontClosePopups; | |||
if (flags & ImGuiInputTextFlags_ReadOnly) | if (flags & ImGuiInputTextFlags_ReadOnly) | |||
BeginDisabled(); | BeginDisabled(); | |||
SameLine(0, style.ItemInnerSpacing.x); | SameLine(0, style.ItemInnerSpacing.x); | |||
if (ButtonEx("-", ImVec2(button_size, button_size), button_flags)) | if (ButtonEx("-", ImVec2(button_size, button_size), button_flags)) | |||
{ | { | |||
skipping to change at line 3493 | skipping to change at line 3437 | |||
TextEx(label, label_end); | TextEx(label, label_end); | |||
} | } | |||
style.FramePadding = backup_frame_padding; | style.FramePadding = backup_frame_padding; | |||
PopID(); | PopID(); | |||
EndGroup(); | EndGroup(); | |||
} | } | |||
else | else | |||
{ | { | |||
if (InputText(label, buf, IM_ARRAYSIZE(buf), flags)) | if (InputText(label, buf, IM_ARRAYSIZE(buf), flags)) | |||
value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.Initia lTextA.Data, data_type, p_data, format); | value_changed = DataTypeApplyFromText(buf, data_type, p_data, format ); | |||
} | } | |||
if (value_changed) | if (value_changed) | |||
MarkItemEdited(g.LastItemData.ID); | MarkItemEdited(g.LastItemData.ID); | |||
return value_changed; | return value_changed; | |||
} | } | |||
bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* p_dat a, int components, const void* p_step, const void* p_step_fast, const char* form at, ImGuiInputTextFlags flags) | bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* p_dat a, int components, const void* p_step, const void* p_step_fast, const char* form at, ImGuiInputTextFlags flags) | |||
{ | { | |||
ImGuiWindow* window = GetCurrentWindow(); | ImGuiWindow* window = GetCurrentWindow(); | |||
skipping to change at line 4120 | skipping to change at line 4064 | |||
SetActiveID(id, window); | SetActiveID(id, window); | |||
SetFocusID(id, window); | SetFocusID(id, window); | |||
FocusWindow(window); | FocusWindow(window); | |||
// Declare our inputs | // Declare our inputs | |||
IM_ASSERT(ImGuiNavInput_COUNT < 32); | IM_ASSERT(ImGuiNavInput_COUNT < 32); | |||
g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right ); | g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right ); | |||
if (is_multiline || (flags & ImGuiInputTextFlags_CallbackHistory)) | if (is_multiline || (flags & ImGuiInputTextFlags_CallbackHistory)) | |||
g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Up) | (1 << ImGuiDir_Dow n); | g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Up) | (1 << ImGuiDir_Dow n); | |||
g.ActiveIdUsingNavInputMask |= (1 << ImGuiNavInput_Cancel); | g.ActiveIdUsingNavInputMask |= (1 << ImGuiNavInput_Cancel); | |||
g.ActiveIdUsingKeyInputMask |= ((ImU64)1 << ImGuiKey_Home) | ((ImU64)1 < | SetActiveIdUsingKey(ImGuiKey_Home); | |||
< ImGuiKey_End); | SetActiveIdUsingKey(ImGuiKey_End); | |||
if (is_multiline) | if (is_multiline) | |||
g.ActiveIdUsingKeyInputMask |= ((ImU64)1 << ImGuiKey_PageUp) | ((ImU | { | |||
64)1 << ImGuiKey_PageDown); | SetActiveIdUsingKey(ImGuiKey_PageUp); | |||
if (flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlag | SetActiveIdUsingKey(ImGuiKey_PageDown); | |||
s_AllowTabInput)) // Disable keyboard tabbing out as we will use the \t charact | } | |||
er. | if (flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlag | |||
g.ActiveIdUsingKeyInputMask |= ((ImU64)1 << ImGuiKey_Tab); | s_AllowTabInput)) // Disable keyboard tabbing out as we will use the \t characte | |||
r. | ||||
{ | ||||
SetActiveIdUsingKey(ImGuiKey_Tab); | ||||
} | ||||
} | } | |||
// We have an edge case if ActiveId was set through another widget (e.g. wid get being swapped), clear id immediately (don't wait until the end of the functi on) | // We have an edge case if ActiveId was set through another widget (e.g. wid get being swapped), clear id immediately (don't wait until the end of the functi on) | |||
if (g.ActiveId == id && state == NULL) | if (g.ActiveId == id && state == NULL) | |||
ClearActiveID(); | ClearActiveID(); | |||
// Release focus when we click outside | // Release focus when we click outside | |||
if (g.ActiveId == id && io.MouseClicked[0] && !init_state && !init_make_acti ve) //-V560 | if (g.ActiveId == id && io.MouseClicked[0] && !init_state && !init_make_acti ve) //-V560 | |||
clear_active_id = true; | clear_active_id = true; | |||
skipping to change at line 4254 | skipping to change at line 4204 | |||
stb_textedit_drag(state, &state->Stb, mouse_x, mouse_y); | stb_textedit_drag(state, &state->Stb, mouse_x, mouse_y); | |||
state->CursorAnimReset(); | state->CursorAnimReset(); | |||
state->CursorFollow = true; | state->CursorFollow = true; | |||
} | } | |||
if (state->SelectedAllMouseLock && !io.MouseDown[0]) | if (state->SelectedAllMouseLock && !io.MouseDown[0]) | |||
state->SelectedAllMouseLock = false; | state->SelectedAllMouseLock = false; | |||
// It is ill-defined whether the backend needs to send a \t character wh en pressing the TAB keys. | // It is ill-defined whether the backend needs to send a \t character wh en pressing the TAB keys. | |||
// Win32 and GLFW naturally do it but not SDL. | // Win32 and GLFW naturally do it but not SDL. | |||
const bool ignore_char_inputs = (io.KeyCtrl && !io.KeyAlt) || (is_osx && io.KeySuper); | const bool ignore_char_inputs = (io.KeyCtrl && !io.KeyAlt) || (is_osx && io.KeySuper); | |||
if ((flags & ImGuiInputTextFlags_AllowTabInput) && IsKeyPressedMap(ImGui Key_Tab) && !ignore_char_inputs && !io.KeyShift && !is_readonly) | if ((flags & ImGuiInputTextFlags_AllowTabInput) && IsKeyPressed(ImGuiKey _Tab) && !ignore_char_inputs && !io.KeyShift && !is_readonly) | |||
if (!io.InputQueueCharacters.contains('\t')) | if (!io.InputQueueCharacters.contains('\t')) | |||
{ | { | |||
unsigned int c = '\t'; // Insert TAB | unsigned int c = '\t'; // Insert TAB | |||
if (InputTextFilterCharacter(&c, flags, callback, callback_user_ data, ImGuiInputSource_Keyboard)) | if (InputTextFilterCharacter(&c, flags, callback, callback_user_ data, ImGuiInputSource_Keyboard)) | |||
state->OnKeyPressed((int)c); | state->OnKeyPressed((int)c); | |||
} | } | |||
// Process regular text input (before we check for Return because using some IME will effectively send a Return?) | // Process regular text input (before we check for Return because using some IME will effectively send a Return?) | |||
// We ignore CTRL inputs, but need to allow ALT+CTRL as some keyboards ( e.g. German) use AltGR (which _is_ Alt+Ctrl) to input certain characters. | // We ignore CTRL inputs, but need to allow ALT+CTRL as some keyboards ( e.g. German) use AltGR (which _is_ Alt+Ctrl) to input certain characters. | |||
if (io.InputQueueCharacters.Size > 0) | if (io.InputQueueCharacters.Size > 0) | |||
skipping to change at line 4301 | skipping to change at line 4251 | |||
const int k_mask = (io.KeyShift ? STB_TEXTEDIT_K_SHIFT : 0); | const int k_mask = (io.KeyShift ? STB_TEXTEDIT_K_SHIFT : 0); | |||
const bool is_osx = io.ConfigMacOSXBehaviors; | const bool is_osx = io.ConfigMacOSXBehaviors; | |||
const bool is_osx_shift_shortcut = is_osx && (io.KeyMods == (ImGuiKeyMod Flags_Super | ImGuiKeyModFlags_Shift)); | const bool is_osx_shift_shortcut = is_osx && (io.KeyMods == (ImGuiKeyMod Flags_Super | ImGuiKeyModFlags_Shift)); | |||
const bool is_wordmove_key_down = is_osx ? io.KeyAlt : io.KeyCtrl; // OS X style: Text editing cursor movement using Alt instead of Ctrl | const bool is_wordmove_key_down = is_osx ? io.KeyAlt : io.KeyCtrl; // OS X style: Text editing cursor movement using Alt instead of Ctrl | |||
const bool is_startend_key_down = is_osx && io.KeySuper && !io.KeyCtrl & & !io.KeyAlt; // OS X style: Line/Text Start and End using Cmd+Arrows instead o f Home/End | const bool is_startend_key_down = is_osx && io.KeySuper && !io.KeyCtrl & & !io.KeyAlt; // OS X style: Line/Text Start and End using Cmd+Arrows instead o f Home/End | |||
const bool is_ctrl_key_only = (io.KeyMods == ImGuiKeyModFlags_Ctrl); | const bool is_ctrl_key_only = (io.KeyMods == ImGuiKeyModFlags_Ctrl); | |||
const bool is_shift_key_only = (io.KeyMods == ImGuiKeyModFlags_Shift); | const bool is_shift_key_only = (io.KeyMods == ImGuiKeyModFlags_Shift); | |||
const bool is_shortcut_key = g.IO.ConfigMacOSXBehaviors ? (io.KeyMods == ImGuiKeyModFlags_Super) : (io.KeyMods == ImGuiKeyModFlags_Ctrl); | const bool is_shortcut_key = g.IO.ConfigMacOSXBehaviors ? (io.KeyMods == ImGuiKeyModFlags_Super) : (io.KeyMods == ImGuiKeyModFlags_Ctrl); | |||
const bool is_cut = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_X)) | const bool is_cut = ((is_shortcut_key && IsKeyPressed(ImGuiKey_X)) || | |||
|| (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Delete))) && !is_readonly && ! | (is_shift_key_only && IsKeyPressed(ImGuiKey_Delete))) && !is_readonly && !is_pas | |||
is_password && (!is_multiline || state->HasSelection()); | sword && (!is_multiline || state->HasSelection()); | |||
const bool is_copy = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_C)) | const bool is_copy = ((is_shortcut_key && IsKeyPressed(ImGuiKey_C)) || | |||
|| (is_ctrl_key_only && IsKeyPressedMap(ImGuiKey_Insert))) && !is_password && ( | (is_ctrl_key_only && IsKeyPressed(ImGuiKey_Insert))) && !is_password && (!is_mu | |||
!is_multiline || state->HasSelection()); | ltiline || state->HasSelection()); | |||
const bool is_paste = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_V)) | const bool is_paste = ((is_shortcut_key && IsKeyPressed(ImGuiKey_V)) || | |||
|| (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Insert))) && !is_readonly; | (is_shift_key_only && IsKeyPressed(ImGuiKey_Insert))) && !is_readonly; | |||
const bool is_undo = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Z)) | const bool is_undo = ((is_shortcut_key && IsKeyPressed(ImGuiKey_Z)) && | |||
&& !is_readonly && is_undoable); | !is_readonly && is_undoable); | |||
const bool is_redo = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Y)) | const bool is_redo = ((is_shortcut_key && IsKeyPressed(ImGuiKey_Y)) || | |||
|| (is_osx_shift_shortcut && IsKeyPressedMap(ImGuiKey_Z))) && !is_readonly && is | (is_osx_shift_shortcut && IsKeyPressed(ImGuiKey_Z))) && !is_readonly && is_undoa | |||
_undoable; | ble; | |||
// We allow validate/cancel with Nav source (gamepad) to makes it easier to undo an accidental NavInput press with no keyboard wired, but otherwise it i sn't very useful. | // We allow validate/cancel with Nav source (gamepad) to makes it easier to undo an accidental NavInput press with no keyboard wired, but otherwise it i sn't very useful. | |||
const bool is_validate_enter = IsKeyPressedMap(ImGuiKey_Enter) || IsKeyP | const bool is_validate_enter = IsKeyPressed(ImGuiKey_Enter) || IsKeyPres | |||
ressedMap(ImGuiKey_KeyPadEnter); | sed(ImGuiKey_KeypadEnter); | |||
const bool is_validate_nav = (IsNavInputTest(ImGuiNavInput_Activate, ImG | const bool is_validate_nav = (IsNavInputTest(ImGuiNavInput_Activate, ImG | |||
uiInputReadMode_Pressed) && !IsKeyPressedMap(ImGuiKey_Space)) || IsNavInputTest( | uiInputReadMode_Pressed) && !IsKeyPressed(ImGuiKey_Space)) || IsNavInputTest(ImG | |||
ImGuiNavInput_Input, ImGuiInputReadMode_Pressed); | uiNavInput_Input, ImGuiInputReadMode_Pressed); | |||
const bool is_cancel = IsKeyPressedMap(ImGuiKey_Escape) || IsNavInputT | const bool is_cancel = IsKeyPressed(ImGuiKey_Escape) || IsNavInputTest | |||
est(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed); | (ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed); | |||
if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { state- | if (IsKeyPressed(ImGuiKey_LeftArrow)) { state->On | |||
>OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key | KeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_do | |||
_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); } | wn ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); } | |||
else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { state- | else if (IsKeyPressed(ImGuiKey_RightArrow)) { state->On | |||
>OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_d | KeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down | |||
own ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); } | ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); } | |||
else if (IsKeyPressedMap(ImGuiKey_UpArrow) && is_multiline) { if (io | else if (IsKeyPressed(ImGuiKey_UpArrow) && is_multiline) { if (io.Ke | |||
.KeyCtrl) SetScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f | yCtrl) SetScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); | |||
)); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : | else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB | |||
STB_TEXTEDIT_K_UP) | k_mask); } | _TEXTEDIT_K_UP) | k_mask); } | |||
else if (IsKeyPressedMap(ImGuiKey_DownArrow) && is_multiline) { if (io | else if (IsKeyPressed(ImGuiKey_DownArrow) && is_multiline) { if (io.Ke | |||
.KeyCtrl) SetScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetS | yCtrl) SetScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScro | |||
crollMaxY())); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_T | llMaxY())); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXT | |||
EXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); } | END : STB_TEXTEDIT_K_DOWN) | k_mask); } | |||
else if (IsKeyPressedMap(ImGuiKey_PageUp) && is_multiline) { state- | else if (IsKeyPressed(ImGuiKey_PageUp) && is_multiline) { state->On | |||
>OnKeyPressed(STB_TEXTEDIT_K_PGUP | k_mask); scroll_y -= row_count_per_page * g. | KeyPressed(STB_TEXTEDIT_K_PGUP | k_mask); scroll_y -= row_count_per_page * g.Fon | |||
FontSize; } | tSize; } | |||
else if (IsKeyPressedMap(ImGuiKey_PageDown) && is_multiline) { state- | else if (IsKeyPressed(ImGuiKey_PageDown) && is_multiline) { state->On | |||
>OnKeyPressed(STB_TEXTEDIT_K_PGDOWN | k_mask); scroll_y += row_count_per_page * | KeyPressed(STB_TEXTEDIT_K_PGDOWN | k_mask); scroll_y += row_count_per_page * g.F | |||
g.FontSize; } | ontSize; } | |||
else if (IsKeyPressedMap(ImGuiKey_Home)) { state- | else if (IsKeyPressed(ImGuiKey_Home)) { state->On | |||
>OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LI | KeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINES | |||
NESTART | k_mask); } | TART | k_mask); } | |||
else if (IsKeyPressedMap(ImGuiKey_End)) { state- | else if (IsKeyPressed(ImGuiKey_End)) { state->On | |||
>OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINE | KeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | |||
END | k_mask); } | | k_mask); } | |||
else if (IsKeyPressedMap(ImGuiKey_Delete) && !is_readonly && !is_cut) { | else if (IsKeyPressed(ImGuiKey_Delete) && !is_readonly && !is_cut) { sta | |||
state->OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); } | te->OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); } | |||
else if (IsKeyPressedMap(ImGuiKey_Backspace) && !is_readonly) | else if (IsKeyPressed(ImGuiKey_Backspace) && !is_readonly) | |||
{ | { | |||
if (!state->HasSelection()) | if (!state->HasSelection()) | |||
{ | { | |||
if (is_wordmove_key_down) | if (is_wordmove_key_down) | |||
state->OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K _SHIFT); | state->OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K _SHIFT); | |||
else if (is_osx && io.KeySuper && !io.KeyAlt && !io.KeyCtrl) | else if (is_osx && io.KeySuper && !io.KeyAlt && !io.KeyCtrl) | |||
state->OnKeyPressed(STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_ K_SHIFT); | state->OnKeyPressed(STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_ K_SHIFT); | |||
} | } | |||
state->OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask); | state->OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask); | |||
} | } | |||
skipping to change at line 4360 | skipping to change at line 4310 | |||
} | } | |||
else if (is_cancel) | else if (is_cancel) | |||
{ | { | |||
clear_active_id = cancel_edit = true; | clear_active_id = cancel_edit = true; | |||
} | } | |||
else if (is_undo || is_redo) | else if (is_undo || is_redo) | |||
{ | { | |||
state->OnKeyPressed(is_undo ? STB_TEXTEDIT_K_UNDO : STB_TEXTEDIT_K_R EDO); | state->OnKeyPressed(is_undo ? STB_TEXTEDIT_K_UNDO : STB_TEXTEDIT_K_R EDO); | |||
state->ClearSelection(); | state->ClearSelection(); | |||
} | } | |||
else if (is_shortcut_key && IsKeyPressedMap(ImGuiKey_A)) | else if (is_shortcut_key && IsKeyPressed(ImGuiKey_A)) | |||
{ | { | |||
state->SelectAll(); | state->SelectAll(); | |||
state->CursorFollow = true; | state->CursorFollow = true; | |||
} | } | |||
else if (is_cut || is_copy) | else if (is_cut || is_copy) | |||
{ | { | |||
// Cut, Copy | // Cut, Copy | |||
if (io.SetClipboardTextFn) | if (io.SetClipboardTextFn) | |||
{ | { | |||
const int ib = state->HasSelection() ? ImMin(state->Stb.select_s tart, state->Stb.select_end) : 0; | const int ib = state->HasSelection() ? ImMin(state->Stb.select_s tart, state->Stb.select_end) : 0; | |||
skipping to change at line 4466 | skipping to change at line 4416 | |||
ImTextStrToUtf8(state->TextA.Data, state->TextA.Size, state->Tex tW.Data, NULL); | ImTextStrToUtf8(state->TextA.Data, state->TextA.Size, state->Tex tW.Data, NULL); | |||
} | } | |||
// User callback | // User callback | |||
if ((flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTex tFlags_CallbackHistory | ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_ CallbackAlways)) != 0) | if ((flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTex tFlags_CallbackHistory | ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_ CallbackAlways)) != 0) | |||
{ | { | |||
IM_ASSERT(callback != NULL); | IM_ASSERT(callback != NULL); | |||
// The reason we specify the usage semantic (Completion/History) is that Completion needs to disable keyboard TABBING at the moment. | // The reason we specify the usage semantic (Completion/History) is that Completion needs to disable keyboard TABBING at the moment. | |||
ImGuiInputTextFlags event_flag = 0; | ImGuiInputTextFlags event_flag = 0; | |||
ImGuiKey event_key = ImGuiKey_COUNT; | ImGuiKey event_key = ImGuiKey_None; | |||
if ((flags & ImGuiInputTextFlags_CallbackCompletion) != 0 && IsK | if ((flags & ImGuiInputTextFlags_CallbackCompletion) != 0 && IsK | |||
eyPressedMap(ImGuiKey_Tab)) | eyPressed(ImGuiKey_Tab)) | |||
{ | { | |||
event_flag = ImGuiInputTextFlags_CallbackCompletion; | event_flag = ImGuiInputTextFlags_CallbackCompletion; | |||
event_key = ImGuiKey_Tab; | event_key = ImGuiKey_Tab; | |||
} | } | |||
else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && I sKeyPressedMap(ImGuiKey_UpArrow)) | else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && I sKeyPressed(ImGuiKey_UpArrow)) | |||
{ | { | |||
event_flag = ImGuiInputTextFlags_CallbackHistory; | event_flag = ImGuiInputTextFlags_CallbackHistory; | |||
event_key = ImGuiKey_UpArrow; | event_key = ImGuiKey_UpArrow; | |||
} | } | |||
else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && I sKeyPressedMap(ImGuiKey_DownArrow)) | else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && I sKeyPressed(ImGuiKey_DownArrow)) | |||
{ | { | |||
event_flag = ImGuiInputTextFlags_CallbackHistory; | event_flag = ImGuiInputTextFlags_CallbackHistory; | |||
event_key = ImGuiKey_DownArrow; | event_key = ImGuiKey_DownArrow; | |||
} | } | |||
else if ((flags & ImGuiInputTextFlags_CallbackEdit) && state->Ed ited) | else if ((flags & ImGuiInputTextFlags_CallbackEdit) && state->Ed ited) | |||
{ | { | |||
event_flag = ImGuiInputTextFlags_CallbackEdit; | event_flag = ImGuiInputTextFlags_CallbackEdit; | |||
} | } | |||
else if (flags & ImGuiInputTextFlags_CallbackAlways) | else if (flags & ImGuiInputTextFlags_CallbackAlways) | |||
{ | { | |||
skipping to change at line 4763 | skipping to change at line 4713 | |||
{ | { | |||
state->CursorAnim += io.DeltaTime; | state->CursorAnim += io.DeltaTime; | |||
bool cursor_is_visible = (!g.IO.ConfigInputTextCursorBlink) || (stat e->CursorAnim <= 0.0f) || ImFmod(state->CursorAnim, 1.20f) <= 0.80f; | bool cursor_is_visible = (!g.IO.ConfigInputTextCursorBlink) || (stat e->CursorAnim <= 0.0f) || ImFmod(state->CursorAnim, 1.20f) <= 0.80f; | |||
ImVec2 cursor_screen_pos = ImFloor(draw_pos + cursor_offset - draw_s croll); | ImVec2 cursor_screen_pos = ImFloor(draw_pos + cursor_offset - draw_s croll); | |||
ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y - g.FontSize + 0.5f, cursor_screen_pos.x + 1.0f, cursor_screen_pos.y - 1.5f); | ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y - g.FontSize + 0.5f, cursor_screen_pos.x + 1.0f, cursor_screen_pos.y - 1.5f); | |||
if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect)) | if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect)) | |||
draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_sc reen_rect.GetBL(), GetColorU32(ImGuiCol_Text)); | draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_sc reen_rect.GetBL(), GetColorU32(ImGuiCol_Text)); | |||
// Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.) | // Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.) | |||
if (!is_readonly) | if (!is_readonly) | |||
g.PlatformImePos = ImVec2(cursor_screen_pos.x - 1.0f, cursor_scr | { | |||
een_pos.y - g.FontSize); | g.PlatformImeData.WantVisible = true; | |||
g.PlatformImeData.InputPos = ImVec2(cursor_screen_pos.x - 1.0f, | ||||
cursor_screen_pos.y - g.FontSize); | ||||
g.PlatformImeData.InputLineHeight = g.FontSize; | ||||
} | ||||
} | } | |||
} | } | |||
else | else | |||
{ | { | |||
// Render text only (no selection, no cursor) | // Render text only (no selection, no cursor) | |||
if (is_multiline) | if (is_multiline) | |||
text_size = ImVec2(inner_size.x, InputTextCalcTextLenAndLineCount(bu f_display, &buf_display_end) * g.FontSize); // We don't need width | text_size = ImVec2(inner_size.x, InputTextCalcTextLenAndLineCount(bu f_display, &buf_display_end) * g.FontSize); // We don't need width | |||
else if (!is_displaying_hint && g.ActiveId == id) | else if (!is_displaying_hint && g.ActiveId == id) | |||
buf_display_end = buf_display + state->CurLenA; | buf_display_end = buf_display + state->CurLenA; | |||
else if (!is_displaying_hint) | else if (!is_displaying_hint) | |||
skipping to change at line 4976 | skipping to change at line 4930 | |||
if (flags & ImGuiColorEditFlags_Float) | if (flags & ImGuiColorEditFlags_Float) | |||
{ | { | |||
value_changed |= DragFloat(ids[n], &f[n], 1.0f / 255.0f, 0.0f, h dr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n]); | value_changed |= DragFloat(ids[n], &f[n], 1.0f / 255.0f, 0.0f, h dr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n]); | |||
value_changed_as_float |= value_changed; | value_changed_as_float |= value_changed; | |||
} | } | |||
else | else | |||
{ | { | |||
value_changed |= DragInt(ids[n], &i[n], 1.0f, 0, hdr ? 0 : 255, fmt_table_int[fmt_idx][n]); | value_changed |= DragInt(ids[n], &i[n], 1.0f, 0, hdr ? 0 : 255, fmt_table_int[fmt_idx][n]); | |||
} | } | |||
if (!(flags & ImGuiColorEditFlags_NoOptions)) | if (!(flags & ImGuiColorEditFlags_NoOptions)) | |||
OpenPopupOnItemClick("context"); | OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight ); | |||
} | } | |||
} | } | |||
else if ((flags & ImGuiColorEditFlags_DisplayHex) != 0 && (flags & ImGuiColo rEditFlags_NoInputs) == 0) | else if ((flags & ImGuiColorEditFlags_DisplayHex) != 0 && (flags & ImGuiColo rEditFlags_NoInputs) == 0) | |||
{ | { | |||
// RGB Hexadecimal Input | // RGB Hexadecimal Input | |||
char buf[64]; | char buf[64]; | |||
if (alpha) | if (alpha) | |||
ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X%02X", ImClamp( i[0], 0, 255), ImClamp(i[1], 0, 255), ImClamp(i[2], 0, 255), ImClamp(i[3], 0, 25 5)); | ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X%02X", ImClamp( i[0], 0, 255), ImClamp(i[1], 0, 255), ImClamp(i[2], 0, 255), ImClamp(i[3], 0, 25 5)); | |||
else | else | |||
ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", ImClamp(i[0] , 0, 255), ImClamp(i[1], 0, 255), ImClamp(i[2], 0, 255)); | ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", ImClamp(i[0] , 0, 255), ImClamp(i[1], 0, 255), ImClamp(i[2], 0, 255)); | |||
skipping to change at line 5004 | skipping to change at line 4958 | |||
i[0] = i[1] = i[2] = 0; | i[0] = i[1] = i[2] = 0; | |||
i[3] = 0xFF; // alpha default to 255 is not parsed by scanf (e.g. in putting #FFFFFF omitting alpha) | i[3] = 0xFF; // alpha default to 255 is not parsed by scanf (e.g. in putting #FFFFFF omitting alpha) | |||
int r; | int r; | |||
if (alpha) | if (alpha) | |||
r = sscanf(p, "%02X%02X%02X%02X", (unsigned int*)&i[0], (unsigne d int*)&i[1], (unsigned int*)&i[2], (unsigned int*)&i[3]); // Treat at unsigned (%X is unsigned) | r = sscanf(p, "%02X%02X%02X%02X", (unsigned int*)&i[0], (unsigne d int*)&i[1], (unsigned int*)&i[2], (unsigned int*)&i[3]); // Treat at unsigned (%X is unsigned) | |||
else | else | |||
r = sscanf(p, "%02X%02X%02X", (unsigned int*)&i[0], (unsigned in t*)&i[1], (unsigned int*)&i[2]); | r = sscanf(p, "%02X%02X%02X", (unsigned int*)&i[0], (unsigned in t*)&i[1], (unsigned int*)&i[2]); | |||
IM_UNUSED(r); // Fixes C6031: Return value ignored: 'sscanf'. | IM_UNUSED(r); // Fixes C6031: Return value ignored: 'sscanf'. | |||
} | } | |||
if (!(flags & ImGuiColorEditFlags_NoOptions)) | if (!(flags & ImGuiColorEditFlags_NoOptions)) | |||
OpenPopupOnItemClick("context"); | OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight); | |||
} | } | |||
ImGuiWindow* picker_active_window = NULL; | ImGuiWindow* picker_active_window = NULL; | |||
if (!(flags & ImGuiColorEditFlags_NoSmallPreview)) | if (!(flags & ImGuiColorEditFlags_NoSmallPreview)) | |||
{ | { | |||
const float button_offset_x = ((flags & ImGuiColorEditFlags_NoInputs) || (style.ColorButtonPosition == ImGuiDir_Left)) ? 0.0f : w_inputs + style.ItemInn erSpacing.x; | const float button_offset_x = ((flags & ImGuiColorEditFlags_NoInputs) || (style.ColorButtonPosition == ImGuiDir_Left)) ? 0.0f : w_inputs + style.ItemInn erSpacing.x; | |||
window->DC.CursorPos = ImVec2(pos.x + button_offset_x, pos.y); | window->DC.CursorPos = ImVec2(pos.x + button_offset_x, pos.y); | |||
const ImVec4 col_v4(col[0], col[1], col[2], alpha ? col[3] : 1.0f); | const ImVec4 col_v4(col[0], col[1], col[2], alpha ? col[3] : 1.0f); | |||
if (ColorButton("##ColorButton", col_v4, flags)) | if (ColorButton("##ColorButton", col_v4, flags)) | |||
{ | { | |||
if (!(flags & ImGuiColorEditFlags_NoPicker)) | if (!(flags & ImGuiColorEditFlags_NoPicker)) | |||
{ | { | |||
// Store current color and open a picker | // Store current color and open a picker | |||
g.ColorPickerRef = col_v4; | g.ColorPickerRef = col_v4; | |||
OpenPopup("picker"); | OpenPopup("picker"); | |||
SetNextWindowPos(g.LastItemData.Rect.GetBL() + ImVec2(-1, style. ItemSpacing.y)); | SetNextWindowPos(g.LastItemData.Rect.GetBL() + ImVec2(0.0f, styl e.ItemSpacing.y)); | |||
} | } | |||
} | } | |||
if (!(flags & ImGuiColorEditFlags_NoOptions)) | if (!(flags & ImGuiColorEditFlags_NoOptions)) | |||
OpenPopupOnItemClick("context"); | OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight); | |||
if (BeginPopup("picker")) | if (BeginPopup("picker")) | |||
{ | { | |||
picker_active_window = g.CurrentWindow; | picker_active_window = g.CurrentWindow; | |||
if (label != label_display_end) | if (label != label_display_end) | |||
{ | { | |||
TextEx(label, label_display_end); | TextEx(label, label_display_end); | |||
Spacing(); | Spacing(); | |||
} | } | |||
ImGuiColorEditFlags picker_flags_to_forward = ImGuiColorEditFlags_Da taTypeMask_ | ImGuiColorEditFlags_PickerMask_ | ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_Alp haBar; | ImGuiColorEditFlags picker_flags_to_forward = ImGuiColorEditFlags_Da taTypeMask_ | ImGuiColorEditFlags_PickerMask_ | ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_Alp haBar; | |||
skipping to change at line 5239 | skipping to change at line 5193 | |||
if (!ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_ pc, current_off_unrotated)) | if (!ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_ pc, current_off_unrotated)) | |||
current_off_unrotated = ImTriangleClosestPoint(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; | float uu, vv, ww; | |||
ImTriangleBarycentricCoords(triangle_pa, triangle_pb, triangle_p c, current_off_unrotated, uu, vv, ww); | ImTriangleBarycentricCoords(triangle_pa, triangle_pb, triangle_p c, current_off_unrotated, uu, vv, ww); | |||
V = ImClamp(1.0f - vv, 0.0001f, 1.0f); | V = ImClamp(1.0f - vv, 0.0001f, 1.0f); | |||
S = ImClamp(uu / V, 0.0001f, 1.0f); | S = ImClamp(uu / V, 0.0001f, 1.0f); | |||
value_changed = value_changed_sv = true; | value_changed = value_changed_sv = true; | |||
} | } | |||
} | } | |||
if (!(flags & ImGuiColorEditFlags_NoOptions)) | if (!(flags & ImGuiColorEditFlags_NoOptions)) | |||
OpenPopupOnItemClick("context"); | OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight); | |||
} | } | |||
else if (flags & ImGuiColorEditFlags_PickerHueBar) | else if (flags & ImGuiColorEditFlags_PickerHueBar) | |||
{ | { | |||
// SV rectangle logic | // SV rectangle logic | |||
InvisibleButton("sv", ImVec2(sv_picker_size, sv_picker_size)); | InvisibleButton("sv", ImVec2(sv_picker_size, sv_picker_size)); | |||
if (IsItemActive()) | if (IsItemActive()) | |||
{ | { | |||
S = ImSaturate((io.MousePos.x - picker_pos.x) / (sv_picker_size - 1) ); | S = ImSaturate((io.MousePos.x - picker_pos.x) / (sv_picker_size - 1) ); | |||
V = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_si ze - 1)); | V = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_si ze - 1)); | |||
// Greatly reduces hue jitter and reset to 0 when hue == 255 and col or is rapidly modified using SV square. | // Greatly reduces hue jitter and reset to 0 when hue == 255 and col or is rapidly modified using SV square. | |||
if (g.ColorEditLastColor == ColorConvertFloat4ToU32(ImVec4(col[0], c ol[1], col[2], 0))) | if (g.ColorEditLastColor == ColorConvertFloat4ToU32(ImVec4(col[0], c ol[1], col[2], 0))) | |||
H = g.ColorEditLastHue; | H = g.ColorEditLastHue; | |||
value_changed = value_changed_sv = true; | value_changed = value_changed_sv = true; | |||
} | } | |||
if (!(flags & ImGuiColorEditFlags_NoOptions)) | if (!(flags & ImGuiColorEditFlags_NoOptions)) | |||
OpenPopupOnItemClick("context"); | OpenPopupOnItemClick("context", ImGuiPopupFlags_MouseButtonRight); | |||
// Hue bar logic | // Hue bar logic | |||
SetCursorScreenPos(ImVec2(bar0_pos_x, picker_pos.y)); | SetCursorScreenPos(ImVec2(bar0_pos_x, picker_pos.y)); | |||
InvisibleButton("hue", ImVec2(bars_width, sv_picker_size)); | InvisibleButton("hue", ImVec2(bars_width, sv_picker_size)); | |||
if (IsItemActive()) | if (IsItemActive()) | |||
{ | { | |||
H = ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size - 1) ); | H = ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size - 1) ); | |||
value_changed = value_changed_h = true; | value_changed = value_changed_h = true; | |||
} | } | |||
} | } | |||
skipping to change at line 6937 | skipping to change at line 6891 | |||
// The reference position stored in popup_pos will be used by Begin() to fin d a suitable position for the child menu, | // The reference position stored in popup_pos will be used by Begin() to fin d a suitable position for the child menu, | |||
// However the final position is going to be different! It is chosen by Find BestWindowPosForPopup(). | // However the final position is going to be different! It is chosen by Find BestWindowPosForPopup(). | |||
// e.g. Menus tend to overlap each other horizontally to amplify relative Z- ordering. | // e.g. Menus tend to overlap each other horizontally to amplify relative Z- ordering. | |||
ImVec2 popup_pos, pos = window->DC.CursorPos; | ImVec2 popup_pos, pos = window->DC.CursorPos; | |||
PushID(label); | PushID(label); | |||
if (!enabled) | if (!enabled) | |||
BeginDisabled(); | BeginDisabled(); | |||
const ImGuiMenuColumns* offsets = &window->DC.MenuColumns; | const ImGuiMenuColumns* offsets = &window->DC.MenuColumns; | |||
bool pressed; | bool pressed; | |||
const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_NoHolding ActiveID | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_DontClosePo pups; | ||||
if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) | if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) | |||
{ | { | |||
// Menu inside an horizontal menu bar | // Menu inside an horizontal menu bar | |||
// Selectable extend their highlight by half ItemSpacing in each directi on. | // Selectable extend their highlight by half ItemSpacing in each directi on. | |||
// For ChildMenu, the popup position will be overwritten by the call to FindBestWindowPosForPopup() in Begin() | // For ChildMenu, the popup position will be overwritten by the call to FindBestWindowPosForPopup() in Begin() | |||
popup_pos = ImVec2(pos.x - 1.0f - IM_FLOOR(style.ItemSpacing.x * 0.5f), pos.y - style.FramePadding.y + window->MenuBarHeight()); | popup_pos = ImVec2(pos.x - 1.0f - IM_FLOOR(style.ItemSpacing.x * 0.5f), pos.y - style.FramePadding.y + window->MenuBarHeight()); | |||
window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * 0.5f); | window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * 0.5f); | |||
PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0 f, style.ItemSpacing.y)); | PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0 f, style.ItemSpacing.y)); | |||
float w = label_size.x; | float w = label_size.x; | |||
ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->D C.CursorPos.y + window->DC.CurrLineTextBaseOffset); | ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->D C.CursorPos.y + window->DC.CurrLineTextBaseOffset); | |||
pressed = Selectable("", menu_is_open, ImGuiSelectableFlags_NoHoldingAct iveID | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_DontClosePopup s, ImVec2(w, 0.0f)); | pressed = Selectable("", menu_is_open, selectable_flags, ImVec2(w, 0.0f) ); | |||
RenderText(text_pos, label); | RenderText(text_pos, label); | |||
PopStyleVar(); | PopStyleVar(); | |||
window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * (-1.0f + 0.5f)) ; // -1 spacing to compensate the spacing added when Selectable() did a SameLine (). It would also work to call SameLine() ourselves after the PopStyleVar(). | window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * (-1.0f + 0.5f)) ; // -1 spacing to compensate the spacing added when Selectable() did a SameLine (). It would also work to call SameLine() ourselves after the PopStyleVar(). | |||
} | } | |||
else | else | |||
{ | { | |||
// Menu inside a regular/vertical menu | // Menu inside a regular/vertical menu | |||
// (In a typical menu window where all items are BeginMenu() or MenuItem () calls, extra_w will always be 0.0f. | // (In a typical menu window where all items are BeginMenu() or MenuItem () calls, extra_w will always be 0.0f. | |||
// Only when they are other items sticking out we're going to add spaci ng, yet only register minimum width into the layout system. | // Only when they are other items sticking out we're going to add spaci ng, yet only register minimum width into the layout system. | |||
popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y); | popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y); | |||
float icon_w = (icon && icon[0]) ? CalcTextSize(icon, NULL).x : 0.0f; | float icon_w = (icon && icon[0]) ? CalcTextSize(icon, NULL).x : 0.0f; | |||
float checkmark_w = IM_FLOOR(g.FontSize * 1.20f); | float checkmark_w = IM_FLOOR(g.FontSize * 1.20f); | |||
float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, 0 .0f, checkmark_w); // Feedback to next frame | float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, 0 .0f, checkmark_w); // Feedback to next frame | |||
float extra_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); | float extra_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); | |||
ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->D C.CursorPos.y + window->DC.CurrLineTextBaseOffset); | ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->D C.CursorPos.y + window->DC.CurrLineTextBaseOffset); | |||
pressed = Selectable("", menu_is_open, ImGuiSelectableFlags_NoHoldingAct iveID | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_DontClosePopup s | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, 0.0f)); | pressed = Selectable("", menu_is_open, selectable_flags | ImGuiSelectabl eFlags_SpanAvailWidth, ImVec2(min_w, 0.0f)); | |||
RenderText(text_pos, label); | RenderText(text_pos, label); | |||
if (icon_w > 0.0f) | if (icon_w > 0.0f) | |||
RenderText(pos + ImVec2(offsets->OffsetIcon, 0.0f), icon); | RenderText(pos + ImVec2(offsets->OffsetIcon, 0.0f), icon); | |||
RenderArrow(window->DrawList, pos + ImVec2(offsets->OffsetMark + extra_w + g.FontSize * 0.30f, 0.0f), GetColorU32(ImGuiCol_Text), ImGuiDir_Right); | RenderArrow(window->DrawList, pos + ImVec2(offsets->OffsetMark + extra_w + g.FontSize * 0.30f, 0.0f), GetColorU32(ImGuiCol_Text), ImGuiDir_Right); | |||
} | } | |||
if (!enabled) | if (!enabled) | |||
EndDisabled(); | EndDisabled(); | |||
const bool hovered = (g.HoveredId == id) && enabled; | const bool hovered = (g.HoveredId == id) && enabled; | |||
if (menuset_is_open) | if (menuset_is_open) | |||
End of changes. 33 change blocks. | ||||
163 lines changed or deleted | 101 lines changed or added |