1gShowBounds = false
2gUseBlurInTransitions = false
3
4gPath = "/skia/trunk/resources/"
5
6function load_file(file)
7    local prev_path = package.path
8    package.path = package.path .. ";" .. gPath .. file .. ".lua"
9    require(file)
10    package.path = prev_path
11end
12
13load_file("slides_utils")
14
15gSlides = parse_file(io.open("/skia/trunk/resources/slides_content2.lua", "r"))
16
17function make_rect(l, t, r, b)
18    return { left = l, top = t, right = r, bottom = b }
19end
20
21function make_paint(typefacename, stylebits, size, color)
22    local paint = Sk.newPaint();
23    paint:setAntiAlias(true)
24    paint:setSubpixelText(true)
25    paint:setTypeface(Sk.newTypeface(typefacename, stylebits))
26    paint:setTextSize(size)
27    paint:setColor(color)
28    return paint
29end
30
31function draw_bullet(canvas, x, y, paint, indent)
32    if 0 == indent then
33        return
34    end
35    local ps = paint:getTextSize()
36    local cx = x - ps * .8
37    local cy = y - ps * .4
38    local radius = ps * .2
39    canvas:drawCircle(cx, cy, radius, paint)
40end
41
42function stroke_rect(canvas, rect, color)
43    local paint = Sk.newPaint()
44    paint:setStroke(true);
45    paint:setColor(color)
46    canvas:drawRect(rect, paint)
47end
48
49function drawSlide(canvas, slide, master_template)
50
51    if #slide == 1 then
52        template = master_template.title
53        canvas:drawText(slide[1].text, 320, 240, template[1])
54        return
55    end
56
57    template = master_template.slide
58
59    local x = template.margin_x
60    local y = template.margin_y
61    local scale = 1.25
62
63    if slide.blockstyle == "code" then
64        local paint = master_template.codePaint
65        local fm = paint:getFontMetrics()
66        local height = #slide * (fm.descent - fm.ascent)
67        y = (480 - height) / 2
68        for i = 1, #slide do
69            local node = slide[i]
70            y = y - fm.ascent * scale
71            canvas:drawText(node.text, x, y, paint)
72            y = y + fm.descent * scale
73        end
74        return
75    end
76
77    for i = 1, #slide do
78        local node = slide[i]
79        local paint = template[node.indent + 1].paint
80        local extra_dy = template[node.indent + 1].extra_dy
81        local fm = paint:getFontMetrics()
82        local x_offset = -fm.ascent * node.indent * 1.25
83
84        local bounds = make_rect(x + x_offset, y, 620, 640)
85        local blob, newBottom = Sk.newTextBlob(node.text, bounds, paint)
86        draw_bullet(canvas, x + x_offset, y - fm.ascent, paint, node.indent)
87        canvas:drawTextBlob(blob, 0, 0, paint)
88        y = newBottom + paint:getTextSize() * .5 + extra_dy
89
90        if gShowBounds then
91            bounds.bottom = newBottom
92            stroke_rect(canvas, bounds, {a=1,r=0,g=1,b=0})
93            stroke_rect(canvas, blob:bounds(), {a=1,r=1,g=0,b=0})
94        end
95
96    end
97end
98
99--------------------------------------------------------------------------------------
100function make_tmpl(paint, extra_dy)
101    return { paint = paint, extra_dy = extra_dy }
102end
103
104function SkiaPoint_make_template()
105    local title = {
106        margin_x = 30,
107        margin_y = 100,
108    }
109    title[1] = make_paint("Arial", 1, 45, { a=1, r=1, g=1, b=1 })
110    title[1]:setTextAlign("center")
111    title[2] = make_paint("Arial", 1, 25, { a=1, r=.75, g=.75, b=.75 })
112    title[2]:setTextAlign("center")
113
114    local slide = {
115        margin_x = 20,
116        margin_y = 25,
117    }
118    slide[1] = make_tmpl(make_paint("Arial", 1, 35, { a=1, r=1, g=1, b=1 }), 18)
119    slide[2] = make_tmpl(make_paint("Arial", 0, 25, { a=1, r=1, g=1, b=1 }), 10)
120    slide[3] = make_tmpl(make_paint("Arial", 0, 20, { a=1, r=.9, g=.9, b=.9 }), 5)
121
122    return {
123        title = title,
124        slide = slide,
125        codePaint = make_paint("Courier", 0, 20, { a=1, r=.9, g=.9, b=.9 }),
126    }
127end
128
129gTemplate = SkiaPoint_make_template()
130
131gRedPaint = Sk.newPaint()
132gRedPaint:setAntiAlias(true)
133gRedPaint:setColor{a=1, r=1, g=0, b=0 }
134
135-- animation.proc is passed the canvas before drawing.
136-- The animation.proc returns itself or another animation (which means keep animating)
137-- or it returns nil, which stops the animation.
138--
139local gCurrAnimation
140
141gSlideIndex = 1
142
143-----------------------------------------------------------------------------
144
145function new_drawable_picture(pic)
146    return {
147        picture = pic,
148        width = pic:width(),
149        height = pic:height(),
150        draw = function (self, canvas, x, y, paint)
151            canvas:drawPicture(self.picture, x, y, paint)
152        end
153    }
154end
155
156function new_drawable_image(img)
157    return {
158        image = img,
159        width = img:width(),
160        height = img:height(),
161        draw = function (self, canvas, x, y, paint)
162            canvas:drawImage(self.image, x, y, paint)
163        end
164    }
165end
166
167function convert_to_picture_drawable(slide)
168    local rec = Sk.newPictureRecorder()
169    drawSlide(rec:beginRecording(640, 480), slide, gTemplate)
170    return new_drawable_picture(rec:endRecording())
171end
172
173function convert_to_image_drawable(slide)
174    local surf = Sk.newRasterSurface(640, 480)
175    drawSlide(surf:getCanvas(), slide, gTemplate)
176    return new_drawable_image(surf:newImageSnapshot())
177end
178
179function new_drawable_slide(slide)
180    return {
181        slide = slide,
182        draw = function (self, canvas, x, y, paint)
183            if (nil == paint or ("number" == type(paint) and (1 == paint))) then
184                canvas:save()
185            else
186                canvas:saveLayer(paint)
187            end
188            canvas:translate(x, y)
189            drawSlide(canvas, self.slide, gTemplate)
190            canvas:restore()
191        end
192    }
193end
194
195gNewDrawableFactory = {
196    default = new_drawable_slide,
197    picture = convert_to_picture_drawable,
198    image = convert_to_image_drawable,
199}
200
201-----------------------------------------------------------------------------
202
203function next_slide()
204    local prev = gSlides[gSlideIndex]
205
206    if gSlideIndex < #gSlides then
207        gSlideIndex = gSlideIndex + 1
208        spawn_transition(prev, gSlides[gSlideIndex], true)
209    end
210end
211
212function prev_slide()
213    local prev = gSlides[gSlideIndex]
214
215    if gSlideIndex > 1 then
216        gSlideIndex = gSlideIndex - 1
217        spawn_transition(prev, gSlides[gSlideIndex], false)
218    end
219end
220
221gDrawableType = "default"
222
223load_file("slides_transitions")
224
225function spawn_transition(prevSlide, nextSlide, is_forward)
226    local transition
227    if is_forward then
228        transition = gTransitionTable[nextSlide.transition]
229    else
230        transition = gTransitionTable[prevSlide.transition]
231    end
232
233    if not transition then
234        transition = fade_slide_transition
235    end
236
237    local prevDrawable = gNewDrawableFactory[gDrawableType](prevSlide)
238    local nextDrawable = gNewDrawableFactory[gDrawableType](nextSlide)
239    gCurrAnimation = transition(prevDrawable, nextDrawable, is_forward)
240end
241
242--------------------------------------------------------------------------------------
243
244function spawn_rotate_animation()
245    gCurrAnimation = {
246        angle = 0,
247        angle_delta = 5,
248        pivot_x = 320,
249        pivot_y = 240,
250        proc = function (self, canvas, drawSlideProc)
251            if self.angle >= 360 then
252                drawSlideProc(canvas)
253                return nil
254            end
255            canvas:translate(self.pivot_x, self.pivot_y)
256            canvas:rotate(self.angle)
257            canvas:translate(-self.pivot_x, -self.pivot_y)
258            drawSlideProc(canvas)
259
260            self.angle = self.angle + self.angle_delta
261            return self
262        end
263    }
264end
265
266function spawn_scale_animation()
267    gCurrAnimation = {
268        scale = 1,
269        scale_delta = .95,
270        scale_limit = 0.2,
271        pivot_x = 320,
272        pivot_y = 240,
273        proc = function (self, canvas, drawSlideProc)
274            if self.scale < self.scale_limit then
275                self.scale = self.scale_limit
276                self.scale_delta = 1 / self.scale_delta
277            end
278            if self.scale > 1 then
279                drawSlideProc(canvas)
280                return nil
281            end
282            canvas:translate(self.pivot_x, self.pivot_y)
283            canvas:scale(self.scale, self.scale)
284            canvas:translate(-self.pivot_x, -self.pivot_y)
285            drawSlideProc(canvas)
286
287            self.scale = self.scale * self.scale_delta
288            return self
289        end
290    }
291end
292
293local bgPaint = nil
294
295function draw_bg(canvas)
296    if not bgPaint then
297        bgPaint = Sk.newPaint()
298        local grad = Sk.newLinearGradient(  0,   0, { a=1, r=0, g=0, b=.3 },
299                                          640, 480, { a=1, r=0, g=0, b=.8 })
300        bgPaint:setShader(grad)
301        bgPaint:setDither(true)
302    end
303
304    canvas:drawPaint(bgPaint)
305end
306
307function onDrawContent(canvas, width, height)
308    local matrix = Sk.newMatrix()
309    matrix:setRectToRect(make_rect(0, 0, 640, 480), make_rect(0, 0, width, height), "center")
310    canvas:concat(matrix)
311
312    draw_bg(canvas)
313
314    local drawSlideProc = function(canvas)
315        drawSlide(canvas, gSlides[gSlideIndex], gTemplate)
316    end
317
318    if gCurrAnimation then
319        gCurrAnimation = gCurrAnimation:proc(canvas, drawSlideProc)
320        return true
321    else
322        drawSlideProc(canvas)
323        return false
324    end
325end
326
327function onClickHandler(x, y)
328    return false
329end
330
331local keyProcs = {
332    n = next_slide,
333    p = prev_slide,
334    r = spawn_rotate_animation,
335    s = spawn_scale_animation,
336    ["="] = function () scale_text_delta(gTemplate, 1) end,
337    ["-"] = function () scale_text_delta(gTemplate, -1) end,
338
339    b = function () gShowBounds = not gShowBounds end,
340    B = function () gUseBlurInTransitions = not gUseBlurInTransitions end,
341
342    ["1"] = function () gDrawableType = "default" end,
343    ["2"] = function () gDrawableType = "picture" end,
344    ["3"] = function () gDrawableType = "image" end,
345}
346
347function onCharHandler(uni)
348    local proc = keyProcs[uni]
349    if proc then
350        proc()
351        return true
352    end
353    return false
354end
355