// SPDX-License-Identifier: MIT OR Apache-2.0 use cosmic_text::{Attrs, AttrsList, Color, Family, FontSystem, Style, SwashCache, TextAction, TextBuffer, TextBufferLine, TextMetrics, Weight}; use orbclient::{EventOption, Renderer, Window, WindowFlag}; use std::{process, thread, time::{Duration, Instant}}; fn main() { env_logger::init(); let font_system = FontSystem::new(); let display_scale = match orbclient::get_display_size() { Ok((w, h)) => { log::info!("Display size: {}, {}", w, h); (h as i32 / 1600) + 1 } Err(err) => { log::warn!("Failed to get display size: {}", err); 1 } }; let mut window = Window::new_flags( -1, -1, 1024 * display_scale as u32, 768 * display_scale as u32, &format!("COSMIC TEXT - {}", font_system.locale), &[WindowFlag::Resizable], ) .unwrap(); let mut buffer = TextBuffer::new( &font_system, TextMetrics::new(32, 44).scale(display_scale) ); buffer.set_size( window.width() as i32, window.height() as i32 ); let attrs = Attrs::new(); let serif_attrs = attrs.family(Family::Serif); let mono_attrs = attrs.monospaced(true).family(Family::Monospace); let comic_attrs = attrs.family(Family::Name("Comic Neue")); buffer.lines.clear(); let lines: &[&[(&str, Attrs)]] = &[ &[ ("B", attrs.weight(Weight::BOLD)), ("old ", attrs), ("I", attrs.style(Style::Italic)), ("talic ", attrs), ("f", attrs), ("i ", attrs), ("f", attrs.weight(Weight::BOLD)), ("i ", attrs), ("f", attrs.style(Style::Italic)), ("i ", attrs), ], &[ ("Sans-Serif Normal ", attrs), ("Sans-Serif Bold ", attrs.weight(Weight::BOLD)), ("Sans-Serif Italic ", attrs.style(Style::Italic)), ("Sans-Serif Bold Italic", attrs.weight(Weight::BOLD).style(Style::Italic)), ], &[ ("Serif Normal ", serif_attrs), ("Serif Bold ", serif_attrs.weight(Weight::BOLD)), ("Serif Italic ", serif_attrs.style(Style::Italic)), ("Serif Bold Italic", serif_attrs.weight(Weight::BOLD).style(Style::Italic)), ], &[ ("Mono Normal ", mono_attrs), ("Mono Bold ", mono_attrs.weight(Weight::BOLD)), ("Mono Italic ", mono_attrs.style(Style::Italic)), ("Mono Bold Italic", mono_attrs.weight(Weight::BOLD).style(Style::Italic)), ], &[ ("Comic Normal ", comic_attrs), ("Comic Bold ", comic_attrs.weight(Weight::BOLD)), ("Comic Italic ", comic_attrs.style(Style::Italic)), ("Comic Bold Italic", comic_attrs.weight(Weight::BOLD).style(Style::Italic)), ], &[ ("R", attrs.color(Color::rgb(0xFF, 0x00, 0x00))), ("A", attrs.color(Color::rgb(0xFF, 0x7F, 0x00))), ("I", attrs.color(Color::rgb(0xFF, 0xFF, 0x00))), ("N", attrs.color(Color::rgb(0x00, 0xFF, 0x00))), ("B", attrs.color(Color::rgb(0x00, 0x00, 0xFF))), ("O", attrs.color(Color::rgb(0x4B, 0x00, 0x82))), ("W ", attrs.color(Color::rgb(0x94, 0x00, 0xD3))), ("Red ", attrs.color(Color::rgb(0xFF, 0x00, 0x00))), ("Orange ", attrs.color(Color::rgb(0xFF, 0x7F, 0x00))), ("Yellow ", attrs.color(Color::rgb(0xFF, 0xFF, 0x00))), ("Green ", attrs.color(Color::rgb(0x00, 0xFF, 0x00))), ("Blue ", attrs.color(Color::rgb(0x00, 0x00, 0xFF))), ("Indigo ", attrs.color(Color::rgb(0x4B, 0x00, 0x82))), ("Violet ", attrs.color(Color::rgb(0x94, 0x00, 0xD3))), ("U", attrs.color(Color::rgb(0x94, 0x00, 0xD3))), ("N", attrs.color(Color::rgb(0x4B, 0x00, 0x82))), ("I", attrs.color(Color::rgb(0x00, 0x00, 0xFF))), ("C", attrs.color(Color::rgb(0x00, 0xFF, 0x00))), ("O", attrs.color(Color::rgb(0xFF, 0xFF, 0x00))), ("R", attrs.color(Color::rgb(0xFF, 0x7F, 0x00))), ("N", attrs.color(Color::rgb(0xFF, 0x00, 0x00))), ] ]; for &line in lines { let mut line_text = String::new(); let mut attrs_list = AttrsList::new(attrs); for &(text, attrs) in line { let start = line_text.len(); line_text.push_str(text); let end = line_text.len(); attrs_list.add_span(start..end, attrs); } buffer.lines.push(TextBufferLine::new(line_text, attrs_list)); } let mut swash_cache = SwashCache::new(&font_system); //TODO: make window not async? let mut mouse_x = -1; let mut mouse_y = -1; let mut mouse_left = false; loop { let bg_color = orbclient::Color::rgb(0x34, 0x34, 0x34); let font_color = Color::rgb(0xFF, 0xFF, 0xFF); if buffer.cursor_moved { buffer.shape_until_cursor(); buffer.cursor_moved = false; } else { buffer.shape_until_scroll(); } if buffer.redraw { let instant = Instant::now(); window.set(bg_color); buffer.draw(&mut swash_cache, font_color, |x, y, w, h, color| { window.rect(x, y, w, h, orbclient::Color { data: color.0 }); }); window.sync(); buffer.redraw = false; let duration = instant.elapsed(); log::debug!("redraw: {:?}", duration); } for event in window.events() { match event.to_option() { EventOption::Key(event) => match event.scancode { orbclient::K_LEFT if event.pressed => buffer.action(TextAction::Left), orbclient::K_RIGHT if event.pressed => buffer.action(TextAction::Right), orbclient::K_UP if event.pressed => buffer.action(TextAction::Up), orbclient::K_DOWN if event.pressed => buffer.action(TextAction::Down), orbclient::K_HOME if event.pressed => buffer.action(TextAction::Home), orbclient::K_END if event.pressed => buffer.action(TextAction::End), orbclient::K_PGUP if event.pressed => buffer.action(TextAction::PageUp), orbclient::K_PGDN if event.pressed => buffer.action(TextAction::PageDown), orbclient::K_ENTER if event.pressed => buffer.action(TextAction::Enter), orbclient::K_BKSP if event.pressed => buffer.action(TextAction::Backspace), orbclient::K_DEL if event.pressed => buffer.action(TextAction::Delete), _ => (), }, EventOption::TextInput(event) => buffer.action(TextAction::Insert(event.character)), EventOption::Mouse(mouse) => { mouse_x = mouse.x; mouse_y = mouse.y; if mouse_left { buffer.action(TextAction::Drag { x: mouse_x, y: mouse_y }); } }, EventOption::Button(button) => { mouse_left = button.left; if mouse_left { buffer.action(TextAction::Click { x: mouse_x, y: mouse_y }); } }, EventOption::Resize(resize) => { buffer.set_size(resize.width as i32, resize.height as i32); buffer.redraw = true; }, EventOption::Quit(_) => process::exit(0), _ => (), } } thread::sleep(Duration::from_millis(1)); } }