|
|
|
@ -131,11 +131,8 @@
|
|
|
|
|
ImGui::NewFrame();
|
|
|
|
|
|
|
|
|
|
// 3) most of your application code here
|
|
|
|
|
ImGui::Begin("My window");
|
|
|
|
|
ImGui::Text("Hello, world.");
|
|
|
|
|
ImGui::End();
|
|
|
|
|
MyGameUpdate(); // may use ImGui functions
|
|
|
|
|
MyGameRender(); // may use ImGui functions
|
|
|
|
|
MyGameUpdate(); // may use any ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End();
|
|
|
|
|
MyGameRender(); // may use any ImGui functions
|
|
|
|
|
|
|
|
|
|
// 4) render & swap video buffers
|
|
|
|
|
ImGui::Render();
|
|
|
|
@ -153,8 +150,9 @@
|
|
|
|
|
Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code.
|
|
|
|
|
Also read releases logs https://github.com/ocornut/imgui/releases for more details.
|
|
|
|
|
|
|
|
|
|
- 2016/06/xx (1.xx) - removed ColorEditMode() and ImGuiColorEditMode in favor of ImGuiColorEditFlags and parameters to ColorEdit*() functions
|
|
|
|
|
- 2016/08/xx (1.XX) - removed ColorEditMode() and ImGuiColorEditMode in favor of ImGuiColorEditFlags and parameters to ColorEdit*() functions
|
|
|
|
|
replaced ColorEdit4() third parameter 'bool show_alpha=true' to 'ImGuiColorEditFlags flags=0x01' where ImGuiColorEditFlags_Alpha=0x01 for dodgy compatibility
|
|
|
|
|
- 2016/07/30 (1.50) - SameLine(x) with x>0.0f is now relative to left of column/group if any, and not always to left of window. This was sort of always the intent and hopefully breakage should be minimal.
|
|
|
|
|
- 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore.
|
|
|
|
|
If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you.
|
|
|
|
|
However if your TitleBg/TitleBgActive alpha was <1.0f you need to tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar.
|
|
|
|
@ -213,15 +211,15 @@
|
|
|
|
|
- 2015/05/27 (1.40) - removed the third 'repeat_if_held' parameter from Button() - sorry! it was rarely used and inconsistent. Use PushButtonRepeat(true) / PopButtonRepeat() to enable repeat on desired buttons.
|
|
|
|
|
- 2015/05/11 (1.40) - changed BeginPopup() API, takes a string identifier instead of a bool. ImGui needs to manage the open/closed state of popups. Call OpenPopup() to actually set the "open" state of a popup. BeginPopup() returns true if the popup is opened.
|
|
|
|
|
- 2015/05/03 (1.40) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same).
|
|
|
|
|
- 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function (will obsolete).
|
|
|
|
|
- 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function until 1.50.
|
|
|
|
|
- 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API
|
|
|
|
|
- 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive.
|
|
|
|
|
- 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead.
|
|
|
|
|
- 2015/03/17 (1.36) - renamed GetItemBoxMin()/GetItemBoxMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function (will obsolete).
|
|
|
|
|
- 2015/03/17 (1.36) - renamed GetItemBoxMin()/GetItemBoxMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function until 1.50.
|
|
|
|
|
- 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing
|
|
|
|
|
- 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function (will obsolete).
|
|
|
|
|
- 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function until 1.50.
|
|
|
|
|
- 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth (casing)
|
|
|
|
|
- 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function (will obsolete).
|
|
|
|
|
- 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function until 1.50.
|
|
|
|
|
- 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once.
|
|
|
|
|
- 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now.
|
|
|
|
|
- 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior
|
|
|
|
@ -393,10 +391,12 @@
|
|
|
|
|
e.g. when displaying a list of objects, using indices or pointers as ID will preserve the node open/closed state differently. experiment and see what makes more sense!
|
|
|
|
|
|
|
|
|
|
Q: How can I tell when ImGui wants my mouse/keyboard inputs and when I can pass them to my application?
|
|
|
|
|
A: You can read the 'io.WantCaptureXXX' flags in the ImGuiIO structure. Preferably read them after calling ImGui::NewFrame() to avoid those flags lagging by one frame.
|
|
|
|
|
A: You can read the 'io.WantCaptureXXX' flags in the ImGuiIO structure. Preferably read them after calling ImGui::NewFrame() to avoid those flags lagging by one frame, but either should be fine.
|
|
|
|
|
When 'io.WantCaptureMouse' or 'io.WantCaptureKeyboard' flags are set you may want to discard/hide the inputs from the rest of your application.
|
|
|
|
|
When 'io.WantInputsCharacters' is set to may want to notify your OS to popup an on-screen keyboard, if available.
|
|
|
|
|
ImGui is tracking dragging and widget activity that may occur outside the boundary of a window, so 'io.WantCaptureMouse' is a more accurate and complete than testing for ImGui::IsMouseHoveringAnyWindow().
|
|
|
|
|
(Advanced note: text input releases focus on Return 'KeyDown', so the following Return 'KeyUp' event that your application receive will typically have 'io.WantcaptureKeyboard=false'.
|
|
|
|
|
Depending on your application logic it may or not be inconvenient. You might want to track which key-downs were for ImGui (e.g. with an array of bool) and filter out the corresponding key-ups.)
|
|
|
|
|
|
|
|
|
|
Q: How can I load a different font than the default? (default is an embedded version of ProggyClean.ttf, rendered at size 13)
|
|
|
|
|
A: Use the font atlas to load the TTF file you want:
|
|
|
|
@ -490,9 +490,11 @@
|
|
|
|
|
- input text: flag to disable live update of the user buffer (also applies to float/int text input)
|
|
|
|
|
- input text: resize behavior - field could stretch when being edited? hover tooltip shows more text?
|
|
|
|
|
- input text: add ImGuiInputTextFlags_EnterToApply? (off #218)
|
|
|
|
|
- input text: add discard flag (e.g. ImGuiInputTextFlags_DiscardActiveBuffer) or make it easier to clear active focus for text replacement during edition (#725)
|
|
|
|
|
- input text multi-line: don't directly call AddText() which does an unnecessary vertex reserve for character count prior to clipping. and/or more line-based clipping to AddText(). and/or reorganize TextUnformatted/RenderText for more efficiency for large text (e.g TextUnformatted could clip and log separately, etc).
|
|
|
|
|
- input text multi-line: way to dynamically grow the buffer without forcing the user to initially allocate for worse case (follow up on #200)
|
|
|
|
|
- input text multi-line: line numbers? status bar? (follow up on #200)
|
|
|
|
|
- input text multi-line: behave better when user changes input buffer while editing is active (even though it is illegal behavior). namely, the change of buffer can create a scrollbar glitch (#725)
|
|
|
|
|
- input text: allow centering/positioning text so that ctrl+clicking Drag or Slider keeps the textual value at the same pixel position.
|
|
|
|
|
- input number: optional range min/max for Input*() functions
|
|
|
|
|
- input number: holding [-]/[+] buttons could increase the step speed non-linearly (or user-controlled)
|
|
|
|
@ -831,10 +833,7 @@ ImGuiIO::ImGuiIO()
|
|
|
|
|
|
|
|
|
|
// Set OS X style defaults based on __APPLE__ compile time flag
|
|
|
|
|
#ifdef __APPLE__
|
|
|
|
|
WordMovementUsesAltKey = true; // OS X style: Text editing cursor movement using Alt instead of Ctrl
|
|
|
|
|
ShortcutsUseSuperKey = true; // OS X style: Shortcuts using Cmd/Super instead of Ctrl
|
|
|
|
|
DoubleClickSelectsWord = true; // OS X style: Double click selects by word instead of selecting whole text
|
|
|
|
|
MultiSelectUsesSuperKey = true; // OS X style: Multi-selection in lists uses Cmd/Super instead of Ctrl
|
|
|
|
|
OSXBehaviors = true;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -865,7 +864,8 @@ void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
|
|
|
|
|
// HELPERS
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
#define IM_F32_TO_INT8(_VAL) ((int)((_VAL) * 255.0f + 0.5f))
|
|
|
|
|
#define IM_F32_TO_INT8_UNBOUND(_VAL) ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f))) // Unsaturated, for display purpose
|
|
|
|
|
#define IM_F32_TO_INT8_SAT(_VAL) ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) // Saturated, always output 0..255
|
|
|
|
|
|
|
|
|
|
// Play it nice with Windows users. Notepad in 2015 still doesn't display text data with Unix-style \n.
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
@ -896,6 +896,13 @@ int ImStrnicmp(const char* str1, const char* str2, int count)
|
|
|
|
|
return d;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ImStrncpy(char* dst, const char* src, int count)
|
|
|
|
|
{
|
|
|
|
|
if (count < 1) return;
|
|
|
|
|
strncpy(dst, src, (size_t)count);
|
|
|
|
|
dst[count-1] = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char* ImStrdup(const char *str)
|
|
|
|
|
{
|
|
|
|
|
size_t len = strlen(str) + 1;
|
|
|
|
@ -994,7 +1001,6 @@ ImU32 ImHash(const void* data, int data_size, ImU32 seed)
|
|
|
|
|
// - We don't do 'current += 2; continue;' after handling ### to keep the code smaller.
|
|
|
|
|
if (c == '#' && current[0] == '#' && current[1] == '#')
|
|
|
|
|
crc = seed;
|
|
|
|
|
|
|
|
|
|
crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -1186,13 +1192,27 @@ ImVec4 ImGui::ColorConvertU32ToFloat4(ImU32 in)
|
|
|
|
|
ImU32 ImGui::ColorConvertFloat4ToU32(const ImVec4& in)
|
|
|
|
|
{
|
|
|
|
|
ImU32 out;
|
|
|
|
|
out = ((ImU32)IM_F32_TO_INT8(ImSaturate(in.x)));
|
|
|
|
|
out |= ((ImU32)IM_F32_TO_INT8(ImSaturate(in.y))) << 8;
|
|
|
|
|
out |= ((ImU32)IM_F32_TO_INT8(ImSaturate(in.z))) << 16;
|
|
|
|
|
out |= ((ImU32)IM_F32_TO_INT8(ImSaturate(in.w))) << 24;
|
|
|
|
|
out = ((ImU32)IM_F32_TO_INT8_SAT(in.x));
|
|
|
|
|
out |= ((ImU32)IM_F32_TO_INT8_SAT(in.y)) << 8;
|
|
|
|
|
out |= ((ImU32)IM_F32_TO_INT8_SAT(in.z)) << 16;
|
|
|
|
|
out |= ((ImU32)IM_F32_TO_INT8_SAT(in.w)) << 24;
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ImU32 ImGui::GetColorU32(ImGuiCol idx, float alpha_mul)
|
|
|
|
|
{
|
|
|
|
|
ImVec4 c = GImGui->Style.Colors[idx];
|
|
|
|
|
c.w *= GImGui->Style.Alpha * alpha_mul;
|
|
|
|
|
return ImGui::ColorConvertFloat4ToU32(c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ImU32 ImGui::GetColorU32(const ImVec4& col)
|
|
|
|
|
{
|
|
|
|
|
ImVec4 c = col;
|
|
|
|
|
c.w *= GImGui->Style.Alpha;
|
|
|
|
|
return ImGui::ColorConvertFloat4ToU32(c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Convert rgb floats ([0-1],[0-1],[0-1]) to hsv floats ([0-1],[0-1],[0-1]), from Foley & van Dam p592
|
|
|
|
|
// Optimized http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv
|
|
|
|
|
void ImGui::ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v)
|
|
|
|
@ -1297,7 +1317,7 @@ void ImGuiStorage::Clear()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// std::lower_bound but without the bullshit
|
|
|
|
|
static ImVector<ImGuiStorage::Pair>::iterator LowerBound(ImVector<ImGuiStorage::Pair>& data, ImU32 key)
|
|
|
|
|
static ImVector<ImGuiStorage::Pair>::iterator LowerBound(ImVector<ImGuiStorage::Pair>& data, ImGuiID key)
|
|
|
|
|
{
|
|
|
|
|
ImVector<ImGuiStorage::Pair>::iterator first = data.begin();
|
|
|
|
|
ImVector<ImGuiStorage::Pair>::iterator last = data.end();
|
|
|
|
@ -1319,7 +1339,7 @@ static ImVector<ImGuiStorage::Pair>::iterator LowerBound(ImVector<ImGuiStorage::
|
|
|
|
|
return first;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ImGuiStorage::GetInt(ImU32 key, int default_val) const
|
|
|
|
|
int ImGuiStorage::GetInt(ImGuiID key, int default_val) const
|
|
|
|
|
{
|
|
|
|
|
ImVector<Pair>::iterator it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);
|
|
|
|
|
if (it == Data.end() || it->key != key)
|
|
|
|
@ -1327,12 +1347,12 @@ int ImGuiStorage::GetInt(ImU32 key, int default_val) const
|
|
|
|
|
return it->val_i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ImGuiStorage::GetBool(ImU32 key, bool default_val) const
|
|
|
|
|
bool ImGuiStorage::GetBool(ImGuiID key, bool default_val) const
|
|
|
|
|
{
|
|
|
|
|
return GetInt(key, default_val ? 1 : 0) != 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float ImGuiStorage::GetFloat(ImU32 key, float default_val) const
|
|
|
|
|
float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const
|
|
|
|
|
{
|
|
|
|
|
ImVector<Pair>::iterator it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);
|
|
|
|
|
if (it == Data.end() || it->key != key)
|
|
|
|
@ -1379,7 +1399,7 @@ void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// FIXME-OPT: Need a way to reuse the result of lower_bound when doing GetInt()/SetInt() - not too bad because it only happens on explicit interaction (maximum one a frame)
|
|
|
|
|
void ImGuiStorage::SetInt(ImU32 key, int val)
|
|
|
|
|
void ImGuiStorage::SetInt(ImGuiID key, int val)
|
|
|
|
|
{
|
|
|
|
|
ImVector<Pair>::iterator it = LowerBound(Data, key);
|
|
|
|
|
if (it == Data.end() || it->key != key)
|
|
|
|
@ -1390,12 +1410,12 @@ void ImGuiStorage::SetInt(ImU32 key, int val)
|
|
|
|
|
it->val_i = val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ImGuiStorage::SetBool(ImU32 key, bool val)
|
|
|
|
|
void ImGuiStorage::SetBool(ImGuiID key, bool val)
|
|
|
|
|
{
|
|
|
|
|
SetInt(key, val ? 1 : 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ImGuiStorage::SetFloat(ImU32 key, float val)
|
|
|
|
|
void ImGuiStorage::SetFloat(ImGuiID key, float val)
|
|
|
|
|
{
|
|
|
|
|
ImVector<Pair>::iterator it = LowerBound(Data, key);
|
|
|
|
|
if (it == Data.end() || it->key != key)
|
|
|
|
@ -1406,7 +1426,7 @@ void ImGuiStorage::SetFloat(ImU32 key, float val)
|
|
|
|
|
it->val_f = val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ImGuiStorage::SetVoidPtr(ImU32 key, void* val)
|
|
|
|
|
void ImGuiStorage::SetVoidPtr(ImGuiID key, void* val)
|
|
|
|
|
{
|
|
|
|
|
ImVector<Pair>::iterator it = LowerBound(Data, key);
|
|
|
|
|
if (it == Data.end() || it->key != key)
|
|
|
|
@ -1432,7 +1452,7 @@ ImGuiTextFilter::ImGuiTextFilter(const char* default_filter)
|
|
|
|
|
{
|
|
|
|
|
if (default_filter)
|
|
|
|
|
{
|
|
|
|
|
ImFormatString(InputBuf, IM_ARRAYSIZE(InputBuf), "%s", default_filter);
|
|
|
|
|
ImStrncpy(InputBuf, default_filter, IM_ARRAYSIZE(InputBuf));
|
|
|
|
|
Build();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
@ -1614,12 +1634,14 @@ float ImGuiSimpleColumns::CalcExtraSpace(float avail_w)
|
|
|
|
|
|
|
|
|
|
static void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height)
|
|
|
|
|
{
|
|
|
|
|
// Setting those fields so that SetScrollHere() can properly function after the end of our clipper usage.
|
|
|
|
|
// If we end up needing more accurate data (to e.g. use SameLine) we may as well make the clipper have a fourth step to let user process and display the last item in their list.
|
|
|
|
|
// Set cursor position and a few other things so that SetScrollHere() and Columns() can work when seeking cursor.
|
|
|
|
|
// FIXME: It is problematic that we have to do that here, because custom/equivalent end-user code would stumble on the same issue. Consider moving within SetCursorXXX functions?
|
|
|
|
|
ImGui::SetCursorPosY(pos_y);
|
|
|
|
|
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
|
|
|
|
window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height;
|
|
|
|
|
window->DC.PrevLineHeight = (line_height - GImGui->Style.ItemSpacing.y);
|
|
|
|
|
window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height; // Setting those fields so that SetScrollHere() can properly function after the end of our clipper usage.
|
|
|
|
|
window->DC.PrevLineHeight = (line_height - GImGui->Style.ItemSpacing.y); // If we end up needing more accurate data (to e.g. use SameLine) we may as well make the clipper have a fourth step to let user process and display the last item in their list.
|
|
|
|
|
if (window->DC.ColumnsCount > 1)
|
|
|
|
|
window->DC.ColumnsCellMinY = window->DC.CursorPos.y; // Setting this so that cell Y position are set properly
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Use case A: Begin() called from constructor with items_height<0, then called again from Sync() in StepNo 1
|
|
|
|
@ -1672,8 +1694,9 @@ bool ImGuiListClipper::Step()
|
|
|
|
|
if (ItemsCount == 1) { ItemsCount = -1; return false; }
|
|
|
|
|
float items_height = ImGui::GetCursorPosY() - StartPosY;
|
|
|
|
|
IM_ASSERT(items_height > 0.0f); // If this triggers, it means Item 0 hasn't moved the cursor vertically
|
|
|
|
|
ImGui::SetCursorPosY(StartPosY); // Rewind cursor so we can Begin() again, this time with a known height.
|
|
|
|
|
Begin(ItemsCount, items_height);
|
|
|
|
|
Begin(ItemsCount-1, items_height);
|
|
|
|
|
DisplayStart++;
|
|
|
|
|
DisplayEnd++;
|
|
|
|
|
StepNo = 3;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
@ -1765,6 +1788,12 @@ ImGuiID ImGuiWindow::GetID(const void* ptr)
|
|
|
|
|
return id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ImGuiID ImGuiWindow::GetIDNoKeepAlive(const char* str, const char* str_end)
|
|
|
|
|
{
|
|
|
|
|
ImGuiID seed = IDStack.back();
|
|
|
|
|
return ImHash(str, str_end ? (int)(str_end - str) : 0, seed);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// Internal API exposed in imgui_internal.h
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
@ -1823,7 +1852,7 @@ void ImGui::ItemSize(const ImVec2& size, float text_offset_y)
|
|
|
|
|
window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x);
|
|
|
|
|
window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y);
|
|
|
|
|
|
|
|
|
|
//window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, 0xFF0000FF, 4); // Debug
|
|
|
|
|
//window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // Debug
|
|
|
|
|
|
|
|
|
|
window->DC.PrevLineHeight = line_height;
|
|
|
|
|
window->DC.PrevLineTextBaseOffset = text_base_offset;
|
|
|
|
@ -1947,8 +1976,7 @@ float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x)
|
|
|
|
|
else if (wrap_pos_x > 0.0f)
|
|
|
|
|
wrap_pos_x += window->Pos.x - window->Scroll.x; // wrap_pos_x is provided is window local space
|
|
|
|
|
|
|
|
|
|
const float wrap_width = wrap_pos_x > 0.0f ? ImMax(wrap_pos_x - pos.x, 0.00001f) : 0.0f;
|
|
|
|
|
return wrap_width;
|
|
|
|
|
return ImMax(wrap_pos_x - pos.x, 1.0f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
@ -2235,14 +2263,11 @@ void ImGui::NewFrame()
|
|
|
|
|
window->SizeFull *= scale;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
else if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse))
|
|
|
|
|
{
|
|
|
|
|
// Scroll
|
|
|
|
|
if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse))
|
|
|
|
|
{
|
|
|
|
|
const int scroll_lines = (window->Flags & ImGuiWindowFlags_ComboBox) ? 3 : 5;
|
|
|
|
|
SetWindowScrollY(window, window->Scroll.y - g.IO.MouseWheel * window->CalcFontSize() * scroll_lines);
|
|
|
|
|
}
|
|
|
|
|
const int scroll_lines = (window->Flags & ImGuiWindowFlags_ComboBox) ? 3 : 5;
|
|
|
|
|
SetWindowScrollY(window, window->Scroll.y - g.IO.MouseWheel * window->CalcFontSize() * scroll_lines);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2260,6 +2285,15 @@ void ImGui::NewFrame()
|
|
|
|
|
window->Accessed = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Closing the focused window restore focus to the first active root window in descending z-order
|
|
|
|
|
if (g.FocusedWindow && !g.FocusedWindow->WasActive)
|
|
|
|
|
for (int i = g.Windows.Size-1; i >= 0; i--)
|
|
|
|
|
if (g.Windows[i]->WasActive && !(g.Windows[i]->Flags & ImGuiWindowFlags_ChildWindow))
|
|
|
|
|
{
|
|
|
|
|
FocusWindow(g.Windows[i]);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// No window should be open at the beginning of the frame.
|
|
|
|
|
// But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear.
|
|
|
|
|
g.CurrentWindowStack.resize(0);
|
|
|
|
@ -2670,10 +2704,10 @@ void ImGui::Render()
|
|
|
|
|
const ImVec2 size = cursor_data.Size;
|
|
|
|
|
const ImTextureID tex_id = g.IO.Fonts->TexID;
|
|
|
|
|
g.OverlayDrawList.PushTextureID(tex_id);
|
|
|
|
|
g.OverlayDrawList.AddImage(tex_id, pos+ImVec2(1,0), pos+ImVec2(1,0) + size, cursor_data.TexUvMin[1], cursor_data.TexUvMax[1], 0x30000000); // Shadow
|
|
|
|
|
g.OverlayDrawList.AddImage(tex_id, pos+ImVec2(2,0), pos+ImVec2(2,0) + size, cursor_data.TexUvMin[1], cursor_data.TexUvMax[1], 0x30000000); // Shadow
|
|
|
|
|
g.OverlayDrawList.AddImage(tex_id, pos, pos + size, cursor_data.TexUvMin[1], cursor_data.TexUvMax[1], 0xFF000000); // Black border
|
|
|
|
|
g.OverlayDrawList.AddImage(tex_id, pos, pos + size, cursor_data.TexUvMin[0], cursor_data.TexUvMax[0], 0xFFFFFFFF); // White fill
|
|
|
|
|
g.OverlayDrawList.AddImage(tex_id, pos+ImVec2(1,0), pos+ImVec2(1,0) + size, cursor_data.TexUvMin[1], cursor_data.TexUvMax[1], IM_COL32(0,0,0,48)); // Shadow
|
|
|
|
|
g.OverlayDrawList.AddImage(tex_id, pos+ImVec2(2,0), pos+ImVec2(2,0) + size, cursor_data.TexUvMin[1], cursor_data.TexUvMax[1], IM_COL32(0,0,0,48)); // Shadow
|
|
|
|
|
g.OverlayDrawList.AddImage(tex_id, pos, pos + size, cursor_data.TexUvMin[1], cursor_data.TexUvMax[1], IM_COL32(0,0,0,255)); // Black border
|
|
|
|
|
g.OverlayDrawList.AddImage(tex_id, pos, pos + size, cursor_data.TexUvMin[0], cursor_data.TexUvMax[0], IM_COL32(255,255,255,255)); // White fill
|
|
|
|
|
g.OverlayDrawList.PopTextureID();
|
|
|
|
|
}
|
|
|
|
|
if (!g.OverlayDrawList.VtxBuffer.empty())
|
|
|
|
@ -3897,16 +3931,10 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us
|
|
|
|
|
else
|
|
|
|
|
PushClipRect(fullscreen_rect.Min, fullscreen_rect.Max, true);
|
|
|
|
|
|
|
|
|
|
// New windows appears in front
|
|
|
|
|
if (!window_was_active)
|
|
|
|
|
{
|
|
|
|
|
window->AutoPosLastDirection = -1;
|
|
|
|
|
|
|
|
|
|
if (!(flags & ImGuiWindowFlags_NoFocusOnAppearing))
|
|
|
|
|
if (!(flags & (ImGuiWindowFlags_ChildWindow|ImGuiWindowFlags_Tooltip)) || (flags & ImGuiWindowFlags_Popup))
|
|
|
|
|
FocusWindow(window);
|
|
|
|
|
|
|
|
|
|
// Popup first latch mouse position, will position itself when it appears next frame
|
|
|
|
|
window->AutoPosLastDirection = -1;
|
|
|
|
|
if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api)
|
|
|
|
|
window->PosFloat = g.IO.MousePos;
|
|
|
|
|
}
|
|
|
|
@ -4083,7 +4111,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us
|
|
|
|
|
if (window->ScrollTarget.y < FLT_MAX)
|
|
|
|
|
{
|
|
|
|
|
float center_ratio = window->ScrollTargetCenterRatio.y;
|
|
|
|
|
window->Scroll.y = window->ScrollTarget.y - ((1.0f - center_ratio) * window->TitleBarHeight()) - (center_ratio * window->SizeFull.y);
|
|
|
|
|
window->Scroll.y = window->ScrollTarget.y - ((1.0f - center_ratio) * (window->TitleBarHeight() + window->MenuBarHeight())) - (center_ratio * window->SizeFull.y);
|
|
|
|
|
window->ScrollTarget.y = FLT_MAX;
|
|
|
|
|
}
|
|
|
|
|
window->Scroll = ImMax(window->Scroll, ImVec2(0.0f, 0.0f));
|
|
|
|
@ -4209,6 +4237,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us
|
|
|
|
|
|
|
|
|
|
// Setup drawing context
|
|
|
|
|
window->DC.IndentX = 0.0f + window->WindowPadding.x - window->Scroll.x;
|
|
|
|
|
window->DC.GroupOffsetX = 0.0f;
|
|
|
|
|
window->DC.ColumnsOffsetX = 0.0f;
|
|
|
|
|
window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.IndentX + window->DC.ColumnsOffsetX, window->TitleBarHeight() + window->MenuBarHeight() + window->WindowPadding.y - window->Scroll.y);
|
|
|
|
|
window->DC.CursorPos = window->DC.CursorStartPos;
|
|
|
|
@ -4243,6 +4272,11 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us
|
|
|
|
|
if (window->AutoFitFramesY > 0)
|
|
|
|
|
window->AutoFitFramesY--;
|
|
|
|
|
|
|
|
|
|
// New windows appears in front (we need to do that AFTER setting DC.CursorStartPos so our initial navigation reference rectangle can start around there)
|
|
|
|
|
if (!window_was_active && !(flags & ImGuiWindowFlags_NoFocusOnAppearing))
|
|
|
|
|
if (!(flags & (ImGuiWindowFlags_ChildWindow|ImGuiWindowFlags_Tooltip)) || (flags & ImGuiWindowFlags_Popup))
|
|
|
|
|
FocusWindow(window);
|
|
|
|
|
|
|
|
|
|
// Title bar
|
|
|
|
|
if (!(flags & ImGuiWindowFlags_NoTitleBar))
|
|
|
|
|
{
|
|
|
|
@ -4266,7 +4300,8 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us
|
|
|
|
|
if (style.WindowTitleAlign & ImGuiAlign_Center) pad_right = pad_left;
|
|
|
|
|
if (pad_left) text_min.x += g.FontSize + style.ItemInnerSpacing.x;
|
|
|
|
|
if (pad_right) text_max.x -= g.FontSize + style.ItemInnerSpacing.x;
|
|
|
|
|
RenderTextClipped(text_min, text_max, name, NULL, &text_size, style.WindowTitleAlign, NULL, &clip_max);
|
|
|
|
|
ImVec2 clip_min = ImVec2(text_min.x, window->Pos.y);
|
|
|
|
|
RenderTextClipped(text_min, text_max, name, NULL, &text_size, style.WindowTitleAlign, &clip_min, &clip_max);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Save clipped aabb so we can access it in constant-time in FindHoveredWindow()
|
|
|
|
@ -4907,8 +4942,7 @@ void ImGui::SetWindowFocus(const char* name)
|
|
|
|
|
{
|
|
|
|
|
if (name)
|
|
|
|
|
{
|
|
|
|
|
ImGuiWindow* window = FindWindowByName(name);
|
|
|
|
|
if (window)
|
|
|
|
|
if (ImGuiWindow* window = FindWindowByName(name))
|
|
|
|
|
FocusWindow(window);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
@ -5071,13 +5105,13 @@ ImVec2 ImGui::GetCursorPos()
|
|
|
|
|
|
|
|
|
|
float ImGui::GetCursorPosX()
|
|
|
|
|
{
|
|
|
|
|
ImGuiWindow* window = GetCurrentWindow();
|
|
|
|
|
ImGuiWindow* window = GetCurrentWindowRead();
|
|
|
|
|
return window->DC.CursorPos.x - window->Pos.x + window->Scroll.x;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float ImGui::GetCursorPosY()
|
|
|
|
|
{
|
|
|
|
|
ImGuiWindow* window = GetCurrentWindow();
|
|
|
|
|
ImGuiWindow* window = GetCurrentWindowRead();
|
|
|
|
|
return window->DC.CursorPos.y - window->Pos.y + window->Scroll.y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -5118,6 +5152,7 @@ void ImGui::SetCursorScreenPos(const ImVec2& screen_pos)
|
|
|
|
|
{
|
|
|
|
|
ImGuiWindow* window = GetCurrentWindow();
|
|
|
|
|
window->DC.CursorPos = screen_pos;
|
|
|
|
|
window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float ImGui::GetScrollX()
|
|
|
|
@ -5152,7 +5187,7 @@ void ImGui::SetScrollX(float scroll_x)
|
|
|
|
|
void ImGui::SetScrollY(float scroll_y)
|
|
|
|
|
{
|
|
|
|
|
ImGuiWindow* window = GetCurrentWindow();
|
|
|
|
|
window->ScrollTarget.y = scroll_y + window->TitleBarHeight(); // title bar height canceled out when using ScrollTargetRelY
|
|
|
|
|
window->ScrollTarget.y = scroll_y + window->TitleBarHeight() + window->MenuBarHeight(); // title bar height canceled out when using ScrollTargetRelY
|
|
|
|
|
window->ScrollTargetCenterRatio.y = 0.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -5355,9 +5390,7 @@ void ImGui::TextUnformatted(const char* text, const char* text_end)
|
|
|
|
|
const ImVec2 text_size = CalcTextSize(text_begin, text_end, false, wrap_width);
|
|
|
|
|
|
|
|
|
|
// Account of baseline offset
|
|
|
|
|
ImVec2 text_pos = window->DC.CursorPos;
|
|
|
|
|
text_pos.y += window->DC.CurrentLineTextBaseOffset;
|
|
|
|
|
|
|
|
|
|
ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrentLineTextBaseOffset);
|
|
|
|
|
ImRect bb(text_pos, text_pos + text_size);
|
|
|
|
|
ItemSize(text_size);
|
|
|
|
|
if (!ItemAdd(bb, NULL))
|
|
|
|
@ -6148,7 +6181,7 @@ void ImGui::BulletTextV(const char* fmt, va_list args)
|
|
|
|
|
|
|
|
|
|
const char* text_begin = g.TempBuffer;
|
|
|
|
|
const char* text_end = text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
|
|
|
|
|
const ImVec2 label_size = CalcTextSize(text_begin, text_end, true);
|
|
|
|
|
const ImVec2 label_size = CalcTextSize(text_begin, text_end, false);
|
|
|
|
|
const float text_base_offset_y = ImMax(0.0f, window->DC.CurrentLineTextBaseOffset); // Latch before ItemSize changes it
|
|
|
|
|
const float line_height = ImMax(ImMin(window->DC.CurrentLineHeight, g.FontSize + g.Style.FramePadding.y*2), g.FontSize);
|
|
|
|
|
const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize + (label_size.x > 0.0f ? (label_size.x + style.FramePadding.x*2) : 0.0f), ImMax(line_height, label_size.y))); // Empty text doesn't add padding
|
|
|
|
@ -6158,7 +6191,7 @@ void ImGui::BulletTextV(const char* fmt, va_list args)
|
|
|
|
|
|
|
|
|
|
// Render
|
|
|
|
|
RenderBullet(bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f));
|
|
|
|
|
RenderText(bb.Min+ImVec2(g.FontSize + style.FramePadding.x*2, text_base_offset_y), text_begin, text_end);
|
|
|
|
|
RenderText(bb.Min+ImVec2(g.FontSize + style.FramePadding.x*2, text_base_offset_y), text_begin, text_end, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ImGui::BulletText(const char* fmt, ...)
|
|
|
|
@ -7400,6 +7433,7 @@ static void STB_TEXTEDIT_DELETECHARS(STB_TEXTEDIT_STRING* obj, int pos, int n)
|
|
|
|
|
static bool STB_TEXTEDIT_INSERTCHARS(STB_TEXTEDIT_STRING* obj, int pos, const ImWchar* new_text, int new_text_len)
|
|
|
|
|
{
|
|
|
|
|
const int text_len = obj->CurLenW;
|
|
|
|
|
IM_ASSERT(pos <= text_len);
|
|
|
|
|
if (new_text_len + text_len + 1 > obj->Text.Size)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
@ -7607,10 +7641,6 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
|
|
|
|
|
// NB: we are only allowed to access 'edit_state' if we are the active widget.
|
|
|
|
|
ImGuiTextEditState& edit_state = g.InputTextState;
|
|
|
|
|
|
|
|
|
|
const bool is_ctrl_down = io.KeyCtrl;
|
|
|
|
|
const bool is_shift_down = io.KeyShift;
|
|
|
|
|
const bool is_alt_down = io.KeyAlt;
|
|
|
|
|
const bool is_super_down = io.KeySuper;
|
|
|
|
|
const bool focus_requested = FocusableItemRegister(window, g.ActiveId == id, (flags & (ImGuiInputTextFlags_CallbackCompletion|ImGuiInputTextFlags_AllowTabInput)) == 0); // Using completion callback disable keyboard tabbing
|
|
|
|
|
const bool focus_requested_by_code = focus_requested && (window->FocusIdxAllCounter == window->FocusIdxAllRequestCurrent);
|
|
|
|
|
const bool focus_requested_by_tab = focus_requested && !focus_requested_by_code;
|
|
|
|
@ -7622,7 +7652,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
|
|
|
|
|
g.MouseCursor = ImGuiMouseCursor_TextInput;
|
|
|
|
|
}
|
|
|
|
|
const bool user_clicked = hovered && io.MouseClicked[0];
|
|
|
|
|
const bool user_scrolled = is_multiline && g.ActiveId == 0 && edit_state.Id == id && g.ActiveIdPreviousFrame == draw_window->GetID("#SCROLLY");
|
|
|
|
|
const bool user_scrolled = is_multiline && g.ActiveId == 0 && edit_state.Id == id && g.ActiveIdPreviousFrame == draw_window->GetIDNoKeepAlive("#SCROLLY");
|
|
|
|
|
|
|
|
|
|
bool select_all = (g.ActiveId != id) && (flags & ImGuiInputTextFlags_AutoSelectAll) != 0;
|
|
|
|
|
if (focus_requested || user_clicked || user_scrolled)
|
|
|
|
@ -7633,9 +7663,9 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
|
|
|
|
|
// Take a copy of the initial buffer value (both in original UTF-8 format and converted to wchar)
|
|
|
|
|
// From the moment we focused we are ignoring the content of 'buf' (unless we are in read-only mode)
|
|
|
|
|
const int prev_len_w = edit_state.CurLenW;
|
|
|
|
|
edit_state.Text.resize(buf_size+1); // wchar count <= utf-8 count. we use +1 to make sure that .Data isn't NULL so it doesn't crash.
|
|
|
|
|
edit_state.InitialText.resize(buf_size+1); // utf-8. we use +1 to make sure that .Data isn't NULL so it doesn't crash.
|
|
|
|
|
ImFormatString(edit_state.InitialText.Data, edit_state.InitialText.Size, "%s", buf);
|
|
|
|
|
edit_state.Text.resize(buf_size+1); // wchar count <= UTF-8 count. we use +1 to make sure that .Data isn't NULL so it doesn't crash.
|
|
|
|
|
edit_state.InitialText.resize(buf_size+1); // UTF-8. we use +1 to make sure that .Data isn't NULL so it doesn't crash.
|
|
|
|
|
ImStrncpy(edit_state.InitialText.Data, buf, edit_state.InitialText.Size);
|
|
|
|
|
const char* buf_end = NULL;
|
|
|
|
|
edit_state.CurLenW = ImTextStrFromUtf8(edit_state.Text.Data, edit_state.Text.Size, buf, NULL, &buf_end);
|
|
|
|
|
edit_state.CurLenA = (int)(buf_end - buf); // We can't get the result from ImFormatString() above because it is not UTF-8 aware. Here we'll cut off malformed UTF-8.
|
|
|
|
@ -7660,7 +7690,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
|
|
|
|
|
}
|
|
|
|
|
if (flags & ImGuiInputTextFlags_AlwaysInsertMode)
|
|
|
|
|
edit_state.StbState.insert_mode = true;
|
|
|
|
|
if (!is_multiline && (focus_requested_by_tab || (user_clicked && is_ctrl_down)))
|
|
|
|
|
if (!is_multiline && (focus_requested_by_tab || (user_clicked && io.KeyCtrl)))
|
|
|
|
|
select_all = true;
|
|
|
|
|
}
|
|
|
|
|
SetActiveID(id, window);
|
|
|
|
@ -7695,15 +7725,16 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
|
|
|
|
|
g.ActiveIdAllowOverlap = !io.MouseDown[0];
|
|
|
|
|
|
|
|
|
|
// Edit in progress
|
|
|
|
|
const float mouse_x = (g.IO.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + edit_state.ScrollX;
|
|
|
|
|
const float mouse_y = (is_multiline ? (g.IO.MousePos.y - draw_window->DC.CursorPos.y - style.FramePadding.y) : (g.FontSize*0.5f));
|
|
|
|
|
const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + edit_state.ScrollX;
|
|
|
|
|
const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y - style.FramePadding.y) : (g.FontSize*0.5f));
|
|
|
|
|
|
|
|
|
|
if (select_all || (hovered && !io.DoubleClickSelectsWord && io.MouseDoubleClicked[0]))
|
|
|
|
|
const bool osx_double_click_selects_words = io.OSXBehaviors; // OS X style: Double click selects by word instead of selecting whole text
|
|
|
|
|
if (select_all || (hovered && !osx_double_click_selects_words && io.MouseDoubleClicked[0]))
|
|
|
|
|
{
|
|
|
|
|
edit_state.SelectAll();
|
|
|
|
|
edit_state.SelectedAllMouseLock = true;
|
|
|
|
|
}
|
|
|
|
|
else if (hovered && io.DoubleClickSelectsWord && io.MouseDoubleClicked[0])
|
|
|
|
|
else if (hovered && osx_double_click_selects_words && io.MouseDoubleClicked[0])
|
|
|
|
|
{
|
|
|
|
|
// Select a word only, OS X style (by simulating keystrokes)
|
|
|
|
|
edit_state.OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT);
|
|
|
|
@ -7723,14 +7754,14 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
|
|
|
|
|
if (edit_state.SelectedAllMouseLock && !io.MouseDown[0])
|
|
|
|
|
edit_state.SelectedAllMouseLock = false;
|
|
|
|
|
|
|
|
|
|
if (g.IO.InputCharacters[0])
|
|
|
|
|
if (io.InputCharacters[0])
|
|
|
|
|
{
|
|
|
|
|
// Process text input (before we check for Return because using some IME will effectively send a Return?)
|
|
|
|
|
// We ignore CTRL inputs, but need to allow CTRL+ALT as some keyboards (e.g. German) use AltGR - which is Alt+Ctrl - to input certain characters.
|
|
|
|
|
if (!(is_ctrl_down && !is_alt_down) && is_editable)
|
|
|
|
|
if (!(io.KeyCtrl && !io.KeyAlt) && is_editable)
|
|
|
|
|
{
|
|
|
|
|
for (int n = 0; n < IM_ARRAYSIZE(g.IO.InputCharacters) && g.IO.InputCharacters[n]; n++)
|
|
|
|
|
if (unsigned int c = (unsigned int)g.IO.InputCharacters[n])
|
|
|
|
|
for (int n = 0; n < IM_ARRAYSIZE(io.InputCharacters) && io.InputCharacters[n]; n++)
|
|
|
|
|
if (unsigned int c = (unsigned int)io.InputCharacters[n])
|
|
|
|
|
{
|
|
|
|
|
// Insert character if they pass filtering
|
|
|
|
|
if (!InputTextFilterCharacter(&c, flags, callback, user_data))
|
|
|
|
@ -7745,22 +7776,31 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
|
|
|
|
|
|
|
|
|
|
// Handle various key-presses
|
|
|
|
|
bool cancel_edit = false;
|
|
|
|
|
const int k_mask = (is_shift_down ? STB_TEXTEDIT_K_SHIFT : 0);
|
|
|
|
|
const bool is_shortcutkey_only = (io.ShortcutsUseSuperKey ? (is_super_down && !is_alt_down && !is_shift_down && !is_ctrl_down) : (is_ctrl_down && !is_alt_down && !is_shift_down && !is_super_down));
|
|
|
|
|
const bool is_wordmove_key_down = (io.WordMovementUsesAltKey ? io.KeyAlt : io.KeyCtrl);
|
|
|
|
|
const int k_mask = (io.KeyShift ? STB_TEXTEDIT_K_SHIFT : 0);
|
|
|
|
|
const bool is_shortcut_key_only = (io.OSXBehaviors ? (io.KeySuper && !io.KeyCtrl) : (io.KeyCtrl && !io.KeySuper)) && !io.KeyAlt && !io.KeyShift; // OS X style: Shortcuts using Cmd/Super instead of Ctrl
|
|
|
|
|
const bool is_wordmove_key_down = io.OSXBehaviors ? io.KeyAlt : io.KeyCtrl; // OS X style: Text editing cursor movement using Alt instead of Ctrl
|
|
|
|
|
const bool is_startend_key_down = io.OSXBehaviors && io.KeySuper && !io.KeyCtrl && !io.KeyAlt; // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End
|
|
|
|
|
|
|
|
|
|
if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { edit_state.OnKeyPressed(is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT | k_mask : STB_TEXTEDIT_K_LEFT | k_mask); }
|
|
|
|
|
else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { edit_state.OnKeyPressed(is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT | k_mask : STB_TEXTEDIT_K_RIGHT | k_mask); }
|
|
|
|
|
else if (is_multiline && IsKeyPressedMap(ImGuiKey_UpArrow)) { if (is_ctrl_down) SetWindowScrollY(draw_window, draw_window->Scroll.y - g.FontSize); else edit_state.OnKeyPressed(STB_TEXTEDIT_K_UP | k_mask); }
|
|
|
|
|
else if (is_multiline && IsKeyPressedMap(ImGuiKey_DownArrow)) { if (is_ctrl_down) SetWindowScrollY(draw_window, draw_window->Scroll.y + g.FontSize); else edit_state.OnKeyPressed(STB_TEXTEDIT_K_DOWN| k_mask); }
|
|
|
|
|
else if (IsKeyPressedMap(ImGuiKey_Home)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); }
|
|
|
|
|
else if (IsKeyPressedMap(ImGuiKey_End)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); }
|
|
|
|
|
if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); }
|
|
|
|
|
else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); }
|
|
|
|
|
else if (IsKeyPressedMap(ImGuiKey_UpArrow) && is_multiline) { if (io.KeyCtrl) SetWindowScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); }
|
|
|
|
|
else if (IsKeyPressedMap(ImGuiKey_DownArrow) && is_multiline) { if (io.KeyCtrl) SetWindowScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); }
|
|
|
|
|
else if (IsKeyPressedMap(ImGuiKey_Home)) { edit_state.OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); }
|
|
|
|
|
else if (IsKeyPressedMap(ImGuiKey_End)) { edit_state.OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); }
|
|
|
|
|
else if (IsKeyPressedMap(ImGuiKey_Delete) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); }
|
|
|
|
|
else if (IsKeyPressedMap(ImGuiKey_Backspace) && is_editable) { if (is_ctrl_down && !edit_state.HasSelection()) edit_state.OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT|STB_TEXTEDIT_K_SHIFT); edit_state.OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask); }
|
|
|
|
|
else if (IsKeyPressedMap(ImGuiKey_Backspace) && is_editable)
|
|
|
|
|
{
|
|
|
|
|
if (!edit_state.HasSelection())
|
|
|
|
|
{
|
|
|
|
|
if (is_wordmove_key_down) edit_state.OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT|STB_TEXTEDIT_K_SHIFT);
|
|
|
|
|
else if (io.OSXBehaviors && io.KeySuper && !io.KeyAlt && !io.KeyCtrl) edit_state.OnKeyPressed(STB_TEXTEDIT_K_LINESTART|STB_TEXTEDIT_K_SHIFT);
|
|
|
|
|
}
|
|
|
|
|
edit_state.OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask);
|
|
|
|
|
}
|
|
|
|
|
else if (IsKeyPressedMap(ImGuiKey_Enter))
|
|
|
|
|
{
|
|
|
|
|
bool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0;
|
|
|
|
|
if (!is_multiline || (ctrl_enter_for_new_line && !is_ctrl_down) || (!ctrl_enter_for_new_line && is_ctrl_down))
|
|
|
|
|
if (!is_multiline || (ctrl_enter_for_new_line && !io.KeyCtrl) || (!ctrl_enter_for_new_line && io.KeyCtrl))
|
|
|
|
|
{
|
|
|
|
|
SetActiveID(0);
|
|
|
|
|
enter_pressed = true;
|
|
|
|
@ -7772,30 +7812,30 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
|
|
|
|
|
edit_state.OnKeyPressed((int)c);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if ((flags & ImGuiInputTextFlags_AllowTabInput) && IsKeyPressedMap(ImGuiKey_Tab) && !is_ctrl_down && !is_shift_down && !is_alt_down && is_editable)
|
|
|
|
|
else if ((flags & ImGuiInputTextFlags_AllowTabInput) && IsKeyPressedMap(ImGuiKey_Tab) && !io.KeyCtrl && !io.KeyShift && !io.KeyAlt && is_editable)
|
|
|
|
|
{
|
|
|
|
|
unsigned int c = '\t'; // Insert TAB
|
|
|
|
|
if (InputTextFilterCharacter(&c, flags, callback, user_data))
|
|
|
|
|
edit_state.OnKeyPressed((int)c);
|
|
|
|
|
}
|
|
|
|
|
else if (IsKeyPressedMap(ImGuiKey_Escape)) { SetActiveID(0); cancel_edit = true; }
|
|
|
|
|
else if (is_shortcutkey_only && IsKeyPressedMap(ImGuiKey_Z) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_UNDO); edit_state.ClearSelection(); }
|
|
|
|
|
else if (is_shortcutkey_only && IsKeyPressedMap(ImGuiKey_Y) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_REDO); edit_state.ClearSelection(); }
|
|
|
|
|
else if (is_shortcutkey_only && IsKeyPressedMap(ImGuiKey_A)) { edit_state.SelectAll(); edit_state.CursorFollow = true; }
|
|
|
|
|
else if (is_shortcutkey_only && !is_password && ((IsKeyPressedMap(ImGuiKey_X) && is_editable) || IsKeyPressedMap(ImGuiKey_C)) && (!is_multiline || edit_state.HasSelection()))
|
|
|
|
|
else if (is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_Z) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_UNDO); edit_state.ClearSelection(); }
|
|
|
|
|
else if (is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_Y) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_REDO); edit_state.ClearSelection(); }
|
|
|
|
|
else if (is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_A)) { edit_state.SelectAll(); edit_state.CursorFollow = true; }
|
|
|
|
|
else if (is_shortcut_key_only && !is_password && ((IsKeyPressedMap(ImGuiKey_X) && is_editable) || IsKeyPressedMap(ImGuiKey_C)) && (!is_multiline || edit_state.HasSelection()))
|
|
|
|
|
{
|
|
|
|
|
// Cut, Copy
|
|
|
|
|
const bool cut = IsKeyPressedMap(ImGuiKey_X);
|
|
|
|
|
if (cut && !edit_state.HasSelection())
|
|
|
|
|
edit_state.SelectAll();
|
|
|
|
|
|
|
|
|
|
if (g.IO.SetClipboardTextFn)
|
|
|
|
|
if (io.SetClipboardTextFn)
|
|
|
|
|
{
|
|
|
|
|
const int ib = edit_state.HasSelection() ? ImMin(edit_state.StbState.select_start, edit_state.StbState.select_end) : 0;
|
|
|
|
|
const int ie = edit_state.HasSelection() ? ImMax(edit_state.StbState.select_start, edit_state.StbState.select_end) : edit_state.CurLenW;
|
|
|
|
|
edit_state.TempTextBuffer.resize((ie-ib) * 4 + 1);
|
|
|
|
|
ImTextStrToUtf8(edit_state.TempTextBuffer.Data, edit_state.TempTextBuffer.Size, edit_state.Text.Data+ib, edit_state.Text.Data+ie);
|
|
|
|
|
g.IO.SetClipboardTextFn(edit_state.TempTextBuffer.Data);
|
|
|
|
|
io.SetClipboardTextFn(edit_state.TempTextBuffer.Data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cut)
|
|
|
|
@ -7804,35 +7844,32 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
|
|
|
|
|
stb_textedit_cut(&edit_state, &edit_state.StbState);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (is_shortcutkey_only && IsKeyPressedMap(ImGuiKey_V) && is_editable)
|
|
|
|
|
else if (is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_V) && is_editable)
|
|
|
|
|
{
|
|
|
|
|
// Paste
|
|
|
|
|
if (g.IO.GetClipboardTextFn)
|
|
|
|
|
if (const char* clipboard = io.GetClipboardTextFn ? io.GetClipboardTextFn() : NULL)
|
|
|
|
|
{
|
|
|
|
|
if (const char* clipboard = g.IO.GetClipboardTextFn())
|
|
|
|
|
// Filter pasted buffer
|
|
|
|
|
const int clipboard_len = (int)strlen(clipboard);
|
|
|
|
|
ImWchar* clipboard_filtered = (ImWchar*)ImGui::MemAlloc((clipboard_len+1) * sizeof(ImWchar));
|
|
|
|
|
int clipboard_filtered_len = 0;
|
|
|
|
|
for (const char* s = clipboard; *s; )
|
|
|
|
|
{
|
|
|
|
|
// Remove new-line from pasted buffer
|
|
|
|
|
const int clipboard_len = (int)strlen(clipboard);
|
|
|
|
|
ImWchar* clipboard_filtered = (ImWchar*)ImGui::MemAlloc((clipboard_len+1) * sizeof(ImWchar));
|
|
|
|
|
int clipboard_filtered_len = 0;
|
|
|
|
|
for (const char* s = clipboard; *s; )
|
|
|
|
|
{
|
|
|
|
|
unsigned int c;
|
|
|
|
|
s += ImTextCharFromUtf8(&c, s, NULL);
|
|
|
|
|
if (c == 0)
|
|
|
|
|
break;
|
|
|
|
|
if (c >= 0x10000 || !InputTextFilterCharacter(&c, flags, callback, user_data))
|
|
|
|
|
continue;
|
|
|
|
|
clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c;
|
|
|
|
|
}
|
|
|
|
|
clipboard_filtered[clipboard_filtered_len] = 0;
|
|
|
|
|
if (clipboard_filtered_len > 0) // If everything was filtered, ignore the pasting operation
|
|
|
|
|
{
|
|
|
|
|
stb_textedit_paste(&edit_state, &edit_state.StbState, clipboard_filtered, clipboard_filtered_len);
|
|
|
|
|
edit_state.CursorFollow = true;
|
|
|
|
|
}
|
|
|
|
|
ImGui::MemFree(clipboard_filtered);
|
|
|
|
|
unsigned int c;
|
|
|
|
|
s += ImTextCharFromUtf8(&c, s, NULL);
|
|
|
|
|
if (c == 0)
|
|
|
|
|
break;
|
|
|
|
|
if (c >= 0x10000 || !InputTextFilterCharacter(&c, flags, callback, user_data))
|
|
|
|
|
continue;
|
|
|
|
|
clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c;
|
|
|
|
|
}
|
|
|
|
|
clipboard_filtered[clipboard_filtered_len] = 0;
|
|
|
|
|
if (clipboard_filtered_len > 0) // If everything was filtered, ignore the pasting operation
|
|
|
|
|
{
|
|
|
|
|
stb_textedit_paste(&edit_state, &edit_state.StbState, clipboard_filtered, clipboard_filtered_len);
|
|
|
|
|
edit_state.CursorFollow = true;
|
|
|
|
|
}
|
|
|
|
|
ImGui::MemFree(clipboard_filtered);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -7841,7 +7878,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
|
|
|
|
|
// Restore initial value
|
|
|
|
|
if (is_editable)
|
|
|
|
|
{
|
|
|
|
|
ImFormatString(buf, buf_size, "%s", edit_state.InitialText.Data);
|
|
|
|
|
ImStrncpy(buf, edit_state.InitialText.Data, buf_size);
|
|
|
|
|
value_changed = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -7927,28 +7964,33 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
|
|
|
|
|
// Copy back to user buffer
|
|
|
|
|
if (is_editable && strcmp(edit_state.TempTextBuffer.Data, buf) != 0)
|
|
|
|
|
{
|
|
|
|
|
ImFormatString(buf, buf_size, "%s", edit_state.TempTextBuffer.Data);
|
|
|
|
|
ImStrncpy(buf, edit_state.TempTextBuffer.Data, buf_size);
|
|
|
|
|
value_changed = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Render
|
|
|
|
|
// Select which buffer we are going to display. When ImGuiInputTextFlags_NoLiveEdit is set 'buf' might still be the old value. We set buf to NULL to prevent accidental usage from now on.
|
|
|
|
|
const char* buf_display = (g.ActiveId == id && is_editable) ? edit_state.TempTextBuffer.Data : buf; buf = NULL;
|
|
|
|
|
|
|
|
|
|
if (!is_multiline)
|
|
|
|
|
RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
|
|
|
|
|
|
|
|
|
|
// Render
|
|
|
|
|
const ImVec4 clip_rect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + size.x, frame_bb.Min.y + size.y); // Not using frame_bb.Max because we have adjusted size
|
|
|
|
|
ImVec2 render_pos = is_multiline ? draw_window->DC.CursorPos : frame_bb.Min + style.FramePadding;
|
|
|
|
|
ImVec2 text_size(0.f, 0.f);
|
|
|
|
|
if (g.ActiveId == id || (edit_state.Id == id && is_multiline && g.ActiveId == draw_window->GetID("#SCROLLY")))
|
|
|
|
|
const bool is_currently_scrolling = (edit_state.Id == id && is_multiline && g.ActiveId == draw_window->GetIDNoKeepAlive("#SCROLLY"));
|
|
|
|
|
if (g.ActiveId == id || is_currently_scrolling)
|
|
|
|
|
{
|
|
|
|
|
edit_state.CursorAnim += g.IO.DeltaTime;
|
|
|
|
|
edit_state.CursorAnim += io.DeltaTime;
|
|
|
|
|
|
|
|
|
|
// We need to:
|
|
|
|
|
// - Display the text (this can be more easily clipped)
|
|
|
|
|
// This is going to be messy. We need to:
|
|
|
|
|
// - Display the text (this alone can be more easily clipped)
|
|
|
|
|
// - Handle scrolling, highlight selection, display cursor (those all requires some form of 1d->2d cursor position calculation)
|
|
|
|
|
// - Measure text height (for scrollbar)
|
|
|
|
|
// We are attempting to do most of that in **one main pass** to minimize the computation cost (non-negligible for large amount of text) + 2nd pass for selection rendering (we could merge them by an extra refactoring effort)
|
|
|
|
|
// FIXME: This should occur on buf_display but we'd need to maintain cursor/select_start/select_end for UTF-8.
|
|
|
|
|
const ImWchar* text_begin = edit_state.Text.Data;
|
|
|
|
|
ImVec2 cursor_offset, select_start_offset;
|
|
|
|
|
|
|
|
|
@ -8062,7 +8104,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
draw_window->DrawList->AddText(g.Font, g.FontSize, render_pos - render_scroll, GetColorU32(ImGuiCol_Text), buf, buf+edit_state.CurLenA, 0.0f, is_multiline ? NULL : &clip_rect);
|
|
|
|
|
draw_window->DrawList->AddText(g.Font, g.FontSize, render_pos - render_scroll, GetColorU32(ImGuiCol_Text), buf_display, buf_display + edit_state.CurLenA, 0.0f, is_multiline ? NULL : &clip_rect);
|
|
|
|
|
|
|
|
|
|
// Draw blinking cursor
|
|
|
|
|
bool cursor_is_visible = (g.InputTextState.CursorAnim <= 0.0f) || fmodf(g.InputTextState.CursorAnim, 1.20f) <= 0.80f;
|
|
|
|
@ -8080,8 +8122,8 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
|
|
|
|
|
// Render text only
|
|
|
|
|
const char* buf_end = NULL;
|
|
|
|
|
if (is_multiline)
|
|
|
|
|
text_size = ImVec2(size.x, InputTextCalcTextLenAndLineCount(buf, &buf_end) * g.FontSize); // We don't need width
|
|
|
|
|
draw_window->DrawList->AddText(g.Font, g.FontSize, render_pos, GetColorU32(ImGuiCol_Text), buf, buf_end, 0.0f, is_multiline ? NULL : &clip_rect);
|
|
|
|
|
text_size = ImVec2(size.x, InputTextCalcTextLenAndLineCount(buf_display, &buf_end) * g.FontSize); // We don't need width
|
|
|
|
|
draw_window->DrawList->AddText(g.Font, g.FontSize, render_pos, GetColorU32(ImGuiCol_Text), buf_display, buf_end, 0.0f, is_multiline ? NULL : &clip_rect);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is_multiline)
|
|
|
|
@ -8089,6 +8131,8 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
|
|
|
|
|
Dummy(text_size + ImVec2(0.0f, g.FontSize)); // Always add room to scroll an extra line
|
|
|
|
|
EndChildFrame();
|
|
|
|
|
EndGroup();
|
|
|
|
|
if (g.ActiveId == id || is_currently_scrolling) // Set LastItemId which was lost by EndChild/EndGroup, so user can use IsItemActive()
|
|
|
|
|
window->DC.LastItemId = g.ActiveId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is_password)
|
|
|
|
@ -8096,7 +8140,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
|
|
|
|
|
|
|
|
|
|
// Log as text
|
|
|
|
|
if (g.LogEnabled && !is_password)
|
|
|
|
|
LogRenderedText(render_pos, buf, NULL);
|
|
|
|
|
LogRenderedText(render_pos, buf_display, NULL);
|
|
|
|
|
|
|
|
|
|
if (label_size.x > 0)
|
|
|
|
|
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
|
|
|
|
@ -8110,14 +8154,12 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
|
|
|
|
|
bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data)
|
|
|
|
|
{
|
|
|
|
|
IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); // call InputTextMultiline()
|
|
|
|
|
bool ret = InputTextEx(label, buf, (int)buf_size, ImVec2(0,0), flags, callback, user_data);
|
|
|
|
|
return ret;
|
|
|
|
|
return InputTextEx(label, buf, (int)buf_size, ImVec2(0,0), flags, callback, user_data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ImGui::InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data)
|
|
|
|
|
{
|
|
|
|
|
bool ret = InputTextEx(label, buf, (int)buf_size, size, flags | ImGuiInputTextFlags_Multiline, callback, user_data);
|
|
|
|
|
return ret;
|
|
|
|
|
return InputTextEx(label, buf, (int)buf_size, size, flags | ImGuiInputTextFlags_Multiline, callback, user_data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NB: scalar_format here must be a simple "%xx" format string with no prefix/suffix (unlike the Drag/Slider functions "display_format" argument)
|
|
|
|
@ -8851,7 +8893,7 @@ bool ImGui::ColorButton(const ImVec4& col, bool small_height, bool outline_borde
|
|
|
|
|
RenderFrame(bb.Min, bb.Max, GetColorU32(col), outline_border, style.FrameRounding);
|
|
|
|
|
|
|
|
|
|
if (hovered)
|
|
|
|
|
SetTooltip("Color:\n(%.2f,%.2f,%.2f,%.2f)\n#%02X%02X%02X%02X", col.x, col.y, col.z, col.w, IM_F32_TO_INT8(col.x), IM_F32_TO_INT8(col.y), IM_F32_TO_INT8(col.z), IM_F32_TO_INT8(col.z));
|
|
|
|
|
SetTooltip("Color:\n(%.2f,%.2f,%.2f,%.2f)\n#%02X%02X%02X%02X", col.x, col.y, col.z, col.w, IM_F32_TO_INT8_SAT(col.x), IM_F32_TO_INT8_SAT(col.y), IM_F32_TO_INT8_SAT(col.z), IM_F32_TO_INT8_SAT(col.z));
|
|
|
|
|
|
|
|
|
|
return pressed;
|
|
|
|
|
}
|
|
|
|
@ -8898,7 +8940,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
|
|
|
|
|
if (flags & ImGuiColorEditFlags_HSV)
|
|
|
|
|
ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]);
|
|
|
|
|
|
|
|
|
|
int i[4] = { IM_F32_TO_INT8(f[0]), IM_F32_TO_INT8(f[1]), IM_F32_TO_INT8(f[2]), IM_F32_TO_INT8(f[3]) };
|
|
|
|
|
int i[4] = { IM_F32_TO_INT8_UNBOUND(f[0]), IM_F32_TO_INT8_UNBOUND(f[1]), IM_F32_TO_INT8_UNBOUND(f[2]), IM_F32_TO_INT8_UNBOUND(f[3]) };
|
|
|
|
|
|
|
|
|
|
bool alpha = (flags & ImGuiColorEditFlags_Alpha) != 0;
|
|
|
|
|
bool value_changed = false;
|
|
|
|
@ -9004,7 +9046,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
|
|
|
|
|
|
|
|
|
|
// Recreate our own tooltip over's ColorButton() one because we want to display correct alpha here
|
|
|
|
|
if (IsItemHovered())
|
|
|
|
|
SetTooltip("Color:\n(%.2f,%.2f,%.2f,%.2f)\n#%02X%02X%02X%02X", col[0], col[1], col[2], col[3], IM_F32_TO_INT8(col[0]), IM_F32_TO_INT8(col[1]), IM_F32_TO_INT8(col[2]), IM_F32_TO_INT8(col[3]));
|
|
|
|
|
SetTooltip("Color:\n(%.2f,%.2f,%.2f,%.2f)\n#%02X%02X%02X%02X", col[0], col[1], col[2], col[3], IM_F32_TO_INT8_SAT(col[0]), IM_F32_TO_INT8_SAT(col[1]), IM_F32_TO_INT8_SAT(col[2]), IM_F32_TO_INT8_SAT(col[3]));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (label != label_display_end)
|
|
|
|
@ -9066,6 +9108,10 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
|
|
|
|
|
float bar0_pos_x = picker_pos.x + sv_picker_size + style.ItemInnerSpacing.x;
|
|
|
|
|
float bar1_pos_x = bar0_pos_x + bars_width + style.ItemInnerSpacing.x;
|
|
|
|
|
|
|
|
|
|
// Recreate our own tooltip over's ColorButton() one because we want to display correct alpha here
|
|
|
|
|
if (IsItemHovered())
|
|
|
|
|
SetTooltip("Color:\n(%.2f,%.2f,%.2f,%.2f)\n#%02X%02X%02X%02X", col[0], col[1], col[2], col[3], IM_F32_TO_INT8_SAT(col[0]), IM_F32_TO_INT8_SAT(col[1]), IM_F32_TO_INT8_SAT(col[2]), IM_F32_TO_INT8_SAT(col[3]));
|
|
|
|
|
|
|
|
|
|
float H,S,V;
|
|
|
|
|
ImGui::ColorConvertRGBtoHSV(col[0], col[1], col[2], H, S, V);
|
|
|
|
|
|
|
|
|
@ -9245,6 +9291,12 @@ bool ImGui::IsRectVisible(const ImVec2& size)
|
|
|
|
|
return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max)
|
|
|
|
|
{
|
|
|
|
|
ImGuiWindow* window = GetCurrentWindowRead();
|
|
|
|
|
return window->ClipRect.Overlaps(ImRect(rect_min, rect_max));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Lock horizontal starting position + capture group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.)
|
|
|
|
|
void ImGui::BeginGroup()
|
|
|
|
|
{
|
|
|
|
@ -9260,7 +9312,8 @@ void ImGui::BeginGroup()
|
|
|
|
|
group_data.BackupLogLinePosY = window->DC.LogLinePosY;
|
|
|
|
|
group_data.AdvanceCursor = true;
|
|
|
|
|
|
|
|
|
|
window->DC.IndentX = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffsetX;
|
|
|
|
|
window->DC.GroupOffsetX = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffsetX;
|
|
|
|
|
window->DC.IndentX = window->DC.GroupOffsetX;
|
|
|
|
|
window->DC.CursorMaxPos = window->DC.CursorPos;
|
|
|
|
|
window->DC.CurrentLineHeight = 0.0f;
|
|
|
|
|
window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f;
|
|
|
|
@ -9284,6 +9337,7 @@ void ImGui::EndGroup()
|
|
|
|
|
window->DC.CurrentLineHeight = group_data.BackupCurrentLineHeight;
|
|
|
|
|
window->DC.CurrentLineTextBaseOffset = group_data.BackupCurrentLineTextBaseOffset;
|
|
|
|
|
window->DC.IndentX = group_data.BackupIndentX;
|
|
|
|
|
window->DC.GroupOffsetX = window->DC.IndentX;
|
|
|
|
|
window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f;
|
|
|
|
|
|
|
|
|
|
if (group_data.AdvanceCursor)
|
|
|
|
@ -9300,7 +9354,7 @@ void ImGui::EndGroup()
|
|
|
|
|
|
|
|
|
|
// Gets back to previous line and continue with horizontal layout
|
|
|
|
|
// pos_x == 0 : follow right after previous item
|
|
|
|
|
// pos_x != 0 : align to specified x position
|
|
|
|
|
// pos_x != 0 : align to specified x position (relative to window/group left)
|
|
|
|
|
// spacing_w < 0 : use default spacing if pos_x == 0, no spacing if pos_x != 0
|
|
|
|
|
// spacing_w >= 0 : enforce spacing amount
|
|
|
|
|
void ImGui::SameLine(float pos_x, float spacing_w)
|
|
|
|
@ -9313,7 +9367,7 @@ void ImGui::SameLine(float pos_x, float spacing_w)
|
|
|
|
|
if (pos_x != 0.0f)
|
|
|
|
|
{
|
|
|
|
|
if (spacing_w < 0.0f) spacing_w = 0.0f;
|
|
|
|
|
window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + pos_x + spacing_w;
|
|
|
|
|
window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + pos_x + spacing_w + window->DC.GroupOffsetX + window->DC.ColumnsOffsetX;
|
|
|
|
|
window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
@ -9340,37 +9394,34 @@ void ImGui::NewLine()
|
|
|
|
|
void ImGui::NextColumn()
|
|
|
|
|
{
|
|
|
|
|
ImGuiWindow* window = GetCurrentWindow();
|
|
|
|
|
if (window->SkipItems)
|
|
|
|
|
if (window->SkipItems || window->DC.ColumnsCount <= 1)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
|
|
if (window->DC.ColumnsCount > 1)
|
|
|
|
|
PopItemWidth();
|
|
|
|
|
PopClipRect();
|
|
|
|
|
|
|
|
|
|
window->DC.ColumnsCellMaxY = ImMax(window->DC.ColumnsCellMaxY, window->DC.CursorPos.y);
|
|
|
|
|
if (++window->DC.ColumnsCurrent < window->DC.ColumnsCount)
|
|
|
|
|
{
|
|
|
|
|
PopItemWidth();
|
|
|
|
|
PopClipRect();
|
|
|
|
|
|
|
|
|
|
window->DC.ColumnsCellMaxY = ImMax(window->DC.ColumnsCellMaxY, window->DC.CursorPos.y);
|
|
|
|
|
if (++window->DC.ColumnsCurrent < window->DC.ColumnsCount)
|
|
|
|
|
{
|
|
|
|
|
// Columns 1+ cancel out IndentX
|
|
|
|
|
window->DC.ColumnsOffsetX = GetColumnOffset(window->DC.ColumnsCurrent) - window->DC.IndentX + g.Style.ItemSpacing.x;
|
|
|
|
|
window->DrawList->ChannelsSetCurrent(window->DC.ColumnsCurrent);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
window->DC.ColumnsCurrent = 0;
|
|
|
|
|
window->DC.ColumnsOffsetX = 0.0f;
|
|
|
|
|
window->DC.ColumnsCellMinY = window->DC.ColumnsCellMaxY;
|
|
|
|
|
window->DrawList->ChannelsSetCurrent(0);
|
|
|
|
|
}
|
|
|
|
|
window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX);
|
|
|
|
|
window->DC.CursorPos.y = window->DC.ColumnsCellMinY;
|
|
|
|
|
window->DC.CurrentLineHeight = 0.0f;
|
|
|
|
|
window->DC.CurrentLineTextBaseOffset = 0.0f;
|
|
|
|
|
|
|
|
|
|
PushColumnClipRect();
|
|
|
|
|
PushItemWidth(GetColumnWidth() * 0.65f); // FIXME: Move on columns setup
|
|
|
|
|
// Columns 1+ cancel out IndentX
|
|
|
|
|
window->DC.ColumnsOffsetX = GetColumnOffset(window->DC.ColumnsCurrent) - window->DC.IndentX + g.Style.ItemSpacing.x;
|
|
|
|
|
window->DrawList->ChannelsSetCurrent(window->DC.ColumnsCurrent);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
window->DC.ColumnsCurrent = 0;
|
|
|
|
|
window->DC.ColumnsOffsetX = 0.0f;
|
|
|
|
|
window->DC.ColumnsCellMinY = window->DC.ColumnsCellMaxY;
|
|
|
|
|
window->DrawList->ChannelsSetCurrent(0);
|
|
|
|
|
}
|
|
|
|
|
window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX);
|
|
|
|
|
window->DC.CursorPos.y = window->DC.ColumnsCellMinY;
|
|
|
|
|
window->DC.CurrentLineHeight = 0.0f;
|
|
|
|
|
window->DC.CurrentLineTextBaseOffset = 0.0f;
|
|
|
|
|
|
|
|
|
|
PushColumnClipRect();
|
|
|
|
|
PushItemWidth(GetColumnWidth() * 0.65f); // FIXME: Move on columns setup
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ImGui::GetColumnIndex()
|
|
|
|
@ -9499,7 +9550,7 @@ void ImGui::Columns(int columns_count, const char* id, bool border)
|
|
|
|
|
if (held)
|
|
|
|
|
{
|
|
|
|
|
if (g.ActiveIdIsJustActivated)
|
|
|
|
|
g.ActiveIdClickOffset.x -= 4; // Store from center of column line
|
|
|
|
|
g.ActiveIdClickOffset.x -= 4; // Store from center of column line (we used a 8 wide rect for columns clicking)
|
|
|
|
|
x = GetDraggedColumnOffset(i);
|
|
|
|
|
SetColumnOffset(i, x);
|
|
|
|
|
}
|
|
|
|
@ -9632,7 +9683,7 @@ void ImGui::ValueColor(const char* prefix, const ImVec4& v)
|
|
|
|
|
ColorButton(v, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ImGui::ValueColor(const char* prefix, unsigned int v)
|
|
|
|
|
void ImGui::ValueColor(const char* prefix, ImU32 v)
|
|
|
|
|
{
|
|
|
|
|
Text("%s: %08X", prefix, v);
|
|
|
|
|
SameLine();
|
|
|
|
@ -9664,12 +9715,8 @@ void ImGui::ValueColor(const char* prefix, unsigned int v)
|
|
|
|
|
|
|
|
|
|
static const char* GetClipboardTextFn_DefaultImpl()
|
|
|
|
|
{
|
|
|
|
|
static char* buf_local = NULL;
|
|
|
|
|
if (buf_local)
|
|
|
|
|
{
|
|
|
|
|
ImGui::MemFree(buf_local);
|
|
|
|
|
buf_local = NULL;
|
|
|
|
|
}
|
|
|
|
|
static ImVector<char> buf_local;
|
|
|
|
|
buf_local.clear();
|
|
|
|
|
if (!OpenClipboard(NULL))
|
|
|
|
|
return NULL;
|
|
|
|
|
HANDLE wbuf_handle = GetClipboardData(CF_UNICODETEXT);
|
|
|
|
@ -9678,19 +9725,18 @@ static const char* GetClipboardTextFn_DefaultImpl()
|
|
|
|
|
if (ImWchar* wbuf_global = (ImWchar*)GlobalLock(wbuf_handle))
|
|
|
|
|
{
|
|
|
|
|
int buf_len = ImTextCountUtf8BytesFromStr(wbuf_global, NULL) + 1;
|
|
|
|
|
buf_local = (char*)ImGui::MemAlloc(buf_len * sizeof(char));
|
|
|
|
|
ImTextStrToUtf8(buf_local, buf_len, wbuf_global, NULL);
|
|
|
|
|
buf_local.resize(buf_len);
|
|
|
|
|
ImTextStrToUtf8(buf_local.Data, buf_len, wbuf_global, NULL);
|
|
|
|
|
}
|
|
|
|
|
GlobalUnlock(wbuf_handle);
|
|
|
|
|
CloseClipboard();
|
|
|
|
|
return buf_local;
|
|
|
|
|
return buf_local.Data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void SetClipboardTextFn_DefaultImpl(const char* text)
|
|
|
|
|
{
|
|
|
|
|
if (!OpenClipboard(NULL))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
const int wbuf_length = ImTextCountCharsFromUtf8(text, NULL) + 1;
|
|
|
|
|
HGLOBAL wbuf_handle = GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(ImWchar));
|
|
|
|
|
if (wbuf_handle == NULL)
|
|
|
|
@ -9729,7 +9775,7 @@ static void SetClipboardTextFn_DefaultImpl(const char* text)
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Win32 API IME support (for Asian languages, etc.)
|
|
|
|
|
#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS)
|
|
|
|
|
#if defined(_WIN32) && !defined(__GNUC__) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS)
|
|
|
|
|
|
|
|
|
|
#include <imm.h>
|
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
@ -9847,6 +9893,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
|
|
|
|
|
return;
|
|
|
|
|
NodeDrawList(window->DrawList, "DrawList");
|
|
|
|
|
ImGui::BulletText("Size: (%.1f,%.1f), SizeContents (%.1f,%.1f)", window->Size.x, window->Size.y, window->SizeContents.x, window->SizeContents.y);
|
|
|
|
|
ImGui::BulletText("Scroll: (%.2f,%.2f)", window->Scroll.x, window->Scroll.y);
|
|
|
|
|
if (window->RootWindow != window) NodeWindow(window->RootWindow, "RootWindow");
|
|
|
|
|
if (window->DC.ChildWindows.Size > 0) NodeWindows(window->DC.ChildWindows, "ChildWindows");
|
|
|
|
|
ImGui::BulletText("Storage: %d bytes", window->StateStorage.Data.Size * (int)sizeof(ImGuiStorage::Pair));
|
|
|
|
|