ocornut / imgui

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

Docking branch feature request related to ImGuiDockFamily #2248

Open tobiasford opened 5 years ago

tobiasford commented 5 years ago

I'm currently using the official docking branch to implement a from scratch engine editor. One thing that I'm trying to do is mimic photoshop's palettes inside of multi-level dock-spaces. basically, these are small tab windows that are dockable with each other (in and out of their parent dock), and with a parent window that is a child of the overall editor.

While I'm still prototyping my ui, it's looking like I won't be able to pull off the polish that I'm wanting with the current implementation of ImGuiDockFamily.

What I'd rather see, instead of ImGuiDockFamily, are callbacks to allow approving a window being docked with any other window. This pattern could also probably be used to filter docking with the center, left, right, top, bottom.

I would imagine that this would be somewhat similar to the callbacks from ImGui::SetNextWindowSizeConstraints.

ocornut commented 5 years ago

Hello,

I'm currently using the official docking branch to implement a from scratch engine editor. One thing that I'm trying to do is mimic photoshop's palettes inside of multi-level dock-spaces. basically, these are small tab windows that are dockable with each other (in and out of their parent dock), and with a parent window that is a child of the overall editor.

Could you provide more details about the desired effect?

tobiasford commented 5 years ago

something in the api that would look like this as a replacement for ImGuiDockFamily:

enum ImGuiDockDir
{
    ImGuiDockDir_None         = 0,
    ImGuiDockDir_Center       = 1 << 0,
    ImGuiDockDir_InnerLeft    = 1 << 1,
    ImGuiDockDir_InnerRight   = 1 << 2,
    ImGuiDockDir_InnerUp      = 1 << 3,
    ImGuiDockDir_InnerDown    = 1 << 4,
    ImGuiDockDir_OuterLeft    = 1 << 5,
    ImGuiDockDir_OuterRight   = 1 << 6,
    ImGuiDockDir_OuterUp      = 1 << 7,
    ImGuiDockDir_OuterDown    = 1 << 0,
};

struct ImGuiDockingCallbackData
{
    void*   UserData;                // Read-only
    ImGuiID SourceDockId;            // Read-only
    ImGuiID SourceWindowId;          // Read-only
    ImGuiID DestinationDockId;       // Read-only
    ImGuiID DestinationWindowId;     // Read-only
    ImGuiDockDir DesiredDestination; // Read-write
};

// user supplied callback where they can control everything!!!
struct ImGuiDockingCallback
{
    static void execute(ImGuiDockingCallbackData * const data)
    {
        ImGuiID const & SourceDockId = data.SourceDockId;
        ImGuiID const & SourceWindowId = data.SourceDockId;
        ImGuiID const & DestinationDockId = data.SourceDockId;
        ImGuiID const & DestinationWindowId = data.SourceDockId;
        ImGuiDockDir & DesiredDestination = data.SourceDockId;

        if (   SourceWindowId == DestinationWindowId    // don't dock with self
            || DestinationDockId == topToolbarDockId    // don't dock with the top toolbar
            || DestinationDockId == leftToolbarDockId   // don't dock with the left toolbar
            || DestinationDockId == bottomToolbarDockId // don't dock with the bottom toolbar
            )
        {
            DesiredDestination = ImGuiDockDir_None;
            return;
        }

        bool const sourceWindowIsPalette = IsSourceWindowIsPalette(SourceWindowId);                // function supplied by me
        bool const destinationWindowIsPalette = IsDestinationWindowIsPalette(DestinationWindowId); // function supplied by me

        if (sourceWindowIsPalette && destinationWindowIsPalette)
        {
            // Palette can always dock with one another
            DesiredDestination = ImGuiDockDir_None;
            DesiredDestination |= ImGuiDockDir_Center;
            DesiredDestination |= ImGuiDockDir_OuterUp;
            DesiredDestination |= ImGuiDockDir_OuterDown;
            return;
        }

        // TODO : additional logic photoshop-like tool palette managing rules.
    }
};

ImGui::SetNextDockingConstraints(ImGuiDockingCallback::execute, nullptr);
ocornut commented 5 years ago

It is mostly that I would like to understand the use case with a concrete few exemples / user scenario (I am not familar with photoshop) before evaluating at a proposed solution. Those details you posted are also helpful.

(I’ve been reworking the dock family system for another use for a client, so it is currently in flux. Currently toward becoming a more general “window class” concept.)

tobiasford commented 5 years ago

I figured that the system was still churning, which is why I posted this as a request instead of just making the change myself.

The use case is really just attempting to mimic the usability, intuitiveness, and polish of photoshop when it comes to dock management and presentation. They've done a wonderful job of presenting a lot of complex and simple concepts in a way that can be completely customized by the artist/user. In my opinion, it's heads and shoulders above Maya or Max when managing things in a workspace.

My proposed change would really just allow finer control over what is allowed to go where and how it’s able to ‘fit’ into the dock. I’m sorry that I don’t have a more concrete example other then just photoshop… The example above, would make getting there pretty easy.

That said, I’d totally recommend spending 10 dollars to subscribe to photoshop for a month to just look and play with how it's docking works.

traverseda commented 5 years ago

Seems like something worth doing, I imagine they put a lot of time in to the usability studies.

ocornut commented 5 years ago

I’m sorry that I don’t have a more concrete example other then just photoshop…

At a quick glance at Photoshop it seems like the main differences compared to what dear imgui does are:

1) Windows can be docked on the outer side of floating windows, it makes the two window attached but they each preserve their own rectangle and size (vs. we are splitting from within, like Visual Studio)

image

image

2) The visible window of given "node"/"tab group" owns and maintain its size and dictates it to the docking node. (vs. we are doing the opposite, the docking node owns the size and sets it in the individual windows)

3) Tab groups can be collapsed by double-clicking on a tab. I have an unfinished PR for this. It has issues with our current docking scheme but would work better with the features described in 1 and 2.

4) Tab groups can be turned into vertical-ish icon bars by clicking on the << button.

image

Now, I understand the value of all of those schemes (in particularly 1) but I don't understand the connection with your proposal to alter the dock family system with a filter, those seems to be completely unrelated concepts and I don't see how the callback would allow us to implement that.

Unless I am misunderstanding the thread, it feels like you are requested a large group of feature not specifically related to dock family/filtering, and focusing on that dock family/filtering aspect as a suggestion that this mechanism could allow the user fine-tuning which option they want, instead of clarifying the larger feature first.

I've been looking for a concrete example of what you are interested in in the form of e.g. a GIF or series describing precisely what aspect of Photoshop behavior you are interested in. I imagine it seems absolutely obvious to you but having spend time into the gritty details of docking I read a lots of ambiguity in the paragraphs above.

(Consider that a sentence "mimic photoshop's palettes inside of multi-level dock-spaces. basically, these are small tab windows that are dockable with each other (in and out of their parent dock), and with a parent window that is a child of the overall editor." is full of jargon which can all mean different thing to each of us)

vprimachenko commented 5 years ago

what is special about Photoshop behaviour is that there are two types of windows, with slightly different docking behaviour: tools and documents. Adding to your observations i like to add:

5: tools can be docked only to the edges ot the overall workpane (or other tools), and reduce the workpanes size (note the main toolset expanding to fill entire height)

5

6: most notably tools cant be docked between documents

6

7: tools cant dock to documents, albeit there is some snapping 7

8: document can only be docked to each other as tabs while floating

8

i, for one, would really like to see 1, 2 and 5 implemented in Dear ImGui

tobiasford commented 5 years ago

Thank you for articulating my intention. You did a much better job then I would have.

My project originally began as a QT project. When trying out imgui, I refactored all of my ui related state management into a generic api that can sit atop either qt or imgui through a shared interface. Because I’m managing my own ui state at a higher level, I was able to implement enough of the above mentioned functionality without too much trouble.

The only real issue I have is the lack of fine control in being able to determine which window can dock with which dock space or merge with which window and how that merge would occur (main, top, bottom, etc).

Having a filter that is used when dragging a window over another window would allow that control.

In no way am I discouraging any of the other above changes. I think that they would be great.

ocornut commented 5 years ago

Tobias,

The only real issue I have is the lack of fine control in being able to determine which window can dock with which dock space or merge with which window and how that merge would occur (main, top, bottom, etc).

You are still not providing a concrete example linked to your real world app of how you would take meaningful advantage of this. I can’t design a feature properly without having concrete cases in mind.

tobiasford commented 5 years ago

I'm building an artistic productivity tool that manipulates both 2d and 3d assets. I can't say anymore for various reasons.

I see 8 very inspirational examples in this thread along with a minimal api description that would allow others to do most of the heavy lifting on their own.