Merge remote-tracking branch 'origin' into 2016-02-colorpicker

This commit is contained in:
ocornut 2016-08-11 22:53:26 +02:00
commit 996eb080fa
9 changed files with 279 additions and 223 deletions

View File

@ -168,13 +168,14 @@ Inspiration, feedback, and testing for early versions: Casey Muratori, Atman Bin
Ongoing ImGui development is financially supported on [**Patreon**](http://www.patreon.com/imgui). Ongoing ImGui development is financially supported on [**Patreon**](http://www.patreon.com/imgui).
Double-chocolate sponsors: Double-chocolate sponsors:
- Media Molecule, Mobigame - Media Molecule
- Mobigame
Salty caramel supporters: Salty caramel supporters:
- Jetha Chan, Wild Sheep Studio, Pastagames, Mārtiņš Možeiko, Daniel Collin, Stefano Cristiano, Chris Genova, ikrima - Jetha Chan, Wild Sheep Studio, Pastagames, Mārtiņš Možeiko, Daniel Collin, Stefano Cristiano, Chris Genova, ikrima, Glenn Fiedler, Geoffrey Evans, Dakko Dakko.
Caramel supporters: Caramel supporters:
- Michel Courtine, César Leblic, Dale Kim, Alex Evans, Rui Figueira, Paul Patrashcu, Jerome Lanquetot, Ctrl Alt Ninja, Paul Fleming, Neil Henning, Stephan Dilly, Neil Blakey-Milner, Aleksei, NeiloGD, Justin Paver, FiniteSol, Vincent Pancaldi, James Billot, Robin Hübner, furrtek, Eric, Simon Barratt, Game Atelier, Julian Bosch, Simon Lundmark, Vincent Hamm, Farhan Wali, Jeff Roberts, Matt Reyer, Colin Riley. - Michel Courtine, César Leblic, Dale Kim, Alex Evans, Rui Figueira, Paul Patrashcu, Jerome Lanquetot, Ctrl Alt Ninja, Paul Fleming, Neil Henning, Stephan Dilly, Neil Blakey-Milner, Aleksei, NeiloGD, Justin Paver, FiniteSol, Vincent Pancaldi, James Billot, Robin Hübner, furrtek, Eric, Simon Barratt, Game Atelier, Julian Bosch, Simon Lundmark, Vincent Hamm, Farhan Wali, Jeff Roberts, Matt Reyer, Colin Riley, Victor Martins, Josh Simmons, Garrett Hoofman, Sergio Gonzales, Andrew Berridge, Roy Eltham, Game Preservation Society.
And other supporters; thanks! And other supporters; thanks!

View File

@ -152,7 +152,6 @@ bool ImGui_ImplSdlGL3_ProcessEvent(SDL_Event* event)
} }
case SDL_TEXTINPUT: case SDL_TEXTINPUT:
{ {
ImGuiIO& io = ImGui::GetIO();
io.AddInputCharactersUTF8(event->text.text); io.AddInputCharactersUTF8(event->text.text);
return true; return true;
} }
@ -186,6 +185,7 @@ void ImGui_ImplSdlGL3_CreateFontsTexture()
glBindTexture(GL_TEXTURE_2D, g_FontTexture); glBindTexture(GL_TEXTURE_2D, g_FontTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// Store our identifier // Store our identifier

View File

@ -131,7 +131,6 @@ bool ImGui_ImplSdl_ProcessEvent(SDL_Event* event)
} }
case SDL_TEXTINPUT: case SDL_TEXTINPUT:
{ {
ImGuiIO& io = ImGui::GetIO();
io.AddInputCharactersUTF8(event->text.text); io.AddInputCharactersUTF8(event->text.text);
return true; return true;
} }
@ -165,6 +164,7 @@ bool ImGui_ImplSdl_CreateDeviceObjects()
glBindTexture(GL_TEXTURE_2D, g_FontTexture); glBindTexture(GL_TEXTURE_2D, g_FontTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels); glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels);
// Store our identifier // Store our identifier

421
imgui.cpp
View File

@ -131,11 +131,8 @@
ImGui::NewFrame(); ImGui::NewFrame();
// 3) most of your application code here // 3) most of your application code here
ImGui::Begin("My window"); MyGameUpdate(); // may use any ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End();
ImGui::Text("Hello, world."); MyGameRender(); // may use any ImGui functions
ImGui::End();
MyGameUpdate(); // may use ImGui functions
MyGameRender(); // may use ImGui functions
// 4) render & swap video buffers // 4) render & swap video buffers
ImGui::Render(); 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. 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. 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 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. - 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. 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. 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/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/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/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/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. - 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. - 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/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/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/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/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 - 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! 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? 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.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. 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(). 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) 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: 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: 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: resize behavior - field could stretch when being edited? hover tooltip shows more text?
- input text: add ImGuiInputTextFlags_EnterToApply? (off #218) - 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: 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: 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: 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 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: optional range min/max for Input*() functions
- input number: holding [-]/[+] buttons could increase the step speed non-linearly (or user-controlled) - 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 // Set OS X style defaults based on __APPLE__ compile time flag
#ifdef __APPLE__ #ifdef __APPLE__
WordMovementUsesAltKey = true; // OS X style: Text editing cursor movement using Alt instead of Ctrl OSXBehaviors = true;
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
#endif #endif
} }
@ -865,7 +864,8 @@ void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
// HELPERS // 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. // Play it nice with Windows users. Notepad in 2015 still doesn't display text data with Unix-style \n.
#ifdef _WIN32 #ifdef _WIN32
@ -896,6 +896,13 @@ int ImStrnicmp(const char* str1, const char* str2, int count)
return d; 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) char* ImStrdup(const char *str)
{ {
size_t len = strlen(str) + 1; 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. // - We don't do 'current += 2; continue;' after handling ### to keep the code smaller.
if (c == '#' && current[0] == '#' && current[1] == '#') if (c == '#' && current[0] == '#' && current[1] == '#')
crc = seed; crc = seed;
crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c]; crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
} }
} }
@ -1186,13 +1192,27 @@ ImVec4 ImGui::ColorConvertU32ToFloat4(ImU32 in)
ImU32 ImGui::ColorConvertFloat4ToU32(const ImVec4& in) ImU32 ImGui::ColorConvertFloat4ToU32(const ImVec4& in)
{ {
ImU32 out; ImU32 out;
out = ((ImU32)IM_F32_TO_INT8(ImSaturate(in.x))); out = ((ImU32)IM_F32_TO_INT8_SAT(in.x));
out |= ((ImU32)IM_F32_TO_INT8(ImSaturate(in.y))) << 8; out |= ((ImU32)IM_F32_TO_INT8_SAT(in.y)) << 8;
out |= ((ImU32)IM_F32_TO_INT8(ImSaturate(in.z))) << 16; out |= ((ImU32)IM_F32_TO_INT8_SAT(in.z)) << 16;
out |= ((ImU32)IM_F32_TO_INT8(ImSaturate(in.w))) << 24; out |= ((ImU32)IM_F32_TO_INT8_SAT(in.w)) << 24;
return out; 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 // 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 // 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) 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 // 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 first = data.begin();
ImVector<ImGuiStorage::Pair>::iterator last = data.end(); ImVector<ImGuiStorage::Pair>::iterator last = data.end();
@ -1319,7 +1339,7 @@ static ImVector<ImGuiStorage::Pair>::iterator LowerBound(ImVector<ImGuiStorage::
return first; 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); ImVector<Pair>::iterator it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);
if (it == Data.end() || it->key != 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; 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; 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); ImVector<Pair>::iterator it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);
if (it == Data.end() || it->key != 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) // 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); ImVector<Pair>::iterator it = LowerBound(Data, key);
if (it == Data.end() || it->key != key) if (it == Data.end() || it->key != key)
@ -1390,12 +1410,12 @@ void ImGuiStorage::SetInt(ImU32 key, int val)
it->val_i = val; it->val_i = val;
} }
void ImGuiStorage::SetBool(ImU32 key, bool val) void ImGuiStorage::SetBool(ImGuiID key, bool val)
{ {
SetInt(key, val ? 1 : 0); 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); ImVector<Pair>::iterator it = LowerBound(Data, key);
if (it == Data.end() || it->key != key) if (it == Data.end() || it->key != key)
@ -1406,7 +1426,7 @@ void ImGuiStorage::SetFloat(ImU32 key, float val)
it->val_f = 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); ImVector<Pair>::iterator it = LowerBound(Data, key);
if (it == Data.end() || it->key != key) if (it == Data.end() || it->key != key)
@ -1432,7 +1452,7 @@ ImGuiTextFilter::ImGuiTextFilter(const char* default_filter)
{ {
if (default_filter) if (default_filter)
{ {
ImFormatString(InputBuf, IM_ARRAYSIZE(InputBuf), "%s", default_filter); ImStrncpy(InputBuf, default_filter, IM_ARRAYSIZE(InputBuf));
Build(); Build();
} }
else else
@ -1614,12 +1634,14 @@ float ImGuiSimpleColumns::CalcExtraSpace(float avail_w)
static void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height) 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. // Set cursor position and a few other things so that SetScrollHere() and Columns() can work when seeking cursor.
// 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. // 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); ImGui::SetCursorPosY(pos_y);
ImGuiWindow* window = ImGui::GetCurrentWindow(); ImGuiWindow* window = ImGui::GetCurrentWindow();
window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height; 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); 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 // 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; } if (ItemsCount == 1) { ItemsCount = -1; return false; }
float items_height = ImGui::GetCursorPosY() - StartPosY; 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 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-1, items_height);
Begin(ItemsCount, items_height); DisplayStart++;
DisplayEnd++;
StepNo = 3; StepNo = 3;
return true; return true;
} }
@ -1765,6 +1788,12 @@ ImGuiID ImGuiWindow::GetID(const void* ptr)
return id; 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 // 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.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x);
window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y); 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.PrevLineHeight = line_height;
window->DC.PrevLineTextBaseOffset = text_base_offset; 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) 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 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 ImMax(wrap_pos_x - pos.x, 1.0f);
return wrap_width;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -2235,14 +2263,11 @@ void ImGui::NewFrame()
window->SizeFull *= scale; window->SizeFull *= scale;
} }
} }
else else if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse))
{ {
// Scroll // 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; 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. // 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. // 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); g.CurrentWindowStack.resize(0);
@ -2670,10 +2704,10 @@ void ImGui::Render()
const ImVec2 size = cursor_data.Size; const ImVec2 size = cursor_data.Size;
const ImTextureID tex_id = g.IO.Fonts->TexID; const ImTextureID tex_id = g.IO.Fonts->TexID;
g.OverlayDrawList.PushTextureID(tex_id); 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(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], 0x30000000); // 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], 0xFF000000); // Black border 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], 0xFFFFFFFF); // White fill 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(); g.OverlayDrawList.PopTextureID();
} }
if (!g.OverlayDrawList.VtxBuffer.empty()) 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 else
PushClipRect(fullscreen_rect.Min, fullscreen_rect.Max, true); PushClipRect(fullscreen_rect.Min, fullscreen_rect.Max, true);
// New windows appears in front
if (!window_was_active) 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 // 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) if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api)
window->PosFloat = g.IO.MousePos; 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) if (window->ScrollTarget.y < FLT_MAX)
{ {
float center_ratio = window->ScrollTargetCenterRatio.y; 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->ScrollTarget.y = FLT_MAX;
} }
window->Scroll = ImMax(window->Scroll, ImVec2(0.0f, 0.0f)); 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 // Setup drawing context
window->DC.IndentX = 0.0f + window->WindowPadding.x - window->Scroll.x; window->DC.IndentX = 0.0f + window->WindowPadding.x - window->Scroll.x;
window->DC.GroupOffsetX = 0.0f;
window->DC.ColumnsOffsetX = 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.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; 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) if (window->AutoFitFramesY > 0)
window->AutoFitFramesY--; 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 // Title bar
if (!(flags & ImGuiWindowFlags_NoTitleBar)) 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 (style.WindowTitleAlign & ImGuiAlign_Center) pad_right = pad_left;
if (pad_left) text_min.x += g.FontSize + style.ItemInnerSpacing.x; if (pad_left) text_min.x += g.FontSize + style.ItemInnerSpacing.x;
if (pad_right) text_max.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() // 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) if (name)
{ {
ImGuiWindow* window = FindWindowByName(name); if (ImGuiWindow* window = FindWindowByName(name))
if (window)
FocusWindow(window); FocusWindow(window);
} }
else else
@ -5071,13 +5105,13 @@ ImVec2 ImGui::GetCursorPos()
float ImGui::GetCursorPosX() float ImGui::GetCursorPosX()
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindowRead();
return window->DC.CursorPos.x - window->Pos.x + window->Scroll.x; return window->DC.CursorPos.x - window->Pos.x + window->Scroll.x;
} }
float ImGui::GetCursorPosY() float ImGui::GetCursorPosY()
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindowRead();
return window->DC.CursorPos.y - window->Pos.y + window->Scroll.y; 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(); ImGuiWindow* window = GetCurrentWindow();
window->DC.CursorPos = screen_pos; window->DC.CursorPos = screen_pos;
window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
} }
float ImGui::GetScrollX() float ImGui::GetScrollX()
@ -5152,7 +5187,7 @@ void ImGui::SetScrollX(float scroll_x)
void ImGui::SetScrollY(float scroll_y) void ImGui::SetScrollY(float scroll_y)
{ {
ImGuiWindow* window = GetCurrentWindow(); 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; 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); const ImVec2 text_size = CalcTextSize(text_begin, text_end, false, wrap_width);
// Account of baseline offset // Account of baseline offset
ImVec2 text_pos = window->DC.CursorPos; ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrentLineTextBaseOffset);
text_pos.y += window->DC.CurrentLineTextBaseOffset;
ImRect bb(text_pos, text_pos + text_size); ImRect bb(text_pos, text_pos + text_size);
ItemSize(text_size); ItemSize(text_size);
if (!ItemAdd(bb, NULL)) 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_begin = g.TempBuffer;
const char* text_end = text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args); 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 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 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 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 // Render
RenderBullet(bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f)); 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, ...) 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) 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; const int text_len = obj->CurLenW;
IM_ASSERT(pos <= text_len);
if (new_text_len + text_len + 1 > obj->Text.Size) if (new_text_len + text_len + 1 > obj->Text.Size)
return false; 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. // NB: we are only allowed to access 'edit_state' if we are the active widget.
ImGuiTextEditState& edit_state = g.InputTextState; 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 = 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_code = focus_requested && (window->FocusIdxAllCounter == window->FocusIdxAllRequestCurrent);
const bool focus_requested_by_tab = focus_requested && !focus_requested_by_code; 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; g.MouseCursor = ImGuiMouseCursor_TextInput;
} }
const bool user_clicked = hovered && io.MouseClicked[0]; 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; bool select_all = (g.ActiveId != id) && (flags & ImGuiInputTextFlags_AutoSelectAll) != 0;
if (focus_requested || user_clicked || user_scrolled) 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) // 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) // 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; 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.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. 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); ImStrncpy(edit_state.InitialText.Data, buf, edit_state.InitialText.Size);
const char* buf_end = NULL; const char* buf_end = NULL;
edit_state.CurLenW = ImTextStrFromUtf8(edit_state.Text.Data, edit_state.Text.Size, buf, NULL, &buf_end); 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. 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) if (flags & ImGuiInputTextFlags_AlwaysInsertMode)
edit_state.StbState.insert_mode = true; 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; select_all = true;
} }
SetActiveID(id, window); 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]; g.ActiveIdAllowOverlap = !io.MouseDown[0];
// Edit in progress // Edit in progress
const float mouse_x = (g.IO.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + edit_state.ScrollX; const float mouse_x = (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_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.SelectAll();
edit_state.SelectedAllMouseLock = true; 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) // Select a word only, OS X style (by simulating keystrokes)
edit_state.OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT); 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]) if (edit_state.SelectedAllMouseLock && !io.MouseDown[0])
edit_state.SelectedAllMouseLock = false; 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?) // 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. // 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++) for (int n = 0; n < IM_ARRAYSIZE(io.InputCharacters) && io.InputCharacters[n]; n++)
if (unsigned int c = (unsigned int)g.IO.InputCharacters[n]) if (unsigned int c = (unsigned int)io.InputCharacters[n])
{ {
// Insert character if they pass filtering // Insert character if they pass filtering
if (!InputTextFilterCharacter(&c, flags, callback, user_data)) 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 // Handle various key-presses
bool cancel_edit = false; bool cancel_edit = false;
const int k_mask = (is_shift_down ? STB_TEXTEDIT_K_SHIFT : 0); const int k_mask = (io.KeyShift ? 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_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.WordMovementUsesAltKey ? io.KeyAlt : io.KeyCtrl); 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); } 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_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT | k_mask : STB_TEXTEDIT_K_RIGHT | 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 (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 (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 (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_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(is_ctrl_down ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | 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(is_ctrl_down ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | 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_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)) else if (IsKeyPressedMap(ImGuiKey_Enter))
{ {
bool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0; 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); SetActiveID(0);
enter_pressed = true; 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); 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 unsigned int c = '\t'; // Insert TAB
if (InputTextFilterCharacter(&c, flags, callback, user_data)) if (InputTextFilterCharacter(&c, flags, callback, user_data))
edit_state.OnKeyPressed((int)c); edit_state.OnKeyPressed((int)c);
} }
else if (IsKeyPressedMap(ImGuiKey_Escape)) { SetActiveID(0); cancel_edit = true; } 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_shortcut_key_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_shortcut_key_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_shortcut_key_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 && !is_password && ((IsKeyPressedMap(ImGuiKey_X) && is_editable) || IsKeyPressedMap(ImGuiKey_C)) && (!is_multiline || edit_state.HasSelection()))
{ {
// Cut, Copy // Cut, Copy
const bool cut = IsKeyPressedMap(ImGuiKey_X); const bool cut = IsKeyPressedMap(ImGuiKey_X);
if (cut && !edit_state.HasSelection()) if (cut && !edit_state.HasSelection())
edit_state.SelectAll(); 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 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; 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); 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); 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) 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); 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 // 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 unsigned int c;
const int clipboard_len = (int)strlen(clipboard); s += ImTextCharFromUtf8(&c, s, NULL);
ImWchar* clipboard_filtered = (ImWchar*)ImGui::MemAlloc((clipboard_len+1) * sizeof(ImWchar)); if (c == 0)
int clipboard_filtered_len = 0; break;
for (const char* s = clipboard; *s; ) if (c >= 0x10000 || !InputTextFilterCharacter(&c, flags, callback, user_data))
{ continue;
unsigned int c; clipboard_filtered[clipboard_filtered_len++] = (ImWchar)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);
} }
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 // Restore initial value
if (is_editable) if (is_editable)
{ {
ImFormatString(buf, buf_size, "%s", edit_state.InitialText.Data); ImStrncpy(buf, edit_state.InitialText.Data, buf_size);
value_changed = true; 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 // Copy back to user buffer
if (is_editable && strcmp(edit_state.TempTextBuffer.Data, buf) != 0) 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; 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) if (!is_multiline)
RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); 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 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 render_pos = is_multiline ? draw_window->DC.CursorPos : frame_bb.Min + style.FramePadding;
ImVec2 text_size(0.f, 0.f); 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: // This is going to be messy. We need to:
// - Display the text (this can be more easily clipped) // - 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) // - Handle scrolling, highlight selection, display cursor (those all requires some form of 1d->2d cursor position calculation)
// - Measure text height (for scrollbar) // - 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) // 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; const ImWchar* text_begin = edit_state.Text.Data;
ImVec2 cursor_offset, select_start_offset; 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 // Draw blinking cursor
bool cursor_is_visible = (g.InputTextState.CursorAnim <= 0.0f) || fmodf(g.InputTextState.CursorAnim, 1.20f) <= 0.80f; 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 // Render text only
const char* buf_end = NULL; const char* buf_end = NULL;
if (is_multiline) if (is_multiline)
text_size = ImVec2(size.x, InputTextCalcTextLenAndLineCount(buf, &buf_end) * g.FontSize); // We don't need width 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, buf_end, 0.0f, is_multiline ? NULL : &clip_rect); 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) 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 Dummy(text_size + ImVec2(0.0f, g.FontSize)); // Always add room to scroll an extra line
EndChildFrame(); EndChildFrame();
EndGroup(); 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) if (is_password)
@ -8096,7 +8140,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
// Log as text // Log as text
if (g.LogEnabled && !is_password) if (g.LogEnabled && !is_password)
LogRenderedText(render_pos, buf, NULL); LogRenderedText(render_pos, buf_display, NULL);
if (label_size.x > 0) if (label_size.x > 0)
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); 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) 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() IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); // call InputTextMultiline()
bool ret = InputTextEx(label, buf, (int)buf_size, ImVec2(0,0), flags, callback, user_data); return InputTextEx(label, buf, (int)buf_size, ImVec2(0,0), flags, callback, user_data);
return ret;
} }
bool ImGui::InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* 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 InputTextEx(label, buf, (int)buf_size, size, flags | ImGuiInputTextFlags_Multiline, callback, user_data);
return ret;
} }
// NB: scalar_format here must be a simple "%xx" format string with no prefix/suffix (unlike the Drag/Slider functions "display_format" argument) // 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); RenderFrame(bb.Min, bb.Max, GetColorU32(col), outline_border, style.FrameRounding);
if (hovered) 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; return pressed;
} }
@ -8898,7 +8940,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
if (flags & ImGuiColorEditFlags_HSV) if (flags & ImGuiColorEditFlags_HSV)
ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]); 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 alpha = (flags & ImGuiColorEditFlags_Alpha) != 0;
bool value_changed = false; 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 // Recreate our own tooltip over's ColorButton() one because we want to display correct alpha here
if (IsItemHovered()) 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) 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 bar0_pos_x = picker_pos.x + sv_picker_size + style.ItemInnerSpacing.x;
float bar1_pos_x = bar0_pos_x + bars_width + 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; float H,S,V;
ImGui::ColorConvertRGBtoHSV(col[0], col[1], col[2], 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)); 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.) // 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() void ImGui::BeginGroup()
{ {
@ -9260,7 +9312,8 @@ void ImGui::BeginGroup()
group_data.BackupLogLinePosY = window->DC.LogLinePosY; group_data.BackupLogLinePosY = window->DC.LogLinePosY;
group_data.AdvanceCursor = true; 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.CursorMaxPos = window->DC.CursorPos;
window->DC.CurrentLineHeight = 0.0f; window->DC.CurrentLineHeight = 0.0f;
window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.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.CurrentLineHeight = group_data.BackupCurrentLineHeight;
window->DC.CurrentLineTextBaseOffset = group_data.BackupCurrentLineTextBaseOffset; window->DC.CurrentLineTextBaseOffset = group_data.BackupCurrentLineTextBaseOffset;
window->DC.IndentX = group_data.BackupIndentX; window->DC.IndentX = group_data.BackupIndentX;
window->DC.GroupOffsetX = window->DC.IndentX;
window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f;
if (group_data.AdvanceCursor) if (group_data.AdvanceCursor)
@ -9300,7 +9354,7 @@ void ImGui::EndGroup()
// Gets back to previous line and continue with horizontal layout // Gets back to previous line and continue with horizontal layout
// pos_x == 0 : follow right after previous item // 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 : use default spacing if pos_x == 0, no spacing if pos_x != 0
// spacing_w >= 0 : enforce spacing amount // spacing_w >= 0 : enforce spacing amount
void ImGui::SameLine(float pos_x, float spacing_w) 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 (pos_x != 0.0f)
{ {
if (spacing_w < 0.0f) spacing_w = 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; window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
} }
else else
@ -9340,37 +9394,34 @@ void ImGui::NewLine()
void ImGui::NextColumn() void ImGui::NextColumn()
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems) if (window->SkipItems || window->DC.ColumnsCount <= 1)
return; return;
ImGuiContext& g = *GImGui; 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(); // Columns 1+ cancel out IndentX
PopClipRect(); window->DC.ColumnsOffsetX = GetColumnOffset(window->DC.ColumnsCurrent) - window->DC.IndentX + g.Style.ItemSpacing.x;
window->DrawList->ChannelsSetCurrent(window->DC.ColumnsCurrent);
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
} }
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() int ImGui::GetColumnIndex()
@ -9499,7 +9550,7 @@ void ImGui::Columns(int columns_count, const char* id, bool border)
if (held) if (held)
{ {
if (g.ActiveIdIsJustActivated) 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); x = GetDraggedColumnOffset(i);
SetColumnOffset(i, x); SetColumnOffset(i, x);
} }
@ -9632,7 +9683,7 @@ void ImGui::ValueColor(const char* prefix, const ImVec4& v)
ColorButton(v, true); 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); Text("%s: %08X", prefix, v);
SameLine(); SameLine();
@ -9664,12 +9715,8 @@ void ImGui::ValueColor(const char* prefix, unsigned int v)
static const char* GetClipboardTextFn_DefaultImpl() static const char* GetClipboardTextFn_DefaultImpl()
{ {
static char* buf_local = NULL; static ImVector<char> buf_local;
if (buf_local) buf_local.clear();
{
ImGui::MemFree(buf_local);
buf_local = NULL;
}
if (!OpenClipboard(NULL)) if (!OpenClipboard(NULL))
return NULL; return NULL;
HANDLE wbuf_handle = GetClipboardData(CF_UNICODETEXT); HANDLE wbuf_handle = GetClipboardData(CF_UNICODETEXT);
@ -9678,19 +9725,18 @@ static const char* GetClipboardTextFn_DefaultImpl()
if (ImWchar* wbuf_global = (ImWchar*)GlobalLock(wbuf_handle)) if (ImWchar* wbuf_global = (ImWchar*)GlobalLock(wbuf_handle))
{ {
int buf_len = ImTextCountUtf8BytesFromStr(wbuf_global, NULL) + 1; int buf_len = ImTextCountUtf8BytesFromStr(wbuf_global, NULL) + 1;
buf_local = (char*)ImGui::MemAlloc(buf_len * sizeof(char)); buf_local.resize(buf_len);
ImTextStrToUtf8(buf_local, buf_len, wbuf_global, NULL); ImTextStrToUtf8(buf_local.Data, buf_len, wbuf_global, NULL);
} }
GlobalUnlock(wbuf_handle); GlobalUnlock(wbuf_handle);
CloseClipboard(); CloseClipboard();
return buf_local; return buf_local.Data;
} }
static void SetClipboardTextFn_DefaultImpl(const char* text) static void SetClipboardTextFn_DefaultImpl(const char* text)
{ {
if (!OpenClipboard(NULL)) if (!OpenClipboard(NULL))
return; return;
const int wbuf_length = ImTextCountCharsFromUtf8(text, NULL) + 1; const int wbuf_length = ImTextCountCharsFromUtf8(text, NULL) + 1;
HGLOBAL wbuf_handle = GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(ImWchar)); HGLOBAL wbuf_handle = GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(ImWchar));
if (wbuf_handle == NULL) if (wbuf_handle == NULL)
@ -9729,7 +9775,7 @@ static void SetClipboardTextFn_DefaultImpl(const char* text)
#endif #endif
// Win32 API IME support (for Asian languages, etc.) // 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> #include <imm.h>
#ifdef _MSC_VER #ifdef _MSC_VER
@ -9847,6 +9893,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
return; return;
NodeDrawList(window->DrawList, "DrawList"); 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("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->RootWindow != window) NodeWindow(window->RootWindow, "RootWindow");
if (window->DC.ChildWindows.Size > 0) NodeWindows(window->DC.ChildWindows, "ChildWindows"); if (window->DC.ChildWindows.Size > 0) NodeWindows(window->DC.ChildWindows, "ChildWindows");
ImGui::BulletText("Storage: %d bytes", window->StateStorage.Data.Size * (int)sizeof(ImGuiStorage::Pair)); ImGui::BulletText("Storage: %d bytes", window->StateStorage.Data.Size * (int)sizeof(ImGuiStorage::Pair));

30
imgui.h
View File

@ -62,11 +62,11 @@ struct ImGuiSizeConstraintCallbackData;// Structure used to constraint window si
struct ImGuiListClipper; // Helper to manually clip large list of items struct ImGuiListClipper; // Helper to manually clip large list of items
struct ImGuiContext; // ImGui context (opaque) struct ImGuiContext; // ImGui context (opaque)
// Enumerations (declared as int for compatibility and to not pollute the top of this file) // Typedefs and Enumerations (declared as int for compatibility and to not pollute the top of this file)
typedef unsigned int ImU32; typedef unsigned int ImU32; // 32-bit unsigned integer (typically used to store packed colors)
typedef unsigned int ImGuiID; // unique ID used by widgets (typically hashed from a stack of string)
typedef unsigned short ImWchar; // character for keyboard input/display typedef unsigned short ImWchar; // character for keyboard input/display
typedef void* ImTextureID; // user data to identify a texture (this is whatever to you want it to be! read the FAQ about ImTextureID in imgui.cpp) typedef void* ImTextureID; // user data to identify a texture (this is whatever to you want it to be! read the FAQ about ImTextureID in imgui.cpp)
typedef ImU32 ImGuiID; // unique ID used by widgets (typically hashed from a stack of string)
typedef int ImGuiCol; // a color identifier for styling // enum ImGuiCol_ typedef int ImGuiCol; // a color identifier for styling // enum ImGuiCol_
typedef int ImGuiStyleVar; // a variable identifier for styling // enum ImGuiStyleVar_ typedef int ImGuiStyleVar; // a variable identifier for styling // enum ImGuiStyleVar_
typedef int ImGuiKey; // a key identifier (ImGui-side enum) // enum ImGuiKey_ typedef int ImGuiKey; // a key identifier (ImGui-side enum) // enum ImGuiKey_
@ -353,7 +353,7 @@ namespace ImGui
IMGUI_API void Value(const char* prefix, unsigned int v); IMGUI_API void Value(const char* prefix, unsigned int v);
IMGUI_API void Value(const char* prefix, float v, const char* float_format = NULL); IMGUI_API void Value(const char* prefix, float v, const char* float_format = NULL);
IMGUI_API void ValueColor(const char* prefix, const ImVec4& v); IMGUI_API void ValueColor(const char* prefix, const ImVec4& v);
IMGUI_API void ValueColor(const char* prefix, unsigned int v); IMGUI_API void ValueColor(const char* prefix, ImU32 v);
// Tooltips // Tooltips
IMGUI_API void SetTooltip(const char* fmt, ...) IM_PRINTFARGS(1); // set tooltip under mouse-cursor, typically use with ImGui::IsHovered(). last call wins IMGUI_API void SetTooltip(const char* fmt, ...) IM_PRINTFARGS(1); // set tooltip under mouse-cursor, typically use with ImGui::IsHovered(). last call wins
@ -410,7 +410,8 @@ namespace ImGui
IMGUI_API bool IsRootWindowFocused(); // is current root window focused (root = top-most parent of a child, otherwise self) IMGUI_API bool IsRootWindowFocused(); // is current root window focused (root = top-most parent of a child, otherwise self)
IMGUI_API bool IsRootWindowOrAnyChildFocused(); // is current root window or any of its child (including current window) focused IMGUI_API bool IsRootWindowOrAnyChildFocused(); // is current root window or any of its child (including current window) focused
IMGUI_API bool IsRootWindowOrAnyChildHovered(); // is current root window or any of its child (including current window) hovered and hoverable (not blocked by a popup) IMGUI_API bool IsRootWindowOrAnyChildHovered(); // is current root window or any of its child (including current window) hovered and hoverable (not blocked by a popup)
IMGUI_API bool IsRectVisible(const ImVec2& size); // test if rectangle of given size starting from cursor pos is visible (not clipped). to perform coarse clipping on user's side (as an optimization) IMGUI_API bool IsRectVisible(const ImVec2& size); // test if rectangle (of given size, starting from cursor position) is visible / not clipped.
IMGUI_API bool IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max); // test if rectangle (in screen space) is visible / not clipped. to perform coarse clipping on user's side.
IMGUI_API bool IsPosHoveringAnyWindow(const ImVec2& pos); // is given position hovering any active imgui window IMGUI_API bool IsPosHoveringAnyWindow(const ImVec2& pos); // is given position hovering any active imgui window
IMGUI_API float GetTime(); IMGUI_API float GetTime();
IMGUI_API int GetFrameCount(); IMGUI_API int GetFrameCount();
@ -468,15 +469,9 @@ namespace ImGui
static inline bool CollapsingHeader(const char* label, const char* str_id, bool framed = true, bool default_open = false) { (void)str_id; (void)framed; ImGuiTreeNodeFlags default_open_flags = 1<<5; return CollapsingHeader(label, (default_open ? default_open_flags : 0)); } // OBSOLETE 1.49+ static inline bool CollapsingHeader(const char* label, const char* str_id, bool framed = true, bool default_open = false) { (void)str_id; (void)framed; ImGuiTreeNodeFlags default_open_flags = 1<<5; return CollapsingHeader(label, (default_open ? default_open_flags : 0)); } // OBSOLETE 1.49+
static inline ImFont* GetWindowFont() { return GetFont(); } // OBSOLETE 1.48+ static inline ImFont* GetWindowFont() { return GetFont(); } // OBSOLETE 1.48+
static inline float GetWindowFontSize() { return GetFontSize(); } // OBSOLETE 1.48+ static inline float GetWindowFontSize() { return GetFontSize(); } // OBSOLETE 1.48+
static inline void OpenNextNode(bool open) { ImGui::SetNextTreeNodeOpen(open, 0); } // OBSOLETE 1.34+
static inline bool GetWindowIsFocused() { return ImGui::IsWindowFocused(); } // OBSOLETE 1.36+
static inline bool GetWindowCollapsed() { return ImGui::IsWindowCollapsed(); } // OBSOLETE 1.39+
static inline ImVec2 GetItemBoxMin() { return GetItemRectMin(); } // OBSOLETE 1.36+
static inline ImVec2 GetItemBoxMax() { return GetItemRectMax(); } // OBSOLETE 1.36+
static inline bool IsClipped(const ImVec2& size) { return !IsRectVisible(size); } // OBSOLETE 1.38+
static inline bool IsRectClipped(const ImVec2& size) { return !IsRectVisible(size); } // OBSOLETE 1.39+
static inline bool IsMouseHoveringBox(const ImVec2& rect_min, const ImVec2& rect_max) { return IsMouseHoveringRect(rect_min, rect_max); } // OBSOLETE 1.36+
static inline void SetScrollPosHere() { SetScrollHere(); } // OBSOLETE 1.42+ static inline void SetScrollPosHere() { SetScrollHere(); } // OBSOLETE 1.42+
static inline bool GetWindowCollapsed() { return ImGui::IsWindowCollapsed(); } // OBSOLETE 1.39+
static inline bool IsRectClipped(const ImVec2& size) { return !IsRectVisible(size); } // OBSOLETE 1.39+
#endif #endif
} // namespace ImGui } // namespace ImGui
@ -760,10 +755,7 @@ struct ImGuiIO
ImVec2 DisplayVisibleMax; // <unset> (0.0f,0.0f) // If the values are the same, we defaults to Min=(0.0f) and Max=DisplaySize ImVec2 DisplayVisibleMax; // <unset> (0.0f,0.0f) // If the values are the same, we defaults to Min=(0.0f) and Max=DisplaySize
// Advanced/subtle behaviors // Advanced/subtle behaviors
bool WordMovementUsesAltKey; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl bool OSXBehaviors; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl
bool ShortcutsUseSuperKey; // = defined(__APPLE__) // OS X style: Shortcuts using Cmd/Super instead of Ctrl
bool DoubleClickSelectsWord; // = defined(__APPLE__) // OS X style: Double click selects by word instead of selecting whole text
bool MultiSelectUsesSuperKey; // = defined(__APPLE__) // OS X style: Multi-selection in lists uses Cmd/Super instead of Ctrl [unused yet]
//------------------------------------------------------------------ //------------------------------------------------------------------
// User Functions // User Functions
@ -889,7 +881,8 @@ public:
{ {
if (new_capacity <= Capacity) return; if (new_capacity <= Capacity) return;
T* new_data = (value_type*)ImGui::MemAlloc((size_t)new_capacity * sizeof(value_type)); T* new_data = (value_type*)ImGui::MemAlloc((size_t)new_capacity * sizeof(value_type));
memcpy(new_data, Data, (size_t)Size * sizeof(value_type)); if (Data)
memcpy(new_data, Data, (size_t)Size * sizeof(value_type));
ImGui::MemFree(Data); ImGui::MemFree(Data);
Data = new_data; Data = new_data;
Capacity = new_capacity; Capacity = new_capacity;
@ -1325,6 +1318,7 @@ struct ImFontAtlas
IMGUI_API const ImWchar* GetGlyphRangesJapanese(); // Default + Hiragana, Katakana, Half-Width, Selection of 1946 Ideographs IMGUI_API const ImWchar* GetGlyphRangesJapanese(); // Default + Hiragana, Katakana, Half-Width, Selection of 1946 Ideographs
IMGUI_API const ImWchar* GetGlyphRangesChinese(); // Japanese + full set of about 21000 CJK Unified Ideographs IMGUI_API const ImWchar* GetGlyphRangesChinese(); // Japanese + full set of about 21000 CJK Unified Ideographs
IMGUI_API const ImWchar* GetGlyphRangesCyrillic(); // Default + about 400 Cyrillic characters IMGUI_API const ImWchar* GetGlyphRangesCyrillic(); // Default + about 400 Cyrillic characters
IMGUI_API const ImWchar* GetGlyphRangesThai(); // Default + Thai characters
// Members // Members
// (Access texture data via GetTexData*() calls which will setup a default font for you.) // (Access texture data via GetTexData*() calls which will setup a default font for you.)

View File

@ -1020,24 +1020,24 @@ void ImGui::ShowTestWindow(bool* p_open)
ImGui::Text("Hello\nWorld"); ImGui::SameLine(); ImGui::Text("Hello\nWorld"); ImGui::SameLine();
ImGui::Text("One\nTwo\nThree"); ImGui::Text("One\nTwo\nThree");
ImGui::Button("HOP"); ImGui::SameLine(); ImGui::Button("HOP##1"); ImGui::SameLine();
ImGui::Text("Banana"); ImGui::SameLine(); ImGui::Text("Banana"); ImGui::SameLine();
ImGui::Text("Hello\nWorld"); ImGui::SameLine(); ImGui::Text("Hello\nWorld"); ImGui::SameLine();
ImGui::Text("Banana"); ImGui::Text("Banana");
ImGui::Button("HOP"); ImGui::SameLine(); ImGui::Button("HOP##2"); ImGui::SameLine();
ImGui::Text("Hello\nWorld"); ImGui::SameLine(); ImGui::Text("Hello\nWorld"); ImGui::SameLine();
ImGui::Text("Banana"); ImGui::Text("Banana");
ImGui::Button("TEST"); ImGui::SameLine(); ImGui::Button("TEST##1"); ImGui::SameLine();
ImGui::Text("TEST"); ImGui::SameLine(); ImGui::Text("TEST"); ImGui::SameLine();
ImGui::SmallButton("TEST"); ImGui::SmallButton("TEST##2");
ImGui::AlignFirstTextHeightToWidgets(); // If your line starts with text, call this to align it to upcoming widgets. ImGui::AlignFirstTextHeightToWidgets(); // If your line starts with text, call this to align it to upcoming widgets.
ImGui::Text("Text aligned to Widget"); ImGui::SameLine(); ImGui::Text("Text aligned to Widget"); ImGui::SameLine();
ImGui::Button("Widget"); ImGui::SameLine(); ImGui::Button("Widget##1"); ImGui::SameLine();
ImGui::Text("Widget"); ImGui::SameLine(); ImGui::Text("Widget"); ImGui::SameLine();
ImGui::SmallButton("Widget"); ImGui::SmallButton("Widget##2");
// Tree // Tree
const float spacing = ImGui::GetStyle().ItemInnerSpacing.x; const float spacing = ImGui::GetStyle().ItemInnerSpacing.x;

View File

@ -18,9 +18,11 @@
#include "imgui_internal.h" #include "imgui_internal.h"
#include <stdio.h> // vsnprintf, sscanf, printf #include <stdio.h> // vsnprintf, sscanf, printf
#if !defined(alloca) && !defined(__FreeBSD__) && !defined(__DragonFly__) #if !defined(alloca)
#ifdef _WIN32 #ifdef _WIN32
#include <malloc.h> // alloca #include <malloc.h> // alloca
#elif (defined(__FreeBSD__) || defined(FreeBSD_kernel) || defined(__DragonFly__)) && !defined(__GLIBC__)
#include <stdlib.h> // alloca. FreeBSD uses stdlib.h unless GLIBC
#else #else
#include <alloca.h> // alloca #include <alloca.h> // alloca
#endif #endif
@ -1650,6 +1652,17 @@ const ImWchar* ImFontAtlas::GetGlyphRangesCyrillic()
return &ranges[0]; return &ranges[0];
} }
const ImWchar* ImFontAtlas::GetGlyphRangesThai()
{
static const ImWchar ranges[] =
{
0x0020, 0x00FF, // Basic Latin
0x0E00, 0x0E7F, // Thai
0,
};
return &ranges[0];
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// ImFont // ImFont
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

@ -482,7 +482,7 @@ struct ImGuiContext
ScalarAsInputTextId = 0; ScalarAsInputTextId = 0;
DragCurrentValue = 0.0f; DragCurrentValue = 0.0f;
DragLastMouseDelta = ImVec2(0.0f, 0.0f); DragLastMouseDelta = ImVec2(0.0f, 0.0f);
DragSpeedDefaultRatio = 0.01f; DragSpeedDefaultRatio = 1.0f / 100.0f;
DragSpeedScaleSlow = 0.01f; DragSpeedScaleSlow = 0.01f;
DragSpeedScaleFast = 10.0f; DragSpeedScaleFast = 10.0f;
ScrollbarClickDeltaToGrabCenter = ImVec2(0.0f, 0.0f); ScrollbarClickDeltaToGrabCenter = ImVec2(0.0f, 0.0f);
@ -546,6 +546,7 @@ struct IMGUI_API ImGuiDrawContext
int StackSizesBackup[6]; // Store size of various stacks for asserting int StackSizesBackup[6]; // Store size of various stacks for asserting
float IndentX; // Indentation / start position from left of window (increased by TreePush/TreePop, etc.) float IndentX; // Indentation / start position from left of window (increased by TreePush/TreePop, etc.)
float GroupOffsetX;
float ColumnsOffsetX; // Offset to the current column (if ColumnsCurrent > 0). FIXME: This and the above should be a stack to allow use cases like Tree->Column->Tree. Need revamp columns API. float ColumnsOffsetX; // Offset to the current column (if ColumnsCurrent > 0). FIXME: This and the above should be a stack to allow use cases like Tree->Column->Tree. Need revamp columns API.
int ColumnsCurrent; int ColumnsCurrent;
int ColumnsCount; int ColumnsCount;
@ -642,7 +643,7 @@ struct IMGUI_API ImGuiWindow
ImGuiWindow* RootNonPopupWindow; // If we are a child window, this is pointing to the first non-child non-popup parent window. Else point to ourself. ImGuiWindow* RootNonPopupWindow; // If we are a child window, this is pointing to the first non-child non-popup parent window. Else point to ourself.
ImGuiWindow* ParentWindow; // If we are a child window, this is pointing to our parent window. Else point to NULL. ImGuiWindow* ParentWindow; // If we are a child window, this is pointing to our parent window. Else point to NULL.
// Focus // Navigation / Focus
int FocusIdxAllCounter; // Start at -1 and increase as assigned via FocusItemRegister() int FocusIdxAllCounter; // Start at -1 and increase as assigned via FocusItemRegister()
int FocusIdxTabCounter; // (same, but only count widgets which you can Tab through) int FocusIdxTabCounter; // (same, but only count widgets which you can Tab through)
int FocusIdxAllRequestCurrent; // Item being requested for focus int FocusIdxAllRequestCurrent; // Item being requested for focus
@ -656,6 +657,7 @@ public:
ImGuiID GetID(const char* str, const char* str_end = NULL); ImGuiID GetID(const char* str, const char* str_end = NULL);
ImGuiID GetID(const void* ptr); ImGuiID GetID(const void* ptr);
ImGuiID GetIDNoKeepAlive(const char* str, const char* str_end = NULL);
ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x+Size.x, Pos.y+Size.y); } ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x+Size.x, Pos.y+Size.y); }
float CalcFontSize() const { return GImGui->FontBaseSize * FontWindowScale; } float CalcFontSize() const { return GImGui->FontBaseSize * FontWindowScale; }
@ -700,9 +702,6 @@ namespace ImGui
IMGUI_API void OpenPopupEx(const char* str_id, bool reopen_existing); IMGUI_API void OpenPopupEx(const char* str_id, bool reopen_existing);
inline IMGUI_API ImU32 GetColorU32(ImGuiCol idx, float alpha_mul) { ImVec4 c = GImGui->Style.Colors[idx]; c.w *= GImGui->Style.Alpha * alpha_mul; return ImGui::ColorConvertFloat4ToU32(c); }
inline IMGUI_API ImU32 GetColorU32(const ImVec4& col) { ImVec4 c = col; c.w *= GImGui->Style.Alpha; return ImGui::ColorConvertFloat4ToU32(c); }
// NB: All position are in absolute pixels coordinates (not window coordinates) // NB: All position are in absolute pixels coordinates (not window coordinates)
// FIXME: All those functions are a mess and needs to be refactored into something decent. Avoid use outside of imgui.cpp! // FIXME: All those functions are a mess and needs to be refactored into something decent. Avoid use outside of imgui.cpp!
// We need: a sort of symbol library, preferably baked into font atlas when possible + decent text rendering helpers. // We need: a sort of symbol library, preferably baked into font atlas when possible + decent text rendering helpers.

View File

@ -1,4 +1,5 @@
// [ImGui] this is a slightly modified version of stb_truetype.h 1.8 // [ImGui] this is a slightly modified version of stb_truetype.h 1.8
// [ImGui] - fixed a state corruption/crash bug in stb_text_redo and stb_textedit_discard_redo (#715)
// [ImGui] - fixed a crash bug in stb_textedit_discard_redo (#681) // [ImGui] - fixed a crash bug in stb_textedit_discard_redo (#681)
// [ImGui] - fixed some minor warnings // [ImGui] - fixed some minor warnings
// [ImGui] - added STB_TEXTEDIT_MOVEWORDLEFT/STB_TEXTEDIT_MOVEWORDRIGHT custom handler (#473) // [ImGui] - added STB_TEXTEDIT_MOVEWORDLEFT/STB_TEXTEDIT_MOVEWORDRIGHT custom handler (#473)
@ -1101,8 +1102,8 @@ static void stb_textedit_discard_redo(StbUndoState *state)
if (state->undo_rec[i].char_storage >= 0) if (state->undo_rec[i].char_storage >= 0)
state->undo_rec[i].char_storage = state->undo_rec[i].char_storage + (short) n; // vsnet05 state->undo_rec[i].char_storage = state->undo_rec[i].char_storage + (short) n; // vsnet05
} }
STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point, state->undo_rec + state->redo_point-1, (size_t) ((size_t)(STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point)*sizeof(state->undo_rec[0])));
++state->redo_point; ++state->redo_point;
STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point-1, state->undo_rec + state->redo_point, (size_t) ((size_t)(STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point)*sizeof(state->undo_rec[0])));
} }
} }
@ -1260,6 +1261,7 @@ static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
if (r.insert_length) { if (r.insert_length) {
// easy case: need to insert n characters // easy case: need to insert n characters
STB_TEXTEDIT_INSERTCHARS(str, r.where, &s->undo_char[r.char_storage], r.insert_length); STB_TEXTEDIT_INSERTCHARS(str, r.where, &s->undo_char[r.char_storage], r.insert_length);
s->redo_char_point += r.insert_length;
} }
state->cursor = r.where + r.insert_length; state->cursor = r.where + r.insert_length;