| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088 |
- // https://github.com/vassvik/imgui_docking_minimal/
- //
- // This is free and unencumbered software released into the public domain.
- //
- // Anyone is free to copy, modify, publish, use, compile, sell, or
- // distribute this software, either in source code form or as a compiled
- // binary, for any purpose, commercial or non-commercial, and by any
- // means.
- //
- // In jurisdictions that recognize copyright laws, the author or authors
- // of this software dedicate any and all copyright interest in the
- // software to the public domain. We make this dedication for the benefit
- // of the public at large and to the detriment of our heirs and
- // successors. We intend this dedication to be an overt act of
- // relinquishment in perpetuity of all present and future rights to this
- // software under copyright law.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- // IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- // OTHER DEALINGS IN THE SOFTWARE.
- //
- // For more information, please refer to <http://unlicense.org>
- #include <new> // placement new
- namespace ImGui
- {
- struct DockContext
- {
- enum Slot_
- {
- Slot_Left,
- Slot_Right,
- Slot_Top,
- Slot_Bottom,
- Slot_Tab,
- Slot_Float,
- Slot_None
- };
- enum EndAction_
- {
- EndAction_None,
- EndAction_Panel,
- EndAction_End,
- EndAction_EndChild
- };
- enum Status_
- {
- Status_Docked,
- Status_Float,
- Status_Dragged
- };
- struct Dock
- {
- Dock()
- : id(0)
- , label(NULL)
- , next_tab(NULL)
- , prev_tab(NULL)
- , parent(NULL)
- , pos(0, 0)
- , size(-1, -1)
- , active(true)
- , status(Status_Float)
- , opened(false)
- , first(true)
- {
- location[0] = 0;
- children[0] = children[1] = NULL;
- }
- ~Dock()
- {
- MemFree(label);
- }
- ImVec2 getMinSize() const
- {
- if (!children[0]) return ImVec2(16, 16 + GetTextLineHeightWithSpacing());
- ImVec2 s0 = children[0]->getMinSize();
- ImVec2 s1 = children[1]->getMinSize();
- return isHorizontal() ? ImVec2(s0.x + s1.x, ImMax(s0.y, s1.y))
- : ImVec2(ImMax(s0.x, s1.x), s0.y + s1.y);
- }
- bool isHorizontal() const
- {
- return children[0]->pos.x < children[1]->pos.x;
- }
- void setParent(Dock* dock)
- {
- parent = dock;
- for (Dock* tmp = prev_tab; tmp; tmp = tmp->prev_tab) tmp->parent = dock;
- for (Dock* tmp = next_tab; tmp; tmp = tmp->next_tab) tmp->parent = dock;
- }
- Dock& getSibling()
- {
- IM_ASSERT(parent);
- if (parent->children[0] == &getFirstTab()) return *parent->children[1];
- return *parent->children[0];
- }
- Dock& getFirstTab()
- {
- Dock* tmp = this;
- while (tmp->prev_tab) tmp = tmp->prev_tab;
- return *tmp;
- }
- void setActive()
- {
- active = true;
- for (Dock* tmp = prev_tab; tmp; tmp = tmp->prev_tab) tmp->active = false;
- for (Dock* tmp = next_tab; tmp; tmp = tmp->next_tab) tmp->active = false;
- }
- bool isContainer() const
- {
- return children[0] != NULL;
- }
- void setChildrenPosSize(const ImVec2& _pos, const ImVec2& _size)
- {
- ImVec2 s = children[0]->size;
- if (isHorizontal())
- {
- s.y = _size.y;
- s.x = (float)int(
- _size.x * children[0]->size.x / (children[0]->size.x + children[1]->size.x));
- if (s.x < children[0]->getMinSize().x)
- {
- s.x = children[0]->getMinSize().x;
- }
- else if (_size.x - s.x < children[1]->getMinSize().x)
- {
- s.x = _size.x - children[1]->getMinSize().x;
- }
- children[0]->setPosSize(_pos, s);
- s.x = _size.x - children[0]->size.x;
- ImVec2 p = _pos;
- p.x += children[0]->size.x;
- children[1]->setPosSize(p, s);
- }
- else
- {
- s.x = _size.x;
- s.y = (float)int(
- _size.y * children[0]->size.y / (children[0]->size.y + children[1]->size.y));
- if (s.y < children[0]->getMinSize().y)
- {
- s.y = children[0]->getMinSize().y;
- }
- else if (_size.y - s.y < children[1]->getMinSize().y)
- {
- s.y = _size.y - children[1]->getMinSize().y;
- }
- children[0]->setPosSize(_pos, s);
- s.y = _size.y - children[0]->size.y;
- ImVec2 p = _pos;
- p.y += children[0]->size.y;
- children[1]->setPosSize(p, s);
- }
- }
- void setPosSize(const ImVec2& _pos, const ImVec2& _size)
- {
- size = _size;
- pos = _pos;
- for (Dock* tmp = prev_tab; tmp; tmp = tmp->prev_tab)
- {
- tmp->size = _size;
- tmp->pos = _pos;
- }
- for (Dock* tmp = next_tab; tmp; tmp = tmp->next_tab)
- {
- tmp->size = _size;
- tmp->pos = _pos;
- }
- if (!isContainer()) return;
- setChildrenPosSize(_pos, _size);
- }
- ImU32 id;
- char* label;
- Dock* next_tab;
- Dock* prev_tab;
- Dock* parent;
- ImVec2 pos;
- ImVec2 size;
- bool active;
- Status_ status;
- bool opened;
- Dock* children[2];
- char location[16];
- int last_frame;
- int invalid_frames;
- bool first;
- };
- typedef ImVector<Dock*> DockVector;
- DockVector m_docks;
- ImVec2 m_drag_offset;
- Dock* m_current;
- int m_last_frame;
- EndAction_ m_end_action;
- DockContext()
- : m_current(NULL)
- , m_last_frame(0)
- {
- }
- ~DockContext()
- {
- }
- Dock& getDock(const char* label, bool opened)
- {
- ImU32 id = ImHashStr(label, 0);
- for (int i = 0; i < m_docks.size(); ++i)
- {
- if (m_docks[i]->id == id)
- {
- return *m_docks[i];
- }
- }
- Dock* new_dock = (Dock*)MemAlloc(sizeof(Dock));
- IM_PLACEMENT_NEW(new_dock) Dock();
- m_docks.push_back(new_dock);
- new_dock->label = ImStrdup(label);
- IM_ASSERT(new_dock->label);
- new_dock->id = id;
- new_dock->setActive();
- new_dock->status = Status_Float;
- new_dock->pos = ImVec2(0, 0);
- new_dock->size = GetIO().DisplaySize;
- new_dock->opened = opened;
- new_dock->first = true;
- new_dock->last_frame = 0;
- new_dock->invalid_frames = 0;
- new_dock->location[0] = 0;
- return *new_dock;
- }
- void putInBackground()
- {
- ImGuiWindow* win = GetCurrentWindow();
- ImGuiContext& g = *GImGui;
- if (g.Windows[0] == win) return;
- for (int i = 0; i < g.Windows.Size; i++)
- {
- if (g.Windows[i] == win)
- {
- for (int j = i - 1; j >= 0; --j)
- {
- g.Windows[j + 1] = g.Windows[j];
- }
- g.Windows[0] = win;
- break;
- }
- }
- }
- void splits()
- {
- if (GetFrameCount() == m_last_frame)
- {
- return;
- }
- m_last_frame = GetFrameCount();
- putInBackground();
- ImU32 color = GetColorU32(ImGuiCol_Button);
- ImU32 color_hovered = GetColorU32(ImGuiCol_ButtonHovered);
- ImDrawList* draw_list = GetWindowDrawList();
- ImGuiIO& io = GetIO();
- for (int i = 0; i < m_docks.size(); ++i)
- {
- Dock& dock = *m_docks[i];
- if (!dock.isContainer())
- {
- continue;
- }
- PushID(i);
- if (!IsMouseDown(0))
- {
- dock.status = Status_Docked;
- }
- ImVec2 dsize(0, 0);
- SetCursorScreenPos(dock.children[1]->pos);
- ImVec2 min_size0 = dock.children[0]->getMinSize();
- ImVec2 min_size1 = dock.children[1]->getMinSize();
- if (dock.isHorizontal())
- {
- InvisibleButton("split", ImVec2(3, dock.size.y));
- if (dock.status == Status_Dragged) dsize.x = io.MouseDelta.x;
- dsize.x = -ImMin(-dsize.x, dock.children[0]->size.x - min_size0.x);
- dsize.x = ImMin(dsize.x, dock.children[1]->size.x - min_size1.x);
- }
- else
- {
- InvisibleButton("split", ImVec2(dock.size.x, 3));
- if (dock.status == Status_Dragged) dsize.y = io.MouseDelta.y;
- dsize.y = -ImMin(-dsize.y, dock.children[0]->size.y - min_size0.y);
- dsize.y = ImMin(dsize.y, dock.children[1]->size.y - min_size1.y);
- }
- ImVec2 new_size0 = dock.children[0]->size + dsize;
- ImVec2 new_size1 = dock.children[1]->size - dsize;
- ImVec2 new_pos1 = dock.children[1]->pos + dsize;
- dock.children[0]->setPosSize(dock.children[0]->pos, new_size0);
- dock.children[1]->setPosSize(new_pos1, new_size1);
- if (IsItemHovered() && IsMouseClicked(0))
- {
- dock.status = Status_Dragged;
- }
- draw_list->AddRectFilled(
- GetItemRectMin(), GetItemRectMax(), IsItemHovered() ? color_hovered : color);
- PopID();
- }
- }
- void checkNonexistent()
- {
- int frame_limit = ImMax(0, ImGui::GetFrameCount() - 2);
- for (DockVector::iterator it = m_docks.begin(), itEnd = m_docks.end(); it != itEnd; ++it)
- {
- Dock* dock = *it;
- if (dock->isContainer()) continue;
- if (dock->status == Status_Float) continue;
- if (dock->last_frame < frame_limit)
- {
- ++dock->invalid_frames;
- if (dock->invalid_frames > 2)
- {
- doUndock(*dock);
- dock->status = Status_Float;
- }
- return;
- }
- dock->invalid_frames = 0;
- }
- }
- void beginPanel()
- {
- ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize |
- ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse |
- ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoScrollbar |
- ImGuiWindowFlags_NoScrollWithMouse |
- ImGuiWindowFlags_NoBringToFrontOnFocus;
- Dock* root = getRootDock();
- const ImVec2& displaySize = GetIO().DisplaySize;
- if (root)
- {
- const ImVec2 percentage(displaySize.x / root->size.x, displaySize.y / root->size.y );
- const ImVec2 rescaledPos = root->pos * percentage;
- const ImVec2 rescaledSize = root->size * percentage;
- SetNextWindowPos(rescaledPos);
- SetNextWindowSize(rescaledSize);
- }
- else
- {
- SetNextWindowPos(ImVec2(0, 0));
- SetNextWindowSize(displaySize);
- }
- ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0);
- Begin("###DockPanel", NULL, flags);
- splits();
- checkNonexistent();
- }
- void endPanel()
- {
- End();
- ImGui::PopStyleVar();
- }
- // Doesn't use input??
- Dock* getDockAt(const ImVec2& /*pos*/) const
- {
- for (int i = 0; i < m_docks.size(); ++i)
- {
- Dock& dock = *m_docks[i];
- if (dock.isContainer()) continue;
- if (dock.status != Status_Docked) continue;
- if (IsMouseHoveringRect(dock.pos, dock.pos + dock.size, false))
- {
- return &dock;
- }
- }
- return NULL;
- }
- static ImRect getDockedRect(const ImRect& rect, Slot_ dock_slot)
- {
- ImVec2 half_size = rect.GetSize() * 0.5f;
- switch (dock_slot)
- {
- default: return rect;
- case Slot_Top: return ImRect(rect.Min, rect.Min + ImVec2(rect.Max.x, half_size.y));
- case Slot_Right: return ImRect(rect.Min + ImVec2(half_size.x, 0), rect.Max);
- case Slot_Bottom: return ImRect(rect.Min + ImVec2(0, half_size.y), rect.Max);
- case Slot_Left: return ImRect(rect.Min, rect.Min + ImVec2(half_size.x, rect.Max.y));
- }
- }
- static ImRect getSlotRect(ImRect parent_rect, Slot_ dock_slot)
- {
- ImVec2 size = parent_rect.Max - parent_rect.Min;
- ImVec2 center = parent_rect.Min + size * 0.5f;
- switch (dock_slot)
- {
- default: return ImRect(center - ImVec2(20, 20), center + ImVec2(20, 20));
- case Slot_Top: return ImRect(center + ImVec2(-20, -50), center + ImVec2(20, -30));
- case Slot_Right: return ImRect(center + ImVec2(30, -20), center + ImVec2(50, 20));
- case Slot_Bottom: return ImRect(center + ImVec2(-20, +30), center + ImVec2(20, 50));
- case Slot_Left: return ImRect(center + ImVec2(-50, -20), center + ImVec2(-30, 20));
- }
- }
- static ImRect getSlotRectOnBorder(ImRect parent_rect, Slot_ dock_slot)
- {
- ImVec2 size = parent_rect.Max - parent_rect.Min;
- ImVec2 center = parent_rect.Min + size * 0.5f;
- switch (dock_slot)
- {
- case Slot_Top:
- return ImRect(ImVec2(center.x - 20, parent_rect.Min.y + 10),
- ImVec2(center.x + 20, parent_rect.Min.y + 30));
- case Slot_Left:
- return ImRect(ImVec2(parent_rect.Min.x + 10, center.y - 20),
- ImVec2(parent_rect.Min.x + 30, center.y + 20));
- case Slot_Bottom:
- return ImRect(ImVec2(center.x - 20, parent_rect.Max.y - 30),
- ImVec2(center.x + 20, parent_rect.Max.y - 10));
- case Slot_Right:
- return ImRect(ImVec2(parent_rect.Max.x - 30, center.y - 20),
- ImVec2(parent_rect.Max.x - 10, center.y + 20));
- default: IM_ASSERT(false);
- }
- IM_ASSERT(false);
- return ImRect();
- }
- Dock* getRootDock()
- {
- for (int i = 0; i < m_docks.size(); ++i)
- {
- if (!m_docks[i]->parent &&
- (m_docks[i]->status == Status_Docked || m_docks[i]->children[0]))
- {
- return m_docks[i];
- }
- }
- return NULL;
- }
- bool dockSlots(Dock& dock, Dock* dest_dock, const ImRect& rect, bool on_border)
- {
- ImDrawList* canvas = GetWindowDrawList();
- ImU32 color = GetColorU32(ImGuiCol_Button);
- ImU32 color_hovered = GetColorU32(ImGuiCol_ButtonHovered);
- ImVec2 mouse_pos = GetIO().MousePos;
- for (int i = 0; i < (on_border ? 4 : 5); ++i)
- {
- ImRect r =
- on_border ? getSlotRectOnBorder(rect, (Slot_)i) : getSlotRect(rect, (Slot_)i);
- bool hovered = r.Contains(mouse_pos);
- canvas->AddRectFilled(r.Min, r.Max, hovered ? color_hovered : color);
- if (!hovered) continue;
- if (!IsMouseDown(0))
- {
- doDock(dock, dest_dock ? dest_dock : getRootDock(), (Slot_)i);
- return true;
- }
- ImRect docked_rect = getDockedRect(rect, (Slot_)i);
- canvas->AddRectFilled(docked_rect.Min, docked_rect.Max, GetColorU32(ImGuiCol_Button));
- }
- return false;
- }
- void handleDrag(Dock& dock)
- {
- Dock* dest_dock = getDockAt(GetIO().MousePos);
- Begin("##Overlay",
- NULL,
- ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove |
- ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings |
- ImGuiWindowFlags_AlwaysAutoResize);
- ImDrawList* canvas = GetWindowDrawList();
- canvas->PushClipRectFullScreen();
- ImU32 docked_color = GetColorU32(ImGuiCol_FrameBg);
- docked_color = (docked_color & 0x00ffFFFF) | 0x80000000;
- dock.pos = GetIO().MousePos - m_drag_offset;
- if (dest_dock)
- {
- if (dockSlots(dock,
- dest_dock,
- ImRect(dest_dock->pos, dest_dock->pos + dest_dock->size),
- false))
- {
- canvas->PopClipRect();
- End();
- return;
- }
- }
- if (dockSlots(dock, NULL, ImRect(ImVec2(0, 0), GetIO().DisplaySize), true))
- {
- canvas->PopClipRect();
- End();
- return;
- }
- canvas->AddRectFilled(dock.pos, dock.pos + dock.size, docked_color);
- canvas->PopClipRect();
- if (!IsMouseDown(0))
- {
- dock.status = Status_Float;
- dock.location[0] = 0;
- dock.setActive();
- }
- End();
- }
- void fillLocation(Dock& dock)
- {
- if (dock.status == Status_Float) return;
- char* c = dock.location;
- Dock* tmp = &dock;
- while (tmp->parent)
- {
- *c = getLocationCode(tmp);
- tmp = tmp->parent;
- ++c;
- }
- *c = 0;
- }
- void doUndock(Dock& dock)
- {
- if (dock.prev_tab)
- dock.prev_tab->setActive();
- else if (dock.next_tab)
- dock.next_tab->setActive();
- else
- dock.active = false;
- Dock* container = dock.parent;
- if (container)
- {
- Dock& sibling = dock.getSibling();
- if (container->children[0] == &dock)
- {
- container->children[0] = dock.next_tab;
- }
- else if (container->children[1] == &dock)
- {
- container->children[1] = dock.next_tab;
- }
- bool remove_container = !container->children[0] || !container->children[1];
- if (remove_container)
- {
- if (container->parent)
- {
- Dock*& child = container->parent->children[0] == container
- ? container->parent->children[0]
- : container->parent->children[1];
- child = &sibling;
- child->setPosSize(container->pos, container->size);
- child->setParent(container->parent);
- }
- else
- {
- if (container->children[0])
- {
- container->children[0]->setParent(NULL);
- container->children[0]->setPosSize(container->pos, container->size);
- }
- if (container->children[1])
- {
- container->children[1]->setParent(NULL);
- container->children[1]->setPosSize(container->pos, container->size);
- }
- }
- for (int i = 0; i < m_docks.size(); ++i)
- {
- if (m_docks[i] == container)
- {
- m_docks.erase(m_docks.begin() + i);
- break;
- }
- }
- container->~Dock();
- MemFree(container);
- }
- }
- if (dock.prev_tab) dock.prev_tab->next_tab = dock.next_tab;
- if (dock.next_tab) dock.next_tab->prev_tab = dock.prev_tab;
- dock.parent = NULL;
- dock.prev_tab = dock.next_tab = NULL;
- }
- void drawTabbarListButton(Dock& dock)
- {
- if (!dock.next_tab) return;
- ImDrawList* draw_list = GetWindowDrawList();
- if (InvisibleButton("list", ImVec2(16, 16)))
- {
- OpenPopup("tab_list_popup");
- }
- if (BeginPopup("tab_list_popup"))
- {
- Dock* tmp = &dock;
- while (tmp)
- {
- bool dummy = false;
- if (Selectable(tmp->label, &dummy))
- {
- tmp->setActive();
- }
- tmp = tmp->next_tab;
- }
- EndPopup();
- }
- bool hovered = IsItemHovered();
- ImVec2 min = GetItemRectMin();
- ImVec2 max = GetItemRectMax();
- ImVec2 center = (min + max) * 0.5f;
- ImU32 text_color = GetColorU32(ImGuiCol_Text);
- ImU32 color_active = GetColorU32(ImGuiCol_FrameBgActive);
- draw_list->AddRectFilled(ImVec2(center.x - 4, min.y + 3),
- ImVec2(center.x + 4, min.y + 5),
- hovered ? color_active : text_color);
- draw_list->AddTriangleFilled(ImVec2(center.x - 4, min.y + 7),
- ImVec2(center.x + 4, min.y + 7),
- ImVec2(center.x, min.y + 12),
- hovered ? color_active : text_color);
- }
- bool tabbar(Dock& dock, bool close_button)
- {
- float tabbar_height = 2 * GetTextLineHeightWithSpacing();
- ImVec2 size0(dock.size.x, tabbar_height);
- bool tab_closed = false;
- SetCursorScreenPos(dock.pos);
- char tmp[20];
- ImFormatString(tmp, IM_ARRAYSIZE(tmp), "tabs%d", (int)dock.id);
- if (BeginChild(tmp, size0, true))
- {
- Dock* dock_tab = &dock;
- ImDrawList* draw_list = GetWindowDrawList();
- ImU32 color = GetColorU32(ImGuiCol_FrameBg);
- ImU32 color_active = GetColorU32(ImGuiCol_FrameBgActive);
- ImU32 color_hovered = GetColorU32(ImGuiCol_FrameBgHovered);
- ImU32 text_color = GetColorU32(ImGuiCol_Text);
- ImU32 text_color_disabled = GetColorU32(ImGuiCol_TextDisabled);
- float line_height = GetTextLineHeightWithSpacing();
- float tab_base = 0.0f;
- drawTabbarListButton(dock);
- while (dock_tab)
- {
- SameLine(0, 15);
- const char* text_end = FindRenderedTextEnd(dock_tab->label);
- ImVec2 size1(CalcTextSize(dock_tab->label, text_end).x, line_height);
- if (InvisibleButton(dock_tab->label, size1))
- {
- dock_tab->setActive();
- }
- if (IsItemActive() && IsMouseDragging(0))
- {
- m_drag_offset = GetMousePos() - dock_tab->pos;
- doUndock(*dock_tab);
- dock_tab->status = Status_Dragged;
- }
- bool hovered = IsItemHovered();
- ImVec2 pos = GetItemRectMin();
- size1.x += 20 + GetStyle().ItemSpacing.x;
- tab_base = pos.y;
- draw_list->AddRectFilled(pos+ImVec2(-8.0f, 0.0),
- pos+size1,
- hovered ? color_hovered : (dock_tab->active ? color_active : color));
- draw_list->AddText(pos, text_color, dock_tab->label, text_end);
- if (dock_tab->active && close_button)
- {
- SameLine();
- tab_closed = InvisibleButton("close", ImVec2(16, 16));
- ImVec2 center = ((GetItemRectMin() + GetItemRectMax()) * 0.5f);
- draw_list->AddLine( center + ImVec2(-3.5f, -3.5f), center + ImVec2(3.5f, 3.5f), text_color);
- draw_list->AddLine( center + ImVec2(3.5f, -3.5f), center + ImVec2(-3.5f, 3.5f), text_color);
- } else {
- if(!dock_tab->active && close_button) {
- SameLine();
- InvisibleButton("close", ImVec2(16, 16));
- ImVec2 center = ((GetItemRectMin() + GetItemRectMax()) * 0.5f);
- draw_list->AddLine( center + ImVec2(-3.5f, -3.5f), center + ImVec2(3.5f, 3.5f), text_color_disabled);
- draw_list->AddLine( center + ImVec2(3.5f, -3.5f), center + ImVec2(-3.5f, 3.5f), text_color_disabled);
- }
- }
- dock_tab = dock_tab->next_tab;
- }
- ImVec2 cp(dock.pos.x, tab_base + line_height);
- draw_list->AddLine(cp, cp + ImVec2(dock.size.x, 0), color);
- }
- EndChild();
- return tab_closed;
- }
- static void setDockPosSize(Dock& dest, Dock& dock, Slot_ dock_slot, Dock& container)
- {
- IM_ASSERT(!dock.prev_tab && !dock.next_tab && !dock.children[0] && !dock.children[1]);
- dest.pos = container.pos;
- dest.size = container.size;
- dock.pos = container.pos;
- dock.size = container.size;
- switch (dock_slot)
- {
- case Slot_Bottom:
- dest.size.y *= 0.5f;
- dock.size.y *= 0.5f;
- dock.pos.y += dest.size.y;
- break;
- case Slot_Right:
- dest.size.x *= 0.5f;
- dock.size.x *= 0.5f;
- dock.pos.x += dest.size.x;
- break;
- case Slot_Left:
- dest.size.x *= 0.5f;
- dock.size.x *= 0.5f;
- dest.pos.x += dock.size.x;
- break;
- case Slot_Top:
- dest.size.y *= 0.5f;
- dock.size.y *= 0.5f;
- dest.pos.y += dock.size.y;
- break;
- default: IM_ASSERT(false); break;
- }
- dest.setPosSize(dest.pos, dest.size);
- if (container.children[1]->pos.x < container.children[0]->pos.x ||
- container.children[1]->pos.y < container.children[0]->pos.y)
- {
- Dock* tmp = container.children[0];
- container.children[0] = container.children[1];
- container.children[1] = tmp;
- }
- }
- void doDock(Dock& dock, Dock* dest, Slot_ dock_slot)
- {
- IM_ASSERT(!dock.parent);
- if (!dest)
- {
- dock.status = Status_Docked;
- dock.setPosSize(ImVec2(0, 0), GetIO().DisplaySize);
- }
- else if (dock_slot == Slot_Tab)
- {
- Dock* tmp = dest;
- while (tmp->next_tab)
- {
- tmp = tmp->next_tab;
- }
- tmp->next_tab = &dock;
- dock.prev_tab = tmp;
- dock.size = tmp->size;
- dock.pos = tmp->pos;
- dock.parent = dest->parent;
- dock.status = Status_Docked;
- }
- else if (dock_slot == Slot_None)
- {
- dock.status = Status_Float;
- }
- else
- {
- Dock* container = (Dock*)MemAlloc(sizeof(Dock));
- IM_PLACEMENT_NEW(container) Dock();
- m_docks.push_back(container);
- container->children[0] = &dest->getFirstTab();
- container->children[1] = &dock;
- container->next_tab = NULL;
- container->prev_tab = NULL;
- container->parent = dest->parent;
- container->size = dest->size;
- container->pos = dest->pos;
- container->status = Status_Docked;
- container->label = ImStrdup("");
- if (!dest->parent)
- {
- }
- else if (&dest->getFirstTab() == dest->parent->children[0])
- {
- dest->parent->children[0] = container;
- }
- else
- {
- dest->parent->children[1] = container;
- }
- dest->setParent(container);
- dock.parent = container;
- dock.status = Status_Docked;
- setDockPosSize(*dest, dock, dock_slot, *container);
- }
- dock.setActive();
- }
- void rootDock(const ImVec2& pos, const ImVec2& size)
- {
- Dock* root = getRootDock();
- if (!root) return;
- ImVec2 min_size = root->getMinSize();
- ImVec2 requested_size = size;
- root->setPosSize(pos, ImMax(min_size, requested_size));
- }
- void setDockActive()
- {
- IM_ASSERT(m_current);
- if (m_current) m_current->setActive();
- }
- static Slot_ getSlotFromLocationCode(char code)
- {
- switch (code)
- {
- case '1': return Slot_Left;
- case '2': return Slot_Top;
- case '3': return Slot_Bottom;
- default: return Slot_Right;
- }
- }
- static char getLocationCode(Dock* dock)
- {
- if (!dock) return '0';
- if (dock->parent->isHorizontal())
- {
- if (dock->pos.x < dock->parent->children[0]->pos.x) return '1';
- if (dock->pos.x < dock->parent->children[1]->pos.x) return '1';
- return '0';
- }
- else
- {
- if (dock->pos.y < dock->parent->children[0]->pos.y) return '2';
- if (dock->pos.y < dock->parent->children[1]->pos.y) return '2';
- return '3';
- }
- }
- void tryDockToStoredLocation(Dock& dock)
- {
- if (dock.status == Status_Docked) return;
- if (dock.location[0] == 0) return;
- Dock* tmp = getRootDock();
- if (!tmp) return;
- Dock* prev = NULL;
- char* c = dock.location + strlen(dock.location) - 1;
- while (c >= dock.location && tmp)
- {
- prev = tmp;
- tmp = *c == getLocationCode(tmp->children[0]) ? tmp->children[0] : tmp->children[1];
- if(tmp) --c;
- }
- if (tmp && tmp->children[0]) tmp = tmp->parent;
- doDock(dock, tmp ? tmp : prev, tmp && !tmp->children[0] ? Slot_Tab : getSlotFromLocationCode(*c));
- }
- bool begin(const char* label, bool* opened, ImGuiWindowFlags extra_flags)
- {
- Dock& dock = getDock(label, !opened || *opened);
- if (!dock.opened && (!opened || *opened)) tryDockToStoredLocation(dock);
- dock.last_frame = ImGui::GetFrameCount();
- if (strcmp(dock.label, label) != 0)
- {
- MemFree(dock.label);
- dock.label = ImStrdup(label);
- }
- m_end_action = EndAction_None;
- if (dock.first && opened) *opened = dock.opened;
- dock.first = false;
- if (opened && !*opened)
- {
- if (dock.status != Status_Float)
- {
- fillLocation(dock);
- doUndock(dock);
- dock.status = Status_Float;
- }
- dock.opened = false;
- return false;
- }
- dock.opened = true;
- m_end_action = EndAction_Panel;
- beginPanel();
- m_current = &dock;
- if (dock.status == Status_Dragged) handleDrag(dock);
- bool is_float = dock.status == Status_Float;
- if (is_float)
- {
- SetNextWindowPos(dock.pos);
- SetNextWindowSize(dock.size);
- bool ret = Begin(label,
- opened,
- ImGuiWindowFlags_NoCollapse | extra_flags);
- m_end_action = EndAction_End;
- dock.pos = GetWindowPos();
- dock.size = GetWindowSize();
- ImGuiContext& g = *GImGui;
- if (g.ActiveId == GetCurrentWindow()->MoveId && g.IO.MouseDown[0])
- {
- m_drag_offset = GetMousePos() - dock.pos;
- doUndock(dock);
- dock.status = Status_Dragged;
- }
- return ret;
- }
- if (!dock.active && dock.status != Status_Dragged) return false;
- m_end_action = EndAction_EndChild;
- PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0));
- PushStyleColor(ImGuiCol_BorderShadow, ImVec4(0, 0, 0, 0));
- float tabbar_height = GetTextLineHeightWithSpacing();
- if (tabbar(dock.getFirstTab(), opened != NULL))
- {
- fillLocation(dock);
- *opened = false;
- }
- ImVec2 pos = dock.pos;
- ImVec2 size = dock.size;
- pos.y += tabbar_height + GetStyle().WindowPadding.y;
- size.y -= tabbar_height + GetStyle().WindowPadding.y;
- SetCursorScreenPos(pos);
- ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize |
- ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse |
- ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoBringToFrontOnFocus |
- extra_flags;
- char tmp[256];
- strcpy(tmp, label);
- strcat(tmp, "_docked"); // to avoid https://github.com/ocornut/imgui/issues/713
- bool ret = BeginChild(tmp, size, true, flags);
- PopStyleColor();
- PopStyleColor();
- return ret;
- }
- void end()
- {
- if (m_end_action == EndAction_End)
- {
- End();
- }
- else if (m_end_action == EndAction_EndChild)
- {
- PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0));
- PushStyleColor(ImGuiCol_BorderShadow, ImVec4(0, 0, 0, 0));
- EndChild();
- PopStyleColor();
- PopStyleColor();
- }
- m_current = NULL;
- if (m_end_action > EndAction_None) endPanel();
- }
- int getDockIndex(Dock* dock)
- {
- if (!dock) return -1;
- for (int i = 0; i < m_docks.size(); ++i)
- {
- if (dock == m_docks[i]) return i;
- }
- IM_ASSERT(false);
- return -1;
- }
- Dock* getDockByIndex(int idx)
- {
- return idx < 0 ? NULL : m_docks[(int)idx];
- }
- };
- static DockContext* s_dock = NULL;
- IMGUI_API void InitDockContext()
- {
- void* ptr = ImGui::MemAlloc(sizeof(DockContext) );
- s_dock = new(ptr) DockContext;
- }
- IMGUI_API void ShutdownDockContext()
- {
- s_dock->~DockContext();
- ImGui::MemFree(s_dock);
- s_dock = NULL;
- }
- IMGUI_API void RootDock(const ImVec2& pos, const ImVec2& size)
- {
- s_dock->rootDock(pos, size);
- }
- IMGUI_API bool BeginDock(const char* label, bool* opened, ImGuiWindowFlags extra_flags)
- {
- return s_dock->begin(label, opened, extra_flags);
- }
- IMGUI_API void EndDock()
- {
- s_dock->end();
- }
- IMGUI_API void SetDockActive()
- {
- s_dock->setDockActive();
- }
- } // namespace ImGui
|