0045: Split a Window into Panes

There will be times when you’ll need a window separated into two areas with a handle to adjust the division between them. For instance, a file manager has a directory/folder tree on the left and the contents of a selected directory on the right and as I’m sure you’re aware, if you dig deep enough into a directory hierarchy, you have to widen the left-hand area so you can see the full path which is why it’s handy to have that adjustment handle between the two panes.

Today’s code lays the foundation for this type of functionality.

A Pane in the Window… Two, Really

Results of this example:
Current example output
Current example output
Current example terminal output
Current example terminal output (click for enlarged view)

A Paned container can have its child panes side by side or one below the other. And since we may want programmable access to manipulate the child widgets we put in these panes, I’ve created a class derived from Paned and called it SideBySide:

class SideBySide : Paned
{
	Image child01, child02;
	
	this()
	{
		super(Orientation.HORIZONTAL);
		
		auto child01 = new Image("images/e_blues_open.jpg"); 
		add1(child01);
		
		auto child02 = new Image("images/guitar_bridge.jpg");
		add2(child02);
		
		addOnButtonRelease(&showDividerPosition);
		
	} // this()
	
	
	public bool showDividerPosition(Event event, Widget widget)
	{
		writeln("The divider is set to: ", getPosition());
		
		return(true);
		
	} // showDividerPosition()
	
} // class SideBySide

This is just about as simple as it gets with Paned containers. We’ve got two child Image widgets, each tucked into its own pane.

And just to show off one of Paned’s functions, I’ve connected up a generic Widget Event signal to spit out the position of the pane divider handle. Hover the mouse over the handle, click-n-drag, and when you release the mouse button, showDividerPosition() spits out the new position of the handle.

Paned Behaviour

Because there are only two panes in a Paned container, the functions for assigning child Widgets are numbered:

  • add1(child1), and
  • add2(child2).

Or if you want to populate both in one go, you can do it with a single function:

add(child1, child2);

You could also use pack1() and pack2() if you prefer, but the behaviour will be different, so let’s look at that.

Paned Packing (a Vertical Version)

Results of this example:
Current example output
Current example output
Current example terminal output
Current example terminal output (click for enlarged view)

Our second example has a new derived class for a vertical Paned container:

class UppyDowny : Paned
{
	Image child01, child02;
	
	this()
	{
		super(Orientation.VERTICAL);
		
		auto child01 = new Image("images/e_blues_open.jpg"); 
		pack1(child01, true, false);
		
		auto child02 = new Image("images/guitar_bridge_alt.jpg");
		pack2(child02, false, true);
		
		addOnButtonRelease(&showDividerPosition);
		
	} // this()
	
	
	public bool showDividerPosition(Event event, Widget widget)
	{
		writeln("The divider is set to: ", getPosition());
		
		return(true);
		
	} // showDividerPosition()
	
} // class UppyDowny

Here are the differences between this example and the first:

  • the panes are stacked vertically instead of horizontally,
  • pack1() has three arguments instead of one:
    • the child Widget,
    • a bool to determine whether or not the child will expand when the divider handle is moved away from it, and
    • another bool to control whether or not the child Widget will shrink when the handle is moved toward it.
  • when you move the divider handle in the first example, each image slides out of the way as the handle is moved toward it, but…
  • in the second example, only the guitar bridge image moves.

Note also that even though the panes expand or contract as you move the handle, the Images aren’t resizing. So, it’s just the panes that change size, not their contents.

How addX() Imitates packX()

The default behaviour for add1() or add2() allows both panes to resize just as can be done with pack1() and pack2(). That’s because when using the addX() functions, they assume behaviours that would be the same as if you’d used packX() while passing the following arguments:

  • pack1(child1, false, true) = add(child1), and
  • pack2(child2, true, true) = add(child2).

The corollary is, if you want to mimic the behaviour of add1() and add2(), using the above arguments to pack1() and pack2() would do the trick.

And that’s pretty much it for now. See you next time.

Comments? Questions? Observations?

Did we miss a tidbit of information that would make this post even more informative? Let's talk about it in the comments.

You can also subscribe via RSS so you won't miss anything. Thank you very much for dropping by.

© Copyright 2023 Ron Tarrant