0066: How to Tool Up a Toolbar

The old way of doing a GTK Toolbar is falling out of favour, mostly because the StockIDs (such as COPY, CUT, PASTE, etc.) once used to put icons in a ToolButton are all deprecated.

So, that leaves us with two choices, either the IconTheme route—which looks daunting—or rolling our own… sort of. Because everything we need to know to use the second option has been covered already, I’ve chosen to go that route.

But, there’s really no bad news here. We still get a usable Toolbar that looks like a Toolbar and we also get to use whatever images suit our purposes.

So without further ado, here’s…

The Basics of Building a Toolbar

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

Before we start, I’ll mention that a ToolButton is a container that holds a standard Button and a standard Label.

To populate a Toolbar:

  • build one or more ToolButtons,
  • stuff the ToolButton(s) with standard Buttons and text strings to be passed along to the Label(s), and
  • insert() the ToolButton into the Toolbar.

And that’s all there is to it.

A Standard Button

Would look like this:

class PasteButton : Button
{
	Image image;
	string imageFilename = "images/edit-paste-symbolic.symbolic.png";
		
	this()
	{
		super();
		
		image = new Image(imageFilename);
		add(image);
		
	} // this()
	
} // class PasteButton

And it gets stuffed into…

The ToolButton

Which looks like this:

class PasteToolButton : ToolButton
{
	PasteButton pasteButton;
	string actionMessage = "Paste operation.";

	this()
	{
		pasteButton = new PasteButton();
		super(pasteButton, "Paste");		
		addOnClicked(&doSomething);
		
	} // this()


	void doSomething(ToolButton b)
	{
		writeln(actionMessage);
		
	} // doSomething()

} // class PasteToolButton

Notice that we hook up the signal to the ToolButton and not the imbedded Button. The ToolButton doesn’t inherit the getChild() function, so to find out if the embedded Button is reacting to a signal would take extraneous code. Also, hooking up the ToolButton’s signal means a click on the Label is as good as a click on the embedded Button.

Note: There are two other overloads of the ToolButton constructor, but as mentioned earlier, because the StockID enum has been deprecated, they won’t do much to future-proof applications. And since GTK 4.0 might be just around the corner, we’re better off leaving them alone.

The Toolbar Class

Here’s what it looks like:

class MyToolbar : Toolbar
{
	ToolButton cutToolButton, copyToolButton, pasteToolButton;

	this()
	{
		super();
		setStyle(ToolbarStyle.BOTH);

		cutToolButton = new CutToolButton();
		insert(cutToolButton);

		copyToolButton = new CopyToolButton();
		insert(copyToolButton);
		
		pasteToolButton = new PasteToolButton();
		insert(pasteToolButton);
		
	} // this()
	
} // class MyToolbar

Pretty straightforward… all we do is:

  • decide whether we want icons, text, or both and call setStyle() (options are, oddly enough: ICONS, TEXT, or BOTH),
  • instantiate a bunch of ToolButtons, and
  • insert() them into the Toolbar.

As for adding a Toolbar to our hierarchy of application classes, it’s no different than most other things:

class AppBox : Box
{
	bool expand = false, fill = false;
	uint globalPadding = 10, localPadding = 5;
	MyToolbar myToolbar;
	
	this()
	{
		super(Orientation.VERTICAL, globalPadding);
		
		myToolbar = new MyToolbar();
		
		packStart(myToolbar, expand, fill, localPadding); // LEFT justify
		// packEnd(<child object>, expand, fill, localPadding); // RIGHT justify
		
	} // this()

} // class AppBox

Although, you’ll want to give the AppBox an Orientation.VERTICAL so as to keep the Toolbar below the Menu and above the working area of your application… unless you’re going for a unique layout, that is.

Conclusion

And those are the mysteries of the Toolbar.

Later on, we’ll look at how to hook up ToolButtons to the singleton AccelGroup we built for a Menu system so we have a ToolButton, MenuItem and accelerator key all calling a single callback.

And next time around, we’ll look at the Expander.

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