前回の続き、GtkDrawingArea です。
フォトレタッチのようにマウス軌跡の連続線を GTK+ で描きたい。
って探すまでもなく GTK+ 3 Reference Manual に書いてあった。
Custom Drawing: GTK+ 3 Reference Manual
つまり軌跡を残すには draw シグナル引数にある cairo_t の中に描写しない。
サーフェス(面の意味)を別に作ってそちらに描写する、当然追記になる。
そのまま gtk_widget_queue_draw 関数を呼び出し draw シグナルを送る。
ハンドラにて先程のサーフェスを cairo_t にセットする。
解ってしまえばそりゃそうだ、みたいな。
しかし gjs へのバインディング記法がサッパリ解らない。
Gir の cairo は何もできないし、使おうとした人なら解ってくれるよね。
Gdk.cairo*** も GTK+ と同様に書き換えるとエラー。
cr.set_source_rgb みたいなバインドではないようだ、うーん。
installed-tests/js/testCairo.js ? master ? GNOME / gjs ? GitLab
散々遠回りをしてやっとこんなのを捜し出した。
リソースにある cairo を使えばいいってことね。
しかしコッチは GTK+ と違って C 言語とかなり違う表記を強いられる。
// C // JavaScript cairo_create (surface); new Cairo.Context(surface); cairo_set_source_surface (cr, surface, 0, 0); cr.setSourceSurface(surface, 0, 0); cairo_set_source_rgb (cr, 1, 1, 1); cr.setSource(Cairo.SolidPattern.createRGB(1, 1, 1)); gdk_window_create_similar_surface widget.window.create_similar_surface //Gdk.Window.create_similar_surface // Error CAIRO_CONTENT_COLOR Cairo.Content.COLOR
てな感じ。
ということで、実際に上手くいったソース。
#!/usr/bin/gjs // Resource const System = imports.system; const Cairo = imports.cairo; // Gir const GObject = imports.gi.GObject; const GLib = imports.gi.GLib; const Gio = imports.gi.Gio; const Gtk = imports.gi.Gtk; const Gdk = imports.gi.Gdk; var DrawingWindow = GObject.registerClass({ GTypeName: "DrawingWindow" }, class DrawingWindow extends Gtk.ApplicationWindow { _init(app) { super._init({application: app}); // var this.surface = null; // HeadreBar let hb = new Gtk.HeaderBar({show_close_button: true}); let clearButton = new Gtk.Button({label: "Clear"}); clearButton.connect("clicked", ()=> { this.clearSurface(); this.canvas.queue_draw(); }); hb.pack_start(clearButton); this.set_titlebar(hb); // DrawingArea this.canvas = new Gtk.DrawingArea(); this.canvas.set_events( Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.BUTTON_RELEASE_MASK | Gdk.EventMask.BUTTON1_MOTION_MASK | Gdk.EventMask.STRUCTURE_MASK ); this.canvas.connect("configure-event", (widget, event)=> { this.surface = this.canvas.window.create_similar_surface( Cairo.Content.COLOR, widget.get_allocated_width(), widget.get_allocated_height() ); this.clearSurface(); return true; }); this.canvas.connect("button-release-event", (widget, event)=> { return false; }); this.canvas.connect("button-press-event", (widget, event)=> { if (event.get_button()[1] === 1) { let [res, x, y] = event.get_coords(); hb.set_title(`${x}/${y}`); this.drawBrush(x, y); } return false; }); this.canvas.connect("motion-notify-event", (widget, event)=> { let [res, x, y] = event.get_coords(); hb.set_title(`${x}/${y}`); this.drawBrush(x, y); return false; }); this.canvas.connect("draw", (widget, cr)=> { cr.setSourceSurface(this.surface, 0, 0); cr.paint(); return false; }); this.add(this.canvas); // this this.resize(400, 400); this.show_all(); } drawBrush(x, y) { let cr = new Cairo.Context(this.surface); cr.arc(x, y, 10.0, 0.0, 2*Math.PI); cr.fill(); //this.canvas.queue_draw(); this.canvas.queue_draw_area(x-10, y-10, 20, 20); } clearSurface() { let cr = new Cairo.Context(this.surface); cr.setSource(Cairo.SolidPattern.createRGB(1, 1, 1)); cr.paint(); } }); var DrawingApplication = GObject.registerClass({ GTypeName: "DrawingApplication" }, class DrawingApplication extends Gtk.Application { _init(v) { GLib.set_prgname("Program"); super._init({ application_id: "org.sasakima.drawwin", flags: Gio.ApplicationFlags.HANDLES_OPEN }); } vfunc_startup() { super.vfunc_startup(); new DrawingWindow(this); } vfunc_open(files, hint) { this.active_window.present(); } vfunc_activate() { this.active_window.present(); } }); new DrawingApplication().run([System.programInvocationName].concat(ARGV));
で。
となります。
ImageSurface に画像を指定して文字入れ、なんてのもこの応用で可能。
フォトレタッチとはとても言えないけど手段は解ったということで。