Hi Philip,
I must admit I'm way more excited about GJS and Gtk than familiar with it, so I'm not even sure why you would create properties that needs to go "up and down" the bindings instead of simply keeping it in the JS side when it makes sense.
However, since like I've said I don't have enough background, I've read again your example and tried to think about a possible solution.
Right now, ES6 classes syntax is not suitable for things like `Properties` at class definition.
There are three options here, and I don't know which one would be better:
- define properties like it was a generic instance one (properties proposal), it looks close to what you have now but it's based on ES6 syntax (I'll show you later an example)
- using class decorators, probably the best approach since those are the way to enrich or extend ( ` nativeProperties({list, of, props}) class Label extends Gtk.Label {}` ). This doesn't look so familiar though ...
- using an intermediate layer at class definition such `class Label extends Gtk.Label.withProperties({count, etc}) {}` where `withProperties` comes from `Function.prototype` or `__noSuchMethod__` ... although this one feels obtrusive and less future proof
To give you an idea about the first method, here an example with some API improvement (or let's say an easier to write list of properties)
```js
const Gtk = require('Gtk');
class TimerLabel extends Gtk.Label {
properties = {
interval: {
type: 'uint',
value: 1000,
flags: ['rw', 'co'] // constructor_only
}, // will set it on creation
count: { // as mark it as non writable
type: 'uint',
flags: 'r' // as read only, creates a _count
} // with default uint value
} // readable through count getter
constructor(props) {
super(props);
this.label = 'Hello World!';
setInterval(() => {
this._count++;
this.notify('count');
}, this.interval);
}
}
Gtk.init(null);
let win = new Gtk.Window();
win.add(
new TimerLabel()
.on('notify::count', (obj) => {
if (obj.count === 2 && obj.interval === 1000)
Gtk.mainQuit(); // ^ just as example
})
);
win
.on('show', Gtk.main)
.on('destroy', Gtk.mainQuit)
.showAll()
;
```
Above code uses properties as if it's instance property and in my case it works well if I add more transformers but, at the same time, it requires logical hacks (properties has nothing to do with the instance shape) and technical hacks (parsing at runtime transformed code with stuff that should happen at definition time).
Ideally, decorators will make the extension both look nicer and hopefully easier to implement:
```js
@GObjectProperties({
interval: {
type: 'uint',
value: 1000,
flags: ['rw', 'co']
},
count: {type: 'uint', flags: 'r'}
});
class TimerLabel extends Gtk.Label {
constructor(props) {
super(props);
this.label = 'Hello World!';
setInterval(() => {
this._count++;
this.notify('count');
}, this.interval);
}
}
```
I find above variant more elegant.
To answer your other questions:
- `emit` and `on` in `jsgtk` uses native signals, where possible, or custom one. This is right now independent
- `jsgtk` is backward compatible, you can always switch to `this.notify()` instead of `emit` and `this.connect()` instead of `this.on()` or `this.once()`. Although in latter cases you need to store the returned `connect` reference/id since `on` and `once` works through handlers, not returned ids (the returned value is the object for chainability sake)
Last but not least, the idea behind simplified flags is that it takes long time to remember the amount of arguments and their position in those ParamSpec methods, plus it's nice to play with both prototype and instances using flags so that
- read only are getters in the proto with automatic _key = value created at initialization time ... no need to duplicate each time the JS coutnerpart
- write only works like read only with this._key = value as setter counterpart
- readwrite, which should probably be the default, simply create an own property at initialization time, like it is for the `interval` one I've used before ... this makes you write code that is reachable from "both worlds" using the same property, and even a `this.count++` would work (I'll write and push code later today)
- it private is specified, and it's a readwrite, the definition will be as example `interval` but the JS side will have only a non enumerable `_interval`, as opposite of generically enumerable `interval` defined at construction time
- if the flag is construction_only, the instance will have its own property value defined once during initialization but non writable
These are just few ideas on top of my head to make writing code easier than it's now.
Best Regards