|
|
@@ -13,14 +13,14 @@ Index of this file:
|
|
|
// Forward declarations and basic types
|
|
|
// ImGui API (Dear ImGui end-user API)
|
|
|
// Flags & Enumerations
|
|
|
-// ImVector
|
|
|
+// ImVector<>
|
|
|
// ImGuiStyle
|
|
|
// ImGuiIO
|
|
|
// Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiPayload)
|
|
|
// Obsolete functions
|
|
|
// Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, ImColor)
|
|
|
// Draw List API (ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListFlags, ImDrawList, ImDrawData)
|
|
|
-// Font API (ImFontConfig, ImFontGlyph, ImFontAtlasFlags, ImFontAtlas, ImFont)
|
|
|
+// Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFont)
|
|
|
|
|
|
*/
|
|
|
|
|
|
@@ -1156,73 +1156,63 @@ enum ImGuiCond_
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
// Helper: ImVector<>
|
|
|
-// Lightweight std::vector<>-like class to avoid dragging dependencies (also: some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug).
|
|
|
+// Lightweight std::vector<>-like class to avoid dragging dependencies (also, some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug).
|
|
|
// You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our data structures are relying on it.
|
|
|
+// Important: clear() frees memory, resize(0) keep the allocated buffer. We use resize(0) a lot to intentionally recycle allocated buffers across frames and amortize our costs.
|
|
|
// Important: our implementation does NOT call C++ constructors/destructors, we treat everything as raw data! This is intentional but be extra mindful of that,
|
|
|
-// do NOT use this class as a std::vector replacement in your own code!
|
|
|
+// do NOT use this class as a std::vector replacement in your own code! Many of the structures used by dear imgui can be safely initialized by a zero-memset.
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
template<typename T>
|
|
|
-class ImVector
|
|
|
+struct ImVector
|
|
|
{
|
|
|
-public:
|
|
|
- int Size;
|
|
|
- int Capacity;
|
|
|
- T* Data;
|
|
|
+ int Size;
|
|
|
+ int Capacity;
|
|
|
+ T* Data;
|
|
|
|
|
|
+ // Provide standard typedefs but we don't use them ourselves.
|
|
|
typedef T value_type;
|
|
|
typedef value_type* iterator;
|
|
|
typedef const value_type* const_iterator;
|
|
|
|
|
|
- inline ImVector() { Size = Capacity = 0; Data = NULL; }
|
|
|
- inline ~ImVector() { if (Data) ImGui::MemFree(Data); }
|
|
|
- inline ImVector(const ImVector<T>& src) { Size = Capacity = 0; Data = NULL; operator=(src); }
|
|
|
- inline ImVector<T>& operator=(const ImVector<T>& src) { clear(); resize(src.Size); memcpy(Data, src.Data, (size_t)Size * sizeof(value_type)); return *this; }
|
|
|
-
|
|
|
- inline bool empty() const { return Size == 0; }
|
|
|
- inline int size() const { return Size; }
|
|
|
- inline int capacity() const { return Capacity; }
|
|
|
- inline value_type& operator[](int i) { IM_ASSERT(i < Size); return Data[i]; }
|
|
|
- inline const value_type& operator[](int i) const { IM_ASSERT(i < Size); return Data[i]; }
|
|
|
-
|
|
|
- inline void clear() { if (Data) { Size = Capacity = 0; ImGui::MemFree(Data); Data = NULL; } }
|
|
|
- inline iterator begin() { return Data; }
|
|
|
- inline const_iterator begin() const { return Data; }
|
|
|
- inline iterator end() { return Data + Size; }
|
|
|
- inline const_iterator end() const { return Data + Size; }
|
|
|
- inline value_type& front() { IM_ASSERT(Size > 0); return Data[0]; }
|
|
|
- inline const value_type& front() const { IM_ASSERT(Size > 0); return Data[0]; }
|
|
|
- inline value_type& back() { IM_ASSERT(Size > 0); return Data[Size - 1]; }
|
|
|
- inline const value_type& back() const { IM_ASSERT(Size > 0); return Data[Size - 1]; }
|
|
|
- inline void swap(ImVector<value_type>& rhs) { int rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; int rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; value_type* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; }
|
|
|
-
|
|
|
- inline int _grow_capacity(int sz) const { int new_capacity = Capacity ? (Capacity + Capacity/2) : 8; return new_capacity > sz ? new_capacity : sz; }
|
|
|
- inline void resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; }
|
|
|
- inline void resize(int new_size,const value_type& v){ if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) memcpy(&Data[n], &v, sizeof(v)); Size = new_size; }
|
|
|
- inline void reserve(int new_capacity)
|
|
|
- {
|
|
|
- if (new_capacity <= Capacity)
|
|
|
- return;
|
|
|
- value_type* new_data = (value_type*)ImGui::MemAlloc((size_t)new_capacity * sizeof(value_type));
|
|
|
- if (Data)
|
|
|
- {
|
|
|
- memcpy(new_data, Data, (size_t)Size * sizeof(value_type));
|
|
|
- ImGui::MemFree(Data);
|
|
|
- }
|
|
|
- Data = new_data;
|
|
|
- Capacity = new_capacity;
|
|
|
- }
|
|
|
+ // Constructors, destructor
|
|
|
+ inline ImVector() { Size = Capacity = 0; Data = NULL; }
|
|
|
+ inline ImVector(const ImVector<T>& src) { Size = Capacity = 0; Data = NULL; operator=(src); }
|
|
|
+ inline ImVector<T>& operator=(const ImVector<T>& src) { clear(); resize(src.Size); memcpy(Data, src.Data, (size_t)Size * sizeof(T)); return *this; }
|
|
|
+ inline ~ImVector() { if (Data) ImGui::MemFree(Data); }
|
|
|
+
|
|
|
+ inline bool empty() const { return Size == 0; }
|
|
|
+ inline int size() const { return Size; }
|
|
|
+ inline int capacity() const { return Capacity; }
|
|
|
+ inline T& operator[](int i) { IM_ASSERT(i < Size); return Data[i]; }
|
|
|
+ inline const T& operator[](int i) const { IM_ASSERT(i < Size); return Data[i]; }
|
|
|
+
|
|
|
+ inline void clear() { if (Data) { Size = Capacity = 0; ImGui::MemFree(Data); Data = NULL; } }
|
|
|
+ inline T* begin() { return Data; }
|
|
|
+ inline const T* begin() const { return Data; }
|
|
|
+ inline T* end() { return Data + Size; }
|
|
|
+ inline const T* end() const { return Data + Size; }
|
|
|
+ inline T& front() { IM_ASSERT(Size > 0); return Data[0]; }
|
|
|
+ inline const T& front() const { IM_ASSERT(Size > 0); return Data[0]; }
|
|
|
+ inline T& back() { IM_ASSERT(Size > 0); return Data[Size - 1]; }
|
|
|
+ inline const T& back() const { IM_ASSERT(Size > 0); return Data[Size - 1]; }
|
|
|
+ inline void swap(ImVector<T>& rhs) { int rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; int rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; T* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; }
|
|
|
+
|
|
|
+ inline int _grow_capacity(int sz) const { int new_capacity = Capacity ? (Capacity + Capacity/2) : 8; return new_capacity > sz ? new_capacity : sz; }
|
|
|
+ inline void resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; }
|
|
|
+ inline void resize(int new_size, const T& v) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) memcpy(&Data[n], &v, sizeof(v)); Size = new_size; }
|
|
|
+ inline void reserve(int new_capacity) { if (new_capacity <= Capacity) return; T* new_data = (T*)ImGui::MemAlloc((size_t)new_capacity * sizeof(T)); if (Data) { memcpy(new_data, Data, (size_t)Size * sizeof(T)); ImGui::MemFree(Data); } Data = new_data; Capacity = new_capacity; }
|
|
|
|
|
|
// NB: It is illegal to call push_back/push_front/insert with a reference pointing inside the ImVector data itself! e.g. v.push_back(v[10]) is forbidden.
|
|
|
- inline void push_back(const value_type& v) { if (Size == Capacity) reserve(_grow_capacity(Size + 1)); memcpy(&Data[Size], &v, sizeof(v)); Size++; }
|
|
|
- inline void pop_back() { IM_ASSERT(Size > 0); Size--; }
|
|
|
- inline void push_front(const value_type& v) { if (Size == 0) push_back(v); else insert(Data, v); }
|
|
|
- inline iterator erase(const_iterator it) { IM_ASSERT(it >= Data && it < Data+Size); const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + 1, ((size_t)Size - (size_t)off - 1) * sizeof(value_type)); Size--; return Data + off; }
|
|
|
- inline iterator erase(const_iterator it, const_iterator it_last){ IM_ASSERT(it >= Data && it < Data+Size && it_last > it && it_last <= Data+Size); const ptrdiff_t count = it_last - it; const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + count, ((size_t)Size - (size_t)off - count) * sizeof(value_type)); Size -= (int)count; return Data + off; }
|
|
|
- inline iterator erase_unsorted(const_iterator it) { IM_ASSERT(it >= Data && it < Data+Size); const ptrdiff_t off = it - Data; if (it < Data+Size-1) memcpy(Data + off, Data + Size - 1, sizeof(value_type)); Size--; return Data + off; }
|
|
|
- inline iterator insert(const_iterator it, const value_type& v) { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; if (Size == Capacity) reserve(_grow_capacity(Size + 1)); if (off < (int)Size) memmove(Data + off + 1, Data + off, ((size_t)Size - (size_t)off) * sizeof(value_type)); memcpy(&Data[off], &v, sizeof(v)); Size++; return Data + off; }
|
|
|
- inline bool contains(const value_type& v) const { const T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data++ == v) return true; return false; }
|
|
|
- inline int index_from_pointer(const_iterator it) const { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; return (int)off; }
|
|
|
+ inline void push_back(const T& v) { if (Size == Capacity) reserve(_grow_capacity(Size + 1)); memcpy(&Data[Size], &v, sizeof(v)); Size++; }
|
|
|
+ inline void pop_back() { IM_ASSERT(Size > 0); Size--; }
|
|
|
+ inline void push_front(const T& v) { if (Size == 0) push_back(v); else insert(Data, v); }
|
|
|
+ inline T* erase(const T* it) { IM_ASSERT(it >= Data && it < Data+Size); const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + 1, ((size_t)Size - (size_t)off - 1) * sizeof(T)); Size--; return Data + off; }
|
|
|
+ inline T* erase(const T* it, const T* it_last){ IM_ASSERT(it >= Data && it < Data+Size && it_last > it && it_last <= Data+Size); const ptrdiff_t count = it_last - it; const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + count, ((size_t)Size - (size_t)off - count) * sizeof(T)); Size -= (int)count; return Data + off; }
|
|
|
+ inline T* erase_unsorted(const T* it) { IM_ASSERT(it >= Data && it < Data+Size); const ptrdiff_t off = it - Data; if (it < Data+Size-1) memcpy(Data + off, Data + Size - 1, sizeof(T)); Size--; return Data + off; }
|
|
|
+ inline T* insert(const T* it, const T& v) { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; if (Size == Capacity) reserve(_grow_capacity(Size + 1)); if (off < (int)Size) memmove(Data + off + 1, Data + off, ((size_t)Size - (size_t)off) * sizeof(T)); memcpy(&Data[off], &v, sizeof(v)); Size++; return Data + off; }
|
|
|
+ inline bool contains(const T& v) const { const T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data++ == v) return true; return false; }
|
|
|
+ inline int index_from_ptr(const T* it) const { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; return (int)off; }
|
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
@@ -1944,12 +1934,14 @@ struct ImFontGlyph
|
|
|
};
|
|
|
|
|
|
// Helper to build glyph ranges from text/string data. Feed your application strings/characters to it then call BuildRanges().
|
|
|
+// This is essentially a tightly packed of vector of 64k booleans = 8KB storage.
|
|
|
struct ImFontGlyphRangesBuilder
|
|
|
{
|
|
|
- ImVector<unsigned char> UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used)
|
|
|
- ImFontGlyphRangesBuilder() { UsedChars.resize(0x10000 / 8); memset(UsedChars.Data, 0, 0x10000 / 8); }
|
|
|
- bool GetBit(int n) const { return (UsedChars[n >> 3] & (1 << (n & 7))) != 0; }
|
|
|
- void SetBit(int n) { UsedChars[n >> 3] |= 1 << (n & 7); } // Set bit 'c' in the array
|
|
|
+ ImVector<int> UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used)
|
|
|
+
|
|
|
+ ImFontGlyphRangesBuilder() { UsedChars.resize(0x10000 / 32); memset(UsedChars.Data, 0, 0x10000 / 32); }
|
|
|
+ bool GetBit(int n) const { int off = (n >> 5); int mask = 1 << (n & 31); return (UsedChars[off] & mask) != 0; } // Get bit n in the array
|
|
|
+ void SetBit(int n) { int off = (n >> 5); int mask = 1 << (n & 31); UsedChars[off] |= mask; } // Set bit n in the array
|
|
|
void AddChar(ImWchar c) { SetBit(c); } // Add character
|
|
|
IMGUI_API void AddText(const char* text, const char* text_end = NULL); // Add string (each character of the UTF-8 string are added)
|
|
|
IMGUI_API void AddRanges(const ImWchar* ranges); // Add ranges, e.g. builder.AddRanges(ImFontAtlas::GetGlyphRangesDefault()) to force add all of ASCII/Latin+Ext
|