// Copyright (c) 2022 Marceline Cramer // SPDX-License-Identifier: AGPL-3.0-or-later #[global_allocator] static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; use api::*; use canary_script::*; canary_script::export_abi!(bind_panel_impl); pub fn bind_panel_impl(panel: Panel, _protocol: Message, message: Message) -> Box { MusicPlayerPanel::bind(panel, message) } const DISPLAY_FONT: &str = "Liberation Sans"; pub struct MusicPlayerPanel { panel: Panel, display_font: Font, label: Label, } impl PanelImpl for MusicPlayerPanel { fn update(&mut self, dt: f32) {} fn draw(&mut self) { let ctx = DrawContext::new(self.panel); let offset = Vec2 { x: 5.0, y: 12.0 }; let size = 8.0; let color = Color::WHITE; self.label.draw(&ctx, offset, size, color); } fn on_resize(&mut self, new_size: Vec2) {} fn on_cursor_event(&mut self, kind: CursorEventKind, at: Vec2) {} fn on_message(&mut self, msg: Message) { use canary_music_player::{serde_json, InMsg}; let msg = msg.to_vec(); let msg = serde_json::from_slice::(&msg); self.label.set_text(format!("{:#?}", msg)); } } impl MusicPlayerPanel { pub fn bind(panel: Panel, _message: Message) -> Box { let display_font = Font::new(DISPLAY_FONT); let label = Label::new(display_font, "Hello, world!".into(), 1.2); let panel = Self { panel, display_font, label, }; Box::new(panel) } } pub struct Label { font: Font, text: String, line_height: f32, layout: Option>, } impl Label { pub fn new(font: Font, text: String, line_height: f32) -> Self { Self { font, text, line_height, layout: None, } } pub fn draw(&mut self, ctx: &DrawContext, offset: Vec2, size: f32, color: Color) { let layout = self.layout.get_or_insert_with(|| { self.text .lines() .map(|line| TextLayout::new(&self.font, line)) .collect() }); for (line, layout) in layout.iter().enumerate() { let offset = Vec2 { x: offset.x, y: self.line_height * size * line as f32 + offset.y, }; ctx.draw_text_layout(layout, offset.into(), size, color); } } pub fn set_text(&mut self, text: String) { self.text = text; self.layout = None; } }