Closed Nitr0-G closed 10 months ago
A few notes:
EndChild()
must be called even if the corresponding BeginChild()
returns falseHere is an example source with mouse cursor manipulation thrown in as a quick reference:
#define IMGUI_DEFINE_MATH_OPERATORS
#include <imgui.h>
bool SplitterH( const char* id, int* posX, int width, const ImVec2& posMin, const ImVec2& posMax )
{
if ( ( posX == nullptr ) || ( posMin.x >= posMax.x ) || ( posMin.y >= posMax.y ) )
return false;
ImGui::SetCursorPos( ImVec2( (float)*posX, posMin.y ) );
ImGui::InvisibleButton( id, ImVec2( (float)width, posMax.y - posMin.y ) );
if ( ImGui::IsItemHovered() || ImGui::IsItemActive() )
ImGui::SetMouseCursor( ImGuiMouseCursor_ResizeEW );
static int startPosX = 0;
int lastPosX = *posX;
if ( ImGui::IsItemActive() )
{
int move = (int)ImGui::GetMouseDragDelta( ImGuiMouseButton_Left ).x;
if ( move != 0 )
{
*posX = startPosX + move;
if ( *posX < (int)posMin.x )
*posX = (int)posMin.x;
if ( *posX > (int)posMax.x - width )
*posX = (int)posMax.x - width;
}
}
else
startPosX = *posX;
return *posX != lastPosX;
}
bool SplitterV( const char* id, int* posY, int height, const ImVec2& posMin, const ImVec2& posMax )
{
if ( ( posY == nullptr ) || ( posMin.x >= posMax.x ) || ( posMin.y >= posMax.y ) )
return false;
ImGui::SetCursorPos( ImVec2( posMin.x, (float)*posY ) );
ImGui::InvisibleButton( id, ImVec2( posMax.x - posMin.x, (float)height ) );
if ( ImGui::IsItemHovered() || ImGui::IsItemActive() )
ImGui::SetMouseCursor( ImGuiMouseCursor_ResizeNS );
static int startPosY = 0;
int lastPosY = *posY;
if ( ImGui::IsItemActive() )
{
int move = (int)ImGui::GetMouseDragDelta( ImGuiMouseButton_Left ).y;
if ( move != 0 )
{
*posY = startPosY + move;
if ( *posY < (int)posMin.y )
*posY = (int)posMin.y;
if ( *posY > (int)posMax.y - height )
*posY = (int)posMax.y - height;
}
}
else
startPosY = *posY;
return *posY != lastPosY;
}
void DrawFrame()
{
ImDrawList* drawList = ImGui::GetWindowDrawList();
ImVec2 posMin = ImGui::GetCursorScreenPos();
ImVec2 posMax = posMin + ImGui::GetContentRegionAvail();
drawList->AddRect( posMin + ImVec2( 1.0f, 1.0f ), posMax - ImVec2( 1.0f, 1.0f ), 0xFF808080, 0.0f, 0, 1.0f );
}
void DrawChildWindow( const char* id, const ImVec2& pos, const ImVec2& size )
{
if ( ( size.x <= 0.0f ) || ( size.y <= 0.0f ) )
return;
ImGui::SetCursorPos( pos );
if ( ImGui::BeginChild( id, size ) )
{
DrawFrame();
}
ImGui::EndChild();
}
void ExampleSplitter()
{
if ( ImGui::Begin( "Example Splitter" ) )
{
const int splitterSize = 4;
ImVec2 pos = ImGui::GetCursorPos();
ImVec2 size = ImGui::GetContentRegionAvail();
static float splitter1_relPosX = 0.85f;
static float splitter2_relPosY = 0.5f;
int splitter1_posX = (int)( pos.x - 0.5f * (float)splitterSize + splitter1_relPosX * size.x );
if ( SplitterH( "splitter1", &splitter1_posX, splitterSize, pos, pos + size ) )
splitter1_relPosX = ( (float)splitter1_posX + 0.5f * (float)splitterSize - pos.x ) / size.x;
ImVec2 left_pos = pos;
ImVec2 left_size = ImVec2( (float)splitter1_posX - pos.x, size.y );
ImVec2 right_pos = ImVec2( left_pos.x + left_size.x + (float)splitterSize, pos.y );
ImVec2 right_size = ImVec2( pos.x + size.x - right_pos.x, size.y );
int splitter2_posY = (int)( right_pos.y - 0.5f * (float)splitterSize + splitter2_relPosY * right_size.y );
if ( SplitterV( "splitter2", &splitter2_posY, splitterSize, right_pos, right_pos + right_size ) )
splitter2_relPosY = ( (float)splitter2_posY + 0.5f * (float)splitterSize - right_pos.y ) / right_size.y;
ImVec2 right_top_pos = right_pos;
ImVec2 right_top_size = ImVec2( right_size.x, (float)splitter2_posY - right_pos.y );
ImVec2 right_bottom_pos = ImVec2( right_pos.x, right_top_pos.y + right_top_size.y + (float)splitterSize );
ImVec2 right_bottom_size = ImVec2( right_size.x, right_pos.y + right_size.y - right_bottom_pos.y );
DrawChildWindow( "child1", left_pos, left_size );
DrawChildWindow( "child2", right_top_pos, right_top_size );
DrawChildWindow( "child3", right_bottom_pos, right_bottom_size );
}
ImGui::End();
}
Could use lots of improvements still, but I didn't want to put too much time into it.
There is a SplitterBehavior()
function in imgui_internal.h which I'd encourage you to use to implement this case of behavior.
I consider #319 still open as we'd need to:
Note that 1.90 is very likely (very soon) to have a way to ask for child windows to be manually resizable from the bottom or right side, which may be an alternative option to use for those. This'll come with support for saved settings.
There is a
SplitterBehavior()
function in imgui_internal.h which I'd encourage you to use to implement this case of behavior. I consider #319 still open as we'd need to:* formalize an API for specifying resizing policy (stretched, fixed, with auto rescaling of fixed components when dpi factor changes etc) * allow to get that info to easily persist in .ini file.
Note that 1.90 is very likely (very soon) to have a way to ask for child windows to be manually resizable from the bottom or right side, which may be an alternative option to use for those. This'll come with support for saved settings.
There is such a framework as FTXUI(https://github.com/ArthurSonzogni/FTXUI ). Windows and similar information in it are essentially a container, and there I and others, for example, people can quickly arrange windows along their borders on the right, left, bottom or top(https://github.com/ArthurSonzogni/FTXUI/blob/main/examples/component/resizable_split.cpp#L14) (screenshot). So I think, yes, it would be great if a person could align the windows right away. Thank you and other participants for developing imgui.
A few notes:
* `EndChild()` must be called even if the corresponding `BeginChild()` returns false * you should positions and sizes to integers, otherwise you could get a blurry UI * splitters are usually a fixed width/height, not relative to the window they are in * handle all of your splitters first, otherwise there might be a single frame lag for some child windows * you can set the cursor explicitly for best control
Here is an example source with mouse cursor manipulation thrown in as a quick reference:
Thank you very much for such detailed advice and response! Thanks!
Version/Branch of Dear ImGui:
Version: 1.89.9 Branch: master
Back-end/Renderer/Compiler/OS Back-ends: imgui_impl_win32.cpp + imgui_impl_opengl3.cpp Compiler: MSVC/Clang-cl Operating System: Windows 10
My Issue/Question: Hello to all readers!
At the moment I have this It should be moved to the place of the red square and be proportional to the first two child windows when i change resolution of host window. I understand that the position of x and y is statically set, but the whole problem is that I don't understand how I can update this static variable, because if I set 0, then it will stretch to the right size, but I won't know the X or Y axis and I won't be able to change the window size within X and Y via splitters.
I'm sorry that there is so much code, but I can't give you less, because the context of the task will be lost. Thanks in advance to everyone who will take the time and suggest possible solutions to this problem.
I will be glad if someone helps, then after two days of trying I can't do it and my ideas are exhausted. In fact, you need to do something like a formula for calculating the static size depending on the size of the window, but how will it look? Or maybe there is a ready-made function/flag in imgui for this?
P.S.I apologize for, most likely, a stupid question, but I've never really done interfaces before.
Standalone, minimal, complete and verifiable example: (the screenshot shows how after changing the screen resolution, the square itself does not expand in resolution, since my x and y are static, but if I make them dynamic, that is, I put zero instead of x, then the user cannot resize windows through the splitter, and the MainCPUDisasm window begins to show crash, since it fills the entire screen, but if you give it static coordinates, then it is normally displayed as in the screenshot, but does not have a proportional resolution to the resolution of the host window) I have a similar code