3
-- based on http://svn.o-hand.com/repos/clutter/trunk/toys/courasel/
4
-- (http://git.clutter-project.org/cgit.cgi?url=toys/tree/courasel)
9
local init_duration = 1000 -- in ms
12
{ "accessories-text-editor.png", "Text Editor" },
13
{ "applications-games.png", "Game" },
14
{ "dates.png", "Dates" },
15
{ "im-client.png", "Chat" },
16
{ "preferences-desktop-theme.png", "Preferences" },
17
{ "tasks.png", "Todo List" },
18
{ "utilities-terminal.png", "Terminal" },
19
{ "web-browser.png", "Browser"},
21
local alpha_low = 0x66
22
local scale_small = 0.6
23
local ms_per_step = 400 -- higher value is lower rotation speed
24
-- end configuration --
26
local stage, timeline, csw, csh, label, label_behave
27
local items = {} -- actor, move, opacity, scale, text
28
local selected_index = 1 -- currently selected item
29
local STEP = 360 / #items_init
30
local running = 0 -- current direction (-1 or 1) or 0 when stopped
31
local alpha_sine_inc -- alpha function for the movement
32
local stop_from_pos = 0 -- at which timeline position the stop was initiated
34
local mydir = string.gsub(arg[0], "[%w.-]+$", "")
38
-- During the intro, all items start at angle -90 and move at different speeds
39
-- to their target positions. The selected item will be scaled to 1.0 and
42
function introduce_items()
43
for i, item in pairs(items) do
44
item.move:set_angle_start(-90)
45
item.move:set_angle_end(STEP * i)
47
if i == selected_index then
48
item.opacity:set('opacity-end', 0xff)
49
item.scale:set('x-scale-end', 1, 'y-scale-end', 1)
59
-- Configure the timeline to rotate one item forward or backward, then start
62
function rotate_items()
63
local from_index, ang, b, scale, opacity
66
from_index = selected_index
67
ang = 360 - from_index * STEP + 90
68
selected_index = 1 + (selected_index - step - 1 + #items) % #items
70
for i, item in ipairs(items) do
72
b:set_direction(step > 0 and clutter.ROTATE_CW or clutter.ROTATE_CCW)
73
b:set_angle_start(ang)
74
b:set_angle_end(ang + STEP * step)
76
opacity = { alpha_low, alpha_low }
77
scale = { scale_small, scale_small }
79
if i == from_index then
82
elseif i == selected_index then
87
item.opacity:set('opacity-start', opacity[1], 'opacity-end',
89
item.scale:set('x-scale-start', scale[1], 'y-scale-start',
90
scale[1], 'x-scale-end', scale[2], 'y-scale-end', scale[2])
99
-- Key Symbols are not available... yet?
101
clutter.Right = 65363
104
local handler_press = {
105
[clutter.Left] = function() running=-1; rotate_items() end,
106
[clutter.Right] = function() running=1; rotate_items() end,
110
-- Respond to some key presses.
112
function on_key_press(actor, event, self)
113
local sym = event.key:symbol()
114
if sym == clutter.q then
119
-- currently stopping - don't disturb that.
126
if timeline:is_playing() then
130
local fn = handler_press[sym]
134
-- release: may be followed immediately by press, which means that the
135
-- key is being held down.
136
function on_key_release(actor, event, self)
137
local sym = event.key:symbol()
138
if sym == clutter.Left or sym == clutter.Right then
140
stop_from_pos = timeline:get_progress()
145
function on_scroll_event(actor, event)
146
if not timeline:is_playing() then
147
running = (event.scroll.direction == clutter.SCROLL_UP) and -1 or 1
153
function movement_alpha(alpha)
154
local tl = alpha:get_timeline()
155
local p = tl:get_progress()
157
-- continuous operation: linear
158
if stop_from_pos == nil then
159
return math.floor(p * 65535)
162
-- otherwise, gradual stop
164
local range = 1 - stop_from_pos
165
local p2 = (p - stop_from_pos) / range
166
p = stop_from_pos + range * (math.sin(p2 * math.pi / 2))
168
return math.floor(p * 65535)
173
-- Change the label text at the middle of the animation, which is when
174
-- the text has been faded out.
176
function on_timeline_new_frame(timeline, frame_num, app)
177
if frame_num == math.floor(timeline:get_n_frames() / 2) then
178
label:set_text(items[selected_index].text)
184
-- Rotating should be quick, regardless of the intro speed.
186
function on_timeline_completed(timeline, frame_num, app)
187
timeline:set_duration(ms_per_step)
189
if not stop_from_pos then
195
local color, item, alpha_ramp, ac
197
stage = clutter.stage_get_default()
198
stage:set_size(800, 600)
199
stage:set_title"Clutter Carousel Demo"
201
color = clutter.new"Color"
202
color:from_pixel(0x343939ff)
203
stage:set_color(color)
205
-- the into should be 1 second long.
206
timeline = clutter.timeline_new(init_duration * fps / 1000, fps)
208
cl = gnome.closure(movement_alpha)
209
alpha_sine_inc = clutter.alpha_new_full(timeline, cl, nil, nil)
210
alpha_ramp = clutter.alpha_new_full(timeline, clutter.sine_half_func,
212
alpha_scale = clutter.alpha_new_full(timeline, clutter.sine_inc_func, nil,
215
csw = stage:get_width()
216
csh = stage:get_height()
218
for k, v in pairs(items_init) do
219
ac = clutter.texture_new_from_file(mydir .. v[1], nil)
220
assert(ac, "Couldn't load file " .. mydir .. tostring(v[1]))
224
move = clutter.behaviour_ellipse_new(alpha_sine_inc,
225
csw/4, csh-(csh/2), csw/2, csh-(csh/4),
226
clutter.ROTATE_CW, 0, 360),
227
opacity = clutter.behaviour_opacity_new(alpha_sine_inc,
228
alpha_low, alpha_low),
229
scale = clutter.behaviour_scale_new(alpha_scale,
230
scale_small, scale_small, scale_small, scale_small),
234
item.opacity:apply(ac)
237
items[#items + 1] = item
240
color:from_pixel(0x729fcfff)
241
label = clutter.label_new_with_text('Coolvetica 60px', '')
242
label:set_color(color)
243
label:set_size(300, 200)
244
label:set_line_wrap(false)
245
label:set_position(csw/2-40, 40)
246
stage:add_actor(label)
248
label_behave = clutter.behaviour_opacity_new(alpha_ramp, 0xff, 0)
249
label_behave:apply(label)
251
stage:connect('key-press-event', on_key_press)
252
stage:connect('key-release-event', on_key_release)
253
stage:connect('scroll-event', on_scroll_event)
254
timeline:connect('new-frame', on_timeline_new_frame)
255
timeline:connect('completed', on_timeline_completed)
256
stage:connect('destroy', clutter.main_quit)
265
collectgarbage"collect"
266
collectgarbage"collect"