Modular UI questions

How do I detect the front-most component meeting some particular condition at a screen position by the way?

I’ve got this:

DockBase* DockableWindowManager::getDockUnderScreenPosition(Point<int> position)
{
	for (auto d : docks)
		if (d->containsScreenPosition(position))
			return d;

	return nullptr;
}

But I need to handle the situation where there are multiple matches…

Well, I added some basic tab code to it as well now. So you can drag things into tabs, move the tabs around, drag tabs into windows and pop them back into docks etc.etc.

Still need to solve nested docks…

Well the AdvancedDock finally got some attention today, and it works, more or less like Visual Studio, and I hardly had to touch the rest of the code I’d written. So that’s promising :slight_smile:

5 Likes

And now with StretchableLayoutResizerBar’s it’s like a ballet of std::vector<>.

PS. It’d be really handy if the StretchableLayoutManager could operate on some rectangles as an alternative to operating on Components themselves. It’s not the first time I’ve thought that, and I think it’s as simple as this:

void StretchableLayoutManager::layOutRectangles(Array<Rectangle> & areas,
	int x, int y, int w, int h,
	const bool vertically,
	const bool resizeOtherDimension)
{
	setTotalSize(vertically ? h : w);
	int pos = vertically ? y : x;

	for (int i = 0; i < areas.size(); ++i)
	{
		if (const ItemLayoutProperties* const layout = getInfoFor(i))
		{
			auto & c = areas[i];

			if (i == areas.size() - 1)
			{
				// if it's the last item, crop it to exactly fit the available space..
				if (resizeOtherDimension)
				{
					if (vertically)
						c->setBounds(x, pos, w, jmax(layout->currentSize, h - pos));
					else
						c->setBounds(pos, y, jmax(layout->currentSize, w - pos), h);
				}
				else
				{
					if (vertically)
						c->setBounds(c->getX(), pos, c->getWidth(), jmax(layout->currentSize, h - pos));
					else
						c->setBounds(pos, c->getY(), jmax(layout->currentSize, w - pos), c->getHeight());
				}
			}
			else
			{
				if (resizeOtherDimension)
				{
					if (vertically)
						c->setBounds(x, pos, w, layout->currentSize);
					else
						c->setBounds(pos, y, layout->currentSize, h);
				}
				else
				{
					if (vertically)
						c->setBounds(c->getX(), pos, c->getWidth(), layout->currentSize);
					else
						c->setBounds(pos, c->getY(), layout->currentSize, c->getHeight());
				}
			}

			pos += layout->currentSize;
		}
	}

You’ll be wondering why I want that in the layout manager. Well, the dock is a single component, and it made sense to write it without having lots of nested components. Maybe I could rehack it so each row is a Component to make the layout manager easier to work with … but it seems to just be overhead?

Could it be done nicely by modifying the resizer bar to operate on a Flexbox layout?

Oh, let me have a look at that new-fangled stuff. I’ll get back to you :slight_smile:

It works fine if the FlexLayout grow parameters are all set to 0, I can take the delta from the dragged resizer and apply it to the Flex-Basis. But what’s really needed is the stretching behaviour as well.

The common desktop app behaviour is that the resizer bar only adjusts its local boundaries and doesn’t affect the size of any other components. (This isn’t how StretchableLayoutManager works either).

Any bright ideas? It’d be nice to use the new-fangled stuff.

Otherwise I could write a new layout manager that implements this otherwise pretty simple behaviour…

@bazrush, I just tried this out. It’s very impressive. I wonder how hard it would be to have panels resize to fill blank spaces left after dragging, as shown in the image below? I’ve taken a look though your code but I’d need a week and lots of strong coffee to get my head around it. I would to use this in one of my open source projects, but the blank space issue is a deal breaker. :frowning:

The blank space there is because there are multiple containers (docks) for the windows. That’s an empty dock. If you just use the advanced dock (center one) you won’t have any blank space.

Or failing that it’d not be hard for a dock to shrink itself to almost 0 size if it was empty. There are hooks in there, I think, that you could use for that.

Let me know if you need further pointers …

I think I’ve pushed three dock types to the github. There should be:

  • Vertical dock - shows windows in a vertical stack with matching sizes, no resizers. This is really just a demo to show how to write a dock.
  • Tabbed dock - this shows roughly how the existing TabbedComponent could be done as an component of more advanced dockable windows system.
  • Advanced dock - this the bare bones of the all-in-one dockable system. It’s loosely based around the way Visual Studio works with windows. I’ll be refining and using this for some real apps.
1 Like

Great stuff. I look forward to trying this out. It’s just the sugar my app needs :wink:

1 Like

Did you push something today? Last commit seems to have been 2 months ago? I just want to be sure I’m using the most up to date source. I feel like a child at Christmas!

Not today. I think what’s there should be good. Any problems let me know and I’ll check when I’m home.

I can see how the vertical and tabbed docks work, but the Advanced one is confusing me a little. I guess I should add a component to a DockableComponentWrapper and then attached the DockableComponentWrappers to my advanced tab? I’m also away from my PC right now. I guess it will make sense once I try it out. Cheers.

Ah - you’ve spotted an omission.

I’ll fix it :slight_smile:

It needs something like: void WindowDockVertical::addComponentToDock() but for the advanced dock.

You’ll also note, I think eventually, that there’s nothing in there to help save and restore window positions yet.

1 Like

Ok - this is fixed now. I’ve added an example addComponentToDock function into the JAdvancedDock classes. It needs further work so it can insert a component in a location of your choice, but it’s an example at least that works :slight_smile:

Great. It’s working fine now. Thanks again for this. Lots to learn from!

edit: any idea how I can get the components to be shown in a default layout? My app only have two components. I would like to have them placed side by side on startup. I see some references to AdvancedDockPlaces? When I do this:

advancedDock.addComponentToDock(propertiesComponent);
advancedDock.addComponentToDock(editor);

Only the editor component appears. I have to then manually move it around to see the the properties component?

Okay - this is the bit that I was thinking needed work. You should see them both in tabs by default? I.e. like this?

If they don’t start up like that there’s a bug :wink:

Hang on … thought I had a solution but just realised it’s a bit more complicated than that. Update coming shortly …