Giter VIP home page Giter VIP logo

Comments (17)

PathogenDavid avatar PathogenDavid commented on May 24, 2024 1

Have you tried the range_select branch to see if it meets your needs?

I know Omar is looking for feedback on it, and in the near future it should be the canonical way to handle what you're doing.

It can be merged into docking with some minor conflict resolution.

from imgui.

tasiek30 avatar tasiek30 commented on May 24, 2024 1

I need couple days to try it :)

from imgui.

tasiek30 avatar tasiek30 commented on May 24, 2024 1

This feature looks very promising. But actually i don't know if there is posibility to select input widgets i.e. InputScalar?. Also i have some strange behavior during rectangle selection (video)

Nagrywanie.2024-04-18.134417.mp4
    ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_ClearOnClickVoid | ImGuiMultiSelectFlags_BoxSelect2d);

    static ImGuiSelectionBasicStorage selection;
    selection.ApplyRequests(ms_io, 16*16);

    ImGui::Text("Selection: %d/%d", selection.Size, 16*16);
    if ( ImGui::BeginTable("MAP NEW", 16, flags) ) {
        ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGui::GetStyleColorVec4(ImGuiCol_ChildBg));
        for(int y=0; y<16; y++) {
            ImGui::TableNextRow();
            for(int x=0; x<16; x++) {
                ImGui::TableNextColumn();
                ImGui::PushID(y+x*16);
                ImGui::SetNextItemWidth(50.0);

                bool IsSelected = selection.Contains((ImGuiID)(y+x*16));

                ImGui::SetNextItemSelectionUserData(y+x*16);

                if(IsSelected) {
                    ImGui::PushStyleColor(ImGuiCol_FrameBg, IM_COL32(0, 130, 216, 50));
                }

                char label[64];
                sprintf(label, "%d", y+x*16);
                ImGui::Selectable(label, IsSelected);
                //ImGui::Text(label);
                //ImGui::Checkbox(label, (bool*)&data[y][x]);
                /*if (ImGui::InputScalar("##Data", ImGuiDataType_Float, &data[y][x], NULL, NULL, "%.2f", ImGuiInputTextFlags_EnterReturnsTrue) ) {
                    dataToSet = data[y][x];
                }*/

                if(IsSelected) {
                    ImGui::PopStyleColor();
                }

                ImGui::PopID();
            }
        }
        ImGui::PopStyleColor();
        ImGui::EndTable();
    }

    ms_io = ImGui::EndMultiSelect();

    selection.ApplyRequests(ms_io, 16*16);

from imgui.

ocornut avatar ocornut commented on May 24, 2024 1

I am going to try working on a simple demo to demonstrate a grid with text editable items that allows multi-write like this.

from imgui.

ocornut avatar ocornut commented on May 24, 2024

Thank you for your thoughtful and careful repro, I will investigate it.

An InputScalar() is not selectable but I'm not sure what it would mean to select it.
Would the underlying intent to e.g. select many fields and type in all of them together ?

from imgui.

ocornut avatar ocornut commented on May 24, 2024

Note how you are using "y + x * 16" everywhere, meaning your selectables are not submitted in the same sequential order as their value, and by default ImGuiSelectionBasicStorage assume that value passed to ImGui::SetNextItemSelectionUserData() are interpolable indices.

[A] If you instead use:

//int idx = y + x * 16; // Broken
int idx = x + y * 16; // OK

(and change all values to use idx)

Note the value order now goes left-to-right, top-to-bottom:
image

Then it works, but note that shift+down/up assume a type of selection that's not necessarily what you want here (I think we may need a flag to make shift+select use 2d coordinates rather than sequential?). That's the case for all three alternatives.

[B] Alternatively, you change change the idx->stored selection id mapping:

selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage*, int idx)
{
    int x = idx % 16;
    int y = idx / 16;
    return (ImGuiID)(y + x * 16);
};
int idx = x + y * 16; // Submission index
int id = y + x * 16; // ID (== selection.AdapterIndexToStorageId(idx))
//IM_ASSERT(selection.AdapterIndexToStorageId(&selection, idx) == id);
[...]
ImGui::PushID(idx); // <-- here it doesn't matter which you use as long as it is unique
[...]
ImGui::SetNextItemSelectionUserData(idx); // <-- here you pass index
[...]
bool IsSelected = selection.Contains((ImGuiID)(id)); // <-- Stored selection ID, == selection.AdapterIndexToStorageId(idx)

image

[C] A third alternative would to submit items in the same order as the id you want to use. aka fill entire column first, but it may be harder to perform clipping there.

(
I also found an issue when using box-select in a window that is not a child window.
The current logic prevents focusing, steals hovers and nav id. I pushed a mitigation (a304677) to allow clicking on title bar at least, and will need to revisit some of the logic for box-select.
)

This is really useful feedback as I found two things to improve already. Thanks!

from imgui.

ocornut avatar ocornut commented on May 24, 2024

(I also found an issue when using box-select in a window that is not a child window.
The current logic prevents focusing, steals hovers and nav id. I pushed a mitigation to allow clicking on title bar at least, and will need to revisit some of the logic for box-select.)

Pushed a better fix d60299d for both ScopeWindow and ScopeRect cases.

from imgui.

tasiek30 avatar tasiek30 commented on May 24, 2024

Thank you for your thoughtful and careful repro, I will investigate it.

An InputScalar() is not selectable but I'm not sure what it would mean to select it. Would the underlying intent to e.g. select many fields and type in all of them together ?

Yes exactly. I need to select cells and be able to change them to same value, increase all or even extrapolate (smooth)

from imgui.

ocornut avatar ocornut commented on May 24, 2024

Yes exactly. I need to select cells and be able to change them to same value, increase all or even extrapolate (smooth)

I think in this case it makes sense to display and focus a single InputText() widget, and when edited apply the value to all of selection.
Aka you don't need (and you cannot have) multiple active InputText(), but one can represent the selection.

from imgui.

tasiek30 avatar tasiek30 commented on May 24, 2024

Is this possible to draw this InputText Over Selectable?

from imgui.

ocornut avatar ocornut commented on May 24, 2024

Yes, you need to pass ImGuiSelectableFlags_AllowOverlap to the `Selectable().

See Demo->Layout->Overlap Mode or Demo->Widgets->Selectables->Rendering more items on the same line

from imgui.

ocornut avatar ocornut commented on May 24, 2024

I wrote a draft of it but it doesn't allow to multi-edit as currently multi-select system has a bias toward unselecting others when e.g. pressing enter on an item, so may need an improvement of multi-select.

void DemoSelectableEditableGrid()
{
    ImGui::Begin("Selection #7424");
    {
        const int COUNT_X = 10;
        const int COUNT_Y = 16;
        const int COUNT = COUNT_X * COUNT_Y;
        static ImGuiSelectionBasicStorage selection;
        static float data[COUNT];
        static int editing_n = -1;
        static int focus_n_next = -1;

        // FIXME: don't clear selection when clicking selected item
        ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect2d);
        selection.ApplyRequests(ms_io, COUNT);
        ImGui::Text("Selection: %d/%d", selection.Size, COUNT);

        const int focus_n_curr = focus_n_next;
        focus_n_next = -1;
        if (ImGui::BeginTable("Array", COUNT_X, ImGuiTableFlags_Borders))
        {
            for (int n = 0; n < COUNT; n++)
            {
                ImGui::TableNextColumn(); // Next cell w/ auto-wrap
                ImGui::PushID(n);

                const bool is_selected = selection.Contains((ImGuiID)n);
                ImGui::SetNextItemSelectionUserData(n);

                ImVec2 p = ImGui::GetCursorScreenPos();
                if (focus_n_curr == n)
                    ImGui::SetKeyboardFocusHere(0);

                if (editing_n != n)
                {
                    char label[64];
                    sprintf(label, "%g###sel", data[n]);
                    ImGui::Selectable(label, is_selected);
                    if (ImGui::IsItemClicked() && ImGui::IsMouseDoubleClicked(0))
                        editing_n = focus_n_next = n;
                    if (ImGui::IsItemFocused() && ImGui::IsKeyPressed(ImGuiKey_Enter))
                        editing_n = focus_n_next = n;
                }
                if (editing_n == n)
                {
                    // May be easier if we had a public-facing version of TempInputXXX functions
                    ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ImGui::GetColorU32(ImGuiCol_Header));
                    ImGui::SetCursorScreenPos(p);
                    ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
                    ImGui::SetNextItemWidth(-FLT_MIN);
                    // FIXME: May want to use InputText() and convert empty string to 0.0f (vs InputFloat preserve value)
                    ImGui::InputFloat("###edit", &data[n], 0.0f, 0.0f, "%g");
                    if (ImGui::IsItemDeactivated())
                    {
                        editing_n = -1;
                        if (ImGui::IsItemFocused() && !ImGui::IsMouseClicked(0))
                            focus_n_next = n;
                    }
                    ImGui::PopStyleVar();
                }
                ImGui::PopID();
            }
            ImGui::EndTable();
        }
        ms_io = ImGui::EndMultiSelect();
        selection.ApplyRequests(ms_io, COUNT);
    }
    ImGui::End();
}

selectable_editable_grid

Honestly this is the kind of thing where there are lots of subtleties which are not trivial to get right/perfect with dear imgui, so it'll require more work. It'll be an interesting demo.

from imgui.

tasiek30 avatar tasiek30 commented on May 24, 2024

Hello

Thank @ocornut for Your reply. I think it is almost done.... One bad thing is that i have changed a little ImGui source code. This should be done in more sophisticated way.

table.mp4
void DemoSelectableEditableGrid()
{
    ImGui::Begin("Selection #7424");
    {
        const int COUNT_X = 10;
        const int COUNT_Y = 16;
        const int COUNT = COUNT_X * COUNT_Y;
        static ImGuiSelectionBasicStorage selection;
        static float data[COUNT];
        static int editing_n = -1;
        static int focus_n_next = -1;
        static bool set_flag = false;
        static bool change_flag = false;
        float change = 0.0f;

        // FIXME: don't clear selection when clicking selected item
        ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(
                ImGuiMultiSelectFlags_ClearOnEscape
                | ImGuiMultiSelectFlags_BoxSelect2d
                | ImGuiMultiSelectFlags_ClearOnClickVoid
                );
        selection.ApplyRequests(ms_io, COUNT);
        ImGui::Text("Selection: %d/%d", selection.Size, COUNT);

        const int focus_n_curr = focus_n_next;
        focus_n_next = -1;
        if (ImGui::BeginTable("Array", COUNT_X, ImGuiTableFlags_Borders))
        {
            if(ImGui::IsKeyPressed(ImGuiKey_KeypadAdd)) {
                change_flag = true;
                change = 1.0f;
            }
            else if(ImGui::IsKeyPressed(ImGuiKey_KeypadSubtract)) {
                change_flag = true;
                change = -1.0f;
            }

            for (int n = 0; n < COUNT; n++)
            {
                ImGui::TableNextColumn(); // Next cell w/ auto-wrap
                ImGui::PushID(n);

                const bool is_selected = selection.Contains((ImGuiID)n);
                ImGui::SetNextItemSelectionUserData(n);

                ImVec2 p = ImGui::GetCursorScreenPos();
                if (focus_n_curr == n)
                    ImGui::SetKeyboardFocusHere(0);

                char label[64];
                sprintf(label, "%g###sel", data[n]);
                ImGui::SetNextItemAllowOverlap();
                ImGui::Selectable(label, is_selected);

                if (ImGui::IsItemClicked() && ImGui::IsMouseDoubleClicked(0)) {
                    editing_n = focus_n_next = n;
                }
                if (ImGui::IsItemFocused() && ImGui::IsKeyPressed(ImGuiKey_Enter)) {
                    editing_n = focus_n_next = n;
                }

                if (editing_n == n)
                {
                    // May be easier if we had a public-facing version of TempInputXXX functions
                    ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ImGui::GetColorU32(ImGuiCol_Header));
                    ImGui::SetCursorScreenPos(p);
                    ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
                    ImGui::SetNextItemWidth(-FLT_MIN);
                    // FIXME: May want to use InputText() and convert empty string to 0.0f (vs InputFloat preserve value)
                    ImGui::SetKeyboardFocusHere(0);

                    ImGui::InputFloat("###edit", &data[n], 0.0f, 0.0f, "%g");
                    if (ImGui::IsItemDeactivated())
                    {
                        set_flag = true;
                        change = data[n];
                        editing_n = -1;
                        if (ImGui::IsItemFocused() && !ImGui::IsMouseClicked(0))
                            focus_n_next = n;
                    }
                    ImGui::PopStyleVar();
                }
                ImGui::PopID();
            }
            ImGui::EndTable();
        }
        ms_io = ImGui::EndMultiSelect();
        selection.ApplyRequests(ms_io, COUNT);

        if(set_flag) {
            set_flag = false;
            for(int n = 0; n < COUNT; n++) {
                if(selection.Contains((ImGuiID)n) ) {
                    data[n] = change;
                }
            }
        }

        if(change_flag) {
            change_flag = false;
            for(int n = 0; n < COUNT; n++) {
                if(selection.Contains((ImGuiID)n) ) {
                    data[n] += change;
                }
            }
        }

    }
    ImGui::End();
}

In Source code i just commented out clear request when focus is lost. ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags) in imgui_widgets.cpp

    else if (g.NavJustMovedFromFocusScopeId == ms->FocusScopeId)
    {
        // Also clear on leaving scope (may be optional?)
        if ((ms->KeyMods & (ImGuiMod_Ctrl | ImGuiMod_Shift)) == 0 && (flags & (ImGuiMultiSelectFlags_NoAutoClear | ImGuiMultiSelectFlags_NoAutoSelect)) == 0) {
            //request_clear = true;
        }
    }

from imgui.

ocornut avatar ocornut commented on May 24, 2024

In Source code i just commented out clear request when focus is lost. ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags) in imgui_widgets.cpp

This is not specifically when focus is lost but when LEAVING the current scope.
Can you clarify why you want/need to disable it? (then I can see if it's worth adding an option for it)

from imgui.

tasiek30 avatar tasiek30 commented on May 24, 2024

In Source code i just commented out clear request when focus is lost. ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags) in imgui_widgets.cpp

This is not specifically when focus is lost but when LEAVING the current scope. Can you clarify why you want/need to disable it? (then I can see if it's worth adding an option for it)

It was the easiest way to keep selection after enter pressed and switch focus to InputFloat

from imgui.

ocornut avatar ocornut commented on May 24, 2024

It was the easiest way to keep selection after enter pressed and switch focus to InputFloat

OK so that's a workaround but I will find a way to design a solution for it. Thanks for clarifying!

from imgui.

ocornut avatar ocornut commented on May 24, 2024
   else if (g.NavJustMovedFromFocusScopeId == ms->FocusScopeId)
    {
        // Also clear on leaving scope (may be optional?)
        if ((ms->KeyMods & (ImGuiMod_Ctrl | ImGuiMod_Shift)) == 0 && (flags & (ImGuiMultiSelectFlags_NoAutoClear | ImGuiMultiSelectFlags_NoAutoSelect)) == 0) {
            //request_clear = true;
        }
    }

It's interesting because the logic in my code triggers the NavJustMovedToFocusScopeId block, while the logic in yours triggers the NavJustMovedFromFocusScopeId block. Will need further research before I can design a proper flag.

from imgui.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.