Compare commits

..

17 Commits
v1.02 ... v1.04

Author SHA1 Message Date
cda3aecc6a Fixed combo box (bug introduced earlier today) + adding bit of vertical padding in combo. 2014-08-13 19:26:25 +01:00
b6d1d85d86 Fixed scissoring in OpenGL example 2014-08-13 19:12:50 +01:00
9a426faf4f Added InputFloat2(), SliderFloat2() 2014-08-13 18:46:18 +01:00
b0d5600ffb Merge pull request #14 from Roflraging/constiteratorfix
Fix for gcc type qualifier warnings.
2014-08-13 18:40:18 +01:00
c52a54ef43 Fix for gcc type qualifier warnings.
With -Wall -Wextra -Werror, it is not possible to compile against
imgui.h due to const correctness violation in ImVector.
2014-08-13 11:57:37 -05:00
cc9d63b46a Fixed columns lines not being pixel aligned 2014-08-13 17:08:44 +01:00
d3ad5ce475 Update README.md 2014-08-13 13:23:37 +01:00
cb3d503941 OpenGL example now use the fixed function-pipeline. Code down by 120 lines. 2014-08-13 11:43:51 +01:00
ddc7f8b0b0 Simplified ImDrawList system (samples are 20 lines shorter) + merged title bar draw bar. 2014-08-13 11:34:08 +01:00
57ac561ecb Minor warning fix + removed unused function parameter. 2014-08-12 20:05:10 +01:00
2573ffb6fc Fixed warnings for more stringent compilation settings. Added various small helpers. 2014-08-12 19:57:46 +01:00
c938affcac Update README.md
Added References
2014-08-12 15:09:01 +01:00
a1e176fb07 Added Makefile for MacOS X (courtesy of djoshea) 2014-08-12 13:59:36 +01:00
901e9890d4 Removed stray debug code 2014-08-12 13:55:43 +01:00
f4ee74b312 Renamed Makefile 2014-08-12 13:55:30 +01:00
64e5c2f127 Merge pull request #11 from corpsmoderne/master
Add a quick and dirty makefile to build on linux
2014-08-12 13:53:06 +01:00
e2655d104e add a quick and dirty makefile to build on linux 2014-08-12 14:24:23 +02:00
8 changed files with 330 additions and 385 deletions

View File

@ -1,17 +1,18 @@
ImGui
=====
ImGui is a bloat-free graphical user interface library for C++. It is portable, renderer agnostic and carries minimal amount of dependencies (only 3 files are needed). It is based on an "immediate" graphical user interface paradigm which allows you to build simple user interfaces with ease.
ImGui is a bloat-free graphical user interface library for C++. It outputs vertex buffers that you can render in your 3D-pipeline enabled application. It is portable, renderer agnostic and carries minimal amount of dependencies (only 3 files are needed). It is based on an "immediate" graphical user interface paradigm which allows you to build simple user interfaces with ease.
ImGui is designed to allow programmers to create "content creation" or "debug" tools (as opposed to tools for the average end-user). It favors simplicity and thus lacks certain features normally found in more high-level libraries, such as string localisation.
ImGui is designed to enable fast iteration and allow programmers to create "content creation" or "debug" tools (as opposed to tools for the average end-user). It favors simplicity and thus lacks certain features normally found in more high-level libraries, such as string localisation.
After ImGui is setup in your application, you can use it like in this example:
ImGui is particularly suited to integration in 3D applications, fullscreen applications, embedded applications, games, or any applications on consoles platforms where operating system features are non-standard.
After ImGui is setup in your engine, you can use it like in this example:
![screenshot of sample code alongside its output with ImGui](/web/code_sample_01.png?raw=true)
ImGui outputs vertex buffers and simple command-lists that you can render in your application. Because it doesn't know or touch graphics state directly, you can call ImGui commands anywhere in your code (e.g. in the middle of a running algorithm, or in the middle of your own rendering process). Refer to the sample applications in the examples/ folder for instructions on how to integrate ImGui with your existing codebase.
Gallery
-------
@ -20,6 +21,16 @@ Gallery
![screenshot 3](/web/test_window_03.png?raw=true)
![screenshot 4](/web/test_window_04.png?raw=true)
References
----------
The Immediate Mode GUI paradigm may at first appear unusual to some users. This is mainly because "Retained Mode" GUIs have been so widespread and predominant. The following links can give you a better understanding about how Immediate Mode GUIs works.
- [Johannes 'johno' Norneby's article](http://www.johno.se/book/imgui.html).
- [A presentation by Rickard Gustafsson and Johannes Algelind](http://www.cse.chalmers.se/edu/year/2011/course/TDA361/Advanced%20Computer%20Graphics/IMGUI.pdf).
- [Jari Komppa's tutorial on building an ImGui library](http://iki.fi/sol/imgui/).
- [Casey Muratori's original video that popularized the concept](https://mollyrocket.com/861).
Credits
-------

View File

@ -86,36 +86,15 @@ static void ImImpl_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_c
int vtx_offset = 0;
for (int n = 0; n < cmd_lists_count; n++)
{
// Setup stack of clipping rectangles
int clip_rect_buf_offset = 0;
ImVector<ImVec4> clip_rect_stack;
clip_rect_stack.push_back(ImVec4(-9999,-9999,+9999,+9999));
// Render command list
const ImDrawList* cmd_list = cmd_lists[n];
const ImDrawCmd* pcmd_end = cmd_list->commands.end();
for (const ImDrawCmd* pcmd = cmd_list->commands.begin(); pcmd != pcmd_end; pcmd++)
{
switch (pcmd->cmd_type)
{
case ImDrawCmdType_DrawTriangleList:
{
const ImVec4& clip_rect = clip_rect_stack.back();
const RECT r = { (LONG)clip_rect.x, (LONG)clip_rect.y, (LONG)clip_rect.z, (LONG)clip_rect.w };
g_pd3dDevice->SetScissorRect(&r);
g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, vtx_offset, pcmd->vtx_count/3);
vtx_offset += pcmd->vtx_count;
}
break;
case ImDrawCmdType_PushClipRect:
clip_rect_stack.push_back(cmd_list->clip_rect_buffer[clip_rect_buf_offset++]);
break;
case ImDrawCmdType_PopClipRect:
clip_rect_stack.pop_back();
break;
}
const RECT r = { (LONG)pcmd->clip_rect.x, (LONG)pcmd->clip_rect.y, (LONG)pcmd->clip_rect.z, (LONG)pcmd->clip_rect.w };
g_pd3dDevice->SetScissorRect(&r);
g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, vtx_offset, pcmd->vtx_count/3);
vtx_offset += pcmd->vtx_count;
}
}
}

View File

@ -0,0 +1,18 @@
#
# Quick and dirty makefile to build on Linux
# tested on Ubuntu 14.04.1 32bit
#
SRC = main.cpp ../../imgui.cpp
OBJ = $(SRC:.cpp=.o)
CXXFLAGS = -I../../ `pkg-config --cflags glfw3`
LIBS = `pkg-config --static --libs glfw3` -lGLEW
all: $(OBJ)
$(CXX) $(OBJ) $(LIBS)
clean:
$(RM) -f $(OBJ)

View File

@ -0,0 +1,17 @@
# This makefile currently only works for mac os
# You should install via homebrew:
# brew install glew
# brew install glfw3
#
CXXFLAGS=-framework OpenGL -framework Cocoa -framework IOKit
#CXXFLAGS+=-L/usr/local/Cellar/glew/1.10.0/lib -L/usr/local/Cellar/glfw3/3.0.4/lib
CXXFLAGS+=-lglew -lglfw3
CXXFLAGS+=-I../../
CXXFLAGS+= -D__APPLE__
main: main.cpp ../../imgui.cpp
$(CXX) $(CXXFLAGS) -o $@ $^
clean:
rm main

View File

@ -2,106 +2,65 @@
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h" // for .png loading
#include "stb_image.h" // for .png loading
#include "../../imgui.h"
#ifdef _MSC_VER
#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
#endif
static GLFWwindow* window;
static GLuint vbo;
static GLuint vao;
static GLuint vertexShader;
static GLuint fragmentShader;
static GLuint shaderProgram;
static GLuint fontTex;
// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structuer)
// We are using the fixed pipeline.
// A faster way would be to collate all vertices from all cmd_lists into a single vertex buffer
static void ImImpl_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
{
size_t total_vtx_count = 0;
for (int n = 0; n < cmd_lists_count; n++)
total_vtx_count += cmd_lists[n]->vtx_buffer.size();
if (total_vtx_count == 0)
if (cmd_lists_count == 0)
return;
// Copy all vertices into a single contiguous GL buffer
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBindVertexArray(vao);
glBufferData(GL_ARRAY_BUFFER, total_vtx_count * sizeof(ImDrawVert), NULL, GL_STREAM_DRAW);
unsigned char* buffer_data = (unsigned char*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
if (!buffer_data)
return;
for (int n = 0; n < cmd_lists_count; n++)
{
const ImDrawList* cmd_list = cmd_lists[n];
memcpy(buffer_data, &cmd_list->vtx_buffer[0], cmd_list->vtx_buffer.size() * sizeof(ImDrawVert));
buffer_data += cmd_list->vtx_buffer.size() * sizeof(ImDrawVert);
}
glUnmapBuffer(GL_ARRAY_BUFFER);
// Setup render state: alpha-blending enabled, no face culling, no depth testing
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
// Bind texture and enable our shader
// Bind texture
glBindTexture(GL_TEXTURE_2D, fontTex);
glUseProgram(shaderProgram);
const GLint uniMVP = glGetUniformLocation(shaderProgram, "MVP");
const GLint uniClipRect = glGetUniformLocation(shaderProgram, "ClipRect");
glEnable(GL_TEXTURE_2D);
// Setup orthographic projection matrix
// Setup matrices
const float width = ImGui::GetIO().DisplaySize.x;
const float height = ImGui::GetIO().DisplaySize.y;
const float mvp[4][4] =
{
{ 2.0f/width, 0.0f, 0.0f, 0.0f },
{ 0.0f, 2.0f/-height, 0.0f, 0.0f },
{ 0.0f, 0.0f, -1.0f, 0.0f },
{ -1.0f, 1.0f, 0.0f, 1.0f },
};
glUniformMatrix4fv(uniMVP, 1, GL_FALSE, &mvp[0][0]);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0f, width, height, 0.0f, -1.0f, +1.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Render command lists
int vtx_offset = 0;
for (int n = 0; n < cmd_lists_count; n++)
{
// Setup stack of clipping rectangles
int clip_rect_buf_offset = 0;
ImVector<ImVec4> clip_rect_stack;
clip_rect_stack.push_back(ImVec4(-9999,-9999,+9999,+9999));
// Render command list
const ImDrawList* cmd_list = cmd_lists[n];
const unsigned char* vtx_buffer = (const unsigned char*)cmd_list->vtx_buffer.begin();
glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer));
glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer+8));
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (void*)(vtx_buffer+16));
int vtx_offset = 0;
const ImDrawCmd* pcmd_end = cmd_list->commands.end();
for (const ImDrawCmd* pcmd = cmd_list->commands.begin(); pcmd != pcmd_end; pcmd++)
{
switch (pcmd->cmd_type)
{
case ImDrawCmdType_DrawTriangleList:
glUniform4fv(uniClipRect, 1, (float*)&clip_rect_stack.back());
glDrawArrays(GL_TRIANGLES, vtx_offset, pcmd->vtx_count);
vtx_offset += pcmd->vtx_count;
break;
case ImDrawCmdType_PushClipRect:
clip_rect_stack.push_back(cmd_list->clip_rect_buffer[clip_rect_buf_offset++]);
break;
case ImDrawCmdType_PopClipRect:
clip_rect_stack.pop_back();
break;
}
glScissor((int)pcmd->clip_rect.x, (int)(height - pcmd->clip_rect.w), (int)(pcmd->clip_rect.z - pcmd->clip_rect.x), (int)(pcmd->clip_rect.w - pcmd->clip_rect.y));
glDrawArrays(GL_TRIANGLES, vtx_offset, pcmd->vtx_count);
vtx_offset += pcmd->vtx_count;
}
}
// Cleanup GL state
glBindTexture(GL_TEXTURE_2D, 0);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);
glDisable(GL_SCISSOR_TEST);
}
static const char* ImImpl_GetClipboardTextFn()
@ -122,42 +81,10 @@ static void ImImpl_SetClipboardTextFn(const char* text, const char* text_end)
free(buf);
}
// Shader sources
const GLchar* vertexSource =
"#version 150 core\n"
"uniform mat4 MVP;"
"in vec2 i_pos;"
"in vec2 i_uv;"
"in vec4 i_col;"
"out vec4 col;"
"out vec2 pixel_pos;"
"out vec2 uv;"
"void main() {"
" col = i_col;"
" pixel_pos = i_pos;"
" uv = i_uv;"
" gl_Position = MVP * vec4(i_pos.x, i_pos.y, 0.0f, 1.0f);"
"}";
const GLchar* fragmentSource =
"#version 150 core\n"
"uniform sampler2D Tex;"
"uniform vec4 ClipRect;"
"in vec4 col;"
"in vec2 pixel_pos;"
"in vec2 uv;"
"out vec4 o_col;"
"void main() {"
" o_col = texture(Tex, uv) * col;"
//" if (pixel_pos.x < ClipRect.x || pixel_pos.y < ClipRect.y || pixel_pos.x > ClipRect.z || pixel_pos.y > ClipRect.w) discard;" // Clipping: using discard
//" if (step(ClipRect.x,pixel_pos.x) * step(ClipRect.y,pixel_pos.y) * step(pixel_pos.x,ClipRect.z) * step(pixel_pos.y,ClipRect.w) < 1.0f) discard;" // Clipping: using discard and step
" o_col.w *= (step(ClipRect.x,pixel_pos.x) * step(ClipRect.y,pixel_pos.y) * step(pixel_pos.x,ClipRect.z) * step(pixel_pos.y,ClipRect.w));" // Clipping: branch-less, set alpha 0.0f
"}";
// GLFW callbacks to get events
static void glfw_error_callback(int error, const char* description)
{
fputs(description, stderr);
fputs(description, stderr);
}
static float mouse_wheel = 0.0f;
@ -188,29 +115,17 @@ void InitGL()
{
glfwSetErrorCallback(glfw_error_callback);
if (!glfwInit())
exit(1);
if (!glfwInit())
exit(1);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_REFRESH_RATE, 60);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
window = glfwCreateWindow(1280, 720, "ImGui OpenGL example", NULL, NULL);
glfwMakeContextCurrent(window);
glfwSetKeyCallback(window, glfw_key_callback);
glfwSetScrollCallback(window, glfw_scroll_callback);
glfwSetCharCallback(window, glfw_char_callback);
glewExperimental = GL_TRUE;
glewInit();
// After calling glewInit() our GL error state may be GL_INVALID_ENUM
const GLenum err = glGetError();
(void)err;
IM_ASSERT(err == GL_NO_ERROR || err == GL_INVALID_ENUM);
}
void InitImGui()
@ -219,10 +134,10 @@ void InitImGui()
glfwGetWindowSize(window, &w, &h);
ImGuiIO& io = ImGui::GetIO();
io.DisplaySize = ImVec2((float)w, (float)h); // Display size, in pixels. For clamping windows positions.
io.DeltaTime = 1.0f/60.0f; // Time elapsed since last frame, in seconds (in this sample app we'll override this every frame because our timestep is variable)
io.PixelCenterOffset = 0.5f; // Align OpenGL texels
io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array that we will update during the application lifetime.
io.DisplaySize = ImVec2((float)w, (float)h); // Display size, in pixels. For clamping windows positions.
io.DeltaTime = 1.0f/60.0f; // Time elapsed since last frame, in seconds (in this sample app we'll override this every frame because our timestep is variable)
io.PixelCenterOffset = 0.5f; // Align OpenGL texels
io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array.
io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;
io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT;
io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP;
@ -244,68 +159,11 @@ void InitImGui()
io.SetClipboardTextFn = ImImpl_SetClipboardTextFn;
io.GetClipboardTextFn = ImImpl_GetClipboardTextFn;
// Setup graphics backend
GLint status = GL_TRUE;
GLenum err = GL_NO_ERROR;
err = glGetError(); IM_ASSERT(err == GL_NO_ERROR);
// Create and compile the vertex shader
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexSource, NULL);
glCompileShader(vertexShader);
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &status);
if (status != GL_TRUE)
{
char buffer[512];
glGetShaderInfoLog(vertexShader, 1024, NULL, buffer);
printf("%s", buffer);
IM_ASSERT(status == GL_TRUE);
}
// Create and compile the fragment shader
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentSource, NULL);
glCompileShader(fragmentShader);
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &status);
IM_ASSERT(status == GL_TRUE);
// Link the vertex and fragment shader into a shader program
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glBindFragDataLocation(shaderProgram, 0, "o_col");
glLinkProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &status);
IM_ASSERT(status == GL_TRUE);
// Create Vertex Buffer Objects & Vertex Array Objects
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
GLint posAttrib = glGetAttribLocation(shaderProgram, "i_pos");
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), 0);
glEnableVertexAttribArray(posAttrib);
GLint uvAttrib = glGetAttribLocation(shaderProgram, "i_uv");
glEnableVertexAttribArray(uvAttrib);
glVertexAttribPointer(uvAttrib, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (void*)(2*sizeof(float)));
GLint colAttrib = glGetAttribLocation(shaderProgram, "i_col");
glVertexAttribPointer(colAttrib, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (void*)(4*sizeof(float)));
glEnableVertexAttribArray(colAttrib);
err = glGetError(); IM_ASSERT(err == GL_NO_ERROR);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Load font texture
glGenTextures(1, &fontTex);
glBindTexture(GL_TEXTURE_2D, fontTex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
const void* png_data;
unsigned int png_size;
ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size);
@ -318,13 +176,6 @@ void InitImGui()
void Shutdown()
{
ImGui::Shutdown();
glDeleteProgram(shaderProgram);
glDeleteShader(fragmentShader);
glDeleteShader(vertexShader);
glDeleteBuffers(1, &vbo);
glDeleteVertexArrays(1, &vao);
glfwTerminate();
}
@ -345,10 +196,10 @@ int main(int argc, char** argv)
time = current_time;
double mouse_x, mouse_y;
glfwGetCursorPos(window, &mouse_x, &mouse_y);
io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.)
io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.)
io.MouseDown[0] = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) != 0;
io.MouseDown[1] = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) != 0;
io.MouseWheel = (mouse_wheel != 0) ? mouse_wheel > 0.0f ? 1 : - 1 : 0; // Mouse wheel: -1,0,+1
io.MouseWheel = (mouse_wheel != 0) ? mouse_wheel > 0.0f ? 1 : - 1 : 0; // Mouse wheel: -1,0,+1
mouse_wheel = 0.0f;
ImGui::NewFrame();
@ -375,7 +226,7 @@ int main(int argc, char** argv)
if (show_test_window)
{
// More example code in ShowTestWindow()
ImGui::SetNewWindowDefaultPos(ImVec2(650, 20)); // Normally user code doesn't need/want to call it because positions are saved in .ini file anyway. Here we just want to make the demo initial state a bit more friendly!
ImGui::SetNewWindowDefaultPos(ImVec2(650, 20)); // Normally user code doesn't need/want to call it because positions are saved in .ini file anyway. Here we just want to make the demo initial state a bit more friendly!
ImGui::ShowTestWindow(&show_test_window);
}
@ -386,9 +237,10 @@ int main(int argc, char** argv)
ImGui::End();
}
// 3) Rendering
glClearColor(0.8f, 0.6f, 0.6f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// 3) Rendering
glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
glClearColor(0.8f, 0.6f, 0.6f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
ImGui::Render();
glfwSwapBuffers(window);

View File

@ -28,7 +28,7 @@
/*
namespace ImGui
{
void Value(const char* prefix, cosnt MyVec2& v, const char* float_format = NULL);
void Value(const char* prefix, cosnt MyVec4& v, const char* float_format = NULL);
void Value(const char* prefix, const MyVec2& v, const char* float_format = NULL);
void Value(const char* prefix, const MyVec4& v, const char* float_format = NULL);
};
*/

357
imgui.cpp
View File

@ -110,18 +110,19 @@
ISSUES AND TODO-LIST
- misc: merge ImVec4 / ImGuiAabb, they are essentially duplicate containers
- main: make IsHovered() 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
- window: autofit is losing its purpose when user relies on any dynamic layout (window width multiplier, column). maybe just discard autofit?
- window: support horizontal scroll
- window: fix resize grip scaling along with Rounding style setting
- widgets: switching from "widget-label" to "label-widget" would make it more convenient to integrate widgets in trees
- widgets: clip text? hover clipped text shows it in a tooltip or in-place overlay
- main: make IsHovered() 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: make IsHovered() info stored in a stack? so that 'if TreeNode() { Text; TreePop; } if IsHovered' return the hover state of the TreeNode?
- scrollbar: use relative mouse movement when first-clicking inside of scroll grab box.
- input number: optional range min/max
- input number: holding [-]/[+] buttons should increase the step non-linearly
- input number: rename Input*() to Input(), Slider*() to Slider() ?
- layout: clean up the InputFloat3/SliderFloat3/ColorEdit4 horrible layout code. item width should include frame padding, then we can have a generic horizontal layout helper.
- add input2/4 helper (once above layout helpers are in they'll be smaller)
- add input4 helper (once above layout helpers are in they'll be smaller)
- columns: declare column set (each column: fixed size, %, fill, distribute default size among fills)
- columns: columns header to act as button (~sort op) and allow resize/reorder
- columns: user specify columns size
@ -184,7 +185,7 @@ static void ItemSize(ImVec2 size, ImVec2* adjust_start_offset = NULL);
static void ItemSize(const ImGuiAabb& aabb, ImVec2* adjust_start_offset = NULL);
static void PushColumnClipRect(int column_index = -1);
static bool IsClipped(const ImGuiAabb& aabb);
static bool ClipAdvance(const ImGuiAabb& aabb, bool skip_columns = false);
static bool ClipAdvance(const ImGuiAabb& aabb);
static bool IsMouseHoveringBox(const ImGuiAabb& box);
static bool IsKeyPressedMap(ImGuiKey key, bool repeat = true);
@ -274,7 +275,7 @@ ImGuiIO::ImGuiIO()
// - on Windows you can get those using ToAscii+keyboard state, or via the VM_CHAR message
void ImGuiIO::AddInputCharacter(char c)
{
const int n = strlen(InputCharacters);
const size_t n = strlen(InputCharacters);
if (n < sizeof(InputCharacters) / sizeof(InputCharacters[0]))
{
InputCharacters[n] = c;
@ -287,7 +288,7 @@ void ImGuiIO::AddInputCharacter(char c)
//-----------------------------------------------------------------------------
#undef ARRAYSIZE
#define ARRAYSIZE(_ARR) (sizeof(_ARR)/sizeof(*_ARR))
#define ARRAYSIZE(_ARR) ((int)(sizeof(_ARR)/sizeof(*_ARR)))
#undef PI
const float PI = 3.14159265358979323846f;
@ -337,7 +338,7 @@ static const char* ImStristr(const char* haystack, const char* needle, const cha
if (!needle_end)
needle_end = needle + strlen(needle);
const char un0 = toupper(*needle);
const char un0 = (char)toupper(*needle);
while (*haystack)
{
if (toupper(*haystack) == un0)
@ -382,7 +383,7 @@ static size_t ImFormatString(char* buf, size_t buf_size, const char* fmt, ...)
int w = vsnprintf(buf, buf_size, fmt, args);
va_end(args);
buf[buf_size-1] = 0;
if (w == -1) w = buf_size;
if (w == -1) w = (int)buf_size;
return w;
}
@ -390,7 +391,7 @@ static size_t ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_li
{
int w = vsnprintf(buf, buf_size, fmt, args);
buf[buf_size-1] = 0;
if (w == -1) w = buf_size;
if (w == -1) w = (int)buf_size;
return w;
}
@ -541,7 +542,7 @@ struct ImGuiTextEditState
{
char Text[1024]; // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so own buffer.
char InitialText[1024]; // backup of end-user buffer at focusing time, to ESC key can do a revert. Also used for arithmetic operations (but could use a pre-parsed float there).
int MaxLength; // end-user buffer size <= 1024 (or increase above)
size_t BufSize; // end-user buffer size, <= 1024 (or increase above)
float Width; // widget width
float ScrollX;
STB_TexteditState StbState;
@ -555,7 +556,7 @@ struct ImGuiTextEditState
void CursorAnimReset() { CursorAnim = -0.30f; } // After a user-input the cursor stays on for a while without blinking
bool CursorIsVisible() const { return CursorAnim <= 0.0f || fmodf(CursorAnim, 1.20f) <= 0.80f; } // Blinking
bool HasSelection() const { return StbState.select_start != StbState.select_end; }
void SelectAll() { StbState.select_start = 0; StbState.select_end = strlen(Text); StbState.cursor = StbState.select_end; StbState.has_preferred_x = false; }
void SelectAll() { StbState.select_start = 0; StbState.select_end = (int)strlen(Text); StbState.cursor = StbState.select_end; StbState.has_preferred_x = false; }
void OnKeyboardPressed(int key);
void UpdateScrollOffset();
@ -717,7 +718,7 @@ static ImVector<ImGuiStorage::Pair>::iterator LowerBound(ImVector<ImGuiStorage::
{
ImVector<ImGuiStorage::Pair>::iterator first = data.begin();
ImVector<ImGuiStorage::Pair>::iterator last = data.end();
int count = last - first;
int count = (int)(last - first);
while (count > 0)
{
int count2 = count / 2;
@ -870,18 +871,20 @@ bool ImGuiTextFilter::PassFilter(const char* val) const
//-----------------------------------------------------------------------------
void ImGuiTextBuffer::Append(const char* fmt, ...)
void ImGuiTextBuffer::append(const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
int len = vsnprintf(NULL, 0, fmt, args);
va_end(args);
if (len <= 0)
return;
const size_t write_off = Buf.size();
if (write_off + len >= Buf.capacity())
Buf.reserve(Buf.capacity() * 2);
Buf.resize(write_off + len);
Buf.resize(write_off + (size_t)len);
va_start(args, fmt);
ImFormatStringV(&Buf[write_off] - 1, len+1, fmt, args);
@ -976,7 +979,11 @@ void ImGuiWindow::AddToRenderList()
ImGuiState& g = GImGui;
if (!DrawList->commands.empty() && !DrawList->vtx_buffer.empty())
{
if (DrawList->commands.back().vtx_count == 0)
DrawList->commands.pop_back();
g.RenderDrawLists.push_back(DrawList);
}
for (size_t i = 0; i < DC.ChildWindows.size(); i++)
{
ImGuiWindow* child = DC.ChildWindows[i];
@ -1030,7 +1037,7 @@ static void LoadSettings()
if (fseek(f, 0, SEEK_SET))
return;
char* f_data = new char[f_size+1];
f_size = fread(f_data, 1, f_size, f); // Text conversion alter read size so let's not be fussy about return value
f_size = (long)fread(f_data, 1, f_size, f); // Text conversion alter read size so let's not be fussy about return value
fclose(f);
if (f_size == 0)
{
@ -1165,7 +1172,7 @@ void NewFrame()
else
g.IO.MouseDelta = g.IO.MousePos - g.IO.MousePosPrev;
g.IO.MousePosPrev = g.IO.MousePos;
for (int i = 0; i < ARRAYSIZE(g.IO.MouseDown); i++)
for (size_t i = 0; i < ARRAYSIZE(g.IO.MouseDown); i++)
{
g.IO.MouseDownTime[i] = g.IO.MouseDown[i] ? (g.IO.MouseDownTime[i] < 0.0f ? 0.0f : g.IO.MouseDownTime[i] + g.IO.DeltaTime) : -1.0f;
g.IO.MouseClicked[i] = (g.IO.MouseDownTime[i] == 0.0f);
@ -1185,7 +1192,7 @@ void NewFrame()
}
}
}
for (int i = 0; i < ARRAYSIZE(g.IO.KeysDown); i++)
for (size_t i = 0; i < ARRAYSIZE(g.IO.KeysDown); i++)
g.IO.KeysDownTime[i] = g.IO.KeysDown[i] ? (g.IO.KeysDownTime[i] < 0.0f ? 0.0f : g.IO.KeysDownTime[i] + g.IO.DeltaTime) : -1.0f;
// Clear reference to active widget if the widget isn't alive anymore
@ -1303,7 +1310,6 @@ static void AddWindowToSortedBuffer(ImGuiWindow* window, ImVector<ImGuiWindow*>&
static void PushClipRect(const ImVec4& clip_rect, bool clipped = true)
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
ImVec4 cr = clip_rect;
@ -1320,7 +1326,6 @@ static void PushClipRect(const ImVec4& clip_rect, bool clipped = true)
static void PopClipRect()
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
window->ClipRectStack.pop_back();
window->DrawList->PopClipRect();
@ -1451,9 +1456,9 @@ static void LogText(const ImVec2& ref_pos, const char* text, const char* text_en
else
{
if (log_new_line || !is_first_line)
g.LogClipboard.Append("\n%*s%.*s", tree_depth*4, "", char_count, text_remaining);
g.LogClipboard.append("\n%*s%.*s", tree_depth*4, "", char_count, text_remaining);
else
g.LogClipboard.Append(" %.*s", char_count, text_remaining);
g.LogClipboard.append(" %.*s", char_count, text_remaining);
}
}
@ -1496,7 +1501,6 @@ static void RenderText(ImVec2 pos, const char* text, const char* text_end, const
static void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, float rounding)
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
window->DrawList->AddRectFilled(p_min, p_max, fill_col, rounding);
@ -1509,7 +1513,6 @@ static void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border,
static void RenderCollapseTriangle(ImVec2 p_min, bool open, float scale = 1.0f, bool shadow = false)
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
const float h = window->FontSize() * 1.00f;
@ -1538,7 +1541,6 @@ static void RenderCollapseTriangle(ImVec2 p_min, bool open, float scale = 1.0f,
static ImVec2 CalcTextSize(const char* text, const char* text_end, const bool hide_text_after_hash)
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
const char* text_display_end;
@ -1556,7 +1558,7 @@ static ImGuiWindow* FindHoveredWindow(ImVec2 pos, bool excluding_childs)
ImGuiState& g = GImGui;
for (int i = (int)g.Windows.size()-1; i >= 0; i--)
{
ImGuiWindow* window = g.Windows[i];
ImGuiWindow* window = g.Windows[(size_t)i];
if (!window->Visible)
continue;
if (excluding_childs && (window->Flags & ImGuiWindowFlags_ChildWindow) != 0)
@ -1588,6 +1590,11 @@ static bool IsMouseHoveringBox(const ImGuiAabb& box)
return box_for_touch.Contains(g.IO.MousePos);
}
bool IsMouseHoveringBox(const ImVec2& box_min, const ImVec2& box_max)
{
return IsMouseHoveringBox(ImGuiAabb(box_min, box_max));
}
static bool IsKeyPressedMap(ImGuiKey key, bool repeat)
{
ImGuiState& g = GImGui;
@ -1631,6 +1638,13 @@ bool IsMouseClicked(int button, bool repeat)
return false;
}
bool IsMouseDoubleClicked(int button)
{
ImGuiState& g = GImGui;
IM_ASSERT(button >= 0 && button < ARRAYSIZE(g.IO.MouseDown));
return g.IO.MouseDoubleClicked[button];
}
ImVec2 GetMousePos()
{
return GImGui.IO.MousePos;
@ -1681,7 +1695,7 @@ void BeginChild(const char* str_id, ImVec2 size, bool border, ImGuiWindowFlags e
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
ImU32 flags = ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_ChildWindow;
ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_ChildWindow;
const ImVec2 content_max = window->Pos + ImGui::GetWindowContentRegionMax();
const ImVec2 cursor_pos = window->Pos + ImGui::GetCursorPos();
@ -1791,6 +1805,12 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin
window->SizeFull = size;
if (!(flags & ImGuiWindowFlags_ComboBox))
ImGui::PushClipRect(parent_window->ClipRectStack.back());
else
ImGui::PushClipRect(ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y));
}
else
{
ImGui::PushClipRect(ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y));
}
// ID stack
@ -2026,12 +2046,10 @@ bool Begin(const char* name, bool* open, ImVec2 size, float fill_alpha, ImGuiWin
// Title bar
if (!(window->Flags & ImGuiWindowFlags_NoTitleBar))
{
ImGui::PushClipRect(ImVec4(window->Pos.x-0.5f, window->Pos.y-0.5f, window->Pos.x+window->Size.x-1.5f, window->Pos.y+window->Size.y-1.5f), false);
RenderCollapseTriangle(window->Pos + style.FramePadding, !window->Collapsed, 1.0f, true);
RenderText(window->Pos + style.FramePadding + ImVec2(window->FontSize() + style.ItemInnerSpacing.x, 0), name);
if (open)
ImGui::CloseWindowButton(open);
ImGui::PopClipRect();
}
}
@ -2059,10 +2077,8 @@ void End()
ImGuiWindow* window = g.CurrentWindow;
ImGui::Columns(1, "#CloseColumns");
ImGui::PopClipRect();
if (window->Flags & ImGuiWindowFlags_ChildWindow)
if (!(window->Flags & ImGuiWindowFlags_ComboBox))
ImGui::PopClipRect();
ImGui::PopClipRect(); // inner window clip rectangle
ImGui::PopClipRect(); // outer window clip rectangle
// Select window for move/focus when we're done with all our widgets
ImGuiAabb bb(window->Pos, window->Pos+window->Size);
@ -2084,7 +2100,7 @@ void End()
}
if (g.LogClipboard.size() > 1)
{
g.LogClipboard.Append("\n");
g.LogClipboard.append("\n");
if (g.IO.SetClipboardTextFn)
g.IO.SetClipboardTextFn(g.LogClipboard.begin(), g.LogClipboard.end());
g.LogClipboard.clear();
@ -2296,21 +2312,24 @@ void SetCursorPos(ImVec2 p)
void SetScrollPosHere()
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
window->NextScrollY = (window->DC.CursorPos.y + window->ScrollY) - (window->Pos.y + window->SizeFull.y * 0.5f) - (window->TitleBarHeight() + window->WindowPadding().y);
}
void SetTreeStateStorage(ImGuiStorage* tree)
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
window->DC.StateStorage = tree ? tree : &window->StateStorage;
}
ImGuiStorage* GetTreeStateStorage()
{
ImGuiWindow* window = GetCurrentWindow();
return window->DC.StateStorage;
}
void TextV(const char* fmt, va_list args)
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
return;
@ -2370,10 +2389,6 @@ void TextUnformatted(const char* text, const char* text_end)
pos.y += lines_skipped * line_height;
}
}
else
{
printf("");
}
// lines to render?
if (line < text_end)
@ -2581,7 +2596,6 @@ bool SmallButton(const char* label)
static bool CloseWindowButton(bool* open)
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
const ImGuiID id = window->GetID("##CLOSE");
@ -2617,7 +2631,8 @@ void LogToTTY(int max_depth)
return;
g.LogEnabled = true;
g.LogFile = stdout;
g.LogAutoExpandMaxDepth = max_depth;
if (max_depth >= 0)
g.LogAutoExpandMaxDepth = max_depth;
}
void LogToFile(int max_depth, const char* filename)
@ -2625,10 +2640,12 @@ void LogToFile(int max_depth, const char* filename)
ImGuiState& g = GImGui;
if (g.LogEnabled)
return;
IM_ASSERT(filename);
if (!filename)
filename = g.IO.LogFilename;
g.LogEnabled = true;
g.LogFile = fopen(filename, "at");
g.LogAutoExpandMaxDepth = max_depth;
if (max_depth >= 0)
g.LogAutoExpandMaxDepth = max_depth;
}
void LogToClipboard(int max_depth)
@ -2638,7 +2655,8 @@ void LogToClipboard(int max_depth)
return;
g.LogEnabled = true;
g.LogFile = NULL;
g.LogAutoExpandMaxDepth = max_depth;
if (max_depth >= 0)
g.LogAutoExpandMaxDepth = max_depth;
}
void LogButtons()
@ -2765,7 +2783,7 @@ void BulletText(const char* fmt, ...)
const float line_height = window->FontSize();
const ImVec2 text_size = CalcTextSize(text_begin, text_end);
const ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(line_height + (text_size.x ? (g.Style.FramePadding.x*2) : 0.0f),0) + text_size); // Empty text doesn't add padding
const ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(line_height + (text_size.x > 0.0f ? (g.Style.FramePadding.x*2) : 0.0f),0) + text_size); // Empty text doesn't add padding
ItemSize(bb);
if (ClipAdvance(bb))
@ -2779,10 +2797,6 @@ void BulletText(const char* fmt, ...)
bool TreeNode(const char* str_id, const char* fmt, ...)
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
ImGuiStorage* tree = window->DC.StateStorage;
static char buf[1024];
va_list args;
va_start(args, fmt);
@ -2804,10 +2818,6 @@ bool TreeNode(const char* str_id, const char* fmt, ...)
bool TreeNode(const void* ptr_id, const char* fmt, ...)
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
ImGuiStorage* tree = window->DC.StateStorage;
static char buf[1024];
va_list args;
va_start(args, fmt);
@ -3143,6 +3153,38 @@ bool SliderInt(const char* label, int* v, int v_min, int v_max, const char* disp
return changed;
}
bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* display_format, float power)
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
return false;
const ImGuiStyle& style = g.Style;
bool value_changed = false;
ImGui::PushID(label);
const int components = 2;
const float w_full = window->DC.ItemWidth.back();
const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.FramePadding.x*2.0f+style.ItemInnerSpacing.x)*(components-1)) / (float)components));
const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one+style.FramePadding.x*2.0f+style.ItemInnerSpacing.x)*(components-1)));
ImGui::PushItemWidth(w_item_one);
value_changed |= ImGui::SliderFloat("##X", &v[0], v_min, v_max, display_format, power);
ImGui::SameLine(0, 0);
ImGui::PopItemWidth();
ImGui::PushItemWidth(w_item_last);
value_changed |= ImGui::SliderFloat("##Y", &v[1], v_min, v_max, display_format, power);
ImGui::SameLine(0, 0);
ImGui::PopItemWidth();
ImGui::TextUnformatted(label, FindTextDisplayEnd(label));
ImGui::PopID();
return value_changed;
}
bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* display_format, float power)
{
ImGuiState& g = GImGui;
@ -3151,10 +3193,8 @@ bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const
return false;
const ImGuiStyle& style = g.Style;
const ImVec2 text_size = CalcTextSize(label);
bool value_changed = false;
ImGui::PushID(label);
const int components = 3;
@ -3177,7 +3217,6 @@ bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const
ImGui::TextUnformatted(label, FindTextDisplayEnd(label));
ImGui::PopID();
return value_changed;
}
@ -3196,7 +3235,6 @@ static void Plot(ImGuiPlotType plot_type, const char* label, const float* values
return;
const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label);
const ImVec2 text_size = CalcTextSize(label);
if (graph_size.x == 0)
@ -3413,7 +3451,7 @@ bool RadioButton(const char* label, int* v, int v_button)
// Wrapper for stb_textedit.h to edit text (our wrapper is for: statically sized buffer, single-line, ASCII, fixed-width font)
int STB_TEXTEDIT_STRINGLEN(const STB_TEXTEDIT_STRING* obj) { return (int)strlen(obj->Text); }
char STB_TEXTEDIT_GETCHAR(const STB_TEXTEDIT_STRING* obj, int idx) { return (char)obj->Text[idx]; }
float STB_TEXTEDIT_GETWIDTH(STB_TEXTEDIT_STRING* obj, int line_start_idx, int char_idx) { return obj->Font->CalcTextSize(obj->FontSize, 0, &obj->Text[char_idx], &obj->Text[char_idx]+1, NULL).x; }
float STB_TEXTEDIT_GETWIDTH(STB_TEXTEDIT_STRING* obj, int line_start_idx, int char_idx) { (void)line_start_idx; return obj->Font->CalcTextSize(obj->FontSize, 0, &obj->Text[char_idx], &obj->Text[char_idx]+1, NULL).x; }
char STB_TEXTEDIT_KEYTOTEXT(int key) { return key >= 0x10000 ? 0 : (char)key; }
char STB_TEXTEDIT_NEWLINE = '\n';
void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, STB_TEXTEDIT_STRING* obj, int line_start_idx)
@ -3434,17 +3472,17 @@ static bool is_separator(char c) { return c==',' || c==';' || c=='(' || c==')' |
#define STB_TEXTEDIT_IS_SPACE(c) (is_white(c) || is_separator(c))
void STB_TEXTEDIT_DELETECHARS(STB_TEXTEDIT_STRING* obj, int idx, int n) { char* dst = obj->Text+idx; const char* src = obj->Text+idx+n; while (char c = *src++) *dst++ = c; *dst = '\0'; }
bool STB_TEXTEDIT_INSERTCHARS(STB_TEXTEDIT_STRING* obj, int idx, const char* new_text, int new_text_size)
bool STB_TEXTEDIT_INSERTCHARS(STB_TEXTEDIT_STRING* obj, int idx, const char* new_text, int new_text_len)
{
char* buf_end = obj->Text + obj->MaxLength;
int text_size = strlen(obj->Text);
char* buf_end = obj->Text + obj->BufSize;
const int text_len = (int)strlen(obj->Text);
if (new_text_size > buf_end - (obj->Text + text_size + 1))
if (new_text_len > buf_end - (obj->Text + text_len + 1))
return false;
memmove(obj->Text + idx + new_text_size, obj->Text + idx, text_size - idx);
memcpy(obj->Text + idx, new_text, new_text_size);
obj->Text[text_size + new_text_size] = 0;
memmove(obj->Text + idx + new_text_len, obj->Text + idx, text_len - idx);
memcpy(obj->Text + idx, new_text, new_text_len);
obj->Text[text_len + new_text_len] = 0;
return true;
}
@ -3526,7 +3564,7 @@ void ImGuiTextEditState::RenderTextScrolledClipped(ImFont font, float font_size,
const float clip_end = (text_end[0] != '\0' && text_end > text_start) ? symbol_w : 0.0f;
// Draw text
ImGui::RenderText(pos+ImVec2(clip_begin,0), text_start+(clip_begin?1:0), text_end-(clip_end?1:0), false);//, &text_params_with_clipping);
ImGui::RenderText(pos+ImVec2(clip_begin,0), text_start+(clip_begin>0.0f?1:0), text_end-(clip_end>0.0f?1:0), false);//, &text_params_with_clipping);
// Draw the clip symbol
const char s[2] = {symbol_c,'\0'};
@ -3553,7 +3591,7 @@ bool InputFloat(const char* label, float *v, float step, float step_fast, int de
ImGui::PushID(label);
const float button_sz = window->FontSize();
if (step)
if (step > 0.0f)
ImGui::PushItemWidth(ImMax(1.0f, window->DC.ItemWidth.back() - (button_sz+g.Style.FramePadding.x*2.0f+g.Style.ItemInnerSpacing.x)*2));
char buf[64];
@ -3567,21 +3605,20 @@ bool InputFloat(const char* label, float *v, float step, float step_fast, int de
ApplyNumericalTextInput(buf, v);
value_changed = true;
}
if (step)
ImGui::PopItemWidth();
if (step)
if (step > 0.0f)
{
ImGui::PopItemWidth();
ImGui::SameLine(0, 0);
if (ImGui::Button("-", ImVec2(button_sz,button_sz), true))
{
*v -= g.IO.KeyCtrl && step_fast ? step_fast : step;
*v -= g.IO.KeyCtrl && step_fast > 0.0f ? step_fast : step;
value_changed = true;
}
ImGui::SameLine(0, (int)g.Style.ItemInnerSpacing.x);
if (ImGui::Button("+", ImVec2(button_sz,button_sz), true))
{
*v += g.IO.KeyCtrl && step_fast ? step_fast : step;
*v += g.IO.KeyCtrl && step_fast > 0.0f ? step_fast : step;
value_changed = true;
}
}
@ -3668,7 +3705,7 @@ bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlag
bool cancel_edit = false;
if (g.ActiveId == id)
{
edit_state.MaxLength = buf_size < ARRAYSIZE(edit_state.Text) ? buf_size : ARRAYSIZE(edit_state.Text);
edit_state.BufSize = buf_size < ARRAYSIZE(edit_state.Text) ? buf_size : ARRAYSIZE(edit_state.Text);
edit_state.Font = window->Font();
edit_state.FontSize = window->FontSize();
@ -3733,7 +3770,7 @@ bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlag
if (const char* clipboard = g.IO.GetClipboardTextFn())
{
// Remove new-line from pasted buffer
int clipboard_len = strlen(clipboard);
size_t clipboard_len = strlen(clipboard);
char* clipboard_filtered = (char*)malloc(clipboard_len+1);
int clipboard_filtered_len = 0;
for (int i = 0; clipboard[i]; i++)
@ -3828,6 +3865,38 @@ bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlag
return value_changed;
}
bool InputFloat2(const char* label, float v[2], int decimal_precision)
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
return false;
const ImGuiStyle& style = g.Style;
bool value_changed = false;
ImGui::PushID(label);
const int components = 2;
const float w_full = window->DC.ItemWidth.back();
const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.FramePadding.x*2.0f+style.ItemInnerSpacing.x) * (components-1)) / (float)components));
const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one+style.FramePadding.x*2.0f+style.ItemInnerSpacing.x) * (components-1)));
ImGui::PushItemWidth(w_item_one);
value_changed |= ImGui::InputFloat("##X", &v[0], 0, 0, decimal_precision);
ImGui::SameLine(0, 0);
ImGui::PopItemWidth();
ImGui::PushItemWidth(w_item_last);
value_changed |= ImGui::InputFloat("##Y", &v[1], 0, 0, decimal_precision);
ImGui::SameLine(0, 0);
ImGui::PopItemWidth();
ImGui::TextUnformatted(label, FindTextDisplayEnd(label));
ImGui::PopID();
return value_changed;
}
bool InputFloat3(const char* label, float v[3], int decimal_precision)
{
ImGuiState& g = GImGui;
@ -3836,10 +3905,8 @@ bool InputFloat3(const char* label, float v[3], int decimal_precision)
return false;
const ImGuiStyle& style = g.Style;
const ImVec2 text_size = CalcTextSize(label);
bool value_changed = false;
ImGui::PushID(label);
const int components = 3;
@ -3862,7 +3929,6 @@ bool InputFloat3(const char* label, float v[3], int decimal_precision)
ImGui::TextUnformatted(label, FindTextDisplayEnd(label));
ImGui::PopID();
return value_changed;
}
@ -3971,6 +4037,7 @@ bool Combo(const char* label, int* current_item, bool (*items_getter)(void*, int
ImGuiWindowFlags flags = ImGuiWindowFlags_ComboBox | ((window->Flags & ImGuiWindowFlags_ShowBorders) ? ImGuiWindowFlags_ShowBorders : 0);
ImGui::BeginChild("#ComboBox", popup_aabb.GetSize(), false, flags);
ImGuiWindow* child_window = GetCurrentWindow();
ImGui::Spacing();
bool combo_item_active = false;
combo_item_active |= (g.ActiveId == child_window->GetID("#SCROLLY"));
@ -4087,8 +4154,6 @@ bool ColorEdit4(const char* label, float col[4], bool alpha)
const float w_full = window->DC.ItemWidth.back();
const float square_sz = (window->FontSize() + style.FramePadding.x * 2.0f);
const ImVec2 text_size = CalcTextSize(label);
ImGuiColorEditMode edit_mode = window->DC.ColorEditMode;
if (edit_mode == ImGuiColorEditMode_UserSelect)
edit_mode = g.ColorEditModeStorage.GetInt(id, 0) % 3;
@ -4210,15 +4275,12 @@ bool ColorEdit4(const char* label, float col[4], bool alpha)
void ColorEditMode(ImGuiColorEditMode mode)
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
window->DC.ColorEditMode = mode;
}
void Separator()
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
return;
@ -4229,7 +4291,7 @@ void Separator()
const ImGuiAabb bb(ImVec2(window->Pos.x, window->DC.CursorPos.y), ImVec2(window->Pos.x + window->Size.x, window->DC.CursorPos.y));
ItemSize(ImVec2(0.0f, bb.GetSize().y)); // NB: we don't provide our width so that it doesn't get feed back into AutoFit
if (ClipAdvance(bb, true))
if (ClipAdvance(bb))
{
if (window->DC.ColumnsCount > 1)
ImGui::PushColumnClipRect();
@ -4244,7 +4306,6 @@ void Separator()
void Spacing()
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->Collapsed)
return;
@ -4314,7 +4375,7 @@ bool IsClipped(ImVec2 item_size)
return IsClipped(ImGuiAabb(window->DC.CursorPos, window->DC.CursorPos + item_size));
}
static bool ClipAdvance(const ImGuiAabb& bb, bool skip_columns)
static bool ClipAdvance(const ImGuiAabb& bb)
{
ImGuiWindow* window = GetCurrentWindow();
if (ImGui::IsClipped(bb))
@ -4437,7 +4498,8 @@ void Columns(int columns_count, const char* id, bool border)
// Draw before resize so our items positioning are in sync with the line
const ImU32 col = window->Color(held ? ImGuiCol_ColumnActive : hovered ? ImGuiCol_ColumnHovered : ImGuiCol_Column);
window->DrawList->AddLine(ImVec2(x, y1), ImVec2(x, y2), col);
const float xi = (float)(int)x;
window->DrawList->AddLine(ImVec2(xi, y1), ImVec2(xi, y2), col);
if (held)
{
@ -4551,58 +4613,62 @@ void ImDrawList::Clear()
{
commands.resize(0);
vtx_buffer.resize(0);
clip_rect_buffer.resize(0);
vtx_write_ = NULL;
clip_rect_stack_.resize(0);
vtx_write = NULL;
clip_rect_stack.resize(0);
}
void ImDrawList::PushClipRect(const ImVec4& clip_rect)
{
commands.push_back(ImDrawCmd(ImDrawCmdType_PushClipRect));
clip_rect_buffer.push_back(clip_rect);
clip_rect_stack_.push_back(clip_rect);
if (!commands.empty() && commands.back().vtx_count == 0)
{
// Reuse empty command because high-level clipping may have discarded the other vertices already
commands.back().clip_rect = clip_rect;
}
else
{
ImDrawCmd draw_cmd;
draw_cmd.vtx_count = 0;
draw_cmd.clip_rect = clip_rect;
commands.push_back(draw_cmd);
}
clip_rect_stack.push_back(clip_rect);
}
void ImDrawList::PopClipRect()
{
if (!commands.empty() && commands.back().cmd_type == ImDrawCmdType_PushClipRect)
clip_rect_stack.pop_back();
const ImVec4 clip_rect = clip_rect_stack.empty() ? ImVec4(-9999.0f,-9999.0f, +9999.0f, +9999.0f) : clip_rect_stack.back();
if (!commands.empty() && commands.back().vtx_count == 0)
{
// Discard push/pop combo because high-level clipping may have discarded the other draw commands already
commands.pop_back();
clip_rect_buffer.pop_back();
// Reuse empty command because high-level clipping may have discarded the other vertices already
commands.back().clip_rect = clip_rect;
}
else
{
commands.push_back(ImDrawCmd(ImDrawCmdType_PopClipRect));
ImDrawCmd draw_cmd;
draw_cmd.vtx_count = 0;
draw_cmd.clip_rect = clip_rect;
commands.push_back(draw_cmd);
}
clip_rect_stack_.pop_back();
}
void ImDrawList::AddCommand(ImDrawCmdType cmd_type, int vtx_count)
void ImDrawList::ReserveVertices(unsigned int vtx_count)
{
// Maximum value that can fit in our u16 vtx_count member
const int VTX_COUNT_MAX = (1<<16);
// Merge commands if we can, turning them into less draw calls
ImDrawCmd* prev = commands.empty() ? NULL : &commands.back();
if (vtx_count > 0 && prev && prev->cmd_type == (ImU32)cmd_type && prev->vtx_count + vtx_count < VTX_COUNT_MAX)
prev->vtx_count += vtx_count;
else
commands.push_back(ImDrawCmd(cmd_type, vtx_count));
if (vtx_count > 0)
{
ImDrawCmd& draw_cmd = commands.back();
draw_cmd.vtx_count += vtx_count;
vtx_buffer.resize(vtx_buffer.size() + vtx_count);
vtx_write_ = &vtx_buffer[vtx_buffer.size() - vtx_count];
vtx_write = &vtx_buffer[vtx_buffer.size() - vtx_count];
}
}
void ImDrawList::AddVtx(const ImVec2& pos, ImU32 col)
{
vtx_write_->pos = pos;
vtx_write_->col = col;
vtx_write_->uv = IMDRAW_TEX_UV_FOR_WHITE;
vtx_write_++;
vtx_write->pos = pos;
vtx_write->col = col;
vtx_write->uv = IMDRAW_TEX_UV_FOR_WHITE;
vtx_write++;
}
void ImDrawList::AddVtxLine(const ImVec2& a, const ImVec2& b, ImU32 col)
@ -4624,7 +4690,7 @@ void ImDrawList::AddLine(const ImVec2& a, const ImVec2& b, ImU32 col)
if ((col >> 24) == 0)
return;
AddCommand(ImDrawCmdType_DrawTriangleList, 6);
ReserveVertices(6);
AddVtxLine(a, b, col);
}
@ -4645,7 +4711,7 @@ void ImDrawList::AddArc(const ImVec2& center, float rad, ImU32 col, int a_min, i
if (tris)
{
AddCommand(ImDrawCmdType_DrawTriangleList, (a_max-a_min) * 3);
ReserveVertices((a_max-a_min) * 3);
for (int a = a_min; a < a_max; a++)
{
AddVtx(center + circle_vtx[a % ARRAYSIZE(circle_vtx)] * rad, col);
@ -4655,7 +4721,7 @@ void ImDrawList::AddArc(const ImVec2& center, float rad, ImU32 col, int a_min, i
}
else
{
AddCommand(ImDrawCmdType_DrawTriangleList, (a_max-a_min) * 6);
ReserveVertices((a_max-a_min) * 6);
for (int a = a_min; a < a_max; a++)
AddVtxLine(center + circle_vtx[a % ARRAYSIZE(circle_vtx)] * rad, center + circle_vtx[(a+1) % ARRAYSIZE(circle_vtx)] * rad, col);
}
@ -4673,7 +4739,7 @@ void ImDrawList::AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float roun
if (r == 0.0f || rounding_corners == 0)
{
AddCommand(ImDrawCmdType_DrawTriangleList, 4*6);
ReserveVertices(4*6);
AddVtxLine(ImVec2(a.x,a.y), ImVec2(b.x,a.y), col);
AddVtxLine(ImVec2(b.x,a.y), ImVec2(b.x,b.y), col);
AddVtxLine(ImVec2(b.x,b.y), ImVec2(a.x,b.y), col);
@ -4681,7 +4747,7 @@ void ImDrawList::AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float roun
}
else
{
AddCommand(ImDrawCmdType_DrawTriangleList, 4*6);
ReserveVertices(4*6);
AddVtxLine(ImVec2(a.x + ((rounding_corners & 1)?r:0), a.y), ImVec2(b.x - ((rounding_corners & 2)?r:0), a.y), col);
AddVtxLine(ImVec2(b.x, a.y + ((rounding_corners & 2)?r:0)), ImVec2(b.x, b.y - ((rounding_corners & 4)?r:0)), col);
AddVtxLine(ImVec2(b.x - ((rounding_corners & 4)?r:0), b.y), ImVec2(a.x + ((rounding_corners & 8)?r:0), b.y), col);
@ -4707,7 +4773,7 @@ void ImDrawList::AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, floa
if (r == 0.0f || rounding_corners == 0)
{
// Use triangle so we can merge more draw calls together (at the cost of extra vertices)
AddCommand(ImDrawCmdType_DrawTriangleList, 6);
ReserveVertices(6);
AddVtx(ImVec2(a.x,a.y), col);
AddVtx(ImVec2(b.x,a.y), col);
AddVtx(ImVec2(b.x,b.y), col);
@ -4717,7 +4783,7 @@ void ImDrawList::AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, floa
}
else
{
AddCommand(ImDrawCmdType_DrawTriangleList, 6+6*2);
ReserveVertices(6+6*2);
AddVtx(ImVec2(a.x+r,a.y), col);
AddVtx(ImVec2(b.x-r,a.y), col);
AddVtx(ImVec2(b.x-r,b.y), col);
@ -4755,7 +4821,7 @@ void ImDrawList::AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec
if ((col >> 24) == 0)
return;
AddCommand(ImDrawCmdType_DrawTriangleList, 3);
ReserveVertices(3);
AddVtx(a, col);
AddVtx(b, col);
AddVtx(c, col);
@ -4766,7 +4832,7 @@ void ImDrawList::AddCircle(const ImVec2& centre, float radius, ImU32 col, int nu
if ((col >> 24) == 0)
return;
AddCommand(ImDrawCmdType_DrawTriangleList, num_segments*6);
ReserveVertices(num_segments*6);
const float a_step = 2*PI/(float)num_segments;
float a0 = 0.0f;
for (int i = 0; i < num_segments; i++)
@ -4782,7 +4848,7 @@ void ImDrawList::AddCircleFilled(const ImVec2& centre, float radius, ImU32 col,
if ((col >> 24) == 0)
return;
AddCommand(ImDrawCmdType_DrawTriangleList, num_segments*3);
ReserveVertices(num_segments*3);
const float a_step = 2*PI/(float)num_segments;
float a0 = 0.0f;
for (int i = 0; i < num_segments; i++)
@ -4803,17 +4869,19 @@ void ImDrawList::AddText(ImFont font, float font_size, const ImVec2& pos, ImU32
if (text_end == NULL)
text_end = text_begin + strlen(text_begin);
int char_count = text_end - text_begin;
int vtx_count_max = char_count * 6;
int vtx_begin = vtx_buffer.size();
AddCommand(ImDrawCmdType_DrawTriangleList, vtx_count_max);
// reserve vertices for worse case
const int char_count = (int)(text_end - text_begin);
const int vtx_count_max = char_count * 6;
const size_t vtx_begin = vtx_buffer.size();
ReserveVertices(vtx_count_max);
font->RenderText(font_size, pos, col, clip_rect_stack_.back(), text_begin, text_end, vtx_write_);
vtx_buffer.resize(vtx_write_ - &vtx_buffer.front());
int vtx_count = vtx_buffer.size() - vtx_begin;
font->RenderText(font_size, pos, col, clip_rect_stack.back(), text_begin, text_end, vtx_write);
// give unused vertices
vtx_buffer.resize(vtx_write - &vtx_buffer.front());
const int vtx_count = (int)(vtx_buffer.size() - vtx_begin);
commands.back().vtx_count -= (vtx_count_max - vtx_count);
vtx_write_ -= (vtx_count_max - vtx_count);
vtx_write -= (vtx_count_max - vtx_count);
}
//-----------------------------------------------------------------------------
@ -4862,7 +4930,7 @@ bool ImBitmapFont::LoadFromFile(const char* filename)
fclose(f);
return false;
}
if (fread(Data, 1, DataSize, f) != DataSize)
if ((int)fread(Data, 1, DataSize, f) != DataSize)
{
fclose(f);
free(Data);
@ -4923,7 +4991,7 @@ bool ImBitmapFont::LoadFromMemory(const void* data, int data_size)
void ImBitmapFont::BuildLookupTable()
{
ImU32 max_c = 0;
for (int i = 0; i != GlyphsCount; i++)
for (size_t i = 0; i != GlyphsCount; i++)
if (max_c < Glyphs[i].Id)
max_c = Glyphs[i].Id;
@ -4973,7 +5041,8 @@ ImVec2 ImBitmapFont::CalcTextSize(float size, float max_width, const char* text_
if (const FntGlyph* glyph = FindGlyph((unsigned short)c))
{
const float char_width = (glyph->XAdvance + Info->SpacingHoriz) * scale;
const float char_extend = (glyph->XOffset + glyph->Width * scale);
//const float char_extend = (glyph->XOffset + glyph->Width * scale);
if (line_width + char_width >= max_width)
break;
line_width += char_width;
@ -5015,8 +5084,6 @@ void ImBitmapFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& c
pos.x = (float)(int)pos.x + 0.5f;
pos.y = (float)(int)pos.y + 0.5f;
ImVec2 text_size = ImVec2(0,0);
float line_width = 0.0f;
const ImVec4 clip_rect = clip_rect_ref;
const float uv_offset = GImGui.IO.PixelCenterOffset;
@ -5036,7 +5103,7 @@ void ImBitmapFont::RenderText(float size, ImVec2 pos, ImU32 col, const ImVec4& c
if (const FntGlyph* glyph = FindGlyph((unsigned short)c))
{
const float char_width = (glyph->XAdvance + Info->SpacingHoriz) * scale;
const float char_extend = (glyph->XOffset + glyph->Width * scale);
//const float char_extend = (glyph->XOffset + glyph->Width * scale);
if (c != ' ' && c != '\n')
{
@ -5154,7 +5221,7 @@ void ShowStyleEditor(ImGuiStyle* ref)
filter.Draw("Filter colors", 200);
ImGui::ColorEditMode(edit_mode);
for (size_t i = 0; i < ImGuiCol_COUNT; i++)
for (int i = 0; i < ImGuiCol_COUNT; i++)
{
const char* name = GetStyleColorName(i);
if (!filter.PassFilter(name))
@ -5281,6 +5348,9 @@ void ShowTestWindow(bool* open)
ImGui::InputInt("input int", &i0);
ImGui::InputFloat("input float", &f0, 0.01f, 1.0f);
//static float vec2b[3] = { 0.10f, 0.20f };
//ImGui::InputFloat2("input float2", vec2b);
static float vec3b[3] = { 0.10f, 0.20f, 0.30f };
ImGui::InputFloat3("input float3", vec3b);
@ -5300,6 +5370,9 @@ void ShowTestWindow(bool* open)
static float angle = 0.0f;
ImGui::SliderAngle("angle", &angle);
//static float vec2a[3] = { 0.10f, 0.20f };
//ImGui::SliderFloat2("slider float2", vec2a, 0.0f, 1.0f);
static float vec3a[3] = { 0.10f, 0.20f, 0.30f };
ImGui::SliderFloat3("slider float3", vec3a, 0.0f, 1.0f);
@ -5332,7 +5405,7 @@ void ShowTestWindow(bool* open)
phase += 0.10f*values_offset;
}
}
ImGui::PlotLines("Frame Times", &values.front(), values.size(), values_offset, "avg 0.0", -1.0f, 1.0f, ImVec2(0,70));
ImGui::PlotLines("Frame Times", &values.front(), (int)values.size(), values_offset, "avg 0.0", -1.0f, 1.0f, ImVec2(0,70));
ImGui::SameLine(); ImGui::Checkbox("pause", &pause);
ImGui::PlotHistogram("Histogram", arr, ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0,70));
@ -5480,7 +5553,7 @@ void ShowTestWindow(bool* open)
static float foo = 1.0f;
ImGui::InputFloat("red", &foo, 0.05f, 0, 3); ImGui::NextColumn();
static float bar = 1.0f;
ImGui::InputFloat("blue", &foo, 0.05f, 0, 3); ImGui::NextColumn();
ImGui::InputFloat("blue", &bar, 0.05f, 0, 3); ImGui::NextColumn();
ImGui::Columns(1);
ImGui::Separator();
@ -5540,7 +5613,7 @@ void ShowTestWindow(bool* open)
if (ImGui::Button("Add 1000 lines"))
{
for (size_t i = 0; i < 1000; i++)
log.Append("%i The quick brown fox jumps over the lazy dog\n", lines+i);
log.append("%i The quick brown fox jumps over the lazy dog\n", lines+i);
lines += 1000;
}
ImGui::BeginChild("Log");

41
imgui.h
View File

@ -29,8 +29,8 @@ typedef ImU32 ImGuiID;
typedef int ImGuiCol; // enum ImGuiCol_
typedef int ImGuiKey; // enum ImGuiKey_
typedef int ImGuiColorEditMode; // enum ImGuiColorEditMode_
typedef ImU32 ImGuiWindowFlags; // enum ImGuiWindowFlags_
typedef ImU32 ImGuiInputTextFlags; // enum ImGuiInputTextFlags_
typedef int ImGuiWindowFlags; // enum ImGuiWindowFlags_
typedef int ImGuiInputTextFlags; // enum ImGuiInputTextFlags_
typedef ImBitmapFont* ImFont;
struct ImVec2
@ -85,9 +85,9 @@ public:
inline void clear() { if (_data) { _size = _capacity = 0; free(_data); _data = NULL; } }
inline iterator begin() { return _data; }
inline const iterator begin() const { return _data; }
inline const_iterator begin() const { return _data; }
inline iterator end() { return _data + _size; }
inline const iterator end() const { return _data + _size; }
inline const_iterator end() const { return _data + _size; }
inline value_type& front() { return at(0); }
inline const value_type& front() const { return at(0); }
inline value_type& back() { IM_ASSERT(_size > 0); return at(_size-1); }
@ -143,6 +143,7 @@ namespace ImGui
void SetFontScale(float scale);
void SetScrollPosHere();
void SetTreeStateStorage(ImGuiStorage* tree);
ImGuiStorage* GetTreeStateStorage();
void PushItemWidth(float item_width);
void PopItemWidth();
float GetItemWidth();
@ -182,6 +183,7 @@ namespace ImGui
bool SmallButton(const char* label);
bool CollapsingHeader(const char* label, const char* str_id = NULL, const bool display_frame = true, const bool default_open = false);
bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f);
bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f);
bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f);
bool SliderAngle(const char* label, float* v, float v_degrees_min = -360.0f, float v_degrees_max = +360.0f); // *v in radians
bool SliderInt(const char* label, int* v, int v_min, int v_max, const char* display_format = "%.0f");
@ -192,6 +194,7 @@ namespace ImGui
bool RadioButton(const char* label, bool active);
bool RadioButton(const char* label, int* v, int v_button);
bool InputFloat(const char* label, float* v, float step = 0.0f, float step_fast = 0.0f, int decimal_precision = -1);
bool InputFloat2(const char* label, float v[2], int decimal_precision = -1);
bool InputFloat3(const char* label, float v[3], int decimal_precision = -1);
bool InputInt(const char* label, int* v, int step = 1, int step_fast = 100);
bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0);
@ -221,9 +224,9 @@ namespace ImGui
// Logging
void LogButtons();
void LogToTTY(int max_depth);
void LogToFile(int max_depth, const char* filename);
void LogToClipboard(int max_depth);
void LogToTTY(int max_depth = -1);
void LogToFile(int max_depth = -1, const char* filename = NULL);
void LogToClipboard(int max_depth = -1);
// Utilities
void SetTooltip(const char* fmt, ...); // set tooltip under mouse-cursor, typically use with ImGui::IsHovered(). (currently no contention handling, last call win)
@ -232,6 +235,8 @@ namespace ImGui
bool IsClipped(ImVec2 item_size); // to perform coarse clipping on user's side (as an optimisation)
bool IsKeyPressed(int key_index, bool repeat = true); // key_index into the keys_down[512] array, imgui doesn't know the semantic of each entry
bool IsMouseClicked(int button, bool repeat = false);
bool IsMouseDoubleClicked(int button);
bool IsMouseHoveringBox(const ImVec2& box_min, const ImVec2& box_max);
ImVec2 GetMousePos();
float GetTime();
int GetFrameCount();
@ -469,7 +474,7 @@ struct ImGuiTextBuffer
size_t size() const { return Buf.size()-1; }
bool empty() { return Buf.empty(); }
void clear() { Buf.clear(); Buf.push_back(0); }
void Append(const char* fmt, ...);
void append(const char* fmt, ...);
};
// Helper: Key->value storage
@ -496,19 +501,10 @@ struct ImGuiStorage
// Hold a series of drawing commands. The user provide a renderer for ImDrawList
//-----------------------------------------------------------------------------
enum ImDrawCmdType
{
ImDrawCmdType_DrawTriangleList,
ImDrawCmdType_PushClipRect,
ImDrawCmdType_PopClipRect,
};
// sizeof() == 4
struct ImDrawCmd
{
ImDrawCmdType cmd_type : 16;
unsigned int vtx_count : 16;
ImDrawCmd(ImDrawCmdType _cmd_type = ImDrawCmdType_DrawTriangleList, unsigned int _vtx_count = 0) { cmd_type = _cmd_type; vtx_count = _vtx_count; }
unsigned int vtx_count;
ImVec4 clip_rect;
};
#ifndef IMDRAW_TEX_UV_FOR_WHITE
@ -529,16 +525,15 @@ struct ImDrawList
{
ImVector<ImDrawCmd> commands;
ImVector<ImDrawVert> vtx_buffer; // each command consume ImDrawCmd::vtx_count of those
ImVector<ImVec4> clip_rect_buffer; // each PushClipRect command consume 1 of those
ImVector<ImVec4> clip_rect_stack_; // [internal] clip rect stack while building the command-list (so text command can perform clipping early on)
ImDrawVert* vtx_write_; // [internal] point within vtx_buffer after each add command. allow us to use less [] and .resize on the vector (often slow on windows/debug)
ImVector<ImVec4> clip_rect_stack; // [internal] clip rect stack while building the command-list (so text command can perform clipping early on)
ImDrawVert* vtx_write; // [internal] point within vtx_buffer after each add command (to avoid using the ImVector<> operators too much)
ImDrawList() { Clear(); }
void Clear();
void PushClipRect(const ImVec4& clip_rect);
void PopClipRect();
void AddCommand(ImDrawCmdType cmd_type, int vtx_count);
void ReserveVertices(unsigned int vtx_count);
void AddVtx(const ImVec2& pos, ImU32 col);
void AddVtxLine(const ImVec2& a, const ImVec2& b, ImU32 col);