Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatically adjust height of a docking node #7631

Open
thewoz opened this issue May 28, 2024 · 4 comments
Open

Automatically adjust height of a docking node #7631

thewoz opened this issue May 28, 2024 · 4 comments

Comments

@thewoz
Copy link

thewoz commented May 28, 2024

Version/Branch of Dear ImGui:

Version 1.90.5, Branch: docking

Back-ends:

ImGui_ImplGlfw ImGui_ImplOpenGL3

Compiler, OS:

macOS

Details:

hello everyone, I am in docking branch and I am developing an application but I don't quite understand how to proceed on one point.

The layout of my window is very simple:

Screenshot 2024-05-28 at 16 39 29

at the bottom of the layout i am creating a sequencer. The content, so the height, of the sequencer changes over time.

I would like to figure out how to automatically adjust the height of the window so that everything is flush.

Screenshot 2024-05-28 at 16 39 42

@ocornut
Copy link
Owner

ocornut commented May 28, 2024

I would like to figure out how to automatically adjust the height of the window so that everything is flush.

That might be contradictory with making the bottom part a docking node, aka you cannot expect user to resize this section while making it automatically resizing at all time.

Suggestion 1: We don't have enough information about your setup, but if the setup use a Dockspace() currently you could technically change the vertical split to use BeginChild() with ImGuiChildFlags_ResizeY, however I realize that a rather annoying change as makes the code/logic change based on a seemingly innocuous behavior change.

Suggestion 2: It may be more natural that you directly poke into the dock node where that timeline is docked by finding the ImGuiDockNode* and writing to node->SizeRef.y preferably at the beginning of the frame.

(It's also expected that other constraints in place may prevent that exact value from being full-filed, namely if e.g. the total available height is too small, but that's probably something you'd want)

@ocornut ocornut changed the title height of content created within the window Automatically adjust height of a docking node May 28, 2024
@thewoz
Copy link
Author

thewoz commented May 29, 2024

hi @ocornut
you are absolutely right!
I have not given enough information about the setup step and my request actually seems contradictory.

Sorry about that!

My setup, as in the attached photo, consists of three parts.

  • A central display part.
  • A column on the right with the list of program parameters
  • A Sequencer at the bottom for displaying keyframes.

Screenshot 2024-05-29 at 11 50 41

I also attach a small snippet of the code.

To be clearer, rather than automatically adjusting the height of the bottom part, I would like to put limits on its height. That is, that it cannot be larger than a certain amount. I.e., that it cannot be larger than the contents inside it.

Is there then a way me put these limits and to calculate the size of the content inside it?

    ImGui::Begin("MainWindow", NULL, window_flags);
    ImGui::PopStyleVar();

    float height = ImGui::GetFrameHeight();
    
    if(ImGui::BeginMenuBar()) {
      
      if(ImGui::BeginMenu("Menu")) {
        ImGui::MenuItem("Main menu bar", NULL, false, true);
        ImGui::EndMenu();
      }
      ImGui::EndMenuBar();
      
    }

    if(ImGui::BeginViewportSideBar("StatusBar", viewport, ImGuiDir_Down, height, window_flags)) {
        if (ImGui::BeginMenuBar()) {
            ImGui::Text("status bar");
            ImGui::EndMenuBar();
        }
        ImGui::End();
    }
    
    ImGuiID mainDockSpaceId = ImGui::GetID("MainDockSpace");
    const ImVec2 dockspace_size = ImGui::GetContentRegionAvail();
    ImGui::DockSpace(mainDockSpaceId, ImVec2(0.0f, 0.0f), dockspace_flags);

    ImGuiWindowClass window_class;
    window_class.DockNodeFlagsOverrideSet = ImGuiDockNodeFlags_NoTabBar;
    
    ImGui::SetNextWindowClass(&window_class);
    ImGui::Begin("Down", &show_another_window, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar);
    if(ImGui::BeginNeoSequencer("Sequencer", &currentFrame, &minFrame, &maxFrame)) {
      if(ImGui::BeginNeoGroup("A", &showKeyframes)) { ImGui::EndNeoGroup(); }
      if(ImGui::BeginNeoGroup("B", &showKeyframes)) { ImGui::EndNeoGroup(); }
      if(ImGui::BeginNeoGroup("C", &showKeyframes)) { ImGui::EndNeoGroup(); }
      if(ImGui::BeginNeoGroup("D", &showKeyframes)) { ImGui::EndNeoGroup(); }
      if(ImGui::BeginNeoGroup("E", &showKeyframes)) { ImGui::EndNeoGroup(); }
      ImGui::EndNeoSequencer();
    }
    ImGui::End();
    
    ImGui::SetNextWindowClass(&window_class);
    ImGui::Begin("Left", NULL, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar);
    GLuint texture;
    glGenTextures( 1, &texture );
    glBindTexture( GL_TEXTURE_2D, texture );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
    glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, image.cols, image.rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, image.data );
    ImGui::Image( reinterpret_cast<void*>( static_cast<intptr_t>( texture ) ), ImVec2( image.cols, image.rows ) );
    ImGui::End();
    
    ImGui::SetNextWindowClass(&window_class);
    ImGui::Begin("Right", NULL, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar);
    if(ImGui::CollapsingHeader("A")){ }
    if(ImGui::CollapsingHeader("B")){ }
    if(ImGui::CollapsingHeader("C")){ }
    if(ImGui::CollapsingHeader("D")){ }
    if(ImGui::CollapsingHeader("E")){ }
    ImGui::End();
    
    static bool sFirstFrame = true;
    if(sFirstFrame) {
      
      sFirstFrame = false;
      
      ImGui::DockBuilderRemoveNode(mainDockSpaceId);
      ImGui::DockBuilderAddNode(mainDockSpaceId, ImGuiDockNodeFlags_None);
      ImGui::DockBuilderSetNodeSize(mainDockSpaceId, dockspace_size);

      ImGuiID dock_id_up;
      ImGuiID dock_id_down;
      
      ImGuiID dock_id_left;
      ImGuiID dock_id_right;

      ImGui::DockBuilderSplitNode(mainDockSpaceId, ImGuiDir_Up, 0.5f, &dock_id_up, &dock_id_down);

      ImGui::DockBuilderSplitNode(dock_id_up, ImGuiDir_Right, 0.5f, &dock_id_right, &dock_id_left);
      
      ImGui::DockBuilderDockWindow("Down", dock_id_down);
      ImGui::DockBuilderDockWindow("Left", dock_id_left);
      ImGui::DockBuilderDockWindow("Right", dock_id_right);
      
      ImGui::DockBuilderFinish(mainDockSpaceId);
      
    }

    ImGui::End();

    ImGui::Render();

@ocornut
Copy link
Owner

ocornut commented May 29, 2024

To be clearer, rather than automatically adjusting the height of the bottom part, I would like to put limits on its height. That is, that it cannot be larger than a certain amount. I.e., that it cannot be larger than the contents inside it.

Sizing constraints are currently not supported for docking nodes (#4228, but also technically #6326, #2849).

Some early work I did for potential support for toolbars might help, see code #2648, namely those lines:

        node->WantLockSizeOnce = true;
        node->Size[toolbar_axis_perp] = node->SizeRef[toolbar_axis_perp] = TOOLBAR_SIZE_WHEN_DOCKED;

But generally I think this is not easy to achieve and currently not worth investigating further, considering your need doesn't seem that important (as user can resize).

As mentioned in my first message, another workaround would be to use a manual splitter #319 or two BeginChild() with the top one using ImGuiChildFlags_ResizeY and a constraint on the top window.

@thewoz
Copy link
Author

thewoz commented May 31, 2024

hi @ocornut ,
thanks for the support!

I thought that for my case the best thing is to use a manual splitter as you suggest.
I wrote some code (which I attach) but I can't fix two issues:

  • I can't completely remove the space/border in the top part. As you can see there is still some green.
  • When I press on the window the yellow part covers my status bar
test.mov

what am I doing wrong?
thank you very much

#include <cstdio>
#include <cstdlib>

#include <iostream>

#include <glad/glad.h>

#include <GLFW/glfw3.h>

#define IMGUI_DEFINE_MATH_OPERATORS
#include <imgui/imgui.hpp>

bool Splitter(bool split_vertically, float thickness, float* size1, float* size2, float min_size1, float min_size2, float splitter_long_axis_size = -1.0f)
{
    using namespace ImGui;
    ImGuiContext& g = *GImGui;
    ImGuiWindow* window = g.CurrentWindow;
    ImGuiID id = window->GetID("##Splitter");
    ImRect bb;
    bb.Min = window->DC.CursorPos + (split_vertically ? ImVec2(*size1, 0.0f) : ImVec2(0.0f, *size1));
    bb.Max = bb.Min + CalcItemSize(split_vertically ? ImVec2(thickness, splitter_long_axis_size) : ImVec2(splitter_long_axis_size, thickness), 0.0f, 0.0f);
    return SplitterBehavior(bb, id, split_vertically ? ImGuiAxis_X : ImGuiAxis_Y, size1, size2, min_size1, min_size2, 0.0f);
}

static void glfwErrorCallback(int error, const char * description) {
    fprintf(stderr, "GLFW error (%d): %s\n", error, description);
}

int main(int argc, const char * argv[]) {

  //Attempt to initialize GLFW
  if (!glfwInit()) {
    fprintf(stderr, "GLFW init error\n");
    exit(EXIT_FAILURE);
  }

  // Decide GL+GLSL versions
#if __APPLE__
  // GL 3.2 + GLSL 150
  const char* glsl_version = "#version 100";
  glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
  glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
  glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);  // 3.2+ only
  glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);            // Required on Mac
#else
  // GL 3.0 + GLSL 130
  const char* glsl_version = "#version 130";
  glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
  glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
  //glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);  // 3.2+ only
  //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);            // 3.0+ only
#endif

  //Set GLFW's error callback function
  glfwSetErrorCallback(glfwErrorCallback);

  //GLFW creates a window and its OpenGL context with the next function
  GLFWwindow * window = glfwCreateWindow(640, 480, "Idra", NULL, NULL);

  if(!window) {
    std::cerr << "GLFW failed to create a window and/or OpenGL context :(";
    glfwTerminate();
    exit(0);
  }

  //Window creation was successful. Continue
  glfwMakeContextCurrent(window);
  glfwSwapInterval(1); // Enable vsync

  if(!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress)) {
    fprintf(stderr, "Failed to initialize GLAD\n");
    abort();
  }

  // Setup Dear ImGui context
  IMGUI_CHECKVERSION();
  ImGui::CreateContext();
  //ImGuiIO& io = ImGui::GetIO(); (void)io;
  ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_DockingEnable;

  ImGui_ImplGlfw_InitForOpenGL(window, true);
  ImGui_ImplOpenGL3_Init(glsl_version);
  
  ImGui::StyleColorsDark();

  ImVec4 clear_color = ImColor(60, 55, 15);

  //Set scale based on scale of monitor
  GLFWmonitor * monitor = glfwGetPrimaryMonitor();
  float scale = 2.f;
  glfwGetMonitorContentScale(monitor, &scale, nullptr);
  
  // The render loop
  while (!glfwWindowShouldClose(window)) {
    
    glfwPollEvents();
    
    ImGui_ImplOpenGL3_NewFrame();
    ImGui_ImplGlfw_NewFrame();
    ImGui::NewFrame();

    ImGuiViewport * viewport = ImGui::GetMainViewport();
    ImGui::SetNextWindowPos(viewport->Pos);
    ImGui::SetNextWindowSize(viewport->Size);
    ImGui::SetNextWindowViewport(viewport->ID);
    ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
    
    ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_NoMove;
    
    ImGui::Begin("MainWindow", NULL, window_flags);
    ImGui::PopStyleVar();

    float height = ImGui::GetFrameHeight();
    
    if(ImGui::BeginMenuBar()) {
      if(ImGui::BeginMenu("Menu")) {
        ImGui::MenuItem("Main menu bar", NULL, false, true);
        ImGui::EndMenu();
      }
      ImGui::EndMenuBar();
    }

    if(ImGui::BeginViewportSideBar("StatusBar", viewport, ImGuiDir_Down, height, window_flags)) {
        if (ImGui::BeginMenuBar()) {
            ImGui::Text("status bar");
            ImGui::EndMenuBar();
        }
        ImGui::End();
    }
    
    
    //float h = 200;
    static float h1 = 300;
    static float h2 = 300;
    static float w1 = 300;
    static float w2 = 300;
    
    // horizontal splitter
    Splitter(false, 4.0f, &h1, &h2, 50, 50);
    
    // create top container green
    ImGui::PushStyleColor(ImGuiCol_ChildBg, ImColor(0,255,0).Value);
    ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
    ImGui::BeginChild("1", ImVec2(0, h1), true);
    ImGui::PopStyleVar();
    ImGui::PopStyleColor();
    
      // vertical splitter
      Splitter(true, 4.0f, &w1, &w2, 50, 50);
    
      // right part blue
      ImGui::PushStyleColor(ImGuiCol_ChildBg, ImColor(0,0,255).Value);
      ImGui::BeginChild("3", ImVec2(w1, 0), true);
      ImGui::PopStyleColor();
      ImGui::EndChild();
    
      ImGui::SameLine();
    
      // left part red
      ImGui::PushStyleColor(ImGuiCol_ChildBg, ImColor(255,0,0).Value);
      ImGui::BeginChild("4", ImVec2(0, 0), true);
      ImGui::PopStyleColor();
      ImGui::EndChild();
    
    
    ImGui::EndChild();
    
    // bottom part yellow
    ImGui::PushStyleColor(ImGuiCol_ChildBg, ImColor(255,255,0).Value);
    ImGui::BeginChild("2", ImVec2(0, h2), true);
    ImGui::PopStyleColor();

    ImGui::EndChild();

    ImGui::End();
    
    // Rendering
    ImGui::Render();
    int display_w, display_h;
    glfwGetFramebufferSize(window, &display_w, &display_h);
    glViewport(0, 0, display_w, display_h);
    glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
    glClear(GL_COLOR_BUFFER_BIT);
    ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

    glfwSwapBuffers(window);
    
  }

  // Cleanup
  ImGui_ImplOpenGL3_Shutdown();
  ImGui_ImplGlfw_Shutdown();
  ImGui::DestroyContext();
  
  glfwDestroyWindow(window);
  glfwTerminate();
  
  return 0;
  
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants