Sign up

TreeViewWidget questions (filter, path, iteration)

Hello. I have quite a few questions I hope you can find time to answer me.
For the last few weeks, I have been learning GtkD and taking notes. I made it public so you can find them here

I'm stuck with GtkD's MVC.

1) I have this TreeView. But I can't seem to find a way to find a find a TreeModelFilterVisibleFunc as described here

Here's the code:

import gtk.Application : Application;
import gtk.ApplicationWindow : ApplicationWindow;
import gtk.HeaderBar : HeaderBar;
import gtk.ListStore : ListStore;
import gtk.TreeView : TreeView;
import gtkc.gobjecttypes : GType;
import gtk.TreeViewColumn : TreeViewColumn;
import gtk.CellRendererText : CellRendererText;
import gtk.TreeIter : TreeIter;

private class Album {
private:
ListStore model;

	TreeView view;
	enum COLUMNS {
		ARTIST,
		SONG
	}

	static ListStore generateModel() {
		return new ListStore([GType.STRING, GType.STRING]);
	}

	static TreeView generateView() {
		auto tv = new TreeView();

		auto artistColumn = new TreeViewColumn();
		scope (success)
			tv.appendColumn(artistColumn);
		artistColumn.setTitle("Artist");

		auto artistColumnCell = new CellRendererText();
		artistColumn.packStart(artistColumnCell, true);
		artistColumn.addAttribute(artistColumnCell, "text", COLUMNS.ARTIST);

		auto songColumn = new TreeViewColumn();
		scope (success)
			tv.appendColumn(songColumn);
		songColumn.setTitle("Song");

		auto songColumnCell = new CellRendererText();
		songColumn.packStart(songColumnCell, true);
		songColumn.addAttribute(songColumnCell, "text", COLUMNS.SONG);

		return tv;
	}

public:
	this() {
		model = generateModel();
		view = generateView();
		view.setModel(model);
	}

	void addSong(in string artistName, in string songTitle) {
		auto iter = this.model.createIter();
		model.setValue(iter, COLUMNS.ARTIST, artistName);
		model.setValue(iter, COLUMNS.SONG, songTitle);
	}

	TreeView getView() {
		return this.view;
	}
}

class PrimaryWindow : ApplicationWindow {
private:
	HeaderBar titleBar;
	Album album;

	static HeaderBar makeHeaderBar(string title = "GtkD MVC Demo") {
		auto hb = new HeaderBar();
		hb.setTitle(title);
		hb.setShowCloseButton(true);
		return hb;
	}

public:
	this(Application app) {
		super(app);
		setDefaultSize(480, 360);
		titleBar = makeHeaderBar;
		setTitlebar(titleBar);

		album = new Album();
		album.addSong("Quails", "High Hopes");
		album.addSong("Linkin Park", "Leave Out All The Rest");
		album.addSong("Linkin Park", "Somewhere I belong");
		album.addSong("ANML", "Obsession");
		album.addSong("Eminem", "The Ringer");
		album.addSong("Eminem", "Lucky You");
		album.addSong("Eminem", "Space Bound");
		album.addSong("Johnny Cash", "Hurt");
		album.addSong("Johnny Cash", "Ring of Fire");
		album.addSong("Owl City", "Fireflies");
		album.addSong("Owl City", "On the Wing");

		add(album.getView());
	}
}

int main(string[] args) {
	import gio.Application : GioApp = Application;
	import gtkc.gtktypes : GApplicationFlags;

	auto app = new Application("org.gitlab.gtkdnotes", GApplicationFlags.FLAGS_NONE);
	app.addOnActivate(delegate void(GioApp _) {
		auto pw = new PrimaryWindow(app);
		pw.showAll();
	});
	return app.run(args);
}

2) How can I add a value to the model with a TreePath (AND a TreePath) instead of a TreeIter inside method addSong()?

3) How can I iterate and check for values in a model? For example, I want to find a TreeIter that points to a row that has "Eminem" in the column 0, and "Lucky You" in column 2 in the model?

I will be very happy if you find time to give me code examples, I know it's a bit too much to ask but the documentation isn't helping. Thank you.

Re: TreeViewWidget questions (filter, path, iteration)

On 01-11-18 16:19, aedt wrote:

Hello. I have quite a few questions I hope you can find time to answer me.
For the last few weeks, I have been learning GtkD and taking notes. I made it public so you can find them here

I'm stuck with GtkD's MVC.

1) I have this TreeView. But I can't seem to find a way to find a find a TreeModelFilterVisibleFunc as described here

Here's the code:

...

2) How can I add a value to the model with a TreePath (AND a TreePath) instead of a TreeIter inside method addSong()?

3) How can I iterate and check for values in a model? For example, I want to find a TreeIter that points to a row that has "Eminem" in the column 0, and "Lucky You" in column 2 in the model?

I will be very happy if you find time to give me code examples, I know it's a bit too much to ask but the documentation isn't helping. Thank you.

1) GtkTreeModelFilterVisibleFunc is available in gtk.c.types, only it's
the plain C one, so it's not easy to use. I'll post an more detailed
answer when i have a bit more time.

2) You can convert a TreePath to an iter using the getIter function.

3) The foreach_ function allows you to iterate over all the values in
the model.

Re: TreeViewWidget questions (filter, path, iteration)

On 01-11-18 22:58, Mike Wey wrote:

1) GtkTreeModelFilterVisibleFunc is available in gtk.c.types, only it's
the plain C one, so it's not easy to use. I'll post an more detailed
answer when i have a bit more time.

GtkTreeModelFilterVisibleFunc is a simple C callback, so in the callback
you will need to convert these to D objects.

filter.setVisibleFunc(&FilterTree, null, cast(GDestroyNotify)null);

public static extern(C) int FilterTree(GtkTreeModel* m, GtkTreeIter* i, 
void* data)
{
	TreeModel model = new TreeModel(m);
	TreeIter  iter  = new TreeIter(i);

	string name = model.getValue(iter, 0).getString();
	if (name == "BT")
		return true;
	else
		return false;
}

2) You can convert a TreePath to an iter using the getIter function.

3) The foreach_ function allows you to iterate over all the values in
the model.

The foreach_ function has the same issue as the VisibleFunc:

model.foreach_(&ForEachFunc, null);

public static extern(c) in tForEachFunc(GtkTreeModel* m, GtkTreePath* p, 
GtkTreeIter* i, void* data)
{
	TreeModel model = new TreeModel(m);
	TreePath  path  = new TreePath(p);
	TreeIter  iter  = new TreeIter(i);

	...
}

Re: TreeViewWidget questions (filter, path, iteration)

On Sun, 4 Nov 2018 19:04:20 +0100, Mike Wey wrote:

On 01-11-18 22:58, Mike Wey wrote:

1) GtkTreeModelFilterVisibleFunc is available in gtk.c.types, only it's
the plain C one, so it's not easy to use. I'll post an more detailed
answer when i have a bit more time.

GtkTreeModelFilterVisibleFunc is a simple C callback, so in the callback
you will need to convert these to D objects.

filter.setVisibleFunc(&FilterTree, null, cast(GDestroyNotify)null);

public static extern(C) int FilterTree(GtkTreeModel* m, GtkTreeIter* i, 
void* data)
{
	TreeModel model = new TreeModel(m);
	TreeIter  iter  = new TreeIter(i);

	string name = model.getValue(iter, 0).getString();
	if (name == "BT")
		return true;
	else
		return false;
}

2) You can convert a TreePath to an iter using the getIter function.

3) The foreach_ function allows you to iterate over all the values in
the model.

The foreach_ function has the same issue as the VisibleFunc:

model.foreach_(&ForEachFunc, null);

public static extern(c) in tForEachFunc(GtkTreeModel* m, GtkTreePath* p, 
GtkTreeIter* i, void* data)
{
	TreeModel model = new TreeModel(m);
	TreePath  path  = new TreePath(p);
	TreeIter  iter  = new TreeIter(i);

	...
}

Thank you. Would you mind telling me which module does this foreach_ belong to?

Also, regarding the filter, the compiler complains that the nested function is unable to access the enclosing function, probably because the nested function is static. How can I send a string to fn? I still don't understand how fn itself works too. It seems that fn expects 3 arguments yet when I call filter.setVisibleFunc(&fn, null, cast(GDestroyNotify) null);, I don't see any arguments provided to it.

Re: TreeViewWidget questions (filter, path, iteration)

On Tue, 06 Nov 2018 15:17:01 GMT, aedt wrote:

On Sun, 4 Nov 2018 19:04:20 +0100, Mike Wey wrote:

On 01-11-18 22:58, Mike Wey wrote:
[...]
Also, regarding the filter, the compiler complains that the nested function is unable to access the enclosing function, probably because the nested function is static. How can I send a string to fn? I still don't understand how fn itself works too. It seems that fn expects 3 arguments yet when I call filter.setVisibleFunc(&fn, null, cast(GDestroyNotify) null);, I don't see any arguments provided to it.

It seems that I forgot to add the code:

	TreeModelFilter generateArtistFilter(in string artistName) {
		// nested private function
		static extern (C) int fn(GtkTreeModel* m, GtkTreeIter* i, void* data) {
			TreeModel model_ = new TreeModel(m);
			TreeIter iter = new TreeIter(i);

			string name = model_.getValue(iter, COLUMNS.ARTIST).getString();
			return name == artistName;
		}

		auto filter = new TreeModelFilter(model, null);
		filter.setVisibleFunc(&fn, null, cast(GDestroyNotify) null);
		return filter;
	}

Re: TreeViewWidget questions (filter, path, iteration)

On Tue, 06 Nov 2018 15:18:15 GMT, aedt wrote:

On Tue, 06 Nov 2018 15:17:01 GMT, aedt wrote:

On Sun, 4 Nov 2018 19:04:20 +0100, Mike Wey wrote:

On 01-11-18 22:58, Mike Wey wrote:
[...]
Also, regarding the filter, the compiler complains that the nested function is unable to access the enclosing function, probably because the nested function is static. How can I send a string to fn? I still don't understand how fn itself works too. It seems that fn expects 3 arguments yet when I call filter.setVisibleFunc(&fn, null, cast(GDestroyNotify) null);, I don't see any arguments provided to it.

It seems that I forgot to add the code:

	TreeModelFilter generateArtistFilter(in string artistName) {
		// nested private function
		static extern (C) int fn(GtkTreeModel* m, GtkTreeIter* i, void* data) {
			TreeModel model_ = new TreeModel(m);
			TreeIter iter = new TreeIter(i);

			string name = model_.getValue(iter, COLUMNS.ARTIST).getString();
			return name == artistName;
		}

		auto filter = new TreeModelFilter(model, null);
		filter.setVisibleFunc(&fn, null, cast(GDestroyNotify) null);
		return filter;
	}

Also, I tried this:

        TreeModelFilter generateArtistFilter(in string artistName) {
		auto filter = new TreeModelFilter(model, null);
		filter.setVisibleFunc(&fn(cast(GtkTreeModel*) model,
				cast(GtkTreeIter*) null, cast(void*)&artistName), null, cast(GDestroyNotify) null);
		return filter;
	}

	static extern (C) int fn(GtkTreeModel* m, GtkTreeIter* i, void* data) {
		TreeModel model_ = new TreeModel(m);
		TreeIter iter = new TreeIter(i);

		string name = model_.getValue(iter, COLUMNS.ARTIST).getString();
		return name == *(cast(string*) data);
	}

And then the compiler complains Error: fn(this.model.opCast(), null, & artistName) is not an lvalue and cannot be modified

Re: TreeViewWidget questions (filter, path, iteration)

On 06-11-18 16:18, aedt wrote:

On Tue, 06 Nov 2018 15:17:01 GMT, aedt wrote:

On Sun, 4 Nov 2018 19:04:20 +0100, Mike Wey wrote:

On 01-11-18 22:58, Mike Wey wrote:
[...]
Also, regarding the filter, the compiler complains that the nested function is unable to access the enclosing function, probably because the nested function is static. How can I send a string to fn? I still don't understand how fn itself works too. It seems that fn expects 3 arguments yet when I call filter.setVisibleFunc(&fn, null, cast(GDestroyNotify) null);, I don't see any arguments provided to it.

Gtk itself will be calling the function, with the correct parameters.
you can use the data parameter to send data to the callback.

TreeModelFilter generateArtistFilter(in string artistName) {
	// nested private function
	static extern (C) int fn(GtkTreeModel* m, GtkTreeIter* i, string 
artistName) {
		TreeModel model_ = new TreeModel(m);
		TreeIter iter = new TreeIter(i);

		string name = model_.getValue(iter, COLUMNS.ARTIST).getString();
		return name == artistName;
	}

	auto filter = new TreeModelFilter(model, null);
	filter.setVisibleFunc(&fn, cast(void*)artistName, cast(GDestroyNotify) 
null);
	return filter;
}

Re: TreeViewWidget questions (filter, path, iteration)

On Tue, 6 Nov 2018 22:19:54 +0100, Mike Wey wrote:

On 06-11-18 16:18, aedt wrote:

On Tue, 06 Nov 2018 15:17:01 GMT, aedt wrote:

On Sun, 4 Nov 2018 19:04:20 +0100, Mike Wey wrote:

On 01-11-18 22:58, Mike Wey wrote:
[...]
Also, regarding the filter, the compiler complains that the nested function is unable to access the enclosing function, probably because the nested function is static. How can I send a string to fn? I still don't understand how fn itself works too. It seems that fn expects 3 arguments yet when I call filter.setVisibleFunc(&fn, null, cast(GDestroyNotify) null);, I don't see any arguments provided to it.

Gtk itself will be calling the function, with the correct parameters.
you can use the data parameter to send data to the callback.

...

Unfortunately that produces an error too:

Error: function gtk.TreeModelFilter.TreeModelFilter.setVisibleFunc(extern (C) int function(GtkTreeModel* model, GtkTreeIter* iter, void* data) func, void* data, extern (C) void function(void* data) destroy) is not callable using argument types (extern (C) int function(GtkTreeModel* m, GtkTreeIter* i, string artistName) @system, void*, extern (C) void function(void* data))
source/app.d(69,24):        cannot pass argument & fn of type extern (C) int function(GtkTreeModel* m, GtkTreeIter* i, string artistName) @system to parameter extern (C) int function(GtkTreeModel* model, GtkTreeIter* iter, void* data) func
/usr/bin/dmd failed with exit code 1.

Full code: https://pastebin.com/Ei7MDZzJ

Re: TreeViewWidget questions (filter, path, iteration)

On 07-11-18 02:46, aedt wrote:

Unfortunately that produces an error too:

Error: function gtk.TreeModelFilter.TreeModelFilter.setVisibleFunc(extern (C) int function(GtkTreeModel* model, GtkTreeIter* iter, void* data) func, void* data, extern (C) void function(void* data) destroy) is not callable using argument types (extern (C) int function(GtkTreeModel* m, GtkTreeIter* i, string artistName) @system, void*, extern (C) void function(void* data))
source/app.d(69,24):        cannot pass argument & fn of type extern (C) int function(GtkTreeModel* m, GtkTreeIter* i, string artistName) @system to parameter extern (C) int function(GtkTreeModel* model, GtkTreeIter* iter, void* data) func
/usr/bin/dmd failed with exit code 1.

Full code: https://pastebin.com/Ei7MDZzJ

I forgot a cast in there:

TreeModelFilter generateArtistFilter(in string artistName) {
	// nested private function
	static extern (C) int fn(GtkTreeModel* m, GtkTreeIter* i, string 
artistName) {
		TreeModel model_ = new TreeModel(m);
		TreeIter iter = new TreeIter(i);

		string name = model_.getValue(iter, COLUMNS.ARTIST).getString();
		return name == artistName;
	}

	auto filter = new TreeModelFilter(model, null);
	filter.setVisibleFunc(cast(GtkTreeModelFilterVisibleFunc)&fn, 
cast(void*) artistName, cast(GDestroyNotify) null);
	return filter;
	}