Examples
Examples of using Tuner widgets and bindings.
Simple entry
Let's add Tuner.Entry inside empty group:
blp
using Gtk 4.0;
using Tuner 1;
translation-domain "tuner-base";
Tuner.Page {
title: _("New Page");
icon-name: "computer-symbolic";
Tuner.Group {
Tuner.Entry {
title: _("Our cool entry");
show-apply-button: true;
}
}
}But that entry will not be displayed without binding, so add FileContent binding:
blp
Tuner.Entry {
title: _("Our cool entry");
show-apply-button: true;
binding: Tuner.FileContent {
path: "~/1.txt";
}
}Result

sh
$ cat 1.txt
testThat entry now will by synced with 1.txt file inside current user home folder.
Property show-apply-button allows to save entered text only after pressing Enter or special apply button.
Better file content binding
Now let's create binding with custom behaviour.
vala
public class Base.SimpleJson : Tuner.Binding {
public string path { get; set; }
public string name { get; set; }
public override Type expected_type { get { return Type.STRING; } }
// Load json content to our entry
public override bool get_value(ref Value value) {
try {
var parser = new Json.Parser();
if (parser.load_from_file(Tuner.FileUtil.expand_home(path))) {
var root = parser.get_root();
if (root != null && root.get_object() != null && root.get_object().has_member(name)) {
var node = root.get_object().get_member(name);
if (node != null && node.get_string() != null) {
value.set_string(node.get_string());
return true;
}
}
}
} catch (Error e) {
warning("Error: %s\n", e.message);
}
return false;
}
// Write contents of our entry to file
public override void set_value(Value value) {
try {
Json.Node target = null;
var parser = new Json.Parser();
if (parser.load_from_file(Tuner.FileUtil.expand_home(path))) {
var root = parser.get_root();
if (root != null && root.get_object() != null) {
root.get_object().set_string_member(name, value.get_string());
target = root;
}
}
if (target == null) {
target = new Json.Builder()
.begin_object()
.set_member_name(name)
.add_string_value(value.get_string())
.end_object()
.get_root();
}
var generator = new Json.Generator();
generator.set_root(target);
generator.to_file(Tuner.FileUtil.expand_home(path));
} catch (Error e) {
warning("Error creating/writing file: %s", e.message);
}
}
}Don't forget to register the type if it will be used in markup!
vala
// Insert before calling add_from_resource
typeof(Base.SimpleJson).ensure();Not let's use our binding in markup:
blp
using Gtk 4.0;
using Tuner 1;
translation-domain "tuner-base";
Tuner.Page {
title: _("New Page");
icon-name: "computer-symbolic";
Tuner.Group {
Tuner.Entry {
title: "Name";
show-apply-button: true;
binding: $BaseSimpleJson {
path: "~/1.json";
name: "name";
};
}
Tuner.Entry {
title: "Surname";
show-apply-button: true;
binding: $BaseSimpleJson {
path: "~/1.json";
name: "surname";
};
}
}
}With that binding entry text will be written to file with specified path only to json member with specified name withot overriding other members.
Result

sh
$ cat 1.json
{"name":"Lorem","surname":"Ipsum"}