Iterating over TreeIter

I’m working on a GTK application and found there were a few spots where I needed to iterate over a TreeModel. Doing this in GtkD is a bit of a pain since TreeModelT isn’t implemented as a Range and so you are forced to use the model methods rather then the convenience of foreach.

To make my life easier, I created a small struct that can be used to wrap a TreeModelIF interface and allows it to be used in D’s foreach construct as per this example:

foreach(TreeIter iter; TreeIterRange(lsProfiles)) {
	if (lsProfiles.getValue(iter, COLUMN_UUID).getString() == window.uuid) {
		lsProfiles.setValue(iter, COLUMN_NAME, profile.name); 
	}
}
/**
 * An implementation of a range that allows using foreach over a range
 */
struct TreeIterRange {
 
private:
    TreeModelIF model;
    TreeIter iter;
    bool _empty;
 
public:
    this(TreeModelIF model) {
        this.model = model;
        _empty = model.getIterFirst(iter);
    }
 
    @property bool empty() {
        return _empty;
    }
 
    @property auto front() {
        return iter;
    }
 
    void popFront() {
        _empty = !model.iterNext(iter);
    }
 
    /**
     * Based on the example here https://www.sociomantic.com/blog/2010/06/opapply-recipe/#.Vm8mW7grKEI
     */
    int opApply(int delegate(ref TreeIter iter) dg) {
        int result = 0;
        TreeIter iter;
        bool hasNext = model.getIterFirst(iter);
        while (hasNext) {
            result = dg(iter);
            if (result) break;
            hasNext = model.iterNext(iter);
        }
        return result;
    }
}

Creating Complex Popovers in D and GtkD

I’m working on a new terminal emulator in my spare time and one UI element I definitely wanted to make use of was Popovers. While creating a simple Popover is quite easy, I was struggling a bit with how to handle the more complex layouts like horizontal buttons as the documentation does not make it very clear. Fortunately, Christian Hergert of Builder fame was on IRC one night and was able to point me in the right direction.

The Popover I created is shown in the image below, in the terminal emulator I’m working on it allows you to split the terminal into multiple views or tiles so the user can see multiple views at the same time in an easily managed container. The Popover allows the user to split the terminal horizontally or vertically (note the icons are temporary, plan on “borrowing” Builder’s icons for this at some point).

Popover

The issue I was struggling with was where to set the display-hint, the section being a gio.Menu doesn’t have methods to set an attribute. What Christian pointed out to me is that you need to create an empty MenuItem to represent the section, add the section to that and then add it the menu used in the Popover. You can then set the necessary attributes on the empty MenuItem to get the items displayed in the way you want.

Here is the code I ended up with:

Popover createPopover(Widget parent) {
GMenu model = new GMenu();
 
GMenuItem splitH = new GMenuItem(null, "view.splith");
splitH.setAttributeValue("verb-icon", new GVariant("go-next-symbolic"));
splitH.setIcon(new ThemedIcon("go-next-symbolic"));
 
GMenuItem splitV = new GMenuItem(null, "view.splitv");
splitV.setAttributeValue("verb-icon", new GVariant("go-down-symbolic"));
splitV.setIcon(new ThemedIcon("go-down-symbolic"));
 
GMenu section = new GMenu();
section.appendItem(splitH);
section.appendItem(splitV);
 
GMenuItem splits = new GMenuItem(null, null);
splits.setSection(section);
splits.setLabel("Split");
splits.setAttributeValue("display-hint", new GVariant("horizontal-buttons"));
 
model.appendItem(splits);
 
Popover pm = new Popover(parent, model);
return pm;
}