Updated imgui.

This commit is contained in:
Branimir Karadžić 2015-09-11 22:40:55 -07:00
parent 4ef43dc802
commit 93c6020372
5 changed files with 312 additions and 254 deletions

View file

@ -94,11 +94,11 @@
ImGuiIO& io = ImGui::GetIO();
io.DisplaySize.x = 1920.0f;
io.DisplaySize.y = 1280.0f;
io.DeltaTime = 1.0f/60.0f;
io.IniFilename = "imgui.ini";
io.RenderDrawListsFn = my_render_function; // Setup a render function, or set to NULL and call GetDrawData() after Render() to access the render data.
// TODO: Fill others settings of the io structure
// Load texture
// Load texture atlas
unsigned char* pixels;
int width, height, bytes_per_pixels;
io.Fonts->GetTexDataAsRGBA32(pixels, &width, &height, &bytes_per_pixels);
@ -113,6 +113,7 @@
// 2) TODO: fill all fields of IO structure and call NewFrame
ImGuiIO& io = ImGui::GetIO();
io.DeltaTime = 1.0f/60.0f;
io.MousePos = mouse_pos;
io.MouseDown[0] = mouse_button_0;
io.KeysDown[i] = ...
@ -130,9 +131,9 @@
// swap video buffer, etc.
}
- after calling ImGui::NewFrame() you can read back flags from the IO structure to tell how ImGui intends to use your inputs.
- after calling ImGui::NewFrame() you can read back flags from the IO structure to tell how ImGui intends to use your inputs.
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 onscreen keyboard, if available.
When 'io.WantInputsCharacters' is set to may want to notify your OS to popup an on-screen keyboard, if available.
API BREAKING CHANGES
@ -142,7 +143,7 @@
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.
- 2015/08/29 (1.45) - with the addition of horizontal scrollbar we made various fixes to inconsistencies with dealing with position:
- 2015/08/29 (1.45) - with the addition of horizontal scrollbar we made various fixes to inconsistencies with dealing with cursor position.
GetCursorPos()/SetCursorPos() functions now include the scrolled amount. It shouldn't affect the majority of users, but take note that SetCursorPosX(100.0f) puts you at +100 from the starting x position which may include scrolling, not at +100 from the window left side.
GetContentRegionMax()/GetWindowContentRegionMin()/GetWindowContentRegionMax() functions allow include the scrolled amount. Typically those were used in cases where no scrolling would happen so it may not be a problem, but watch out!
- 2015/08/29 (1.45) - renamed style.ScrollbarWidth to style.ScrollbarSize
@ -238,7 +239,7 @@
stb_rect_pack.h
stb_textedit.h
stb_truetype.h
Don't overwrite imconfig.h if you have modification to your copy.
Don't overwrite imconfig.h if you have made modification to your copy.
Check the "API BREAKING CHANGES" sections for a list of occasional API breaking changes. If you have a problem with a function, search for its name
in the code, there will likely be a comment about it. Please report any issue to the GitHub page!
@ -256,32 +257,37 @@
- ID are uniquely scoped within windows, tree nodes, etc. so no conflict can happen if you have two buttons called "OK" in two different windows
or in two different locations of a tree.
- if you have a same ID twice in the same location, you'll have a conflict:
- If you have a same ID twice in the same location, you'll have a conflict:
Button("OK");
Button("OK"); // ID collision! Both buttons will be treated as the same.
Fear not! this is easy to solve and there are many ways to solve it!
- when passing a label you can optionally specify extra unique ID information within string itself. This helps solving the simpler collision cases.
- When passing a label you can optionally specify extra unique ID information within string itself. This helps solving the simpler collision cases.
use "##" to pass a complement to the ID that won't be visible to the end-user:
Button("Play##0"); // Label = "Play", ID = hash of "Play##0"
Button("Play##1"); // Label = "Play", ID = hash of "Play##1" (different from above)
Button("Play"); // Label = "Play", ID = hash of "Play"
Button("Play##foo1"); // Label = "Play", ID = hash of "Play##foo1" (different from above)
Button("Play##foo2"); // Label = "Play", ID = hash of "Play##foo2" (different from above)
- so if you want to hide the label but need an ID:
- If you want to completely hide the label, but still need an ID:
Checkbox("##On", &b); // Label = "", ID = hash of "##On"
Checkbox("##On", &b); // Label = "", ID = hash of "##On" (no label!)
- occasionally (rarely) you might want change a label while preserving a constant ID. This allows you to animate labels.
use "###" to pass a label that isn't part of ID:
- Occasionally/rarely you might want change a label while preserving a constant ID. This allows you to animate labels.
For example you may want to include varying information in a window title bar (and windows are uniquely identified by their ID.. obviously)
Use "###" to pass a label that isn't part of ID:
Button("Hello###ID"; // Label = "Hello", ID = hash of "ID"
Button("World###ID"; // Label = "World", ID = hash of "ID" (same as above)
sprintf(buf, "My game (%f FPS)###MyGame");
Begin(buf); // Variable label, ID = hash of "MyGame"
- use PushID() / PopID() to create scopes and avoid ID conflicts within the same Window.
this is the most convenient way of distinguish ID if you are iterating and creating many UI elements.
you can push a pointer, a string or an integer value. remember that ID are formed from the addition of everything in the ID stack!
- Use PushID() / PopID() to create scopes and avoid ID conflicts within the same Window.
This is the most convenient way of distinguishing ID if you are iterating and creating many UI elements.
You can push a pointer, a string or an integer value. Remember that ID are formed from the concatenation of everything in the ID stack!
for (int i = 0; i < 100; i++)
{
@ -306,7 +312,7 @@
PopID();
}
- more example showing that you can stack multiple prefixes into the ID stack:
- More example showing that you can stack multiple prefixes into the ID stack:
Button("Click"); // Label = "Click", ID = hash of "Click"
PushID("node");
@ -316,7 +322,7 @@
PopID();
PopID();
- tree nodes implicitly creates a scope for you by calling PushID().
- Tree nodes implicitly creates a scope for you by calling PushID().
Button("Click"); // Label = "Click", ID = hash of "Click"
if (TreeNode("node"))
@ -325,8 +331,8 @@
TreePop();
}
- when working with trees, ID are used to preserve the opened/closed state of each tree node.
depending on your use cases you may want to use strings, indices or pointers as ID.
- When working with trees, ID are used to preserve the opened/closed state of each tree node.
Depending on your use cases you may want to use strings, indices or pointers as ID.
e.g. when displaying a single object that may change over time (1-1 relationship), using a static string as ID will preserve your node open/closed state when the targeted object change.
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!
@ -336,12 +342,14 @@
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:
ImGuiIO& io = ImGui::GetIO();
io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels);
io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8()
Q: How can I load multiple fonts?
A: Use the font atlas to pack them into a single texture:
ImGuiIO& io = ImGui::GetIO();
ImFont* font0 = io.Fonts->AddFontDefault();
ImFont* font1 = io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels);
ImFont* font2 = io.Fonts->AddFontFromFileTTF("myfontfile2.ttf", size_in_pixels);
@ -366,7 +374,7 @@
Read extra_fonts/README.txt or ImFontAtlas class for more details.
Q: How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic?
Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic?
A: When loading a font, pass custom Unicode ranges to specify the glyphs to load. ImGui will support UTF-8 encoding across the board.
Character input depends on you passing the right character code to io.AddInputCharacter(). The example applications do that.
@ -376,9 +384,9 @@
- tip: the construct 'IMGUI_ONCE_UPON_A_FRAME { ... }' will run the block of code only once a frame. You can use it to quickly add custom UI in the middle of a deep nested inner loop in your code.
- tip: you can create widgets without a Begin()/End() block, they will go in an implicit window called "Debug"
- tip: you can call Begin() multiple times with the same name during the same frame, it will keep appending to the same window. this is also useful to set yourself in the context of a window (to get/set other settings)
- tip: you can call Begin() multiple times with the same name during the same frame, it will keep appending to the same window. this is also useful to set yourself in the context of another window (to get/set other settings)
- tip: you can call Render() multiple times (e.g for VR renders).
- tip: call and read the ShowTestWindow() code for more example of how to use ImGui!
- tip: call and read the ShowTestWindow() code in imgui_demo.cpp for more example of how to use ImGui!
ISSUES & TODO-LIST
@ -396,14 +404,13 @@
!- scrolling: allow immediately effective change of scroll if we haven't appended items yet
- widgets: display mode: widget-label, label-widget (aligned on column or using fixed size), label-newline-tab-widget etc.
- widgets: clean up widgets internal toward exposing everything.
- widgets: add a disabled/read-only mode (#211)
- widgets: add disabled and read-only modes (#211)
- main: considering adding EndFrame()/Init(). some constructs are awkward in the implementation because of the lack of them.
- main: IsItemHovered() make it more consistent for various type of widgets, widgets with multiple components, etc. also effectively IsHovered() region sometimes differs from hot region, e.g tree nodes
- main: IsItemHovered() info stored in a stack? so that 'if TreeNode() { Text; TreePop; } if IsHovered' return the hover state of the TreeNode?
- input text: add ImGuiInputTextFlags_EnterToApply? (off #218)
- 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: read-only mode (can still select/copy, always display input buffer)
- 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: use mouse wheel to step up/down
@ -451,7 +458,8 @@
- settings: write more decent code to allow saving/loading new fields
- settings: api for per-tool simple persistent data (bool,int,float,columns sizes,etc.) in .ini file
- style: store rounded corners in texture to use 1 quad per corner (filled and wireframe). so rounding have minor cost.
- style: colorbox not always square?
- style: color-box not always square?
- style: a concept of "compact style" that the end-user can easily rely on (e.g. PushStyleCompact()?) that maps that other settings?
- text: simple markup language for color change?
- log: LogButtons() options for specifying depth and/or hiding depth slider
- log: have more control over the log scope (e.g. stop logging when leaving current tree node scope)
@ -1114,21 +1122,21 @@ void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float&
// Load file content into memory
// Memory allocated with ImGui::MemAlloc(), must be freed by user using ImGui::MemFree()
bool ImLoadFileToMemory(const char* filename, const char* file_open_mode, void** out_file_data, int* out_file_size, int padding_bytes)
void* ImLoadFileToMemory(const char* filename, const char* file_open_mode, int* out_file_size, int padding_bytes)
{
IM_ASSERT(filename && file_open_mode && out_file_data && out_file_size);
*out_file_data = NULL;
*out_file_size = 0;
IM_ASSERT(filename && file_open_mode);
if (out_file_size)
*out_file_size = 0;
FILE* f;
if ((f = fopen(filename, file_open_mode)) == NULL)
return false;
return NULL;
long file_size_signed;
if (fseek(f, 0, SEEK_END) || (file_size_signed = ftell(f)) == -1 || fseek(f, 0, SEEK_SET))
{
fclose(f);
return false;
return NULL;
}
int file_size = (int)file_size_signed;
@ -1136,23 +1144,22 @@ bool ImLoadFileToMemory(const char* filename, const char* file_open_mode, void**
if (file_data == NULL)
{
fclose(f);
return false;
return NULL;
}
if (fread(file_data, 1, (size_t)file_size, f) != (size_t)file_size)
{
fclose(f);
ImGui::MemFree(file_data);
return false;
return NULL;
}
if (padding_bytes > 0)
memset((void *)(((char*)file_data) + file_size), 0, padding_bytes);
fclose(f);
*out_file_data = file_data;
if (out_file_size)
*out_file_size = file_size;
return true;
return file_data;
}
//-----------------------------------------------------------------------------
@ -1769,6 +1776,12 @@ ImGuiStyle& ImGui::GetStyle()
return GImGui->Style;
}
// Same value as passed to your RenderDrawListsFn() function. valid after Render() and until the next call to NewFrame()
ImDrawData* ImGui::GetDrawData()
{
return GImGui->RenderDrawData.Valid ? &GImGui->RenderDrawData : NULL;
}
float ImGui::GetTime()
{
return GImGui->Time;
@ -1786,7 +1799,6 @@ void ImGui::NewFrame()
// Check user data
IM_ASSERT(g.IO.DeltaTime >= 0.0f);
IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f);
IM_ASSERT(g.IO.RenderDrawListsFn != NULL); // Must be implemented
IM_ASSERT(g.IO.Fonts->Fonts.Size > 0); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ?
IM_ASSERT(g.IO.Fonts->Fonts[0]->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ?
IM_ASSERT(g.Style.CurveTessellationTol > 0.0f); // Invalid
@ -1812,6 +1824,11 @@ void ImGui::NewFrame()
g.OverlayDrawList.PushClipRectFullScreen();
g.OverlayDrawList.AddDrawCmd();
// Mark rendering data as invalid to prevent user who may have a handle on it to use it
g.RenderDrawData.Valid = false;
g.RenderDrawData.CmdLists = NULL;
g.RenderDrawData.CmdListsCount = g.RenderDrawData.TotalVtxCount = g.RenderDrawData.TotalIdxCount = 0;
// Update inputs state
if (g.IO.MousePos.x < 0 && g.IO.MousePos.y < 0)
g.IO.MousePos = ImVec2(-9999.0f, -9999.0f);
@ -2066,9 +2083,9 @@ static void LoadSettings()
if (!filename)
return;
char* file_data;
int file_size;
if (!ImLoadFileToMemory(filename, "rb", (void**)&file_data, &file_size, 1))
char* file_data = (char*)ImLoadFileToMemory(filename, "rb", &file_size, 1);
if (!file_data)
return;
ImGuiIniData* settings = NULL;
@ -2197,7 +2214,6 @@ static void AddDrawListToRenderList(ImVector<ImDrawList*>& out_render_list, ImDr
// If this assert triggers because you are drawing lots of stuff manually, A) workaround by calling BeginChild()/EndChild() to put your draw commands in multiple draw lists, B) #define ImDrawIdx to a 'unsigned int' in imconfig.h and render accordingly.
const unsigned long long int max_vtx_idx = (unsigned long long int)1L << (sizeof(ImDrawIdx)*8);
IM_ASSERT((unsigned long long int)draw_list->_VtxCurrentIdx <= max_vtx_idx);
(void)max_vtx_idx;
GImGui->IO.MetricsRenderVertices += draw_list->VtxBuffer.Size;
GImGui->IO.MetricsRenderIndices += draw_list->IdxBuffer.Size;
@ -2367,15 +2383,17 @@ void ImGui::Render()
if (!g.OverlayDrawList.VtxBuffer.empty())
AddDrawListToRenderList(g.RenderDrawLists[0], &g.OverlayDrawList);
// Render
if (!g.RenderDrawLists[0].empty())
// Setup draw data
g.RenderDrawData.Valid = true;
g.RenderDrawData.CmdLists = (g.RenderDrawLists[0].Size > 0) ? &g.RenderDrawLists[0][0] : NULL;
g.RenderDrawData.CmdListsCount = g.RenderDrawLists[0].Size;
g.RenderDrawData.TotalVtxCount = g.IO.MetricsRenderVertices;
g.RenderDrawData.TotalIdxCount = g.IO.MetricsRenderIndices;
// Render. If user hasn't set a callback then they may retrieve the draw data via GetDrawData()
if (g.RenderDrawData.CmdListsCount > 0 && g.IO.RenderDrawListsFn != NULL)
{
ImDrawData data;
data.CmdLists = &g.RenderDrawLists[0][0];
data.CmdListsCount = g.RenderDrawLists[0].Size;
data.TotalVtxCount = g.IO.MetricsRenderVertices;
data.TotalIdxCount = g.IO.MetricsRenderIndices;
g.IO.RenderDrawListsFn(&data);
g.IO.RenderDrawListsFn(&g.RenderDrawData);
}
}
}
@ -3879,13 +3897,13 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
window->DC.ChildWindows.resize(0);
window->DC.LayoutType = ImGuiLayoutType_Vertical;
window->DC.ItemWidth = window->ItemWidthDefault;
window->DC.ItemWidthStack.resize(0);
window->DC.ButtonRepeat = false;
window->DC.ButtonRepeatStack.resize(0);
window->DC.AllowKeyboardFocus = true;
window->DC.AllowKeyboardFocusStack.resize(0);
window->DC.TextWrapPos = -1.0f; // disabled
window->DC.AllowKeyboardFocus = true;
window->DC.ButtonRepeat = false;
window->DC.ItemWidthStack.resize(0);
window->DC.TextWrapPosStack.resize(0);
window->DC.AllowKeyboardFocusStack.resize(0);
window->DC.ButtonRepeatStack.resize(0);
window->DC.ColorEditMode = ImGuiColorEditMode_UserSelect;
window->DC.ColumnsCurrent = 0;
window->DC.ColumnsCount = 1;
@ -7020,6 +7038,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
const ImGuiID id = window->GetID(label);
const bool is_multiline = (flags & ImGuiInputTextFlags_Multiline) != 0;
const bool is_editable = (flags & ImGuiInputTextFlags_ReadOnly) == 0;
ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true);
ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), is_multiline ? ImGui::GetTextLineHeight() * 8.0f : label_size.y); // Arbitrary default of 8 lines high for multi-line
@ -7074,6 +7093,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
// Start edition
// 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'
const int prev_len_w = edit_state.CurLenW;
edit_state.Text.resize(buf_size); // wchar count <= utf-8 count
edit_state.InitialText.resize(buf_size); // utf-8
ImFormatString(edit_state.InitialText.Data, edit_state.InitialText.Size, "%s", buf);
@ -7083,15 +7103,10 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
edit_state.InputCursorScreenPos = ImVec2(-1.f, -1.f);
edit_state.CursorAnimReset();
if (edit_state.Id != id)
{
edit_state.Id = id;
edit_state.ScrollX = 0.f;
stb_textedit_initialize_state(&edit_state.StbState, !is_multiline);
if (!is_multiline && focus_requested_by_code)
select_all = true;
}
else
// Preserve cursor position and undo/redo stack if we come back to same widget
// FIXME: We should probably compare the whole buffer to be on the safety side. Comparing buf (utf8) and edit_state.Text (wchar).
const bool recycle_state = (edit_state.Id == id) && (prev_len_w == edit_state.CurLenW);
if (recycle_state)
{
// Recycle existing cursor/selection/undo stack but clamp position
// Note a single mouse click will override the cursor/position immediately by calling stb_textedit_click handler.
@ -7099,6 +7114,14 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
edit_state.StbState.select_start = ImMin(edit_state.StbState.select_start, edit_state.CurLenW);
edit_state.StbState.select_end = ImMin(edit_state.StbState.select_end, edit_state.CurLenW);
}
else
{
edit_state.Id = id;
edit_state.ScrollX = 0.f;
stb_textedit_initialize_state(&edit_state.StbState, !is_multiline);
if (!is_multiline && focus_requested_by_code)
select_all = true;
}
if (flags & ImGuiInputTextFlags_AlwaysInsertMode)
edit_state.StbState.insert_mode = true;
if (!is_multiline && (focus_requested_by_tab || (user_clicked && is_ctrl_down)))
@ -7151,7 +7174,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
if (g.IO.InputCharacters[0])
{
// Process text input (before we check for Return because using some IME will effectively send a Return?)
if (!is_ctrl_down && !is_alt_down)
if (!is_ctrl_down && !is_alt_down && is_editable)
{
for (int n = 0; n < IM_ARRAYSIZE(g.IO.InputCharacters) && g.IO.InputCharacters[n]; n++)
if (unsigned int c = (unsigned int)g.IO.InputCharacters[n])
@ -7175,8 +7198,8 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
else if (is_multiline && IsKeyPressedMap(ImGuiKey_DownArrow)) { if (is_ctrl_down) SetWindowScrollY(draw_window, draw_window->Scroll.y + g.FontSize); else edit_state.OnKeyPressed(STB_TEXTEDIT_K_DOWN| k_mask); }
else if (IsKeyPressedMap(ImGuiKey_Home)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); }
else if (IsKeyPressedMap(ImGuiKey_End)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); }
else if (IsKeyPressedMap(ImGuiKey_Delete)) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); }
else if (IsKeyPressedMap(ImGuiKey_Backspace)) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | 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) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask); }
else if (IsKeyPressedMap(ImGuiKey_Enter))
{
bool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0;
@ -7185,24 +7208,24 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
SetActiveID(0);
enter_pressed = true;
}
else // New line
else if (is_editable) // New line
{
unsigned int c = '\n';
if (InputTextFilterCharacter(&c, flags, callback, user_data))
edit_state.OnKeyPressed((int)c);
}
}
else if ((flags & ImGuiInputTextFlags_AllowTabInput) && IsKeyPressedMap(ImGuiKey_Tab) && !is_ctrl_down && !is_shift_down && !is_alt_down)
else if ((flags & ImGuiInputTextFlags_AllowTabInput) && IsKeyPressedMap(ImGuiKey_Tab) && !is_ctrl_down && !is_shift_down && !is_alt_down && is_editable)
{
unsigned int c = '\t';
if (InputTextFilterCharacter(&c, flags, callback, user_data))
edit_state.OnKeyPressed((int)c);
}
else if (IsKeyPressedMap(ImGuiKey_Escape)) { SetActiveID(0); cancel_edit = true; }
else if (is_ctrl_only && IsKeyPressedMap(ImGuiKey_Z)) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_UNDO); edit_state.ClearSelection(); }
else if (is_ctrl_only && IsKeyPressedMap(ImGuiKey_Y)) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_REDO); edit_state.ClearSelection(); }
else if (is_ctrl_only && IsKeyPressedMap(ImGuiKey_A)) { edit_state.SelectAll(); edit_state.CursorFollow = true; }
else if (is_ctrl_only && (IsKeyPressedMap(ImGuiKey_X) || IsKeyPressedMap(ImGuiKey_C)) && (!is_multiline || edit_state.HasSelection()))
else if (IsKeyPressedMap(ImGuiKey_Escape)) { SetActiveID(0); cancel_edit = true; }
else if (is_ctrl_only && IsKeyPressedMap(ImGuiKey_Z) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_UNDO); edit_state.ClearSelection(); }
else if (is_ctrl_only && IsKeyPressedMap(ImGuiKey_Y) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_REDO); edit_state.ClearSelection(); }
else if (is_ctrl_only && IsKeyPressedMap(ImGuiKey_A)) { edit_state.SelectAll(); edit_state.CursorFollow = true; }
else if (is_ctrl_only && ((IsKeyPressedMap(ImGuiKey_X) && is_editable) || IsKeyPressedMap(ImGuiKey_C)) && (!is_multiline || edit_state.HasSelection()))
{
// Cut, Copy
const bool cut = IsKeyPressedMap(ImGuiKey_X);
@ -7224,7 +7247,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
stb_textedit_cut(&edit_state, &edit_state.StbState);
}
}
else if (is_ctrl_only && IsKeyPressedMap(ImGuiKey_V))
else if (is_ctrl_only && IsKeyPressedMap(ImGuiKey_V) && is_editable)
{
// Paste
if (g.IO.GetClipboardTextFn)
@ -7259,8 +7282,11 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
if (cancel_edit)
{
// Restore initial value
ImFormatString(buf, buf_size, "%s", edit_state.InitialText.Data);
value_changed = true;
if (is_editable)
{
ImFormatString(buf, buf_size, "%s", edit_state.InitialText.Data);
value_changed = true;
}
}
else
{
@ -7268,8 +7294,11 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
// Note that as soon as we can focus into the input box, the in-widget value gets priority over any underlying modification of the input buffer
// FIXME: We actually always render 'buf' in RenderTextScrolledClipped
// FIXME-OPT: CPU waste to do this every time the widget is active, should mark dirty state from the stb_textedit callbacks
edit_state.TempTextBuffer.resize(edit_state.Text.Size * 4);
ImTextStrToUtf8(edit_state.TempTextBuffer.Data, edit_state.TempTextBuffer.Size, edit_state.Text.Data, NULL);
if (is_editable)
{
edit_state.TempTextBuffer.resize(edit_state.Text.Size * 4);
ImTextStrToUtf8(edit_state.TempTextBuffer.Data, edit_state.TempTextBuffer.Size, edit_state.Text.Data, NULL);
}
// User callback
if ((flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory | ImGuiInputTextFlags_CallbackAlways)) != 0)
@ -7299,12 +7328,14 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
{
ImGuiTextEditCallbackData callback_data;
callback_data.EventFlag = event_flag;
callback_data.Flags = flags;
callback_data.UserData = user_data;
callback_data.ReadOnly = !is_editable;
callback_data.EventKey = event_key;
callback_data.Buf = edit_state.TempTextBuffer.Data;
callback_data.BufSize = edit_state.BufSizeA;
callback_data.BufDirty = false;
callback_data.Flags = flags;
callback_data.UserData = user_data;
// We have to convert from position from wchar to UTF-8 positions
ImWchar* text = edit_state.Text.Data;
@ -7331,7 +7362,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
}
}
if (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);
value_changed = true;
@ -7354,7 +7385,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
// - Display the text (this can be more easily clipped)
// - Handle scrolling, highlight selection, display cursor (those all requires some form of 1d->2d cursor position calculation)
// - Measure text height (for scrollbar)
// We are attempting to do most of that in one main pass to minimize the computation cost (non-negligible for large amount of text) + 2nd pass for selection rendering (we could merge them by an extra refactoring effort)
// 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)
const ImWchar* text_begin = edit_state.Text.Data;
const ImWchar* text_end = text_begin + edit_state.CurLenW;
ImVec2 cursor_offset, select_start_offset;
@ -7473,7 +7504,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
draw_window->DrawList->AddLine(cursor_screen_pos + ImVec2(0.0f,-g.FontSize+0.5f), cursor_screen_pos + ImVec2(0.0f,-1.5f), window->Color(ImGuiCol_Text));
// Notify OS of text input position for advanced IME
if (io.ImeSetInputScreenPosFn && ImLengthSqr(edit_state.InputCursorScreenPos - cursor_screen_pos) > 0.0001f)
if (is_editable && io.ImeSetInputScreenPosFn && ImLengthSqr(edit_state.InputCursorScreenPos - cursor_screen_pos) > 0.0001f)
io.ImeSetInputScreenPosFn((int)cursor_screen_pos.x - 1, (int)(cursor_screen_pos.y - g.FontSize)); // -1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.
edit_state.InputCursorScreenPos = cursor_screen_pos;

View file

@ -3,7 +3,7 @@
// See imgui.cpp file for documentation.
// See ImGui::ShowTestWindow() in imgui_demo.cpp for demo code.
// Read 'Programmer guide' in .cpp for notes on how to setup ImGui in your codebase.
// Read 'Programmer guide' in imgui.cpp for notes on how to setup ImGui in your codebase.
// Get latest version at https://github.com/ocornut/imgui
#pragma once
@ -105,6 +105,7 @@ namespace ImGui
// Main
IMGUI_API ImGuiIO& GetIO();
IMGUI_API ImGuiStyle& GetStyle();
IMGUI_API ImDrawData* GetDrawData(); // same value as passed to your RenderDrawListsFn() function. valid after Render() and until the next call to NewFrame()
IMGUI_API void NewFrame();
IMGUI_API void Render();
IMGUI_API void Shutdown();
@ -177,10 +178,10 @@ namespace ImGui
IMGUI_API void PushItemWidth(float item_width); // width of items for the common item+label case, pixels. 0.0f = default to ~2/3 of windows width, >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -1.0f always align width to the right side)
IMGUI_API void PopItemWidth();
IMGUI_API float CalcItemWidth(); // width of item given pushed settings and current cursor position
IMGUI_API void PushAllowKeyboardFocus(bool v); // allow focusing using TAB/Shift-TAB, enabled by default but you can disable it for certain widgets
IMGUI_API void PopAllowKeyboardFocus();
IMGUI_API void PushTextWrapPos(float wrap_pos_x = 0.0f); // word-wrapping for Text*() commands. < 0.0f: no wrapping; 0.0f: wrap to end of window (or column); > 0.0f: wrap at 'wrap_pos_x' position in window local space
IMGUI_API void PopTextWrapPos();
IMGUI_API void PushAllowKeyboardFocus(bool v); // allow focusing using TAB/Shift-TAB, enabled by default but you can disable it for certain widgets
IMGUI_API void PopAllowKeyboardFocus();
IMGUI_API void PushButtonRepeat(bool repeat); // in 'repeat' mode, Button*() functions return repeated true in a typematic manner (uses io.KeyRepeatDelay/io.KeyRepeatRate for now). Note that you can call IsItemActive() after any Button() to tell if the button is held in the current frame.
IMGUI_API void PopButtonRepeat();
@ -486,6 +487,7 @@ enum ImGuiInputTextFlags_
ImGuiInputTextFlags_CtrlEnterForNewLine = 1 << 11, // In multi-line mode, allow exiting edition by pressing Enter. Ctrl+Enter to add new line (by default adds new lines with Enter).
ImGuiInputTextFlags_NoHorizontalScroll = 1 << 12, // Disable following the cursor horizontally
ImGuiInputTextFlags_AlwaysInsertMode = 1 << 13, // Insert mode
ImGuiInputTextFlags_ReadOnly = 1 << 14, // Read-only mode
// [Internal]
ImGuiInputTextFlags_Multiline = 1 << 20 // For internal use by InputTextMultiline()
};
@ -694,8 +696,9 @@ struct ImGuiIO
// User Functions
//------------------------------------------------------------------
// REQUIRED: rendering function.
// See example code if you are unsure of how to implement this.
// Rendering function, will be called in Render().
// Alternatively you can keep this to NULL and call GetDrawData() after Render() to get the same pointer.
// See example applications if you are unsure of how to implement this.
void (*RenderDrawListsFn)(ImDrawData* data);
// Optional: access OS clipboard
@ -937,6 +940,7 @@ struct ImGuiTextEditCallbackData
ImGuiInputTextFlags EventFlag; // One of ImGuiInputTextFlags_Callback* // Read-only
ImGuiInputTextFlags Flags; // What user passed to InputText() // Read-only
void* UserData; // What user passed to InputText() // Read-only
bool ReadOnly; // Read-only mode // Read-only
// CharFilter event:
ImWchar EventChar; // Character input // Read-write (replace character or set to zero)
@ -1149,14 +1153,16 @@ struct ImDrawList
// All draw data to render an ImGui frame
struct ImDrawData
{
bool Valid; // Only valid after Render() is called and before the next NewFrame() is called.
ImDrawList** CmdLists;
int CmdListsCount;
int TotalVtxCount; // For convenience, sum of all cmd_lists vtx_buffer.Size
int TotalIdxCount; // For convenience, sum of all cmd_lists idx_buffer.Size
// Functions
void DeIndexAllBuffers(); // For backward compatibility: convert all buffers from indexed to de-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. Always prefer indexed rendering!
void ScaleClipRects(const ImVec2& sc); // Helper to scale the ClipRect field of each ImDrawCmd. Use if your final output buffer is at a different scale than ImGui expects, or if there is a difference between your window resolution and framebuffer resolution.
IMGUI_API ImDrawData() { Valid = false; CmdLists = NULL; CmdListsCount = TotalVtxCount = TotalIdxCount = 0; }
IMGUI_API void DeIndexAllBuffers(); // For backward compatibility: convert all buffers from indexed to de-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. Always prefer indexed rendering!
IMGUI_API void ScaleClipRects(const ImVec2& sc); // Helper to scale the ClipRect field of each ImDrawCmd. Use if your final output buffer is at a different scale than ImGui expects, or if there is a difference between your window resolution and framebuffer resolution.
};
struct ImFontConfig
@ -1224,8 +1230,9 @@ struct ImFontAtlas
void* TexID; // User data to refer to the texture once it has been uploaded to user's graphic systems. It ia passed back to you during rendering.
unsigned char* TexPixelsAlpha8; // 1 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight
unsigned int* TexPixelsRGBA32; // 4 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight * 4
int TexWidth;
int TexHeight;
int TexWidth; // Texture width calculated during Build().
int TexHeight; // Texture height calculated during Build().
int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height.
ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel (part of the TexExtraData block)
ImVector<ImFont*> Fonts;

View file

@ -206,9 +206,8 @@ void ImGui::ShowTestWindow(bool* opened)
{
ImGui::TextWrapped("Tip: Load fonts with io.Fonts->AddFontFromFileTTF().");
ImFontAtlas* atlas = ImGui::GetIO().Fonts;
if (ImGui::TreeNode("Atlas texture"))
if (ImGui::TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight))
{
ImGui::Text("%dx%d pixels", atlas->TexWidth, atlas->TexHeight);
ImGui::Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0,0), ImVec2(1,1), ImColor(255,255,255,255), ImColor(255,255,255,128));
ImGui::TreePop();
}
@ -422,8 +421,12 @@ void ImGui::ShowTestWindow(bool* opened)
if (ImGui::TreeNode("Multi-line Text Input"))
{
static bool read_only = false;
static char text[1024*16] = "// F00F bug\nlabel:\n\tlock cmpxchg8b eax\n";
ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-1.0f, ImGui::GetTextLineHeight() * 16), ImGuiInputTextFlags_AllowTabInput);
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0,0));
ImGui::Checkbox("Read-only", &read_only);
ImGui::PopStyleVar();
ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-1.0f, ImGui::GetTextLineHeight() * 16), ImGuiInputTextFlags_AllowTabInput | (read_only ? ImGuiInputTextFlags_ReadOnly : 0));
ImGui::TreePop();
}
@ -832,7 +835,7 @@ void ImGui::ShowTestWindow(bool* opened)
if (ImGui::TreeNode("Groups"))
{
ImGui::TextWrapped("(Using ImGui::BeginGroup()/EndGroup() to layout items. BeginGroup() basically locks the horizontal position. EndGroup() bundled the whole group so that you can use functions such as IsItemHovered() on it.)");
ImGui::TextWrapped("(Using ImGui::BeginGroup()/EndGroup() to layout items. BeginGroup() basically locks the horizontal position. EndGroup() bundles the whole group so that you can use functions such as IsItemHovered() on it.)");
ImGui::BeginGroup();
{
ImGui::BeginGroup();
@ -994,7 +997,8 @@ void ImGui::ShowTestWindow(bool* opened)
ImVec4 clip_rect(pos.x, pos.y, pos.x+size.x, pos.y+size.y);
ImGui::GetWindowDrawList()->AddRectFilled(pos, ImVec2(pos.x+size.x,pos.y+size.y), ImColor(90,90,120,255));
ImGui::GetWindowDrawList()->AddText(ImGui::GetWindowFont(), ImGui::GetWindowFontSize()*2.0f, ImVec2(pos.x+offset.x,pos.y+offset.y), ImColor(255,255,255,255), "Line 1 hello\nLine 2 clip me!", NULL, 0.0f, &clip_rect);
ImGui::Dummy(size);
ImGui::InvisibleButton("##dummy", size);
if (ImGui::IsItemActive() && ImGui::IsMouseDragging()) { offset.x += ImGui::GetIO().MouseDelta.x; offset.y += ImGui::GetIO().MouseDelta.y; }
ImGui::TreePop();
}
}
@ -1367,7 +1371,8 @@ void ImGui::ShowTestWindow(bool* opened)
draw_list->PopClipRect();
ImVec2 value_raw = ImGui::GetMouseDragDelta(0, 0.0f);
ImVec2 value_with_lock_threshold = ImGui::GetMouseDragDelta(0);
ImGui::SameLine(); ImGui::Text("Raw (%.1f, %.1f), WithLockThresold (%.1f, %.1f)", value_raw.x, value_raw.y, value_with_lock_threshold.x, value_with_lock_threshold.y);
ImVec2 mouse_delta = ImGui::GetIO().MouseDelta;
ImGui::SameLine(); ImGui::Text("Raw (%.1f, %.1f), WithLockThresold (%.1f, %.1f), MouseDelta (%.1f, %.1f)", value_raw.x, value_raw.y, value_with_lock_threshold.x, value_with_lock_threshold.y, mouse_delta.x, mouse_delta.y);
}
ImGui::TreePop();
}

View file

@ -48,6 +48,11 @@ namespace IMGUI_STB_NAMESPACE
{
#endif
#ifdef _MSC_VER
#pragma warning (push)
#pragma warning (disable: 4456) // declaration of 'xx' hides previous local declaration
#endif
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-function"
@ -76,6 +81,10 @@ namespace IMGUI_STB_NAMESPACE
#pragma clang diagnostic pop
#endif
#ifdef _MSC_VER
#pragma warning (pop)
#endif
#ifdef IMGUI_STB_NAMESPACE
} // namespace ImGuiStb
using namespace IMGUI_STB_NAMESPACE;
@ -150,6 +159,69 @@ void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data)
AddDrawCmd();
}
void ImDrawList::UpdateClipRect()
{
ImDrawCmd* current_cmd = CmdBuffer.Size ? &CmdBuffer.back() : NULL;
if (!current_cmd || (current_cmd->ElemCount != 0) || current_cmd->UserCallback != NULL)
{
AddDrawCmd();
}
else
{
ImVec4 current_clip_rect = _ClipRectStack.Size ? _ClipRectStack.back() : GNullClipRect;
if (CmdBuffer.Size >= 2 && ImLengthSqr(CmdBuffer.Data[CmdBuffer.Size-2].ClipRect - current_clip_rect) < 0.00001f)
CmdBuffer.pop_back();
else
current_cmd->ClipRect = current_clip_rect;
}
}
// Scissoring. The values in clip_rect are x1, y1, x2, y2.
void ImDrawList::PushClipRect(const ImVec4& clip_rect)
{
_ClipRectStack.push_back(clip_rect);
UpdateClipRect();
}
void ImDrawList::PushClipRectFullScreen()
{
PushClipRect(GNullClipRect);
// FIXME-OPT: This would be more correct but we're not supposed to access ImGuiState from here?
//ImGuiState& g = *GImGui;
//PushClipRect(GetVisibleRect());
}
void ImDrawList::PopClipRect()
{
IM_ASSERT(_ClipRectStack.Size > 0);
_ClipRectStack.pop_back();
UpdateClipRect();
}
void ImDrawList::UpdateTextureID()
{
ImDrawCmd* current_cmd = CmdBuffer.Size ? &CmdBuffer.back() : NULL;
const ImTextureID texture_id = _TextureIdStack.Size ? _TextureIdStack.back() : NULL;
if (!current_cmd || (current_cmd->ElemCount != 0 && current_cmd->TextureId != texture_id) || current_cmd->UserCallback != NULL)
AddDrawCmd();
else
current_cmd->TextureId = texture_id;
}
void ImDrawList::PushTextureID(const ImTextureID& texture_id)
{
_TextureIdStack.push_back(texture_id);
UpdateTextureID();
}
void ImDrawList::PopTextureID()
{
IM_ASSERT(_TextureIdStack.Size > 0);
_TextureIdStack.pop_back();
UpdateTextureID();
}
void ImDrawList::ChannelsSplit(int channels_count)
{
IM_ASSERT(_ChannelsCurrent == 0 && _ChannelsCount == 1);
@ -186,7 +258,6 @@ void ImDrawList::ChannelsSplit(int channels_count)
void ImDrawList::ChannelsMerge()
{
// Note that we never use or rely on channels.Size because it is merely a buffer that we never shrink back to 0 to keep all sub-buffers ready for use.
// This is why this function takes 'channel_count' as a parameter of how many channels to merge (the user knows)
if (_ChannelsCount <= 1)
return;
@ -229,69 +300,6 @@ void ImDrawList::ChannelsSetCurrent(int idx)
_IdxWritePtr = IdxBuffer.Data + IdxBuffer.Size;
}
void ImDrawList::UpdateClipRect()
{
ImDrawCmd* current_cmd = CmdBuffer.Size ? &CmdBuffer.back() : NULL;
if (!current_cmd || (current_cmd->ElemCount != 0) || current_cmd->UserCallback != NULL)
{
AddDrawCmd();
}
else
{
ImVec4 current_clip_rect = _ClipRectStack.Size ? _ClipRectStack.back() : GNullClipRect;
if (CmdBuffer.Size >= 2 && ImLengthSqr(CmdBuffer.Data[CmdBuffer.Size-2].ClipRect - current_clip_rect) < 0.00001f)
CmdBuffer.pop_back();
else
current_cmd->ClipRect = current_clip_rect;
}
}
// Scissoring. The values in clip_rect are x1, y1, x2, y2.
void ImDrawList::PushClipRect(const ImVec4& clip_rect)
{
_ClipRectStack.push_back(clip_rect);
UpdateClipRect();
}
void ImDrawList::PushClipRectFullScreen()
{
PushClipRect(GNullClipRect);
// This would be more correct but we're not supposed to access ImGuiState from here?
//ImGuiState& g = *GImGui;
//PushClipRect(GetVisibleRect());
}
void ImDrawList::PopClipRect()
{
IM_ASSERT(_ClipRectStack.Size > 0);
_ClipRectStack.pop_back();
UpdateClipRect();
}
void ImDrawList::UpdateTextureID()
{
ImDrawCmd* current_cmd = CmdBuffer.Size ? &CmdBuffer.back() : NULL;
const ImTextureID texture_id = _TextureIdStack.Size ? _TextureIdStack.back() : NULL;
if (!current_cmd || (current_cmd->ElemCount != 0 && current_cmd->TextureId != texture_id) || current_cmd->UserCallback != NULL)
AddDrawCmd();
else
current_cmd->TextureId = texture_id;
}
void ImDrawList::PushTextureID(const ImTextureID& texture_id)
{
_TextureIdStack.push_back(texture_id);
UpdateTextureID();
}
void ImDrawList::PopTextureID()
{
IM_ASSERT(_TextureIdStack.Size > 0);
_TextureIdStack.pop_back();
UpdateTextureID();
}
// NB: this can be called with negative count for removing primitives (as long as the result does not underflow)
void ImDrawList::PrimReserve(int idx_count, int vtx_count)
{
@ -348,7 +356,7 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
const ImVec2 uv = GImGui->FontTexUvWhitePixel;
anti_aliased &= GImGui->Style.AntiAliasedLines;
//if (ImGui::GetIO().KeyCtrl) anti_aliased = false;
//if (ImGui::GetIO().KeyCtrl) anti_aliased = false; // Debug
int count = points_count;
if (!closed)
@ -526,7 +534,7 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun
{
const ImVec2 uv = GImGui->FontTexUvWhitePixel;
anti_aliased &= GImGui->Style.AntiAliasedShapes;
//if (ImGui::GetIO().KeyCtrl) anti_aliased = false;
//if (ImGui::GetIO().KeyCtrl) anti_aliased = false; // Debug
if (anti_aliased)
{
@ -777,6 +785,7 @@ void ImDrawList::AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec
{
if ((col >> 24) == 0)
return;
PathLineTo(a);
PathLineTo(b);
PathLineTo(c);
@ -825,7 +834,7 @@ void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos,
IM_ASSERT(font->ContainerAtlas->TexID == _TextureIdStack.back()); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font.
// reserve vertices for worse case
// reserve vertices for worse case (over-reserving is useful and easily amortized)
const int char_count = (int)(text_end - text_begin);
const int vtx_count_max = char_count * 4;
const int idx_count_max = char_count * 6;
@ -844,7 +853,7 @@ void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos,
font->RenderText(font_size, pos, col, clip_rect, text_begin, text_end, this, wrap_width, cpu_fine_clip_rect != NULL);
// give back unused vertices
// FIXME-OPT
// FIXME-OPT: clean this up
VtxBuffer.resize((int)(_VtxWritePtr - VtxBuffer.Data));
IdxBuffer.resize((int)(_IdxWritePtr - IdxBuffer.Data));
int vtx_unused = vtx_count_max - (VtxBuffer.Size - vtx_begin);
@ -860,7 +869,8 @@ void ImDrawList::AddText(const ImVec2& pos, ImU32 col, const char* text_begin, c
{
if ((col >> 24) == 0)
return;
AddText(ImGui::GetWindowFont(), ImGui::GetWindowFontSize(), pos, col, text_begin, text_end);
AddText(GImGui->Font, GImGui->FontSize, pos, col, text_begin, text_end);
}
void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv0, const ImVec2& uv1, ImU32 col)
@ -918,7 +928,7 @@ void ImDrawData::ScaleClipRects(const ImVec2& scale)
}
//-----------------------------------------------------------------------------
// ImFontAtlias
// ImFontAtlas
//-----------------------------------------------------------------------------
ImFontConfig::ImFontConfig()
@ -944,7 +954,7 @@ ImFontAtlas::ImFontAtlas()
TexID = NULL;
TexPixelsAlpha8 = NULL;
TexPixelsRGBA32 = NULL;
TexWidth = TexHeight = 0;
TexWidth = TexHeight = TexDesiredWidth = 0;
TexUvWhitePixel = ImVec2(0, 0);
}
@ -962,14 +972,14 @@ void ImFontAtlas::ClearInputData()
ConfigData[i].FontData = NULL;
}
// When clearing this we lose access to the font name and other information used to build the font.
for (int i = 0; i < Fonts.Size; i++)
if (Fonts[i]->ConfigData >= ConfigData.Data && Fonts[i]->ConfigData < ConfigData.Data + ConfigData.Size)
{
Fonts[i]->ConfigData = NULL;
Fonts[i]->ConfigDataCount = 0;
}
ConfigData.clear();
// When clearing this we lose access to the font name and other information used to build the font.
for (int i = 0; i < Fonts.Size; i++)
if (Fonts[i]->ConfigData >= ConfigData.Data && Fonts[i]->ConfigData < ConfigData.Data + ConfigData.Size)
{
Fonts[i]->ConfigData = NULL;
Fonts[i]->ConfigDataCount = 0;
}
ConfigData.clear();
}
void ImFontAtlas::ClearTexData()
@ -1001,7 +1011,7 @@ void ImFontAtlas::Clear()
void ImFontAtlas::GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel)
{
// Lazily build
// Build atlas on demand
if (TexPixelsAlpha8 == NULL)
{
if (ConfigData.empty())
@ -1017,8 +1027,8 @@ void ImFontAtlas::GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_wid
void ImFontAtlas::GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel)
{
// Lazily convert to RGBA32 format
// Although it is likely to be the most commonly used format, our font rendering is 8 bpp
// Convert to RGBA32 format on demand
// Although it is likely to be the most commonly used format, our font rendering is 1 channel / 8 bpp
if (!TexPixelsRGBA32)
{
unsigned char* pixels;
@ -1064,14 +1074,14 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg)
return Fonts.back();
}
// Default font ttf is compressed with stb_compress then base85 encoded (see extra_fonts/binary_to_compressed_c.cpp for encoder)
// Default font TTF is compressed with stb_compress then base85 encoded (see extra_fonts/binary_to_compressed_c.cpp for encoder)
static unsigned int stb_decompress_length(unsigned char *input);
static unsigned int stb_decompress(unsigned char *output, unsigned char *i, unsigned int length);
static const char* GetDefaultCompressedFontDataTTFBase85();
static unsigned int Decode85Byte(char c) { return c >= '\\' ? c-36 : c-35; }
static void Decode85(const unsigned char* src, unsigned int* dst) { for (; *src; src += 5) *dst++ = Decode85Byte(src[0]) + 85*(Decode85Byte(src[1]) + 85*(Decode85Byte(src[2]) + 85*(Decode85Byte(src[3]) + 85*Decode85Byte(src[4])))); }
// Load embedded ProggyClean.ttf at size 13
// Load embedded ProggyClean.ttf at size 13, disable oversampling
ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template)
{
ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
@ -1089,9 +1099,9 @@ ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template)
ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
{
void* data = NULL;
int data_size = 0;
if (!ImLoadFileToMemory(filename, "rb", (void**)&data, &data_size, 0))
void* data = ImLoadFileToMemory(filename, "rb", &data_size, 0);
if (!data)
{
IM_ASSERT(0); // Could not load file.
return NULL;
@ -1099,6 +1109,7 @@ ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels,
ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
if (font_cfg.Name[0] == '\0')
{
// Store a short copy of filename into into the font name for convenience
const char* p;
for (p = filename + strlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--) {}
snprintf(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "%s", p);
@ -1106,7 +1117,7 @@ ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels,
return AddFontFromMemoryTTF(data, data_size, size_pixels, &font_cfg, glyph_ranges);
}
// Transfer ownership of 'ttf_data' to ImFontAtlas, will be deleted after Build()
// NBM Transfer ownership of 'ttf_data' to ImFontAtlas, unless font_cfg_template->FontDataOwnedByAtlas == false. Owned TTF buffer will be deleted after Build().
ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* ttf_data, int ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
{
ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
@ -1173,6 +1184,7 @@ bool ImFontAtlas::Build()
if (!stbtt_InitFont(&tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset))
return false;
// Count glyphs
if (!cfg.GlyphRanges)
cfg.GlyphRanges = GetGlyphRangesDefault();
for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[1]; in_range += 2)
@ -1183,7 +1195,7 @@ bool ImFontAtlas::Build()
}
// Start packing
TexWidth = (total_glyph_count > 1000) ? 1024 : 512; // Width doesn't actually matters.
TexWidth = (TexDesiredWidth > 0) ? TexDesiredWidth : (total_glyph_count > 2000) ? 2048 : (total_glyph_count > 1000) ? 1024 : 512; // Width doesn't actually matters much but some API/GPU have texture size limitations, and increasing width can decrease height.
TexHeight = 0;
const int max_tex_height = 1024*32;
stbtt_pack_context spc;
@ -1207,7 +1219,7 @@ bool ImFontAtlas::Build()
memset(buf_rects, 0, total_glyph_count * sizeof(stbrp_rect)); // Unnecessary but let's clear this for the sake of sanity.
memset(buf_ranges, 0, total_glyph_range_count * sizeof(stbtt_pack_range));
// First font pass: pack all glyphs (no rendering at this point, we are working with glyph sizes only)
// First font pass: pack all glyphs (no rendering at this point, we are working with rectangles in an infinitely tall texture at this point)
for (int input_i = 0; input_i < ConfigData.Size; input_i++)
{
ImFontConfig& cfg = ConfigData[input_i];
@ -1345,7 +1357,8 @@ bool ImFontAtlas::Build()
void ImFontAtlas::RenderCustomTexData(int pass, void* p_rects)
{
// . = white layer, X = black layer, others are blank
// A work of art lies ahead! (. = white layer, X = black layer, others are blank)
// The white texels on the top left are the ones we'll use everywhere in ImGui to render filled shapes.
const int TEX_DATA_W = 90;
const int TEX_DATA_H = 27;
const char texture_data[TEX_DATA_W*TEX_DATA_H+1] =
@ -1401,35 +1414,36 @@ void ImFontAtlas::RenderCustomTexData(int pass, void* p_rects)
TexPixelsAlpha8[offset0] = texture_data[n] == '.' ? 0xFF : 0x00;
TexPixelsAlpha8[offset1] = texture_data[n] == 'X' ? 0xFF : 0x00;
}
const ImVec2 tex_uv_scale(1.0f / TexWidth, 1.0f / TexHeight);
TexUvWhitePixel = ImVec2((r.x + 0.5f) * tex_uv_scale.x, (r.y + 0.5f) * tex_uv_scale.y);
const ImVec2 tex_uv_scale(1.0f / TexWidth, 1.0f / TexHeight);
TexUvWhitePixel = ImVec2((r.x + 0.5f) * tex_uv_scale.x, (r.y + 0.5f) * tex_uv_scale.y);
const ImVec2 cursor_datas[ImGuiMouseCursor_Count_][3] =
{
// Pos ........ Size ......... Offset ......
{ ImVec2(0,3), ImVec2(12,19), ImVec2( 0, 0) }, // ImGuiMouseCursor_Arrow
{ ImVec2(13,0), ImVec2(7,16), ImVec2( 4, 8) }, // ImGuiMouseCursor_TextInput
{ ImVec2(31,0), ImVec2(23,23), ImVec2(11,11) }, // ImGuiMouseCursor_Move
{ ImVec2(21,0), ImVec2( 9,23), ImVec2( 5,11) }, // ImGuiMouseCursor_ResizeNS
{ ImVec2(55,18),ImVec2(23, 9), ImVec2(11, 5) }, // ImGuiMouseCursor_ResizeEW
{ ImVec2(73,0), ImVec2(17,17), ImVec2( 9, 9) }, // ImGuiMouseCursor_ResizeNESW
{ ImVec2(55,0), ImVec2(17,17), ImVec2( 9, 9) }, // ImGuiMouseCursor_ResizeNWSE
};
// Setup mouse cursors
const ImVec2 cursor_datas[ImGuiMouseCursor_Count_][3] =
{
// Pos ........ Size ......... Offset ......
{ ImVec2(0,3), ImVec2(12,19), ImVec2( 0, 0) }, // ImGuiMouseCursor_Arrow
{ ImVec2(13,0), ImVec2(7,16), ImVec2( 4, 8) }, // ImGuiMouseCursor_TextInput
{ ImVec2(31,0), ImVec2(23,23), ImVec2(11,11) }, // ImGuiMouseCursor_Move
{ ImVec2(21,0), ImVec2( 9,23), ImVec2( 5,11) }, // ImGuiMouseCursor_ResizeNS
{ ImVec2(55,18),ImVec2(23, 9), ImVec2(11, 5) }, // ImGuiMouseCursor_ResizeEW
{ ImVec2(73,0), ImVec2(17,17), ImVec2( 9, 9) }, // ImGuiMouseCursor_ResizeNESW
{ ImVec2(55,0), ImVec2(17,17), ImVec2( 9, 9) }, // ImGuiMouseCursor_ResizeNWSE
};
for (int type = 0; type < ImGuiMouseCursor_Count_; type++)
{
ImGuiMouseCursorData& cursor_data = GImGui->MouseCursorData[type];
ImVec2 pos = cursor_datas[type][0] + ImVec2((float)r.x, (float)r.y);
const ImVec2 size = cursor_datas[type][1];
cursor_data.Type = type;
cursor_data.Size = size;
cursor_data.HotOffset = cursor_datas[type][2];
cursor_data.TexUvMin[0] = (pos) * tex_uv_scale;
cursor_data.TexUvMax[0] = (pos + size) * tex_uv_scale;
pos.x += TEX_DATA_W+1;
cursor_data.TexUvMin[1] = (pos) * tex_uv_scale;
cursor_data.TexUvMax[1] = (pos + size) * tex_uv_scale;
}
for (int type = 0; type < ImGuiMouseCursor_Count_; type++)
{
ImGuiMouseCursorData& cursor_data = GImGui->MouseCursorData[type];
ImVec2 pos = cursor_datas[type][0] + ImVec2((float)r.x, (float)r.y);
const ImVec2 size = cursor_datas[type][1];
cursor_data.Type = type;
cursor_data.Size = size;
cursor_data.HotOffset = cursor_datas[type][2];
cursor_data.TexUvMin[0] = (pos) * tex_uv_scale;
cursor_data.TexUvMax[0] = (pos + size) * tex_uv_scale;
pos.x += TEX_DATA_W+1;
cursor_data.TexUvMin[1] = (pos) * tex_uv_scale;
cursor_data.TexUvMax[1] = (pos + size) * tex_uv_scale;
}
}
}
@ -1593,7 +1607,7 @@ void ImFont::BuildLookupTable()
}
// Create a glyph to handle TAB
// FIXME: Needs proper TAB handling but it needs to be contextualized (can arbitrary say that each string starts at "column 0"
// FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at "column 0" ?)
if (FindGlyph((unsigned short)' '))
{
if (Glyphs.back().Codepoint != '\t') // So we can call this function multiple times
@ -1773,7 +1787,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons
}
}
// Decode and advance source (handle unlikely UTF-8 decoding failure by skipping to the next byte)
// Decode and advance source
const char* prev_s = s;
unsigned int c = (unsigned int)*s;
if (c < 0x80)
@ -1876,7 +1890,7 @@ void ImFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_re
}
}
// Decode and advance source (handle unlikely UTF-8 decoding failure by skipping to the next byte)
// Decode and advance source
unsigned int c = (unsigned int)*s;
if (c < 0x80)
{
@ -1915,7 +1929,7 @@ void ImFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_re
// Clipping on Y is more likely
if (c != ' ' && c != '\t')
{
// We don't do a second finer clipping test on the Y axis (todo: do some measurement see if it is worth it, probably not)
// We don't do a second finer clipping test on the Y axis (TODO: do some measurement see if it is worth it, probably not)
float y1 = (float)(y + glyph->Y0 * scale);
float y2 = (float)(y + glyph->Y1 * scale);
@ -1929,7 +1943,7 @@ void ImFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& clip_re
float u2 = glyph->U1;
float v2 = glyph->V1;
// CPU side clipping used to fit text in their frame when the frame is too small. Only does clipping for axis aligned quads
// CPU side clipping used to fit text in their frame when the frame is too small. Only does clipping for axis aligned quads.
if (cpu_fine_clip)
{
if (x1 < clip_rect.x)

View file

@ -65,7 +65,7 @@ namespace ImGuiStb
// Context
//-----------------------------------------------------------------------------
extern ImGuiState* GImGui;
extern IMGUI_API ImGuiState* GImGui;
//-----------------------------------------------------------------------------
// Helpers
@ -75,28 +75,28 @@ extern ImGuiState* GImGui;
#define IM_PI 3.14159265358979323846f
// Helpers: UTF-8 <> wchar
int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end); // return output UTF-8 bytes count
int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end); // return input UTF-8 bytes count
int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_remaining = NULL); // return input UTF-8 bytes count
int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end); // return number of UTF-8 code-points (NOT bytes count)
int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string as UTF-8 code-points
IMGUI_API int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end); // return output UTF-8 bytes count
IMGUI_API int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end); // return input UTF-8 bytes count
IMGUI_API int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_remaining = NULL); // return input UTF-8 bytes count
IMGUI_API int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end); // return number of UTF-8 code-points (NOT bytes count)
IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string as UTF-8 code-points
// Helpers: Misc
ImU32 ImHash(const void* data, int data_size, ImU32 seed = 0); // Pass data_size==0 for zero-terminated strings
bool ImLoadFileToMemory(const char* filename, const char* file_open_mode, void** out_file_data, int* out_file_size = NULL, int padding_bytes = 0);
bool ImIsPointInTriangle(const ImVec2& p, const ImVec2& a, const ImVec2& b, const ImVec2& c);
static inline bool ImCharIsSpace(int c) { return c == ' ' || c == '\t' || c == 0x3000; }
static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; }
IMGUI_API ImU32 ImHash(const void* data, int data_size, ImU32 seed = 0); // Pass data_size==0 for zero-terminated strings
IMGUI_API void* ImLoadFileToMemory(const char* filename, const char* file_open_mode, int* out_file_size = NULL, int padding_bytes = 0);
IMGUI_API bool ImIsPointInTriangle(const ImVec2& p, const ImVec2& a, const ImVec2& b, const ImVec2& c);
static inline bool ImCharIsSpace(int c) { return c == ' ' || c == '\t' || c == 0x3000; }
static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; }
// Helpers: String
int ImStricmp(const char* str1, const char* str2);
int ImStrnicmp(const char* str1, const char* str2, int count);
char* ImStrdup(const char* str);
int ImStrlenW(const ImWchar* str);
const ImWchar* ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin); // Find beginning-of-line
const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end);
int ImFormatString(char* buf, int buf_size, const char* fmt, ...) IM_PRINTFARGS(3);
int ImFormatStringV(char* buf, int buf_size, const char* fmt, va_list args);
IMGUI_API int ImStricmp(const char* str1, const char* str2);
IMGUI_API int ImStrnicmp(const char* str1, const char* str2, int count);
IMGUI_API char* ImStrdup(const char* str);
IMGUI_API int ImStrlenW(const ImWchar* str);
IMGUI_API const ImWchar*ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin); // Find beginning-of-line
IMGUI_API const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end);
IMGUI_API int ImFormatString(char* buf, int buf_size, const char* fmt, ...) IM_PRINTFARGS(3);
IMGUI_API int ImFormatStringV(char* buf, int buf_size, const char* fmt, va_list args);
// Helpers: Math
// We are keeping those not leaking to the user by default, in the case the user has implicit cast operators between ImVec2 and its own types (when IM_VEC2_CLASS_EXTRA is defined)
@ -182,7 +182,7 @@ enum ImGuiDataType
// 2D axis aligned bounding-box
// NB: we can't rely on ImVec2 math operators being available here
struct ImRect
struct IMGUI_API ImRect
{
ImVec2 Min; // Upper-left
ImVec2 Max; // Lower-right
@ -249,21 +249,21 @@ struct ImGuiGroupData
};
// Simple column measurement currently used for MenuItem() only. This is very short-sighted for now and not a generic helper.
struct ImGuiSimpleColumns
struct IMGUI_API ImGuiSimpleColumns
{
int Count;
float Spacing;
float Width, NextWidth;
float Pos[8], NextWidths[8];
int Count;
float Spacing;
float Width, NextWidth;
float Pos[8], NextWidths[8];
ImGuiSimpleColumns();
void Update(int count, float spacing, bool clear);
float DeclColumns(float w0, float w1, float w2);
float CalcExtraSpace(float avail_w);
void Update(int count, float spacing, bool clear);
float DeclColumns(float w0, float w1, float w2);
float CalcExtraSpace(float avail_w);
};
// Internal state of the currently focused/edited text input box
struct ImGuiTextEditState
struct IMGUI_API ImGuiTextEditState
{
ImGuiID Id; // widget id owning the text state
ImVector<ImWchar> Text; // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so we copy into own buffer.
@ -371,6 +371,7 @@ struct ImGuiState
ImGuiSetCond SetNextTreeNodeOpenedCond;
// Render
ImDrawData RenderDrawData; // Main ImDrawData instance to pass render information to the user
ImVector<ImDrawList*> RenderDrawLists[3];
float ModalWindowDarkeningRatio;
ImDrawList OverlayDrawList; // Optional software render of mouse cursors, if io.MouseDrawCursor is set + a few debug overlays
@ -495,14 +496,14 @@ struct ImGuiDrawContext
ImGuiLayoutType LayoutType;
// We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings.
bool ButtonRepeat; // == ButtonRepeatStack.back() [empty == false]
bool AllowKeyboardFocus; // == AllowKeyboardFocusStack.back() [empty == true]
float ItemWidth; // == ItemWidthStack.back(). 0.0: default, >0.0: width in pixels, <0.0: align xx pixels to the right of window
float TextWrapPos; // == TextWrapPosStack.back() [empty == -1.0f]
ImVector<bool> ButtonRepeatStack;
ImVector<bool> AllowKeyboardFocusStack;
bool AllowKeyboardFocus; // == AllowKeyboardFocusStack.back() [empty == true]
bool ButtonRepeat; // == ButtonRepeatStack.back() [empty == false]
ImVector<float> ItemWidthStack;
ImVector<float> TextWrapPosStack;
ImVector<bool> AllowKeyboardFocusStack;
ImVector<bool> ButtonRepeatStack;
ImVector<ImGuiGroupData>GroupStack;
ImGuiColorEditMode ColorEditMode;
int StackSizesBackup[6]; // Store size of various stacks for asserting
@ -551,7 +552,7 @@ struct ImGuiDrawContext
};
// Windows data
struct ImGuiWindow
struct IMGUI_API ImGuiWindow
{
char* Name;
ImGuiID ID;