Browse Source

ImGuiStorage helper can store float + added functions to get pointer to data. Exposed ImGui::GetId() - may be misleading?

omar 10 years ago
parent
commit
bdb2344db0
2 changed files with 83 additions and 32 deletions
  1. 52 20
      imgui.cpp
  2. 31 12
      imgui.h

+ 52 - 20
imgui.cpp

@@ -924,46 +924,66 @@ static ImVector<ImGuiStorage::Pair>::iterator LowerBound(ImVector<ImGuiStorage::
     return first;
 }
 
-int* ImGuiStorage::Find(ImU32 key)
+int ImGuiStorage::GetInt(ImU32 key, int default_val) const
 {
-    ImVector<Pair>::iterator it = LowerBound(Data, key);
-    if (it == Data.end())
-        return NULL;
-    if (it->key != key)
-        return NULL;
-    return &it->val;
+    ImVector<Pair>::iterator it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);
+    if (it == Data.end() || it->key != key)
+        return default_val;
+    return it->val_i;
 }
 
-int ImGuiStorage::GetInt(ImU32 key, int default_val)
+float ImGuiStorage::GetFloat(ImU32 key, float default_val) const
 {
-    int* pval = Find(key);
-    if (!pval)
+    ImVector<Pair>::iterator it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);
+    if (it == Data.end() || it->key != key)
         return default_val;
-    return *pval;
+    return it->val_f;
+}
+
+int* ImGuiStorage::GetIntPtr(ImGuiID key, int default_val)
+{
+    ImVector<Pair>::iterator it = LowerBound(Data, key);
+    if (it == Data.end() || it->key != key)
+        it = Data.insert(it, Pair(key, default_val));
+    return &it->val_i;
 }
 
-// FIXME-OPT: We are wasting time because all SetInt() are preceeded by GetInt() calls so we should have the result from lower_bound already in place.
+float* ImGuiStorage::GetFloatPtr(ImGuiID key, float default_val)
+{
+    ImVector<Pair>::iterator it = LowerBound(Data, key);
+    if (it == Data.end() || it->key != key)
+        it = Data.insert(it, Pair(key, default_val));
+    return &it->val_f;
+}
+
+// FIXME-OPT: Wasting CPU because all SetInt() are preceeded by GetInt() calls so we should have the result from lower_bound already in place.
 // However we only use SetInt() on explicit user action (so that's maximum once a frame) so the optimisation isn't much needed.
 void ImGuiStorage::SetInt(ImU32 key, int val)
 {
     ImVector<Pair>::iterator it = LowerBound(Data, key);
-    if (it != Data.end() && it->key == key)
+    if (it == Data.end() || it->key != key)
     {
-        it->val = val;
+        Data.insert(it, Pair(key, val));
+        return;
     }
-    else
+    it->val_i = val;
+}
+
+void ImGuiStorage::SetFloat(ImU32 key, float val)
+{
+    ImVector<Pair>::iterator it = LowerBound(Data, key);
+    if (it == Data.end() || it->key != key)
     {
-        Pair pair_key;
-        pair_key.key = key;
-        pair_key.val = val;
-        Data.insert(it, pair_key);
+        Data.insert(it, Pair(key, val));
+        return;
     }
+    it->val_f = val;
 }
 
 void ImGuiStorage::SetAllInt(int v)
 {
     for (size_t i = 0; i < Data.size(); i++)
-        Data[i].val = v;
+        Data[i].val_i = v;
 }
 
 //-----------------------------------------------------------------------------
@@ -3550,6 +3570,18 @@ void ImGui::PopID()
     window->IDStack.pop_back();
 }
 
+ImGuiID ImGui::GetID(const char* str_id)
+{
+    ImGuiWindow* window = GetCurrentWindow();
+    return window->GetID(str_id);
+}
+
+ImGuiID ImGui::GetID(const void* ptr_id)
+{
+    ImGuiWindow* window = GetCurrentWindow();
+    return window->GetID(ptr_id);
+}
+
 // User can input math operators (e.g. +100) to edit a numerical values.
 // NB: only call right after InputText because we are using its InitialValue storage
 static void ApplyNumericalTextInput(const char* buf, float *v)

+ 31 - 12
imgui.h

@@ -117,7 +117,7 @@ public:
     inline void                 pop_back()                      { IM_ASSERT(Size > 0); Size--; }
 
     inline iterator             erase(const_iterator it)        { IM_ASSERT(it >= begin() && it < end()); const ptrdiff_t off = it - begin(); memmove(Data + off, Data + off + 1, (Size - (size_t)off - 1) * sizeof(value_type)); Size--; return Data + off; }
-    inline void                 insert(const_iterator it, const value_type& v)  { IM_ASSERT(it >= begin() && it <= end()); const ptrdiff_t off = it - begin(); if (Size == Capacity) reserve(Capacity ? Capacity * 2 : 4); if (off < (int)Size) memmove(Data + off + 1, Data + off, (Size - (size_t)off) * sizeof(value_type)); Data[off] = v; Size++; }
+    inline iterator             insert(const_iterator it, const value_type& v)  { IM_ASSERT(it >= begin() && it <= end()); const ptrdiff_t off = it - begin(); if (Size == Capacity) reserve(Capacity ? Capacity * 2 : 4); if (off < (int)Size) memmove(Data + off + 1, Data + off, (Size - (size_t)off) * sizeof(value_type)); Data[off] = v; Size++; return Data + off; }
 };
 #endif // #ifndef ImVector
 
@@ -204,10 +204,13 @@ namespace ImGui
     IMGUI_API float         GetTextLineHeight();
 
     // ID scopes
-    IMGUI_API void          PushID(const char* str_id);
+    // If you are creating repeated widgets in a loop you most likely want to push a unique identifier so ImGui can differentiate them.
+    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 void* ptr_id);
     IMGUI_API void          PushID(const int int_id);
     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 void* ptr_id);
 
     // Widgets
     IMGUI_API void          Text(const char* fmt, ...);
@@ -587,22 +590,38 @@ struct ImGuiTextBuffer
 };
 
 // Helper: Key->value storage
-// - Store collapse state for a tree
-// - Store color edit options, etc.
+// - Store collapse state for a tree (Int 0/1)
+// - Store color edit options (Int using values in ImGuiColorEditMode enum).
+// - Custom user storage for temporary values.
 // Typically you don't have to worry about this since a storage is held within each Window.
-// Declare your own storage if you want to manipulate the open/close state of a particular sub-tree in your interface.
+// Declare your own storage if:
+// - You want to manipulate the open/close state of a particular sub-tree in your interface (tree node uses Int 0/1 to store their state).
+// - You want to store custom debug data easily without adding or editing structures in your code.
 struct ImGuiStorage
 {
-    struct Pair { ImU32 key; int val; };
+    struct Pair 
+    { 
+        ImGuiID key; 
+        union { int val_i; float val_f; };        
+        Pair(ImGuiID _key, int _val_i) { key = _key; val_i = _val_i; } 
+        Pair(ImGuiID _key, float _val_f) { key = _key; val_f = _val_f; } 
+    };
     ImVector<Pair>    Data;
 
+    // - Get***() functions find pair, never add/allocate. Pairs are sorted so a query is O(log N)
+    // - Set***() functions find pair, insertion on demand if missing.
+    // - Get***Ptr() functions find pair, insertion on demand if missing, return pointer. Useful if you intend to do Get+Set. 
+    //   A typical use case where this is very convenient:
+    //      ImGui::SliderInt("tmp adjustment", GetIntPtr(key), 0, 100); some_var += *GetIntPtr(key);
+    // - Sorted insertion is costly but should amortize. A typical frame shouldn't need to insert any new pair.
     IMGUI_API void    Clear();
-    IMGUI_API int     GetInt(ImU32 key, int default_val = 0);
-    IMGUI_API void    SetInt(ImU32 key, int val);
-    IMGUI_API void    SetAllInt(int val);
-
-    IMGUI_API int*    Find(ImU32 key);
-    IMGUI_API void    Insert(ImU32 key, int val);
+    IMGUI_API int     GetInt(ImGuiID key, int default_val = 0) const;
+    IMGUI_API void    SetInt(ImGuiID key, int val);
+    IMGUI_API int*    GetIntPtr(ImGuiID key, int default_val = 0);
+    IMGUI_API float   GetFloat(ImGuiID key, float default_val = 0.0f) const;
+    IMGUI_API void    SetFloat(ImGuiID key, float val);
+    IMGUI_API float*  GetFloatPtr(ImGuiID key, float default_val = 0);
+    IMGUI_API void    SetAllInt(int val);    // Use on your own storage if you know only integer are being stored.
 };
 
 // Shared state of InputText(), passed to callback when a ImGuiInputTextFlags_Callback* flag is used.