Browse Source

Merge remote-tracking branch 'origin' into 2015-04-indexed-rendering

Conflicts:
	examples/directx11_example/imgui_impl_dx11.cpp
	imgui.cpp
ocornut 10 years ago
parent
commit
43cb4038c6

+ 1 - 2
examples/directx11_example/imgui_impl_dx11.cpp

@@ -52,8 +52,7 @@ static void ImGui_ImplDX11_RenderDrawLists(ImDrawList** const cmd_lists, int cmd
     for (int n = 0; n < cmd_lists_count; n++)
     for (int n = 0; n < cmd_lists_count; n++)
     {
     {
         const ImDrawList* cmd_list = cmd_lists[n];
         const ImDrawList* cmd_list = cmd_lists[n];
-        const ImDrawVert* vtx_src = &cmd_list->vtx_buffer[0];
-        memcpy(vtx_dst, vtx_src, cmd_list->vtx_buffer.size() * sizeof(ImDrawVert));
+        memcpy(vtx_dst, &cmd_list->vtx_buffer[0], cmd_list->vtx_buffer.size() * sizeof(ImDrawVert));
         memcpy(idx_dst, &cmd_list->idx_buffer[0], cmd_list->idx_buffer.size() * sizeof(ImDrawIdx));
         memcpy(idx_dst, &cmd_list->idx_buffer[0], cmd_list->idx_buffer.size() * sizeof(ImDrawIdx));
         vtx_dst += cmd_list->vtx_buffer.size();
         vtx_dst += cmd_list->vtx_buffer.size();
         idx_dst += cmd_list->idx_buffer.size();
         idx_dst += cmd_list->idx_buffer.size();

+ 6 - 4
examples/opengl3_example/imgui_impl_glfw_gl3.cpp

@@ -135,16 +135,18 @@ void ImGui_ImplGlfwGL3_ScrollCallback(GLFWwindow*, double /*xoffset*/, double yo
     g_MouseWheel += (float)yoffset; // Use fractional mouse wheel, 1.0 unit 5 lines.
     g_MouseWheel += (float)yoffset; // Use fractional mouse wheel, 1.0 unit 5 lines.
 }
 }
 
 
-void ImGui_ImplGlfwGL3_KeyCallback(GLFWwindow*, int key, int, int action, int mods)
+void ImGui_ImplGlfwGL3_KeyCallback(GLFWwindow* window, int key, int, int action, int mods)
 {
 {
     ImGuiIO& io = ImGui::GetIO();
     ImGuiIO& io = ImGui::GetIO();
     if (action == GLFW_PRESS)
     if (action == GLFW_PRESS)
         io.KeysDown[key] = true;
         io.KeysDown[key] = true;
     if (action == GLFW_RELEASE)
     if (action == GLFW_RELEASE)
         io.KeysDown[key] = false;
         io.KeysDown[key] = false;
-    io.KeyCtrl = (mods & GLFW_MOD_CONTROL) != 0;
-    io.KeyShift = (mods & GLFW_MOD_SHIFT) != 0;
-    io.KeyAlt = (mods & GLFW_MOD_ALT) != 0;
+
+    (void)mods; // Modifiers are not reliable across systems
+    io.KeyCtrl = glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || glfwGetKey(window, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS;
+    io.KeyShift = glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS || glfwGetKey(window, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS;
+    io.KeyAlt = glfwGetKey(window, GLFW_KEY_LEFT_ALT) == GLFW_PRESS || glfwGetKey(window, GLFW_KEY_RIGHT_ALT) == GLFW_PRESS;
 }
 }
 
 
 void ImGui_ImplGlfwGL3_CharCallback(GLFWwindow*, unsigned int c)
 void ImGui_ImplGlfwGL3_CharCallback(GLFWwindow*, unsigned int c)

+ 6 - 4
examples/opengl_example/imgui_impl_glfw.cpp

@@ -116,16 +116,18 @@ void ImGui_ImplGlfw_ScrollCallback(GLFWwindow*, double /*xoffset*/, double yoffs
     g_MouseWheel += (float)yoffset; // Use fractional mouse wheel, 1.0 unit 5 lines.
     g_MouseWheel += (float)yoffset; // Use fractional mouse wheel, 1.0 unit 5 lines.
 }
 }
 
 
-void ImGui_ImplGlFw_KeyCallback(GLFWwindow*, int key, int, int action, int mods)
+void ImGui_ImplGlFw_KeyCallback(GLFWwindow* window, int key, int, int action, int mods)
 {
 {
     ImGuiIO& io = ImGui::GetIO();
     ImGuiIO& io = ImGui::GetIO();
     if (action == GLFW_PRESS)
     if (action == GLFW_PRESS)
         io.KeysDown[key] = true;
         io.KeysDown[key] = true;
     if (action == GLFW_RELEASE)
     if (action == GLFW_RELEASE)
         io.KeysDown[key] = false;
         io.KeysDown[key] = false;
-    io.KeyCtrl = (mods & GLFW_MOD_CONTROL) != 0;
-    io.KeyShift = (mods & GLFW_MOD_SHIFT) != 0;
-    io.KeyAlt = (mods & GLFW_MOD_ALT) != 0;
+
+    (void)mods; // Modifiers are not reliable across systems
+    io.KeyCtrl = glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || glfwGetKey(window, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS;
+    io.KeyShift = glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS || glfwGetKey(window, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS;
+    io.KeyAlt = glfwGetKey(window, GLFW_KEY_LEFT_ALT) == GLFW_PRESS || glfwGetKey(window, GLFW_KEY_RIGHT_ALT) == GLFW_PRESS;
 }
 }
 
 
 void ImGui_ImplGlfw_CharCallback(GLFWwindow*, unsigned int c)
 void ImGui_ImplGlfw_CharCallback(GLFWwindow*, unsigned int c)

+ 330 - 0
extra_fonts/binary_to_compressed_c.cpp

@@ -0,0 +1,330 @@
+// ImGui - binary_to_compressed_c.cpp
+// Helper tool to turn a file into a C array.
+// The data is first compressed with stb_compress() to reduce source code size a little.
+// Useful if you want to embed fonts into your code.
+// Note that the output array is likely to be bigger than the binary file..
+// Load compressed TTF fonts with ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF()
+
+#define _CRT_SECURE_NO_WARNINGS
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+const int COLUMNS = 12;
+
+// stb_compress* from stb.h - declaration
+typedef unsigned int stb_uint;
+typedef unsigned char stb_uchar;
+stb_uint stb_compress(stb_uchar *out,stb_uchar *in,stb_uint len);
+
+static bool binary_to_compressed_c(const char* filename, const char* symbol);
+
+int main(int argc, char** argv)
+{
+    if (argc < 3)
+    {
+        printf("Syntax: %s <inputfile> <symbolname>\n", argv[0]);
+        return 0;
+    }
+
+    binary_to_compressed_c(argv[1], argv[2]);
+    return 1;
+}
+
+bool binary_to_compressed_c(const char* filename, const char* symbol)
+{
+    // Read file
+    FILE* f = fopen(filename, "rb");
+    if (!f) return false;
+    int data_sz;
+    if (fseek(f, 0, SEEK_END) || (data_sz = (int)ftell(f)) == -1 || fseek(f, 0, SEEK_SET)) { fclose(f); return false; }
+    char* data = new char[data_sz+4];
+    if (fread(data, 1, data_sz, f) != (size_t)data_sz) { fclose(f); delete[] data; return false; }
+    memset((void *)(((char*)data) + data_sz), 0, 4);
+    fclose(f);
+
+    // Compress
+    int maxlen = data_sz + 512 + (data_sz >> 2) + sizeof(int); // total guess
+    char* compressed = new char[maxlen];
+    int compressed_sz = stb_compress((stb_uchar*)compressed, (stb_uchar*)data, data_sz);
+    memset(compressed + compressed_sz, 0, maxlen - compressed_sz);
+
+    // Output
+    FILE* out = stdout;
+    fprintf(out, "// File: '%s' (%d bytes)\n", filename, (int)data_sz);
+    fprintf(out, "// Exported using binary_to_compressed_c\n");
+    fprintf(out, "static const unsigned int %s_compressed_size = %d;\n", symbol, (int)compressed_sz);
+    fprintf(out, "static const unsigned int %s_compressed_data[%d/4] =\n{", symbol, (int)((compressed_sz+3)/4)*4);
+    int column = 0;
+    for (int i = 0; i < compressed_sz; i += 4)
+    {
+        unsigned int d = *(unsigned int*)(compressed + i);
+        if ((column++ % COLUMNS) == 0)
+            fprintf(out, "\n    0x%08x, ", d);
+        else
+            fprintf(out, "0x%08x, ", d);
+    }
+    fprintf(out, "\n};\n\n");
+
+    // Cleanup
+    delete[] data;
+    delete[] compressed;
+    return true;
+}
+
+// stb_compress* from stb.h - definition
+
+////////////////////           compressor         ///////////////////////
+
+static stb_uint stb_adler32(stb_uint adler32, stb_uchar *buffer, stb_uint buflen)
+{
+    const unsigned long ADLER_MOD = 65521;
+    unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16;
+    unsigned long blocklen, i;
+
+    blocklen = buflen % 5552;
+    while (buflen) {
+        for (i=0; i + 7 < blocklen; i += 8) {
+            s1 += buffer[0], s2 += s1;
+            s1 += buffer[1], s2 += s1;
+            s1 += buffer[2], s2 += s1;
+            s1 += buffer[3], s2 += s1;
+            s1 += buffer[4], s2 += s1;
+            s1 += buffer[5], s2 += s1;
+            s1 += buffer[6], s2 += s1;
+            s1 += buffer[7], s2 += s1;
+
+            buffer += 8;
+        }
+
+        for (; i < blocklen; ++i)
+            s1 += *buffer++, s2 += s1;
+
+        s1 %= ADLER_MOD, s2 %= ADLER_MOD;
+        buflen -= blocklen;
+        blocklen = 5552;
+    }
+    return (s2 << 16) + s1;
+}
+
+static unsigned int stb_matchlen(stb_uchar *m1, stb_uchar *m2, stb_uint maxlen)
+{
+    stb_uint i;
+    for (i=0; i < maxlen; ++i)
+        if (m1[i] != m2[i]) return i;
+    return i;
+}
+
+// simple implementation that just takes the source data in a big block
+
+static stb_uchar *stb__out;
+static FILE      *stb__outfile;
+static stb_uint   stb__outbytes;
+
+static void stb__write(unsigned char v)
+{
+    fputc(v, stb__outfile);
+    ++stb__outbytes;
+}
+
+#define stb_out(v)    (stb__out ? *stb__out++ = (stb_uchar) (v) : stb__write((stb_uchar) (v)))
+
+static void stb_out2(stb_uint v)
+{
+    stb_out(v >> 8);
+    stb_out(v);
+}
+
+static void stb_out3(stb_uint v) { stb_out(v >> 16); stb_out(v >> 8); stb_out(v); }
+static void stb_out4(stb_uint v) { stb_out(v >> 24); stb_out(v >> 16);
+stb_out(v >> 8 ); stb_out(v);                  }
+
+static void outliterals(stb_uchar *in, int numlit)
+{
+    while (numlit > 65536) {
+        outliterals(in,65536);
+        in     += 65536;
+        numlit -= 65536;
+    }
+
+    if      (numlit ==     0)    ;
+    else if (numlit <=    32)    stb_out (0x000020 + numlit-1);
+    else if (numlit <=  2048)    stb_out2(0x000800 + numlit-1);
+    else /*  numlit <= 65536) */ stb_out3(0x070000 + numlit-1);
+
+    if (stb__out) {
+        memcpy(stb__out,in,numlit);
+        stb__out += numlit;
+    } else
+        fwrite(in, 1, numlit, stb__outfile);
+}
+
+static int stb__window = 0x40000; // 256K
+
+static int stb_not_crap(int best, int dist)
+{
+    return   ((best > 2  &&  dist <= 0x00100)     
+        || (best > 5  &&  dist <= 0x04000)
+        || (best > 7  &&  dist <= 0x80000));
+}
+
+static  stb_uint stb__hashsize = 32768;
+
+// note that you can play with the hashing functions all you
+// want without needing to change the decompressor
+#define stb__hc(q,h,c)      (((h) << 7) + ((h) >> 25) + q[c])
+#define stb__hc2(q,h,c,d)   (((h) << 14) + ((h) >> 18) + (q[c] << 7) + q[d])
+#define stb__hc3(q,c,d,e)   ((q[c] << 14) + (q[d] << 7) + q[e])
+
+static unsigned int stb__running_adler;
+
+static int stb_compress_chunk(stb_uchar *history,
+    stb_uchar *start,
+    stb_uchar *end,
+    int length,
+    int *pending_literals,
+    stb_uchar **chash,
+    stb_uint mask)
+{
+    (void)history;
+    int window = stb__window;
+    stb_uint match_max;
+    stb_uchar *lit_start = start - *pending_literals;
+    stb_uchar *q = start;
+
+#define STB__SCRAMBLE(h)   (((h) + ((h) >> 16)) & mask)
+
+    // stop short of the end so we don't scan off the end doing
+    // the hashing; this means we won't compress the last few bytes
+    // unless they were part of something longer
+    while (q < start+length && q+12 < end) {
+        int m;
+        stb_uint h1,h2,h3,h4, h;
+        stb_uchar *t;
+        int best = 2, dist=0;
+
+        if (q+65536 > end)
+            match_max = end-q;
+        else
+            match_max = 65536;
+
+#define stb__nc(b,d)  ((d) <= window && ((b) > 9 || stb_not_crap(b,d)))
+
+#define STB__TRY(t,p)  /* avoid retrying a match we already tried */ \
+    if (p ? dist != q-t : 1)                             \
+    if ((m = stb_matchlen(t, q, match_max)) > best)     \
+    if (stb__nc(m,q-(t)))                                \
+    best = m, dist = q - (t)
+
+        // rather than search for all matches, only try 4 candidate locations,
+        // chosen based on 4 different hash functions of different lengths.
+        // this strategy is inspired by LZO; hashing is unrolled here using the
+        // 'hc' macro
+        h = stb__hc3(q,0, 1, 2); h1 = STB__SCRAMBLE(h);
+        t = chash[h1]; if (t) STB__TRY(t,0);
+        h = stb__hc2(q,h, 3, 4); h2 = STB__SCRAMBLE(h);
+        h = stb__hc2(q,h, 5, 6);        t = chash[h2]; if (t) STB__TRY(t,1);
+        h = stb__hc2(q,h, 7, 8); h3 = STB__SCRAMBLE(h);
+        h = stb__hc2(q,h, 9,10);        t = chash[h3]; if (t) STB__TRY(t,1);
+        h = stb__hc2(q,h,11,12); h4 = STB__SCRAMBLE(h);
+        t = chash[h4]; if (t) STB__TRY(t,1);
+
+        // because we use a shared hash table, can only update it
+        // _after_ we've probed all of them
+        chash[h1] = chash[h2] = chash[h3] = chash[h4] = q;
+
+        if (best > 2)
+            assert(dist > 0);
+
+        // see if our best match qualifies
+        if (best < 3) { // fast path literals
+            ++q;
+        } else if (best > 2  &&  best <= 0x80    &&  dist <= 0x100) {
+            outliterals(lit_start, q-lit_start); lit_start = (q += best);
+            stb_out(0x80 + best-1);
+            stb_out(dist-1);
+        } else if (best > 5  &&  best <= 0x100   &&  dist <= 0x4000) {
+            outliterals(lit_start, q-lit_start); lit_start = (q += best);
+            stb_out2(0x4000 + dist-1);       
+            stb_out(best-1);
+        } else if (best > 7  &&  best <= 0x100   &&  dist <= 0x80000) {
+            outliterals(lit_start, q-lit_start); lit_start = (q += best);
+            stb_out3(0x180000 + dist-1);     
+            stb_out(best-1);
+        } else if (best > 8  &&  best <= 0x10000 &&  dist <= 0x80000) {
+            outliterals(lit_start, q-lit_start); lit_start = (q += best);
+            stb_out3(0x100000 + dist-1);     
+            stb_out2(best-1);
+        } else if (best > 9                      &&  dist <= 0x1000000) {
+            if (best > 65536) best = 65536;
+            outliterals(lit_start, q-lit_start); lit_start = (q += best);
+            if (best <= 0x100) {
+                stb_out(0x06);
+                stb_out3(dist-1);
+                stb_out(best-1);
+            } else {
+                stb_out(0x04);
+                stb_out3(dist-1);
+                stb_out2(best-1);
+            }
+        } else {  // fallback literals if no match was a balanced tradeoff
+            ++q;
+        }
+    }
+
+    // if we didn't get all the way, add the rest to literals
+    if (q-start < length)
+        q = start+length;
+
+    // the literals are everything from lit_start to q
+    *pending_literals = (q - lit_start);
+
+    stb__running_adler = stb_adler32(stb__running_adler, start, q - start);
+    return q - start;
+}
+
+static int stb_compress_inner(stb_uchar *input, stb_uint length)
+{
+    int literals = 0;
+    stb_uint len,i;
+
+    stb_uchar **chash;
+    chash = (stb_uchar**) malloc(stb__hashsize * sizeof(stb_uchar*));
+    if (chash == NULL) return 0; // failure
+    for (i=0; i < stb__hashsize; ++i)
+        chash[i] = NULL;
+
+    // stream signature
+    stb_out(0x57); stb_out(0xbc);
+    stb_out2(0);
+
+    stb_out4(0);       // 64-bit length requires 32-bit leading 0
+    stb_out4(length);
+    stb_out4(stb__window);
+
+    stb__running_adler = 1;
+
+    len = stb_compress_chunk(input, input, input+length, length, &literals, chash, stb__hashsize-1);
+    assert(len == length);
+
+    outliterals(input+length - literals, literals);
+
+    free(chash);
+
+    stb_out2(0x05fa); // end opcode
+
+    stb_out4(stb__running_adler);
+
+    return 1; // success
+}
+
+stb_uint stb_compress(stb_uchar *out, stb_uchar *input, stb_uint length)
+{
+    stb__out = out;
+    stb__outfile = NULL;
+
+    stb_compress_inner(input, length);
+
+    return stb__out - out;
+}

+ 142 - 64
imgui.cpp

@@ -1,4 +1,4 @@
-// ImGui library v1.38 WIP
+// ImGui library v1.38 WIP
 // See ImGui::ShowTestWindow() for sample code.
 // See ImGui::ShowTestWindow() for sample code.
 // Read 'Programmer guide' below for notes on how to setup ImGui in your codebase.
 // Read 'Programmer guide' below for notes on how to setup ImGui in your codebase.
 // Get latest version at https://github.com/ocornut/imgui
 // Get latest version at https://github.com/ocornut/imgui
@@ -135,6 +135,7 @@
  Occasionally introducing changes that are breaking the API. The breakage are generally minor and easy to fix.
  Occasionally introducing changes that are breaking the API. The breakage are generally minor and easy to fix.
  Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code.
  Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code.
  
  
+ - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function (will obsolete).
  - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API
  - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API
  - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive.
  - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive.
  - 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead.
  - 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead.
@@ -491,7 +492,7 @@ static bool         ItemAdd(const ImRect& bb, const ImGuiID* id);
 static void         ItemSize(ImVec2 size, float text_offset_y = 0.0f);
 static void         ItemSize(ImVec2 size, float text_offset_y = 0.0f);
 static void         ItemSize(const ImRect& bb, float text_offset_y = 0.0f);
 static void         ItemSize(const ImRect& bb, float text_offset_y = 0.0f);
 static void         PushColumnClipRect(int column_index = -1);
 static void         PushColumnClipRect(int column_index = -1);
-static bool         IsClipped(const ImRect& bb);
+static bool         IsClippedEx(const ImRect& bb, bool clip_even_when_logged);
 
 
 static bool         IsMouseHoveringRect(const ImRect& bb);
 static bool         IsMouseHoveringRect(const ImRect& bb);
 static bool         IsKeyPressedMap(ImGuiKey key, bool repeat = true);
 static bool         IsKeyPressedMap(ImGuiKey key, bool repeat = true);
@@ -1108,10 +1109,11 @@ struct ImGuiState
     ImGuiWindow*            FocusedWindow;                      // Will catch keyboard inputs
     ImGuiWindow*            FocusedWindow;                      // Will catch keyboard inputs
     ImGuiWindow*            HoveredWindow;                      // Will catch mouse inputs
     ImGuiWindow*            HoveredWindow;                      // Will catch mouse inputs
     ImGuiWindow*            HoveredRootWindow;                  // Will catch mouse inputs (for focus/move only)
     ImGuiWindow*            HoveredRootWindow;                  // Will catch mouse inputs (for focus/move only)
-    ImGuiID                 HoveredId;
-    ImGuiID                 ActiveId;
+    ImGuiID                 HoveredId;                          // Hovered widget
+    ImGuiID                 ActiveId;                           // Active widget
     ImGuiID                 ActiveIdPreviousFrame;
     ImGuiID                 ActiveIdPreviousFrame;
     bool                    ActiveIdIsAlive;
     bool                    ActiveIdIsAlive;
+    bool                    ActiveIdIsJustActivated;            // Set when 
     bool                    ActiveIdIsFocusedOnly;              // Set only by active widget. Denote focus but no active interaction.
     bool                    ActiveIdIsFocusedOnly;              // Set only by active widget. Denote focus but no active interaction.
     ImGuiWindow*            MovedWindow;                        // Track the child window we clicked on to move a window. Only valid if ActiveID is the "#MOVE" identifier of a window.
     ImGuiWindow*            MovedWindow;                        // Track the child window we clicked on to move a window. Only valid if ActiveID is the "#MOVE" identifier of a window.
     float                   SettingsDirtyTimer;
     float                   SettingsDirtyTimer;
@@ -1144,6 +1146,7 @@ struct ImGuiState
     ImGuiID                 ScalarAsInputTextId;                // Temporary text input when CTRL+clicking on a slider, etc.
     ImGuiID                 ScalarAsInputTextId;                // Temporary text input when CTRL+clicking on a slider, etc.
     ImGuiStorage            ColorEditModeStorage;               // for user selection
     ImGuiStorage            ColorEditModeStorage;               // for user selection
     ImGuiID                 ActiveComboID;
     ImGuiID                 ActiveComboID;
+    float                   DragCurrentValue;                   // current dragged value, always float, not rounded by end-user precision settings
     ImVec2                  DragLastMouseDelta;
     ImVec2                  DragLastMouseDelta;
     float                   DragSpeedScaleSlow;
     float                   DragSpeedScaleSlow;
     float                   DragSpeedScaleFast;
     float                   DragSpeedScaleFast;
@@ -1182,6 +1185,7 @@ struct ImGuiState
         ActiveId = 0;
         ActiveId = 0;
         ActiveIdPreviousFrame = 0;
         ActiveIdPreviousFrame = 0;
         ActiveIdIsAlive = false;
         ActiveIdIsAlive = false;
+        ActiveIdIsJustActivated = false;
         ActiveIdIsFocusedOnly = false;
         ActiveIdIsFocusedOnly = false;
         MovedWindow = NULL;
         MovedWindow = NULL;
         SettingsDirtyTimer = 0.0f;
         SettingsDirtyTimer = 0.0f;
@@ -1199,6 +1203,7 @@ struct ImGuiState
 
 
         ScalarAsInputTextId = 0;
         ScalarAsInputTextId = 0;
         ActiveComboID = 0;
         ActiveComboID = 0;
+        DragCurrentValue = 0.0f;
         DragLastMouseDelta = ImVec2(0.0f, 0.0f);
         DragLastMouseDelta = ImVec2(0.0f, 0.0f);
         DragSpeedScaleSlow = 0.01f;
         DragSpeedScaleSlow = 0.01f;
         DragSpeedScaleFast = 10.0f;
         DragSpeedScaleFast = 10.0f;
@@ -1271,7 +1276,7 @@ public:
     ImGuiWindow(const char* name);
     ImGuiWindow(const char* name);
     ~ImGuiWindow();
     ~ImGuiWindow();
 
 
-    ImGuiID     GetID(const char* str);
+    ImGuiID     GetID(const char* str, const char* str_end = NULL);
     ImGuiID     GetID(const void* ptr);
     ImGuiID     GetID(const void* ptr);
 
 
     bool        FocusItemRegister(bool is_active, bool tab_stop = true);      // Return true if focus is requested
     bool        FocusItemRegister(bool is_active, bool tab_stop = true);      // Return true if focus is requested
@@ -1314,6 +1319,7 @@ static void SetActiveId(ImGuiID id)
     ImGuiState& g = *GImGui;
     ImGuiState& g = *GImGui;
     g.ActiveId = id; 
     g.ActiveId = id; 
     g.ActiveIdIsFocusedOnly = false;
     g.ActiveIdIsFocusedOnly = false;
+    g.ActiveIdIsJustActivated = true;
 }
 }
 
 
 static void RegisterAliveId(ImGuiID id)
 static void RegisterAliveId(ImGuiID id)
@@ -1616,10 +1622,10 @@ ImGuiWindow::~ImGuiWindow()
     Name = NULL;
     Name = NULL;
 }
 }
 
 
-ImGuiID ImGuiWindow::GetID(const char* str)
+ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end)
 {
 {
     ImGuiID seed = IDStack.back();
     ImGuiID seed = IDStack.back();
-    const ImGuiID id = ImHash(str, 0, seed);
+    const ImGuiID id = ImHash(str, str_end ? str_end - str : 0, seed);
     RegisterAliveId(id);
     RegisterAliveId(id);
     return id;
     return id;
 }
 }
@@ -1936,6 +1942,7 @@ void ImGui::NewFrame()
         SetActiveId(0);
         SetActiveId(0);
     g.ActiveIdPreviousFrame = g.ActiveId;
     g.ActiveIdPreviousFrame = g.ActiveId;
     g.ActiveIdIsAlive = false;
     g.ActiveIdIsAlive = false;
+    g.ActiveIdIsJustActivated = false;
     if (!g.ActiveId)
     if (!g.ActiveId)
         g.MovedWindow = NULL;
         g.MovedWindow = NULL;
 
 
@@ -2694,6 +2701,14 @@ ImVec2 ImGui::GetMouseDragDelta(int button, float lock_threshold)
     return ImVec2(0.0f, 0.0f);
     return ImVec2(0.0f, 0.0f);
 }
 }
 
 
+void ImGui::ResetMouseDragDelta(int button)
+{
+    ImGuiState& g = *GImGui;
+    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
+    // NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr
+    g.IO.MouseClickedPos[button] = g.IO.MousePos;
+}
+
 ImGuiMouseCursor ImGui::GetMouseCursor()
 ImGuiMouseCursor ImGui::GetMouseCursor()
 {
 {
     return GImGui->MouseCursor;
     return GImGui->MouseCursor;
@@ -2733,6 +2748,13 @@ bool ImGui::IsAnyItemActive()
     return g.ActiveId != 0;
     return g.ActiveId != 0;
 }
 }
 
 
+bool ImGui::IsItemVisible()
+{
+    ImGuiWindow* window = GetCurrentWindow();
+    ImRect r(window->ClipRectStack.back());
+    return r.Overlaps(window->DC.LastItemRect);
+}
+
 ImVec2 ImGui::GetItemRectMin()
 ImVec2 ImGui::GetItemRectMin()
 {
 {
     ImGuiWindow* window = GetCurrentWindow();
     ImGuiWindow* window = GetCurrentWindow();
@@ -4232,7 +4254,7 @@ void ImGui::TextUnformatted(const char* text, const char* text_end)
                 while (line < text_end)
                 while (line < text_end)
                 {
                 {
                     const char* line_end = strchr(line, '\n');
                     const char* line_end = strchr(line, '\n');
-                    if (IsClipped(line_rect))
+                    if (IsClippedEx(line_rect, false))
                         break;
                         break;
 
 
                     const ImVec2 line_size = CalcTextSize(line, line_end, false);
                     const ImVec2 line_size = CalcTextSize(line, line_end, false);
@@ -4943,6 +4965,12 @@ void ImGui::PushID(const char* str_id)
     window->IDStack.push_back(window->GetID(str_id));
     window->IDStack.push_back(window->GetID(str_id));
 }
 }
 
 
+void ImGui::PushID(const char* str_id_begin, const char* str_id_end)
+{
+    ImGuiWindow* window = GetCurrentWindow();
+    window->IDStack.push_back(window->GetID(str_id_begin, str_id_end));
+}
+
 void ImGui::PushID(const void* ptr_id)
 void ImGui::PushID(const void* ptr_id)
 {
 {
     ImGuiWindow* window = GetCurrentWindow();
     ImGuiWindow* window = GetCurrentWindow();
@@ -4968,6 +4996,12 @@ ImGuiID ImGui::GetID(const char* str_id)
     return window->GetID(str_id);
     return window->GetID(str_id);
 }
 }
 
 
+ImGuiID ImGui::GetID(const char* str_id_begin, const char* str_id_end)
+{
+    ImGuiWindow* window = GetCurrentWindow();
+    return window->GetID(str_id_begin, str_id_end);
+}
+
 ImGuiID ImGui::GetID(const void* ptr_id)
 ImGuiID ImGui::GetID(const void* ptr_id)
 {
 {
     ImGuiWindow* window = GetCurrentWindow();
     ImGuiWindow* window = GetCurrentWindow();
@@ -5056,7 +5090,7 @@ static bool SliderFloatAsInputText(const char* label, float* v, ImGuiID id, int
 }
 }
 
 
 // Parse display precision back from the display format string
 // Parse display precision back from the display format string
-static void ParseFormat(const char* fmt, int& decimal_precision)
+static inline void ParseFormat(const char* fmt, int& decimal_precision)
 {
 {
     while ((fmt = strchr(fmt, '%')) != NULL)
     while ((fmt = strchr(fmt, '%')) != NULL)
     {
     {
@@ -5074,6 +5108,21 @@ static void ParseFormat(const char* fmt, int& decimal_precision)
     }
     }
 }
 }
 
 
+static inline float RoundScalar(float value, int decimal_precision)
+{
+    // Round past decimal precision
+    //    0: 1, 1: 0.1, 2: 0.01, etc.
+    // So when our value is 1.99999 with a precision of 0.001 we'll end up rounding to 2.0
+    // FIXME: Investigate better rounding methods
+    const float min_step = 1.0f / powf(10.0f, (float)decimal_precision);
+    const float remainder = fmodf(value, min_step);
+    if (remainder <= min_step*0.5f)
+        value -= remainder;
+    else
+        value += (min_step - remainder);
+    return value;
+}
+
 static bool SliderBehavior(const ImRect& frame_bb, const ImRect& slider_bb, ImGuiID id, float* v, float v_min, float v_max, float power, int decimal_precision, bool horizontal)
 static bool SliderBehavior(const ImRect& frame_bb, const ImRect& slider_bb, ImGuiID id, float* v, float v_min, float v_max, float power, int decimal_precision, bool horizontal)
 {
 {
     ImGuiState& g = *GImGui;
     ImGuiState& g = *GImGui;
@@ -5152,14 +5201,7 @@ static bool SliderBehavior(const ImRect& frame_bb, const ImRect& slider_bb, ImGu
             }
             }
 
 
             // Round past decimal precision
             // Round past decimal precision
-            //    0->1, 1->0.1, 2->0.01, etc.
-            // So when our value is 1.99999 with a precision of 0.001 we'll end up rounding to 2.0
-            const float min_step = 1.0f / powf(10.0f, (float)decimal_precision);
-            const float remainder = fmodf(new_value, min_step);
-            if (remainder <= min_step*0.5f)
-                new_value -= remainder;
-            else
-                new_value += (min_step - remainder);
+            new_value = RoundScalar(new_value, decimal_precision);
 
 
             if (*v != new_value)
             if (*v != new_value)
             {
             {
@@ -5465,7 +5507,7 @@ bool ImGui::SliderInt4(const char* label, int v[4], int v_min, int v_max, const
 }
 }
 
 
 // FIXME-WIP: Work in progress. May change API / behavior.
 // FIXME-WIP: Work in progress. May change API / behavior.
-static bool DragScalarBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_step, float v_min, float v_max)
+static bool DragScalarBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_speed, float v_min, float v_max, int decimal_precision, float power)
 {
 {
     ImGuiState& g = *GImGui;
     ImGuiState& g = *GImGui;
     ImGuiWindow* window = GetCurrentWindow();
     ImGuiWindow* window = GetCurrentWindow();
@@ -5482,23 +5524,52 @@ static bool DragScalarBehavior(const ImRect& frame_bb, ImGuiID id, float* v, flo
     {
     {
         if (g.IO.MouseDown[0])
         if (g.IO.MouseDown[0])
         {
         {
-            const ImVec2 mouse_drag_delta = ImGui::GetMouseDragDelta(0);
+            if (g.ActiveIdIsJustActivated)
+            {
+                // Lock current value on click
+                g.DragCurrentValue = *v;
+                g.DragLastMouseDelta = ImVec2(0.f, 0.f);
+            }
 
 
+            const ImVec2 mouse_drag_delta = ImGui::GetMouseDragDelta(0, 1.0f);
             if (fabsf(mouse_drag_delta.x - g.DragLastMouseDelta.x) > 0.0f)
             if (fabsf(mouse_drag_delta.x - g.DragLastMouseDelta.x) > 0.0f)
             {
             {
-                float step = v_step;
+                float speed = v_speed;
                 if (g.IO.KeyShift && g.DragSpeedScaleFast >= 0.0f)
                 if (g.IO.KeyShift && g.DragSpeedScaleFast >= 0.0f)
-                    step = v_step * g.DragSpeedScaleFast;
+                    speed = v_speed * g.DragSpeedScaleFast;
                 if (g.IO.KeyAlt && g.DragSpeedScaleSlow >= 0.0f)
                 if (g.IO.KeyAlt && g.DragSpeedScaleSlow >= 0.0f)
-                    step = v_step * g.DragSpeedScaleSlow;
+                    speed = v_speed * g.DragSpeedScaleSlow;
 
 
-                *v += (mouse_drag_delta.x - g.DragLastMouseDelta.x) * step;
+                float v_cur = g.DragCurrentValue;
+                float delta = (mouse_drag_delta.x - g.DragLastMouseDelta.x) * speed;
+                if (fabsf(power - 1.0f) > 0.001f)
+                {
+                    // Logarithmic curve on both side of 0.0
+                    float v0_abs = v_cur >= 0.0f ? v_cur : -v_cur;
+                    float v0_sign = v_cur >= 0.0f ? 1.0f : -1.0f;
+                    float v1 = powf(v0_abs, 1.0f / power) + (delta * v0_sign);
+                    float v1_abs = v1 >= 0.0f ? v1 : -v1;
+                    float v1_sign = v1 >= 0.0f ? 1.0f : -1.0f;          // Crossed sign line
+                    v_cur = powf(v1_abs, power) * v0_sign * v1_sign;    // Reapply sign
+                }
+                else
+                {
+                    v_cur += delta;
+                }
+                g.DragLastMouseDelta.x = mouse_drag_delta.x;
 
 
+                // Clamp
                 if (v_min < v_max)
                 if (v_min < v_max)
-                    *v = ImClamp(*v, v_min, v_max);
+                    v_cur = ImClamp(v_cur, v_min, v_max);
+                g.DragCurrentValue = v_cur;
 
 
-                g.DragLastMouseDelta.x = mouse_drag_delta.x;
-                value_changed = true;
+                // Round to user desired precision, then apply
+                v_cur = RoundScalar(v_cur, decimal_precision);
+                if (*v != v_cur)
+                {
+                    *v = v_cur;
+                    value_changed = true;
+                }
             }
             }
         }
         }
         else
         else
@@ -5510,7 +5581,7 @@ static bool DragScalarBehavior(const ImRect& frame_bb, ImGuiID id, float* v, flo
     return value_changed;
     return value_changed;
 }
 }
 
 
-bool ImGui::DragFloat(const char* label, float *v, float v_step, float v_min, float v_max, const char* display_format)
+bool ImGui::DragFloat(const char* label, float *v, float v_speed, float v_min, float v_max, const char* display_format, float power)
 {
 {
     ImGuiState& g = *GImGui;
     ImGuiState& g = *GImGui;
     ImGuiWindow* window = GetCurrentWindow();
     ImGuiWindow* window = GetCurrentWindow();
@@ -5549,7 +5620,6 @@ bool ImGui::DragFloat(const char* label, float *v, float v_step, float v_min, fl
     {
     {
         SetActiveId(id);
         SetActiveId(id);
         FocusWindow(window);
         FocusWindow(window);
-        g.DragLastMouseDelta = ImVec2(0.f, 0.f);
 
 
         if (tab_focus_requested || g.IO.KeyCtrl || g.IO.MouseDoubleClicked[0])
         if (tab_focus_requested || g.IO.KeyCtrl || g.IO.MouseDoubleClicked[0])
         {
         {
@@ -5563,7 +5633,7 @@ bool ImGui::DragFloat(const char* label, float *v, float v_step, float v_min, fl
     ItemSize(total_bb, style.FramePadding.y);
     ItemSize(total_bb, style.FramePadding.y);
 
 
     // Actual drag behavior
     // Actual drag behavior
-    const bool value_changed = DragScalarBehavior(frame_bb, id, v, v_step, v_min, v_max);
+    const bool value_changed = DragScalarBehavior(frame_bb, id, v, v_speed, v_min, v_max, decimal_precision, power);
 
 
     // Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
     // Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
     char value_buf[64];
     char value_buf[64];
@@ -5577,12 +5647,13 @@ bool ImGui::DragFloat(const char* label, float *v, float v_step, float v_min, fl
     return value_changed;
     return value_changed;
 }
 }
 
 
-bool ImGui::DragInt(const char* label, int* v, int v_step, int v_min, int v_max, const char* display_format)
+// NB: v_speed is float to allow adjusting the drag speed with more precision
+bool ImGui::DragInt(const char* label, int* v, float v_speed, int v_min, int v_max, const char* display_format)
 {
 {
     if (!display_format)
     if (!display_format)
         display_format = "%.0f";
         display_format = "%.0f";
     float v_f = (float)*v;
     float v_f = (float)*v;
-    bool value_changed = ImGui::DragFloat(label, &v_f, (float)v_step, (float)v_min, (float)v_max, display_format);
+    bool value_changed = ImGui::DragFloat(label, &v_f, v_speed, (float)v_min, (float)v_max, display_format);
     *v = (int)v_f;
     *v = (int)v_f;
     return value_changed;
     return value_changed;
 }
 }
@@ -7030,7 +7101,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha)
                     ImGui::SameLine(0, (int)style.ItemInnerSpacing.x);
                     ImGui::SameLine(0, (int)style.ItemInnerSpacing.x);
                 if (n + 1 == components)
                 if (n + 1 == components)
                     ImGui::PushItemWidth(w_item_last);
                     ImGui::PushItemWidth(w_item_last);
-                value_changed |= ImGui::DragInt(ids[n], &i[n], 1, 0, 255, fmt[n]);
+                value_changed |= ImGui::DragInt(ids[n], &i[n], 1.0f, 0, 255, fmt[n]);
             }
             }
             ImGui::PopItemWidth();
             ImGui::PopItemWidth();
             ImGui::PopItemWidth();
             ImGui::PopItemWidth();
@@ -7180,20 +7251,23 @@ static inline void ItemSize(const ImRect& bb, float text_offset_y)
     ItemSize(bb.GetSize(), text_offset_y); 
     ItemSize(bb.GetSize(), text_offset_y); 
 }
 }
 
 
-static bool IsClipped(const ImRect& bb)
+static bool IsClippedEx(const ImRect& bb, bool clip_even_when_logged)
 {
 {
     ImGuiState& g = *GImGui;
     ImGuiState& g = *GImGui;
     ImGuiWindow* window = GetCurrentWindow();
     ImGuiWindow* window = GetCurrentWindow();
 
 
-    if (!bb.Overlaps(ImRect(window->ClipRectStack.back())) && !g.LogEnabled)
-        return true;
+    if (!bb.Overlaps(ImRect(window->ClipRectStack.back())))
+    {
+        if (clip_even_when_logged || !g.LogEnabled)
+            return true;
+    }
     return false;
     return false;
 }
 }
 
 
-bool ImGui::IsClipped(const ImVec2& item_size)
+bool ImGui::IsRectClipped(const ImVec2& size)
 {
 {
     ImGuiWindow* window = GetCurrentWindow();
     ImGuiWindow* window = GetCurrentWindow();
-    return IsClipped(ImRect(window->DC.CursorPos, window->DC.CursorPos + item_size));
+    return IsClippedEx(ImRect(window->DC.CursorPos, window->DC.CursorPos + size), true);
 }
 }
 
 
 static bool ItemAdd(const ImRect& bb, const ImGuiID* id)
 static bool ItemAdd(const ImRect& bb, const ImGuiID* id)
@@ -7201,10 +7275,13 @@ static bool ItemAdd(const ImRect& bb, const ImGuiID* id)
     ImGuiWindow* window = GetCurrentWindow();
     ImGuiWindow* window = GetCurrentWindow();
     window->DC.LastItemID = id ? *id : 0;
     window->DC.LastItemID = id ? *id : 0;
     window->DC.LastItemRect = bb;
     window->DC.LastItemRect = bb;
-    if (IsClipped(bb))
+    if (IsClippedEx(bb, false))
     {
     {
-        window->DC.LastItemHoveredAndUsable = window->DC.LastItemHoveredRect = false;
-        return false;
+        if (!id || *id != GImGui->ActiveId)
+        {
+            window->DC.LastItemHoveredAndUsable = window->DC.LastItemHoveredRect = false;
+            return false;
+        }
     }
     }
 
 
     // This is a sensible default, but widgets are free to override it after calling ItemAdd()
     // This is a sensible default, but widgets are free to override it after calling ItemAdd()
@@ -7433,7 +7510,7 @@ void ImGui::Columns(int columns_count, const char* id, bool border)
             const ImGuiID column_id = window->DC.ColumnsSetID + ImGuiID(i);
             const ImGuiID column_id = window->DC.ColumnsSetID + ImGuiID(i);
             const ImRect column_rect(ImVec2(x-4,y1),ImVec2(x+4,y2));
             const ImRect column_rect(ImVec2(x-4,y1),ImVec2(x+4,y2));
 
 
-            if (IsClipped(column_rect))
+            if (IsClippedEx(column_rect, false))
                 continue;
                 continue;
 
 
             bool hovered, held;
             bool hovered, held;
@@ -8138,18 +8215,10 @@ static unsigned int stb_decompress(unsigned char *output, unsigned char *i, unsi
 // Load embedded ProggyClean.ttf at size 13
 // Load embedded ProggyClean.ttf at size 13
 ImFont* ImFontAtlas::AddFontDefault()
 ImFont* ImFontAtlas::AddFontDefault()
 {
 {
-    // Get compressed data
     unsigned int ttf_compressed_size;
     unsigned int ttf_compressed_size;
     const void* ttf_compressed;
     const void* ttf_compressed;
     GetDefaultCompressedFontDataTTF(&ttf_compressed, &ttf_compressed_size);
     GetDefaultCompressedFontDataTTF(&ttf_compressed, &ttf_compressed_size);
-
-    // Decompress
-    const size_t buf_decompressed_size = stb_decompress_length((unsigned char*)ttf_compressed);
-    unsigned char* buf_decompressed = (unsigned char *)ImGui::MemAlloc(buf_decompressed_size);
-    stb_decompress(buf_decompressed, (unsigned char*)ttf_compressed, ttf_compressed_size);
-
-    // Add
-    ImFont* font = AddFontFromMemoryTTF(buf_decompressed, buf_decompressed_size, 13.0f, GetGlyphRangesDefault(), 0);
+    ImFont* font = AddFontFromMemoryCompressedTTF(ttf_compressed, ttf_compressed_size, 13.0f, GetGlyphRangesDefault(), 0);
     font->DisplayOffset.y += 1;
     font->DisplayOffset.y += 1;
     return font;
     return font;
 }
 }
@@ -8164,13 +8233,12 @@ ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels,
         return NULL;
         return NULL;
     }
     }
 
 
-    // Add
     ImFont* font = AddFontFromMemoryTTF(data, data_size, size_pixels, glyph_ranges, font_no);
     ImFont* font = AddFontFromMemoryTTF(data, data_size, size_pixels, glyph_ranges, font_no);
     return font;
     return font;
 }
 }
 
 
 // NB: ownership of 'data' is given to ImFontAtlas which will clear it.
 // NB: ownership of 'data' is given to ImFontAtlas which will clear it.
-ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* in_ttf_data, size_t in_ttf_data_size, float size_pixels, const ImWchar* glyph_ranges, int font_no)
+ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* in_ttf_data, unsigned int in_ttf_data_size, float size_pixels, const ImWchar* glyph_ranges, int font_no)
 {
 {
     // Create new font
     // Create new font
     ImFont* font = (ImFont*)ImGui::MemAlloc(sizeof(ImFont));
     ImFont* font = (ImFont*)ImGui::MemAlloc(sizeof(ImFont));
@@ -8194,6 +8262,18 @@ ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* in_ttf_data, size_t in_ttf_data_
     return font;
     return font;
 }
 }
 
 
+ImFont* ImFontAtlas::AddFontFromMemoryCompressedTTF(const void* in_compressed_ttf_data, unsigned int in_compressed_ttf_data_size, float size_pixels, const ImWchar* glyph_ranges, int font_no)
+{
+    // Decompress
+    const size_t buf_decompressed_size = stb_decompress_length((unsigned char*)in_compressed_ttf_data);
+    unsigned char* buf_decompressed = (unsigned char *)ImGui::MemAlloc(buf_decompressed_size);
+    stb_decompress(buf_decompressed, (unsigned char*)in_compressed_ttf_data, in_compressed_ttf_data_size);
+
+    // Add
+    ImFont* font = AddFontFromMemoryTTF(buf_decompressed, buf_decompressed_size, size_pixels, glyph_ranges, font_no);
+    return font;
+}
+
 bool    ImFontAtlas::Build()
 bool    ImFontAtlas::Build()
 {
 {
     IM_ASSERT(InputData.size() > 0);
     IM_ASSERT(InputData.size() > 0);
@@ -10235,7 +10315,7 @@ void ImGui::ShowTestWindow(bool* opened)
         ImGui::Spacing();
         ImGui::Spacing();
 
 
         // Scrolling columns
         // Scrolling columns
-		/*
+        /*
         ImGui::Text("Scrolling:");
         ImGui::Text("Scrolling:");
         ImGui::BeginChild("##header", ImVec2(0, ImGui::GetTextLineHeightWithSpacing()+ImGui::GetStyle().ItemSpacing.y));
         ImGui::BeginChild("##header", ImVec2(0, ImGui::GetTextLineHeightWithSpacing()+ImGui::GetStyle().ItemSpacing.y));
         ImGui::Columns(3);
         ImGui::Columns(3);
@@ -10258,7 +10338,7 @@ void ImGui::ShowTestWindow(bool* opened)
 
 
         ImGui::Separator();
         ImGui::Separator();
         ImGui::Spacing();
         ImGui::Spacing();
-		*/
+        */
 
 
         // Create multiple items in a same cell before switching to next column
         // Create multiple items in a same cell before switching to next column
         ImGui::Text("Mixed items:");
         ImGui::Text("Mixed items:");
@@ -10947,16 +11027,9 @@ static void ShowExampleAppLongText(bool* opened)
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 // FONT DATA
 // FONT DATA
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
-
-//-----------------------------------------------------------------------------
-// ProggyClean.ttf
-// Copyright (c) 2004, 2005 Tristan Grimmer
-// MIT license (see License.txt in http://www.upperbounds.net/download/ProggyClean.ttf.zip)
-// Download and more information at http://upperbounds.net
-//-----------------------------------------------------------------------------
 // Compressed with stb_compress() then converted to a C array.
 // Compressed with stb_compress() then converted to a C array.
-// Decompressor from stb.h (public domain) by Sean Barrett
-// https://github.com/nothings/stb/blob/master/stb.h
+// Use the program in extra_fonts/binary_to_compressed_c.cpp to create the array from a TTF file.
+// Decompressor from stb.h (public domain) by Sean Barrett https://github.com/nothings/stb/blob/master/stb.h
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
 static unsigned int stb_decompress_length(unsigned char *input)
 static unsigned int stb_decompress_length(unsigned char *input)
@@ -10965,7 +11038,6 @@ static unsigned int stb_decompress_length(unsigned char *input)
 }
 }
 
 
 static unsigned char *stb__barrier, *stb__barrier2, *stb__barrier3, *stb__barrier4;
 static unsigned char *stb__barrier, *stb__barrier2, *stb__barrier3, *stb__barrier4;
-
 static unsigned char *stb__dout;
 static unsigned char *stb__dout;
 static void stb__match(unsigned char *data, unsigned int length)
 static void stb__match(unsigned char *data, unsigned int length)
 {
 {
@@ -11071,6 +11143,12 @@ static unsigned int stb_decompress(unsigned char *output, unsigned char *i, unsi
     }
     }
 }
 }
 
 
+//-----------------------------------------------------------------------------
+// ProggyClean.ttf
+// Copyright (c) 2004, 2005 Tristan Grimmer
+// MIT license (see License.txt in http://www.upperbounds.net/download/ProggyClean.ttf.zip)
+// Download and more information at http://upperbounds.net
+//-----------------------------------------------------------------------------
 static const unsigned int proggy_clean_ttf_compressed_size = 9583;
 static const unsigned int proggy_clean_ttf_compressed_size = 9583;
 static const unsigned int proggy_clean_ttf_compressed_data[9584/4] =
 static const unsigned int proggy_clean_ttf_compressed_data[9584/4] =
 {
 {

+ 12 - 6
imgui.h

@@ -260,10 +260,12 @@ namespace ImGui
     // If you are creating widgets in a loop you most likely want to push a unique identifier so ImGui can differentiate them
     // If you are creating widgets in a loop you most likely want to push a unique identifier so ImGui can differentiate them
     // You can also use "##extra" within your widget name to distinguish them from each others (see 'Programmer Guide')
     // You can also use "##extra" within your widget name to distinguish them from each others (see 'Programmer Guide')
     IMGUI_API void          PushID(const char* str_id);                                         // push identifier into the ID stack. IDs are hash of the *entire* stack!
     IMGUI_API void          PushID(const char* str_id);                                         // push identifier into the ID stack. IDs are hash of the *entire* stack!
+    IMGUI_API void          PushID(const char* str_id_begin, const char* str_id_end);
     IMGUI_API void          PushID(const void* ptr_id);
     IMGUI_API void          PushID(const void* ptr_id);
     IMGUI_API void          PushID(const int int_id);
     IMGUI_API void          PushID(const int int_id);
     IMGUI_API void          PopID();
     IMGUI_API void          PopID();
     IMGUI_API ImGuiID       GetID(const char* str_id);                                          // calculate unique ID (hash of whole ID stack + given parameter). useful if you want to query into ImGuiStorage yourself. otherwise rarely needed
     IMGUI_API ImGuiID       GetID(const char* str_id);                                          // calculate unique ID (hash of whole ID stack + given parameter). useful if you want to query into ImGuiStorage yourself. otherwise rarely needed
+    IMGUI_API ImGuiID       GetID(const char* str_id_begin, const char* str_id_end);
     IMGUI_API ImGuiID       GetID(const void* ptr_id);
     IMGUI_API ImGuiID       GetID(const void* ptr_id);
 
 
     // Widgets
     // Widgets
@@ -316,8 +318,8 @@ namespace ImGui
 
 
     // Widgets: Drags (tip: ctrl+click on a drag box to input text)
     // Widgets: Drags (tip: ctrl+click on a drag box to input text)
     // ImGui 1.38+ work-in-progress, may change name or API.
     // ImGui 1.38+ work-in-progress, may change name or API.
-    IMGUI_API bool          DragFloat(const char* label, float* v, float v_step = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* display_format = "%.3f");   // If v_max >= v_max we have no bound
-    IMGUI_API bool          DragInt(const char* label, int* v, int v_step = 1, int v_min = 0, int v_max = 0, const char* display_format = "%.0f");                // If v_max >= v_max we have no bound
+    IMGUI_API bool          DragFloat(const char* label, float* v, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* display_format = "%.3f", float power = 1.0f);  // If v_max >= v_max we have no bound
+    IMGUI_API bool          DragInt(const char* label, int* v, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* display_format = "%.0f");                                    // If v_max >= v_max we have no bound
 
 
     // Widgets: Input
     // Widgets: Input
     IMGUI_API bool          InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiTextEditCallback callback = NULL, void* user_data = NULL);
     IMGUI_API bool          InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiTextEditCallback callback = NULL, void* user_data = NULL);
@@ -371,13 +373,14 @@ namespace ImGui
     IMGUI_API bool          IsItemHoveredRect();                                                // was the last item hovered by mouse? even if another item is active while we are hovering this
     IMGUI_API bool          IsItemHoveredRect();                                                // was the last item hovered by mouse? even if another item is active while we are hovering this
     IMGUI_API bool          IsItemActive();                                                     // was the last item active? (e.g. button being held, text field being edited- items that don't interact will always return false)
     IMGUI_API bool          IsItemActive();                                                     // was the last item active? (e.g. button being held, text field being edited- items that don't interact will always return false)
     IMGUI_API bool          IsAnyItemActive();                                                  // 
     IMGUI_API bool          IsAnyItemActive();                                                  // 
-    IMGUI_API ImVec2        GetItemRectMin();                                                   // get bounding rect of last item
+    IMGUI_API bool          IsItemVisible();
+    IMGUI_API ImVec2        GetItemRectMin();                                                   // get bounding rect of last item in screen space
     IMGUI_API ImVec2        GetItemRectMax();                                                   // "
     IMGUI_API ImVec2        GetItemRectMax();                                                   // "
     IMGUI_API ImVec2        GetItemRectSize();                                                  // "
     IMGUI_API ImVec2        GetItemRectSize();                                                  // "
     IMGUI_API bool          IsWindowFocused();                                                  // is current window focused (differentiate child windows from each others)
     IMGUI_API bool          IsWindowFocused();                                                  // is current window focused (differentiate child windows from each others)
     IMGUI_API bool          IsRootWindowFocused();                                              // is current root window focused
     IMGUI_API bool          IsRootWindowFocused();                                              // is current root window focused
     IMGUI_API bool          IsRootWindowOrAnyChildFocused();                                    // is current root window or any of its child (including current window) focused
     IMGUI_API bool          IsRootWindowOrAnyChildFocused();                                    // is current root window or any of its child (including current window) focused
-    IMGUI_API bool          IsClipped(const ImVec2& item_size);                                 // to perform coarse clipping on user's side (as an optimization)
+    IMGUI_API bool          IsRectClipped(const ImVec2& size);                                  // test if rectangle of given size starting from cursor pos is out of clipping region. to perform coarse clipping on user's side (as an optimization)
     IMGUI_API 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
     IMGUI_API 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
     IMGUI_API bool          IsMouseClicked(int button, bool repeat = false);
     IMGUI_API bool          IsMouseClicked(int button, bool repeat = false);
     IMGUI_API bool          IsMouseDoubleClicked(int button);
     IMGUI_API bool          IsMouseDoubleClicked(int button);
@@ -388,6 +391,7 @@ namespace ImGui
     IMGUI_API bool          IsPosHoveringAnyWindow(const ImVec2& pos);                          // is given position hovering any active imgui window
     IMGUI_API bool          IsPosHoveringAnyWindow(const ImVec2& pos);                          // is given position hovering any active imgui window
     IMGUI_API ImVec2        GetMousePos();                                                      // shortcut to ImGui::GetIO().MousePos provided by user, to be consistent with other calls
     IMGUI_API ImVec2        GetMousePos();                                                      // shortcut to ImGui::GetIO().MousePos provided by user, to be consistent with other calls
     IMGUI_API ImVec2        GetMouseDragDelta(int button = 0, float lock_threshold = -1.0f);    // dragging amount since clicking, also see: GetItemActiveDragDelta(). if lock_threshold < -1.0f uses io.MouseDraggingThreshold
     IMGUI_API ImVec2        GetMouseDragDelta(int button = 0, float lock_threshold = -1.0f);    // dragging amount since clicking, also see: GetItemActiveDragDelta(). if lock_threshold < -1.0f uses io.MouseDraggingThreshold
+    IMGUI_API void          ResetMouseDragDelta(int button = 0);
     IMGUI_API ImGuiMouseCursor GetMouseCursor();                                                // get desired cursor type, reset in ImGui::NewFrame(), this updated during the frame. valid before Render(). If you use software rendering by setting io.MouseDrawCursor ImGui will render those for you
     IMGUI_API ImGuiMouseCursor GetMouseCursor();                                                // get desired cursor type, reset in ImGui::NewFrame(), this updated during the frame. valid before Render(). If you use software rendering by setting io.MouseDrawCursor ImGui will render those for you
     IMGUI_API void          SetMouseCursor(ImGuiMouseCursor type);                              // set desired cursor type
     IMGUI_API void          SetMouseCursor(ImGuiMouseCursor type);                              // set desired cursor type
     IMGUI_API float         GetTime();
     IMGUI_API float         GetTime();
@@ -416,6 +420,7 @@ namespace ImGui
     static inline bool      GetWindowIsFocused() { return ImGui::IsWindowFocused(); }   // OBSOLETE
     static inline bool      GetWindowIsFocused() { return ImGui::IsWindowFocused(); }   // OBSOLETE
     static inline ImVec2    GetItemBoxMin() { return GetItemRectMin(); }    // OBSOLETE
     static inline ImVec2    GetItemBoxMin() { return GetItemRectMin(); }    // OBSOLETE
     static inline ImVec2    GetItemBoxMax() { return GetItemRectMax(); }    // OBSOLETE
     static inline ImVec2    GetItemBoxMax() { return GetItemRectMax(); }    // OBSOLETE
+    static inline bool      IsClipped(const ImVec2& size) { return IsRectClipped(size); }   // OBSOLETE
     static inline bool      IsMouseHoveringBox(const ImVec2& rect_min, const ImVec2& rect_max) { return IsMouseHoveringRect(rect_min, rect_max); }  // OBSOLETE
     static inline bool      IsMouseHoveringBox(const ImVec2& rect_min, const ImVec2& rect_max) { return IsMouseHoveringRect(rect_min, rect_max); }  // OBSOLETE
 
 
 } // namespace ImGui
 } // namespace ImGui
@@ -948,14 +953,15 @@ struct ImDrawList
 //  2. Call GetTexDataAsAlpha8() or GetTexDataAsRGBA32() to build and retrieve pixels data.
 //  2. Call GetTexDataAsAlpha8() or GetTexDataAsRGBA32() to build and retrieve pixels data.
 //  3. Upload the pixels data into a texture within your graphics system.
 //  3. Upload the pixels data into a texture within your graphics system.
 //  4. Call SetTexID(my_tex_id); and pass the pointer/identifier to your texture. This value will be passed back to you during rendering to identify the texture.
 //  4. Call SetTexID(my_tex_id); and pass the pointer/identifier to your texture. This value will be passed back to you during rendering to identify the texture.
-//  5. Call ClearPixelsData() to free textures memory on the heap.
+//  5. Call ClearTexData() to free textures memory on the heap.
 struct ImFontAtlas
 struct ImFontAtlas
 {
 {
     IMGUI_API ImFontAtlas();
     IMGUI_API ImFontAtlas();
     IMGUI_API ~ImFontAtlas();
     IMGUI_API ~ImFontAtlas();
     IMGUI_API ImFont*           AddFontDefault();
     IMGUI_API ImFont*           AddFontDefault();
     IMGUI_API ImFont*           AddFontFromFileTTF(const char* filename, float size_pixels, const ImWchar* glyph_ranges = NULL, int font_no = 0);
     IMGUI_API ImFont*           AddFontFromFileTTF(const char* filename, float size_pixels, const ImWchar* glyph_ranges = NULL, int font_no = 0);
-    IMGUI_API ImFont*           AddFontFromMemoryTTF(void* in_ttf_data, size_t in_ttf_data_size, float size_pixels, const ImWchar* glyph_ranges = NULL, int font_no = 0); // Pass ownership of 'in_ttf_data' memory.
+    IMGUI_API ImFont*           AddFontFromMemoryTTF(void* in_ttf_data, unsigned int in_ttf_data_size, float size_pixels, const ImWchar* glyph_ranges = NULL, int font_no = 0); // Pass ownership of 'in_ttf_data' memory, will be deleted after build
+    IMGUI_API ImFont*           AddFontFromMemoryCompressedTTF(const void* in_compressed_ttf_data, unsigned int in_compressed_ttf_data_size, float size_pixels, const ImWchar* glyph_ranges = NULL, int font_no = 0); // 'in_compressed_ttf_data' untouched and still owned by caller. compress with binary_to_compressed_c.
     IMGUI_API void              ClearTexData();             // Saves RAM once the texture has been copied to graphics memory.
     IMGUI_API void              ClearTexData();             // Saves RAM once the texture has been copied to graphics memory.
     IMGUI_API void              Clear();
     IMGUI_API void              Clear();