summaryrefslogtreecommitdiff
path: root/ui.lua
blob: 914031d579be6dc49eba52a6aaab09eec7e81937 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
-- luaxpedite UI

local ffi = require("ffi")
local C = ffi.C

local io_write = io.write
local collectgarbage = collectgarbage
local require = require

local util = require("util")
local get_time = util.get_time

local p_fps = 0
local key_func, loop_func

local start = 0

local t_start, t_loop = 0, 0
local f_start, f_loop = 0, 0
local t_name

local data_dir

local menu_active = false

local win_w, win_h

local o_bg, o_wallpaper, o_title, o_byline, o_menu_logo, o_menu_icon,
      o_menu_icon_sel, o_menu_icon_sel2, o_menu_text_sel, o_menu_title
local o_text -- about

local menu = {}
local menu_queue = {}

local menu_sel = 1
local menu_active = false
local menu_anim = 0
local menu_anim_sel = 0

local async_render = false
local cmp_report = false
local profile, engine, loops, fullscreen

local levas = util.get_lib("evas")

local ffi_new = ffi.new
local ffi_cast = ffi.cast
local ffi_str = ffi.string
local sin, cos = math.sin, math.cos

local evas

local M = {}

local ui_func_set, ui_menu, ui_loop

local fpsbuf
local ui_fps = function(fps)
    --fpsbuf = ("ESCAPE - exit, FPS: %4.3f"):format(fps)
    --levas.evas_object_text_text_set(o_byline, fpsbuf)
    p_fps = fps
end

local test_done = false

local ui_fps_std = function(name, t, f)
    if f >= loops and not test_done then
        local fps = f / t
        ui_fps(fps)
        io_write(("%4.2f , %s\n"):format(fps, name))
        --io_write(("Memory usage: %d\n"):format(collectgarbage("count")))
        test_done = true
    end
end

ffi.cdef [[
    struct tm;
    typedef long time_t;
    time_t time(time_t *timer);

    int snprintf   (char *buf, size_t maxlen, const char *fmt, ...);
    size_t strftime(char *buf, size_t maxlen, const char *fmt,
        const struct tm *tp, ...);
    struct tm *localtime(const time_t *timer);
]]

local ui_hide_menu = function()
    levas.evas_object_hide(o_menu_logo)
    levas.evas_object_hide(o_menu_title)
    levas.evas_object_hide(o_menu_icon)
    levas.evas_object_hide(o_menu_icon_sel)
    levas.evas_object_hide(o_menu_icon_sel2)
    levas.evas_object_hide(o_menu_text_sel)
    levas.evas_object_hide(o_title)
    levas.evas_object_hide(o_byline)
end

local ui_all; ui_all = function()
    local fps, wfps = 0, 0
    ui_hide_menu()
    local avgw, t_count = 0, 0
    for i = 1, #menu do
        local mi = menu[i]
        local weight = mi.weight
        if not weight then goto loopend end
        avgw, t_count = avgw + weight, t_count + 1
        if mi.func then
            t_name = mi.text
            mi.func()
        end
        levas.evas_object_hide(o_title)
        levas.evas_object_hide(o_byline)

        if async_render then goto async_loop end

        while p_fps == 0 do
            engine_loop()
            ui_loop()
            levas.evas_render(evas)
        end
        levas.evas_render(evas)
        goto finish

        ::async_loop::
        while p_fps == 0 do
            engine_loop()
            ui_loop()
            levas.evas_sync(evas)
            levas.evas_render_async(evas)
        end
        levas.evas_sync(evas)
        levas.evas_render_async(evas)

        ::finish::
        fps = fps + p_fps
        wfps = wfps + (p_fps * weight)
        key_func("Escape")
        ::loopend::
    end
    avgw = avgw / t_count
    if t_count > 0 then
        local datestr = ffi_new("char[1024]")
        local now = ffi_new("time_t[1]", C.time(nil))
        local tim = C.localtime(now)
        if tim ~= nil then C.strftime(datestr, 1024, "%Y-%m-%d %H:%M:%S", tim)
        else C.snprintf(datestr, 1024, "unknown") end
        --print(("%5.2f , EVAS SPEED"):format(fps / t_count))
        if cmp_report then
            io_write(("%5.2f , EVAS SPEED (WEIGHTED), "
            .. "tn, %i , "
            .. "t, %s , "
            .. "ev , %i.%i.%i.%i , "
            .. "p , %s , "
            .. "sz , %i , %i , "
            .. "c , %i , "
            .. "e , %s , "
            .. "fs , %i\n"):format(wfps / (t_count * avgw),
                --fps / t_count,
                t_count, ffi_str(datestr), levas.evas_version.major,
                levas.evas_version.minor, levas.evas_version.micro,
                levas.evas_version.revision, profile.name, win_w, win_h,
                loops, engine[1], fullscreen and 1 or 0))
        else
            io_write(("\n#####Test Result#####\n"
            .. "evas fps speed: %5.2f\n"
            .. "evas fps speed(weighted): %5.2f\n"
            .. "testcase count: %i\n"
            .. "date: %s\n"
            .. "evas version: %i.%i.%i.%i\n"
            .. "profile: %s\n"
            .. "window size: %i, %i\n"
            .. "loop count: %i\n"
            .. "engine: %s\n"
            .. "full screen: %i\n"):format(fps / t_count,
                (wfps / avgw) / t_count,
                t_count, ffi_str(datestr), levas.evas_version.major,
                levas.evas_version.minor, levas.evas_version.micro,
                levas.evas_version.revision, profile.name, win_w, win_h,
                loops, engine[1], fullscreen and 1 or 0))
        end
    end
end

local ui_num = function(n)
    local fps, wfps = 0, 0
    local t_count = 0
    ui_hide_menu()
    local mi = menu[n]
    if mi then
        local weight = mi.weight
        if not weight then goto done end
        if mi.func then
            t_name = mi.text
            mi.func()
        end
        levas.evas_object_hide(o_title)
        levas.evas_object_hide(o_byline)

        if async_render then goto async_loop end

        while p_fps == 0 do
            engine_loop()
            ui_loop()
            levas.evas_render(evas)
        end
        levas.evas_render(evas)
        goto finish

        ::async_loop::
        while p_fps == 0 do
            engine_loop()
            ui_loop()
            levas.evas_sync(evas)
            levas.evas_render_async(evas)
        end
        levas.evas_sync(evas)
        levas.evas_render_async(evas)

        ::finish::
        t_count = t_count + 1
        fps = fps + p_fps
        wfps = wfps + (p_fps * weight)
        key_func("Escape")
    end
::done::
    local avgw, wn = 0, 0
    for i = 1, #menu do
        local weight = menu[i].weight
        if weight then avgw, wn = avgw + weight, wn + 1 end
    end
    avgw = avgw / wn
    if t_count > 0 then
        io_write(("%5.2f , EVAS SPEED (WEIGHTED)\n")
            :format(wfps / (t_count * avgw)))
    end
end

local ui_select = function()
    local func, text
    ui_hide_menu()
    for i = 1, #menu do
        local mi = menu[i]
        if mi.o_icon then levas.evas_object_hide(mi.o_icon) end
        if i == menu_sel then func, text = mi.func, mi.text end
    end
    menu_active = false
    if func then
        t_name = text
        func()
    end
    levas.evas_object_hide(o_title)
    levas.evas_object_hide(o_byline)
end

local about_start = function()
    ui_func_set(function()
        levas.evas_object_del(o_text)
        o_text = nil
    end, function(t, f) end)

    local o = levas.evas_object_textblock_add(evas)
    levas.evas_object_move(o, 10, 40)
    levas.evas_object_resize(o, win_w - 20, win_h - 50)
    levas.evas_object_show(o)
    local st = levas.evas_textblock_style_new()
    levas.evas_textblock_style_set(st,
        "DEFAULT='font=Vera font_size=8 align=left color=#000 wrap=word'"
        .. "center='+ font=Vera font_size=10 align=center'"
        .. "/center='- \n \n'"
        .. "p='+ font=Vera font_size=10 align=left'"
        .. "/p='- \n \n'")
    levas.evas_object_textblock_style_set(o, st)
    levas.evas_object_textblock_clear(o)
    levas.evas_object_textblock_text_markup_set(o,
        "<center>"
        .. "Enlightenment used to be a window manager project, but "
        .. "since has changed a lot to become a miniature desktop and "
        .. "mobile device environment all of its own. It is now made up "
        .. "of many components (libraries and applications) that have "
        .. "specific uses. It is very large, and so requires more testing "
        .. "and demonstration.</center>"

        .. "<center>"
        .. "Expedite is a full test suite for Evas, which is one of the "
        .. "core components of the Enlightenment Foundation Libraries. "
        .. "Evas handles the realtime display canvas used by EFL "
        .. "applications to render to many targets, including "
        .. "framebuffer, X11, OpenGL, memory, DirectFB and other targets "
        .. "to boot. It handles high level graphic layout descriptions "
        .. "that applications set up, dealing with the hard work of doing "
        .. "the drawing for them.</center>"

        .. "<center>"
        .. "Luaxpedite is a proof of concept pure-LuaJIT port of Expedite "
        .. "created to test performance and usefulness of LuaJIT in real "
        .. "world application programming.</center>")
    levas.evas_textblock_style_free(st)
    o_text = o
    ui_fps(0)
end

ffi.cdef [[
    void sync();
]]

M.setup = function(conf)
    win_w, win_h = conf.profile.w, conf.profile.h
    data_dir = conf.datadir
    async_render = conf.async
    cmp_report = conf.ecmp
    profile = conf.profile
    engine = conf.engine
    loops = conf.loops
    evas = conf.evas
    fullscreen = conf.fullscreen
    M.evas = evas
    M.win_w, M.win_h = win_w, win_h
    local x, y
    local w, h = ffi_new("Evas_Coord[1]"), ffi_new("Evas_Coord[1]")

    local o = levas.evas_object_rectangle_add(evas)
    levas.evas_object_move(o, 0, 0)
    levas.evas_object_resize(o, win_w, win_h)
    levas.evas_object_color_set(o, 0, 0, 0, 0)
    levas.evas_object_layer_set(o, 1000)
    levas.evas_object_focus_set(o, 1)
    levas.evas_object_show(o)

    local down_x, down_y
    local down_menu_sel = 1

    levas.evas_object_event_callback_add(o, levas.EVAS_CALLBACK_KEY_DOWN,
        function(data, e, obj, event_info)
            local ev = ffi_cast("Evas_Event_Key_Down*", event_info)
            local kn = ffi_str(ev.keyname)
            if key_func then
                key_func(kn)
                return
            end
            if kn == "Escape" or kn == "q" or kn == "Q" then
                engine_abort()
            end
            if menu_active then
                if     kn == "Left"     then menu_sel = menu_sel + 1
                elseif kn == "Right"    then menu_sel = menu_sel - 1 end
                if     menu_sel <= 0    then menu_sel = 1
                elseif menu_sel > #menu then menu_sel = #menu end
                menu_anim_sel = menu_sel - 1
                if kn == "Return" then ui_select() end
            end
        end, nil)
    levas.evas_object_event_callback_add(o, levas.EVAS_CALLBACK_MOUSE_DOWN,
        function(data, e, obj, event_info)
            local ev = ffi_cast("Evas_Event_Mouse_Down*", event_info)
            if ev.button ~= 1 then return end
            if menu_active then
                down_x = ev.canvas.x
                down_y = ev.canvas.y
                down_menu_sel = menu_sel
            end
        end, nil)
    levas.evas_object_event_callback_add(o, levas.EVAS_CALLBACK_MOUSE_UP,
        function(data, e, obj, event_info)
            local ev = ffi_cast("Evas_Event_Mouse_Up*", event_info)
            if ev.button ~= 1 then return end
            if menu_active then
                local dx, dy = ev.canvas.x - down_x, ev.canvas.y - down_y
                if (((dx * dx) + (dy * dy)) < (20 * 20)) and
                    (menu_sel == down_menu_sel) then ui_select() end
            else
                levas.evas_event_feed_key_down(evas, "Escape", "Escape",
                    nil, nil, 0, nil)
                levas.evas_event_feed_key_up(evas, "Escape", "Escape",
                    nil, nil, 0, nil)
            end
        end, nil)
    levas.evas_object_event_callback_add(o, levas.EVAS_CALLBACK_MOUSE_MOVE,
        function(data, e, obj, event_info)
            local ev = ffi_cast("Evas_Event_Mouse_Move*", event_info)
            if ev.buttons ~= 1 then return end
            if menu_active then
                menu_sel = down_menu_sel + ((ev.cur.canvas.x - down_x) / 25)
                if     menu_sel <= 0    then menu_sel = 1
                elseif menu_sel > #menu then menu_sel = #menu end
                menu_anim_sel = menu_sel
            end
        end, nil)
    o_bg = o

    o = levas.evas_object_rectangle_add(evas)
    levas.evas_object_move(o, 0, 0)
    levas.evas_object_resize(o, win_w, win_h)
    levas.evas_object_color_set(o, 255, 255, 255, 255)
    levas.evas_object_layer_set(o, -99)
    levas.evas_object_show(o)
    o_wallpaper = o

    o = levas.evas_object_text_add(evas)
    levas.evas_object_text_font_set(o, "Vera-Bold", 10)
    levas.evas_object_text_text_set(o, "LUAXPEDITE")
    levas.evas_object_layer_set(o, 100)
    levas.evas_object_color_set(o, 0, 0, 0, 100)
    levas.evas_object_pass_events_set(o, 1)
    levas.evas_object_geometry_get(o, nil, nil, w, h)
    x = (win_w - w[0]) / 2
    y = 0
    levas.evas_object_move(o, x, y)
    levas.evas_object_show(o)
    o_title = o

    o = levas.evas_object_text_add(evas)
    levas.evas_object_text_font_set(o, "Vera", 9)
    levas.evas_object_text_text_set(o,
        "LEFT/RIGHT - select, ENTER - select, ESCAPE - exit.")
    levas.evas_object_layer_set(o, 100)
    levas.evas_object_color_set(o, 0, 0, 0, 60)
    levas.evas_object_pass_events_set(o, 1)
    levas.evas_object_geometry_get(o, nil, nil, w, nil)
    x = (win_w - w[0]) / 2
    y = h[0] + 2
    levas.evas_object_move(o, x, y)
    levas.evas_object_show(o)
    o_byline = o

    o = levas.evas_object_image_add(evas)
    levas.evas_object_move(o, (win_w - 120) / 2, ((win_h - 160) / 2))
    levas.evas_object_image_file_set(o, util.build_path("e-logo.png"), nil)
    levas.evas_object_image_fill_set(o, 0, 0, 120, 160)
    levas.evas_object_resize(o, 120, 160)
    levas.evas_object_layer_set(o, -98)
    levas.evas_object_color_set(o, 255, 255, 255, 255)
    levas.evas_object_show(o)
    o_menu_logo = o

    o = levas.evas_object_image_add(evas)
    levas.evas_object_move(o, win_w - 128, -128)
    levas.evas_object_image_fill_set(o, 0, 0, 256, 256)
    levas.evas_object_resize(o, 256, 256)
    levas.evas_object_show(o)
    o_menu_icon = o

    o = levas.evas_object_image_add(evas)
    levas.evas_object_move(o, 0, 0)
    levas.evas_object_image_file_set(o, util.build_path("icon_sel.png"), nil)
    levas.evas_object_resize(o, 48, 48)
    levas.evas_object_image_fill_set(o, 0, 0, 48, 48)
    o_menu_icon_sel = o

    o = levas.evas_object_image_add(evas)
    levas.evas_object_move(o, 0, 0)
    levas.evas_object_image_file_set(o, util.build_path("text_sel.png"), nil)
    levas.evas_object_resize(o, 96, 32)
    levas.evas_object_image_fill_set(o, 0, 0, 96, 32)
    levas.evas_object_image_border_set(o, 7, 7, 7, 7)
    o_menu_text_sel = o

    o = levas.evas_object_text_add(evas)
    levas.evas_object_text_font_set(o, "Vera", 10)
    levas.evas_object_text_text_set(o, "")
    levas.evas_object_color_set(o, 0, 0, 0, 100)
    levas.evas_object_pass_events_set(o, 1)
    levas.evas_object_geometry_get(o, nil, nil, w, h)
    x = (win_w - w[0]) / 2
    y = (win_h - h[0]) / 2
    levas.evas_object_move(o, x, y)
    o_menu_title = o

    local menu_item_add = function(icon, text, weight, func)
        local mi = { icon = icon, text = text, weight = weight, func = func }
        mi.o_icon = levas.evas_object_image_add(evas)
        local ic = mi.o_icon
        if ic then
            levas.evas_object_image_file_set(ic, util.build_path(icon), nil)
            levas.evas_object_resize(ic, 32, 32)
            levas.evas_object_image_fill_set(ic, 0, 0, 32, 32)
        end
        menu[#menu + 1] = mi
        levas.evas_object_raise(o_menu_icon_sel2)
    end

    menu_item_add("e.png", "About", nil, about_start)
    menu_item_add("e.png", "All tests", nil, ui_all)
    for i = 1, #menu_queue do
        menu_item_add(unpack(menu_queue[i]))
    end
    menu_item_add("exit.png", "Exit", nil, engine_abort)

    if ffi.os ~= "Windows" then
        C.sync()
        C.sync()
        C.sync()
    end

    local autorun = conf.autorun
    local testn = conf.test

    if autorun then
        local t0 = C.time(nil)
        while true do
            local t = C.time(nil)
            if (t - t0) > 2 then break end
        end
    end

    local exit_after_test = false
    if autorun then
        ui_all()
        exit_after_test = true
    elseif testn and testn > 0 then
        ui_num(testn)
        exit_after_test = true
    elseif conf.list then
        local j = 1
        for i = 1, #menu do
            if menu[i].weight then
                io_write(("%3i - %s (Weight %0.2f)\n"):format(j,
                    menu[i].text, menu[i].weight))
                j = j + 1
            end
        end
    else
        menu_active = true
    end

    if exit_after_test then
        engine_abort()
    end

    start = get_time()
end

local loop_pt = 0
local loop_first = true
local loop_tr = 0
M.loop = function()
    local t, t2

    levas.evas_object_resize(o_bg, win_w, win_h)
    levas.evas_object_resize(o_wallpaper, win_w, win_h)
    if loop_func then
        t = get_time()
        f_loop = f_loop + 1
        f_start = f_start + 1
        if (t - t_loop) >= 1 then
            --ui_fps(f_loop / (t - t_loop))
            t_loop = t
            f_loop = 0
        end
        local t, f = t - t_start, f_start
        loop_func(t, f)
        ui_fps_std(t_name, t, f)
        return
    end
    t2 = get_time()
    if loop_first then
        t = 0.1
        loop_pt = t2
    else
        t = t2 - loop_pt
        loop_pt = t2
    end
    loop_first = false

    -- menu layout
    if menu_active then
        local tt = t
        tt = tt + loop_tr
        while tt > 0.001 do
            menu_anim = (menu_anim * 0.995) + (menu_anim_sel * 0.005)
            tt = tt - 0.001
        end
        loop_tr = tt
        for i = 1, #menu do
            local mi = menu[i]
            local o = mi.o_icon
            local w, h = ffi_new("Evas_Coord[1]"), ffi_new("Evas_Coord[1]")
            levas.evas_object_geometry_get(o_menu_logo, nil, nil, w, h)
            len = ((w[0] * 3) + 10) / 4
            levas.evas_object_geometry_get(o, nil, nil, w, h)
            local x = (win_w / 2) + (sin((menu_anim - i + 1) * 0.33) * len)
                - (w[0] / 2)
            local y = (win_h / 2) + (cos((menu_anim - i + 1) * 0.33) * len)
                - (h[0] / 2)
            levas.evas_object_move(o, x, y)
            local a = menu_anim - i + 1
            if a < 0 then a = -a end
            a = 255 - (30 * a)
            levas.evas_object_color_set(o, a, a, a, a)
            levas.evas_object_show(o)
            if i == menu_sel then
                a = menu_anim - i + 1
                if a < 0 then a = -a end
                a = 255 - (255 * a)
                o = o_menu_icon_sel
                levas.evas_object_move(o, x - ((48 - w[0]) / 2),
                                      y - ((48 - h[0]) / 2))
                levas.evas_object_color_set(o, a, a, a, a)
                o = o_menu_title
                local tw, th = ffi_new("Evas_Coord[1]"),
                               ffi_new("Evas_Coord[1]")
                levas.evas_object_color_set(o, a, a, a, a)
                levas.evas_object_text_text_set(o, mi.text)
                levas.evas_object_geometry_get(o, nil, nil, tw, th)
                x = (win_w - tw[0]) / 2
                y = (win_h / 2) + len + 48
                levas.evas_object_move(o, x, y)
                o = o_menu_text_sel
                w[0] = tw[0] + 24
                h[0] = 28
                x = x - 12
                y= y + ((th[0] - h[0]) / 2)
                levas.evas_object_move(o, x, y)
                levas.evas_object_resize(o, w[0], h[0])
                levas.evas_object_image_fill_set(o, 0, 0, w[0], h[0])
                levas.evas_object_color_set(o, a, a, a, a)
                o = o_menu_icon
                local buf = data_dir .. mi.icon
                levas.evas_object_image_file_set(o, buf, nil)
                levas.evas_object_color_set(o, a / 2, a / 2, a / 2, a / 2)
            end
        end
        levas.evas_object_move(o_menu_logo, (win_w - 120) / 2,
                                       ((win_h - 160) / 2))
        levas.evas_object_show(o_menu_logo)
        levas.evas_object_show(o_menu_title)
        levas.evas_object_show(o_menu_icon)
        levas.evas_object_show(o_menu_icon_sel)
        levas.evas_object_show(o_menu_icon_sel2)
        levas.evas_object_show(o_menu_text_sel)
    end
end
ui_loop = M.loop

M.menu = function()
    levas.evas_object_show(o_title)
    levas.evas_object_show(o_byline)
    levas.evas_object_text_text_set(o_byline,
        "LEFT/RIGHT - select, ENTER - select, ESCAPE - exit.")
    menu_active = true
    key_func, loop_func = nil, nil
    collectgarbage()
    collectgarbage("restart")
end
ui_menu = M.menu

M.func_set = function(cleanupf, loopf)
    collectgarbage()
    collectgarbage("stop")
    loop_func = loopf
    key_func  = function(key)
        if key == "Escape" or key == "q" or key == "Q" then
            cleanupf()
            ui_menu()
        end
    end
    t_start = get_time()
    t_loop  = t_start
    f_loop, f_start = 0, 0
    test_done = false
    ui_fps(0)
end
ui_func_set = M.func_set

local queue_tests = function(tests)
    for i = 1, #tests, 2 do
        local name = "tests." .. tests[i]
        for j = 1, tests[i + 1] do
            menu_queue[#menu_queue + 1] = { require(name)(M, j) }
        end
    end
end

queue_tests {
    "widgets_file_icons",                     7,
    "widgets_list",                           8,
    "image_blend_unscaled",                   7,
    "image_blend_scaled",                    12,
    "image_map_rotate",                      12,
    "image_map_3d_1",                         4,
    "image_map_3d_2",                         2,
    "image_map_3d_flow",                      1,
    "image_quality_scale",                    1,
    "image_data_argb",                        2,
    "image_data_ycbcr601pl",                  1,
    "image_data_ycbcr601pl_wide_stride",      1,
    "image_data_ycbcr601pl_map_solid_rotate", 2,
    "image_crossfade",                        1,
    "text",                                   3,
    "text_change",                            1,
    "textblock_basic",                        1,
    "textblock_intl",                         1,
    "textblock_auto_align",                   1,
    "textblock_text_append",                  1,
    "rect",                                   6,
    "image_blend_occlude",                   12,
    "poly_blend",                             1,
    "proxy_image",                            1,
    "proxy_text_fixed",                       1,
    "proxy_text_random",                      1,
    "line_blend",                             1,
    "image_blend_many_smooth_same_scaled",    1
}

return M