use euclid::default::{Point2D, Size2D};
use flutterbug::{
prelude::*, Atom, Display, Event, EventMask, EventType, ExposeEvent, FlutterbugError,
FunctionKeys, Pixmap, Window,
};
use font_kit::{
canvas::{Canvas, Format, RasterizationOptions},
family_name::FamilyName,
font::Font,
hinting::HintingOptions,
properties::Properties,
source::SystemSource,
};
use pathfinder_geometry::{
transform2d::Transform2F,
vector::{Vector2F, Vector2I},
};
use std::{collections::HashMap, convert::TryInto, env};
fn load_char(
display: &Display,
window: &Window,
font: &Font,
pixmaps: &mut HashMap<char, Pixmap>,
c: char,
) -> Result<(), anyhow::Error> {
if let Some(_c) = pixmaps.get(&c) {
return Ok(());
}
let mut canvas = Canvas::new(Vector2I::splat(32), Format::A8);
let glyph = font
.glyph_for_char(c)
.ok_or_else(|| FlutterbugError::StaticMsg("Key not found"))?;
font.rasterize_glyph(
&mut canvas,
glyph,
32.0,
Transform2F::from_translation(Vector2F::new(0.0, 32.0)),
HintingOptions::None,
RasterizationOptions::GrayscaleAa,
)?;
let depth = display.default_depth()?.try_into().unwrap();
let pix = window.pixmap(Size2D::new(32, 32), depth)?;
let img = pix.image(Point2D::zero(), Size2D::new(32, 32))?;
for y in 0i32..32 {
for x in 0i32..32 {
let loc = (32 * y as usize) + x as usize;
let bright = std::u8::MAX - canvas.pixels[loc];
img.put_pixel(Point2D::new(x, y), bright, bright, bright)?;
}
}
pix.put_image(&img, Point2D::zero(), Point2D::zero(), Size2D::new(32, 32))?;
pixmaps.insert(c, pix);
Ok(())
}
fn main() -> Result<(), anyhow::Error> {
let display = Display::new()?;
let win_size = Size2D::new(400, 200);
let mut window = display.create_simple_window(
None,
Point2D::new(0, 0),
win_size,
1,
display.default_black_pixel()?,
display.default_white_pixel()?,
)?;
window.select_input(EventMask::EXPOSURE_MASK | EventMask::KEY_PRESS_MASK)?;
window.map(true)?;
window.set_standard_properties(Some("Test | Font"), None, None, false)?;
let wdw = display.internal_atom("WM_DELETE_WINDOW", false)?;
window.set_protocols(&mut [wdw])?;
let im = display.input_method()?;
let ic = window.input_context(&im)?;
let mut key: Option<String> = None;
let text = env::args()
.nth(1)
.or_else(|| Some(String::from("Hello world!")))
.unwrap();
let mut chars = HashMap::new();
let font = SystemSource::new()
.select_best_match(
&[FamilyName::Title(String::from("ProFont for Powerline"))],
&Properties::new(),
)?
.load()?;
text.chars()
.map(|c| load_char(&display, &window, &font, &mut chars, c))
.collect::<Result<_, _>>()?;
'el: loop {
let ev = Event::next(&display)?;
match ev {
Event::Expose(_e) => {
window.clear_area(Point2D::zero(), Size2D::new(400, 200), false)?;
text.chars()
.enumerate()
.map(|(i, c)| {
let pix = chars.get(&c).unwrap();
window.copy_area(
pix,
Point2D::new(0, 0),
Point2D::new(20 + (i as i32 * 32), 20),
Size2D::new(32, 32),
)
})
.collect::<Result<_, _>>()?;
if let Some(ref k) = &key {
let c = k.chars().nth(0).unwrap();
if let Err(_e) = load_char(&display, &window, &font, &mut chars, c) {
continue 'el;
}
let pix = chars.get(&c).unwrap();
window.copy_area(
pix,
Point2D::new(0, 0),
Point2D::new(20, 52),
Size2D::new(32, 32),
)?
}
}
Event::Key(mut k) => {
k.set_function(FunctionKeys::CONTROL, false);
let (_, kstr) = k.lookup_utf8(&ic)?;
key = kstr;
let ev = ExposeEvent::new(
EventType::Expose,
0,
&display,
&window,
true,
0,
0,
400,
200,
1,
)?;
let ev = Event::Expose(ev);
ev.send(&display, &window, true, EventMask::EXPOSURE_MASK)?;
}
Event::ClientMessage(cm) => {
if AsRef::<[Atom]>::as_ref(&cm.data())[0] == wdw {
break 'el;
}
}
_ => { }
}
}
Ok(())
}