Closed pegvin closed 1 year ago
Hello,
You should be using the docking
branch for that purpose.
See https://github.com/ocornut/imgui/wiki/Docking
Often people just call `ImGui::DockspaceOverViewport(GetMainViewport());
at the beginning of their frame to allow docking on the side.
i actually did try docking once to make layouts and stuff for my pixel-art editor but i failed miserably, is there a way to fix it without using docking or will i have to actually use docking branch?
i mean no offense but but i am not a smart guy like you all and it gets very complicated for me, but if it's the only way i will have to try it then i guess...
I'm afraid you would have to with docking this is the easiest path.
The simple way is just to call that DockspaceOverViewport()
function and let the user dock the window however they want.
Initial state (first time) will be a little messy but there's no other code to deal with. Probably 2 lines of change in your codebase (set ConfigFlags + DockspaceOverViewport(NULL) call).
If you want a default state that's a little tricky as the API are in imgui_internal.h and not great.
well i want the windows to be pre-docked, so i guess i will dig more deep into the API, probably look into example code i can find and if i am able to do so i will attach an example.
but as for now i am closing the issue.
once again, thanks alot ocornut & contributors for such a beautiful library! I LOVE YOU ALL!!!
I made a generic extension for pre-docked windows a while back, sounds like this is exactly what you need. As general advice, try to collect extensions that are generic enough in a small library that is independent of your actual user interface. Here is a version of mine, reduced to the things you currently need...
First an example usage for your case:
ImGuiID dockRootId = ImGui::DockSpaceOverViewport( nullptr, ImGuiDockNodeFlags_NoDockingInCentralNode | ImGuiDockNodeFlags_PassthruCentralNode );
// ...
// initial size, reference size for pre-docked version
ImGui::SetNextWindowSize( ImVec2( 240, 480 ), ImGuiCond_FirstUseEver );
if ( !ImGuiEx::WindowExistsOrHasPersistentData( "Sidebar" ) )
ImGui::SetNextWindowDockID( ImGuiEx::CreateDockNodeByCentralNode( dockRootId, ImGuiDir_Right, ImGuiDir_None ), ImGuiCond_FirstUseEver );
// now draw the window
if ( ImGui::Begin( "Sidebar", nullptr, ImGuiWindowFlags_None ) )
{
// ...
}
ImGui::End();
ImGuiEx.h:
/*
This header contains extensions (f.e. useful shortcuts) for imgui that do not depend
on anything in our engine and are also platform agnostic, therefore the ImGuiEx namespace
is on the same level as the ImGui namespace.
If you need access to internals of the library (anything from imgui_internal.h), please
wrap those accesses here instead of distributing them throughout the rest of the sources.
*/
#pragma once
#include <imgui.h>
namespace ImGuiEx
{
// use to determine if expensive preparations for a first use of a window are needed
bool WindowExistsOrHasPersistentData( const char* name );
// use to create a dock node next to the central node
// please use this only if WindowExistsOrHasPersistentData() returns false
// call SetNextWindowSize() before calling this to create the split in the correct size
// give the returned ID (returns 0 if there is no central node) to SetNextWindowDockID()
ImGuiID CreateDockNodeByCentralNode( ImGuiID rootId, ImGuiDir mainDir, ImGuiDir subDir );
} // namespace ImGuiEx
ImGuiEx.cpp:
#include "ImGuiEx.h"
#include <imgui_internal.h>
namespace ImGuiEx
{
bool WindowExistsOrHasPersistentData( const char* name )
{
// see ImGui::Begin() internals for reference on implementation
ImGuiWindow* window = ImGui::FindWindowByName( name );
if ( window != nullptr )
return true;
ImGuiID windowId = ImHashStr( name );
ImGuiWindowSettings* settings = ImGui::FindWindowSettings( windowId );
if ( settings != nullptr )
return true;
return false;
}
ImGuiID CreateDockNodeByCentralNode( ImGuiID rootId, ImGuiDir mainDir, ImGuiDir subDir )
{
ImGuiDockNode* root = ImGui::DockBuilderGetNode( rootId );
ImGuiDockNode* central = root->CentralNode;
// early out if there is no central node
if ( central == nullptr )
return (ImGuiID)0;
ImGuiDockNode* node = central;
ImGuiDir dir = mainDir;
ImGuiAxis axis = ( dir == ImGuiDir_Left ) || ( dir == ImGuiDir_Right ) ? ImGuiAxis_X : ImGuiAxis_Y;
// central is already the node to split if there is no sub direction, otherwise search first
if ( subDir != ImGuiDir_None )
{
ImGuiDockNode* sub = node;
int dir0 = ( dir == ImGuiDir_Left ) || ( dir == ImGuiDir_Up ) ? 0 : 1;
int dir1 = 1 - dir0;
// go up while sub is the furthest in the wanted direction
for ( ;; )
{
ImGuiDockNode* parent = sub->ParentNode;
if ( ( parent == nullptr ) || ( parent->SplitAxis != axis ) )
{
sub = nullptr;
break;
}
if ( parent->ChildNodes[ dir1 ] == sub )
{
sub = parent->ChildNodes[ dir0 ];
break;
}
sub = parent;
}
// if there is no node left of central, keep central as the node to split
if ( sub != nullptr )
{
// go down in the other direction to find the neighboring node
while ( sub->IsSplitNode() && ( sub->SplitAxis == axis ) )
sub = sub->ChildNodes[ dir1 ];
// a node in the main direction has been found, switch to sub direction
dir = subDir;
axis = ( dir == ImGuiDir_Left ) || ( dir == ImGuiDir_Right ) ? ImGuiAxis_X : ImGuiAxis_Y;
dir0 = ( dir == ImGuiDir_Left ) || ( dir == ImGuiDir_Up ) ? 0 : 1;
// go to the furthest node in the wanted sub direction
while ( sub->IsSplitNode() && ( sub->SplitAxis == axis ) )
sub = sub->ChildNodes[ dir0 ];
node = sub;
}
}
// calculate split ratio based on the size of the next window
float split_ratio = 0.5f;
ImGuiContext* ctx = ImGui::GetCurrentContext();
if ( ( ctx->NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize ) != 0 )
{
constexpr float DOCKING_SPLITTER_SIZE_ = 2.0f; // from imgui.cpp, replicated here because it is static there
constexpr float MAX_SPLIT_RATIO = 0.75f;
float available = 0.0f;
float wanted = 0.0f;
if ( axis == ImGuiAxis_X )
{
available = node->Size.x - DOCKING_SPLITTER_SIZE_;
wanted = ctx->NextWindowData.SizeVal.x;
}
else
{
available = node->Size.y - DOCKING_SPLITTER_SIZE_;
wanted = ctx->NextWindowData.SizeVal.y;
}
split_ratio = wanted / available;
if ( split_ratio > MAX_SPLIT_RATIO )
split_ratio = MAX_SPLIT_RATIO;
}
return ImGui::DockBuilderSplitNode( node->ID, dir, split_ratio, nullptr, nullptr );
}
} // namespace ImGuiEx
Thanks for sharing the code snippet! i saw it quite some time back but i just didn't get the time to reply.
means alot to me!
Version/Branch of Dear ImGui:
Version: v1.89.5 Branch: master
Back-end/Renderer/Compiler/OS
Back-ends: imgui_impl_glfw.cpp + imgui_impl_opengl3.cpp Compiler: gcc & g++ Operating System: Arch Linux
My Issue/Question:
in the below attached video i have a "sidebar" which is just a regular window clamped on the right side of the "master/native window", as you can see i am able to resize the window from all 4 of it's borders but i only want to allow the window to be resizable from the left side border of the window.
is there a way to achieve such behavior? or i'll just have to make the window a bit bigger so that it overflows thus the overflowed side of the window can't be resized...
Screenshots/Video
https://github.com/ocornut/imgui/assets/75035219/b480a671-e872-4458-8c8f-218de0f84534
thanks alot ocornut and contributors for such a beautiful library!