ocornut / imgui

Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies
MIT License
59.99k stars 10.19k forks source link

Table Not Automatically Adjusting Column width to contained controls. #7771

Closed matthewcrews closed 2 months ago

matthewcrews commented 3 months ago

Version/Branch of Dear ImGui:

Version 1.90.1, Branch: docking

Back-ends:

imgui_impl_sdl2.cpp + imgui_impl_opengl3.cpp

Compiler, OS:

Windows 11 MSVC 2022

Full config/build information:

Dear Imgui -> Dear Bindings -> Odin Imgui

dear_bindings: https://github.com/dearimgui/dear_bindings Odin Imgui: https://gitlab.com/L-4/odin-imgui

Details:

My Issue/Question:

I am trying to create a table where the columns automatically adjust their width to fit the contents and creates a horizontal scroll bar when it is larger than the window. Right now, the columns are being sized to just the headers, and not to the controls in the rows. You can see in the Name column that the InputText is being cut off.

I'm also finding that the InputDouble columns are reserving space to the right of the control instead of filling the entire column

Screenshots/Video:

image

Minimal, Complete and Verifiable Example code:

// Here is how I am creating the table
table_flags :=
    imgui.TableFlags_Borders |
    imgui.TableFlags_ScrollX |
    imgui.TableFlags_ScrollY |
    imgui.TableFlags_SizingFixedFit |
    imgui.TableFlags_NoHostExtendX

// Interrupt Editing
if imgui.BeginTable("##interrupt_editing_table", 16, table_flags) {
    // Headers
    imgui.TableSetupColumn("Enabled")
    imgui.TableSetupColumn("Name")
    imgui.TableSetupColumn("Interrupt Type")
    imgui.TableSetupColumn("Uptime Distribution")
    imgui.TableSetupColumn("Uptime P1")
    imgui.TableSetupColumn("Uptime P2")
    imgui.TableSetupColumn("Uptime P3")
    imgui.TableSetupColumn("Uptime P4")
    imgui.TableSetupColumn("Downtime Distribution")
    imgui.TableSetupColumn("Downtime P1")
    imgui.TableSetupColumn("Downtime P2")
    imgui.TableSetupColumn("Downtime P3")
    imgui.TableSetupColumn("Downtime P4")
    imgui.TableSetupColumn("Downtime Max")
    imgui.TableSetupColumn("Restart Probability")
    imgui.TableSetupColumn("Delete")
    imgui.TableHeadersRow()

    // log.debugf("Count: %i", len(constraint_settings.time_interrupts))

    for &time_interrupt_settings, i in constraint_settings.time_interrupts {
        imgui.TableNextRow()
        // Enabled
        imgui.TableNextColumn()
        is_enabled_label := fmt.ctprintf("##is_enabled_%i", i)
        imgui.Checkbox(is_enabled_label, &time_interrupt_settings.is_enabled)
        // Name
        imgui.TableNextColumn()
        name_label := fmt.ctprintf("##interrupt_name_%i", i)
        imgui.InputText(name_label, time_interrupt_settings.name, 25)
        // Interrupt Type
        imgui.TableNextColumn()
        imgui.Text("Interrupt Type")
        // Uptime Distribution
        imgui.TableNextColumn()
        imgui.Text("Uptime Distribution")
        // Uptime P1
        imgui.TableNextColumn()
        uptime_p1_label := fmt.ctprintf("##uptime_p1_label%i", i)
        imgui.InputDouble(uptime_p1_label, &time_interrupt_settings.uptime_parameter_1, format = "%.2f")
        // Uptime P2
        imgui.TableNextColumn()
        uptime_p2_label := fmt.ctprintf("##uptime_p2_label%i", i)
        imgui.InputDouble(uptime_p2_label, &time_interrupt_settings.uptime_parameter_2)
        // Uptime P3
        imgui.TableNextColumn()
        uptime_p3_label := fmt.ctprintf("##uptime_p3_label%i", i)
        imgui.InputDouble(uptime_p3_label, &time_interrupt_settings.uptime_parameter_3)
        // Uptime P4
        imgui.TableNextColumn()
        uptime_p4_label := fmt.ctprintf("##uptime_p4_label%i", i)
        imgui.InputDouble(uptime_p4_label, &time_interrupt_settings.uptime_parameter_4, format = "%.2f")
        // Downtime Distribution
        imgui.TableNextColumn()
        imgui.Text("Downtime Distribution")
        // Downtime P1
        imgui.TableNextColumn()
        downtime_p1_label := fmt.ctprintf("##downtime_p1_label%i", i)
        imgui.InputDouble(downtime_p1_label, &time_interrupt_settings.downtime_parameter_1)
        // Downtime P2
        imgui.TableNextColumn()
        downtime_p2_label := fmt.ctprintf("##downtime_p2_label%i", i)
        imgui.InputDouble(downtime_p2_label, &time_interrupt_settings.downtime_parameter_2)
        // Downtime P3
        imgui.TableNextColumn()
        downtime_p3_label := fmt.ctprintf("##downtime_p3_label%i", i)
        imgui.InputDouble(downtime_p3_label, &time_interrupt_settings.downtime_parameter_3)
        // Downtime P4
        imgui.TableNextColumn()
        downtime_p4_label := fmt.ctprintf("##downtime_p4_label%i", i)
        imgui.InputDouble(downtime_p4_label, &time_interrupt_settings.downtime_parameter_4)
        // Downtime Max
        imgui.TableNextColumn()
        downtime_max_label := fmt.ctprintf("##downtime_max_label%i", i)
        imgui.InputDouble(downtime_max_label, &time_interrupt_settings.downtime_max)
        // Restart Probability
        imgui.TableNextColumn()
        restart_probability_label := fmt.ctprintf("##restart_probability_label%i", i)
        imgui.InputDouble(
            restart_probability_label,
            &time_interrupt_settings.restart_probability,
        )
        // Delete
        imgui.TableNextColumn()
        if imgui.Button("X##delete_interrupt") {
            ordered_remove(&constraint_settings.time_interrupts, i)
            log.debugf("Count: %i", len(constraint_settings.time_interrupts))
        }
    }
    imgui.EndTable()
}
ocornut commented 3 months ago

The default value for ItemWidth for each column is about two-third of a column. In general SetNextItemWidth(-FLT_MIN); makes the frames items align to the right edge of available space, but in this case it won’t work: you cannot simultaneously request columns to measure the width of their contents and request contents to match the columns width. You probably need to either give a size to your columns, or use SetNextItemWidth() to size your input fields.

PS: you can surround your row with PushID(i)/PopID() and them you won’t have to include i as part of each of your field names, they can become simpler literals.

matthewcrews commented 3 months ago

I want the Input to size to the content and the column to size to the Max Input size. For example, if I have an InputDouble with a format of %.2f that is right-aligned, I would want the InputDouble to be at least wide enough to show the entire number (the content), including the two decimal places, and I would then want the column to be as wide as the widest InputDouble in that column.

ocornut commented 3 months ago

The widest double value is probably DBL_MAX and may not be what you want to use as a width reference. Why not use SetNextItemWidth() with a reasonable amount eg CalcTextSize(“999.99”).x ?

matthewcrews commented 2 months ago

Perfect! Thank you!