Clutter の Effect を使う
今回は、ClutterEffect を使ってみます。ClutterActor の端っこがめくれ上がる ClutterPageTurnEffect です。残念ながら、まだ分かっていない部分もあるので、サンプルの説明はいい加減です。
はじめに C です。シグナル(イベント処理)については、また別の機会で詳しく説明するかもしれません。
#include <clutter/clutter.h> static gboolean enter_event (ClutterActor *actor, ClutterEvent *event, gpointer user_data) { ClutterTransition *transition; transition = clutter_actor_get_transition (actor, "page_turn"); clutter_transition_set_from (transition, G_TYPE_DOUBLE, 0.0); clutter_transition_set_to (transition, G_TYPE_DOUBLE, 0.5); clutter_timeline_rewind (CLUTTER_TIMELINE (transition)); clutter_timeline_start (CLUTTER_TIMELINE (transition)); printf ("enter_event\n"); return CLUTTER_EVENT_STOP; } static gboolean leave_event (ClutterActor *actor, ClutterEvent *event, gpointer user_data) { ClutterTransition *transition; transition = clutter_actor_get_transition (actor, "page_turn"); clutter_transition_set_from (transition, G_TYPE_DOUBLE, 0.5); clutter_transition_set_to (transition, G_TYPE_DOUBLE, 0.0); clutter_timeline_rewind (CLUTTER_TIMELINE (transition)); clutter_timeline_start (CLUTTER_TIMELINE (transition)); printf ("leave_event\n"); return CLUTTER_EVENT_STOP; } int main (int argc, char *argv[]) { ClutterActor *stage, *actor; ClutterEffect *page_turn; ClutterTransition *transition; ClutterInterval *interval; if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; stage = clutter_stage_new (); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); actor = clutter_actor_new (); clutter_actor_set_background_color (actor, clutter_color_get_static (CLUTTER_COLOR_RED)); clutter_actor_set_reactive (actor, TRUE); clutter_actor_set_size (actor, 100, 100); clutter_actor_set_position (actor, 100, 100); g_signal_connect (actor, "enter-event", G_CALLBACK (enter_event), NULL); g_signal_connect (actor, "leave-event", G_CALLBACK (leave_event), NULL); page_turn = clutter_page_turn_effect_new (0.0, 60.0, 10.0); clutter_actor_add_effect_with_name (actor, "page_turn", page_turn); transition = clutter_property_transition_new ("@effects.page_turn.period"); clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 250); clutter_actor_add_transition (actor, "page_turn", transition); g_object_unref (transition); clutter_actor_add_child (stage, actor); clutter_actor_show (stage); clutter_main (); return 0; }
マウスカーソルが ClutterActor に入る時と出る時に、enter_event() と leave_event() が呼ばれます。それらの中身を説明する前に、main() を見ていきます。最初は飛ばして、、、
clutter_actor_set_reactive (actor, TRUE);
この行で、ClutterActor がシグナルに反応するようになります。ちょっと飛んで、、、
g_signal_connect (actor, "enter-event", G_CALLBACK (enter_event), NULL); g_signal_connect (actor, "leave-event", G_CALLBACK (leave_event), NULL);
この2行で、マウスの enter-event と leave-event が発生するたびに、それぞれ enter_event() と leave_event() を呼び出すようにします。
page_turn = clutter_page_turn_effect_new (0.0, 60.0, 10.0); clutter_actor_add_effect_with_name (actor, "page_turn", page_turn);
この2行で、 page_turn という ClutterPageTurnEffectを作成し、"page_turn"という名前で actor に追加します。
transition = clutter_property_transition_new ("@effects.page_turn.period"); clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 250); clutter_actor_add_transition (actor, "page_turn", transition); g_object_unref (transition);
そして、ここがよくわからないところ。ClutterTransition は ClutterActor に追加の機能を与えるものなのですが、作成時に property-name が必要になります。今回は ClutterActor に ClutterEffect を追加して、名前が page_turn で ClutterPageTurnEffect の period プロパティを変更するので、 "@effects.page_turn.periog" で作成するのですが、命名方法がわかっていません。
しかし、これで動くのでよしとします。
名前付きで作成し、アニメーション時間を 250 ms に設定し、ClutterActor に ClutterTransition を追加しています。devhelp にあるように、最後は g_object_unref() します。
こうしておいて、コールバック関数では、以下のようにします。
transition = clutter_actor_get_transition (actor, "page_turn"); clutter_transition_set_from (transition, G_TYPE_DOUBLE, 0.0); clutter_transition_set_to (transition, G_TYPE_DOUBLE, 0.5); clutter_timeline_rewind (CLUTTER_TIMELINE (transition)); clutter_timeline_start (CLUTTER_TIMELINE (transition));
ClutterActor の ClutterTransition を名前で呼び出し、period の最初と最後の値を設定し、タイマーを巻き戻し、タイマーをスタートします。 period はページをめくる量で、0.0はめくっていない 1.0 が完全にめくっている状態です。
こんな感じで、ページをめくるサンプルが完成です。devhelp の ClutterDragAction にサンプルがあるので、そっちを見たほうが良いかもしれません。
次に Gjs です。
#! /usr/bin/env gjs const Clutter = imports.gi.Clutter; const GObject = imports.gi.GObject; function enter_event(actor, event, user_data) { let transition = actor.get_transition("page_turn"); let interval = transition.get_interval(); interval.set_initial(0.0); interval.set_final(0.5); transition.rewind(); transition.start(); } function leave_event(actor, event, user_data) { let transition = actor.get_transition("page_turn"); let interval = transition.get_interval(); interval.set_initial(0.5); interval.set_final(0.0); transition.rewind(); transition.start(); } Clutter.init(null); let stage = new Clutter.Stage(); stage.connect('destroy', Clutter.main_quit); let actor = new Clutter.Actor(); actor.set_background_color(Clutter.Color.get_static (Clutter.StaticColor.RED)); actor.set_reactive(true); actor.set_size(100, 100); actor.set_position(100, 100); actor.connect('enter-event', enter_event); actor.connect('leave-event', leave_event); let page_turn = new Clutter.PageTurnEffect({period:0.0, angle:60.0, radius:10.0}); actor.add_effect_with_name("page_turn", page_turn); let transition = new Clutter.PropertyTransition({property_name:"@effects.page_turn.period"}); transition.set_duration(250); actor.add_transition("page_turn", transition); let interval = new Clutter.Interval({value_type:GObject.TYPE_DOUBLE}); transition.set_interval(interval); stage.add_child(actor); stage.show(); Clutter.main();
基本は変わりませんが、ClutterTransition の set_from() と set_to() メソッドが使えなかったので、 ClutterTransition の最初と最後の値を保持する ClutterInterval を利用して、値を設定します。実はこの方法もよくわからなかったので、BUG だと投げて叱られた経緯があります。。。https://bugzilla.gnome.org/show_bug.cgi?id=683952
ClutterTransition ではなく ClutterInterval を使うことだけ理解できれば説明は不要ですね。