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