1gShowBounds = false 2gUseBlurInTransitions = false 3 4gPath = "resources/lua/" 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("resources/lua/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, 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 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 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 } 129end 130 131gTemplate = SkiaPoint_make_template() 132 133gRedPaint = Sk.newPaint() 134gRedPaint:setAntiAlias(true) 135gRedPaint: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-- 141local gCurrAnimation 142 143gSlideIndex = 1 144 145----------------------------------------------------------------------------- 146 147function 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 } 156end 157 158function 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 } 167end 168 169function 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()) 173end 174 175function 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()) 179end 180 181function 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 } 195end 196 197gNewDrawableFactory = { 198 default = new_drawable_slide, 199 picture = convert_to_picture_drawable, 200 image = convert_to_image_drawable, 201} 202 203----------------------------------------------------------------------------- 204 205function 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 212end 213 214function 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 221end 222 223gDrawableType = "default" 224 225load_file("slides_transitions") 226 227function 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) 242end 243 244-------------------------------------------------------------------------------------- 245 246function 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 } 266end 267 268function 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 } 293end 294 295local bgPaint = nil 296 297function 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) 307end 308 309function 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 327end 328 329function onClickHandler(x, y) 330 return false 331end 332 333local 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 349function onCharHandler(uni) 350 local proc = keyProcs[uni] 351 if proc then 352 proc() 353 return true 354 end 355 return false 356end 357