rmenu/src/lib.rs

127 lines
3 KiB
Rust

pub mod color;
pub mod font;
use color::ColorPair;
use font::FontExt;
use pango::{prelude::FontExt as _, Font, Language, SCALE};
use wmenu_rs::Menu as WMenu;
struct Config {
pub bottom: bool,
pub padding: usize,
pub lines: i32,
pub font: String,
pub font_size: u8,
pub normal_color: ColorPair,
pub prompt_color: ColorPair,
pub selection_color: ColorPair,
}
impl Config {
fn font_string(&self) -> String {
format!("{} {}", self.font, self.font_size)
}
fn font_height(&self, font: &str) -> i32 {
let font = Font::load_from_string(font).unwrap();
let metrics = font.metrics(Some(&Language::default()));
metrics.height() / SCALE
}
fn apply(self, wmenu: &mut WMenu) {
let font_string = self.font_string();
let font_height = self.font_height(&font_string);
let line_height = font_height + 2;
let mut height = line_height;
if self.lines > 0 {
height = height + height * self.lines;
}
wmenu
.height(height)
.bottom(self.bottom)
.padding(self.padding.try_into().unwrap())
.lines(self.lines.try_into().unwrap())
.line_height(line_height)
.font(&font_string)
.normal_bg(self.normal_color.bg.into())
.normal_fg(self.normal_color.fg.into())
.prompt_bg(self.prompt_color.bg.into())
.prompt_fg(self.prompt_color.fg.into())
.selection_bg(self.selection_color.bg.into())
.selection_fg(self.selection_color.fg.into());
}
}
impl Default for Config {
fn default() -> Self {
Self {
bottom: false,
lines: 0,
padding: 16,
font: "monospace".to_string(),
font_size: 12,
normal_color: (0x222222ff, 0xbbbbbbffu32).into(),
prompt_color: (0x005577ff, 0xeeeeeeffu32).into(),
selection_color: (0x005577ff, 0x227799ffu32).into(),
}
}
}
struct Menu {
wmenu: WMenu,
}
impl Menu {
pub fn new(config: Config) -> Self {
let mut wmenu = WMenu::new();
config.apply(&mut wmenu);
Self { wmenu }
}
pub fn inner(&self) -> &WMenu {
&self.wmenu
}
pub fn inner_mut(&mut self) -> &mut WMenu {
&mut self.wmenu
}
pub fn add_item(&mut self, item: &str) -> &mut Menu {
self.inner_mut().add_item(item);
self
}
pub fn add_items(&mut self, items: &[&str]) -> &mut Menu {
self.inner_mut().add_items(items);
self
}
}
impl Default for Menu {
fn default() -> Self {
Self::new(Config::default())
}
}
impl From<Menu> for WMenu {
fn from(value: Menu) -> Self {
value.wmenu
}
}
#[cfg(test)]
mod tests {
use crate::{Config, Menu};
#[test]
fn it_works() {
let mut menu = Menu::new(Config::default());
menu.add_items(&["rowern", "sybil", "vex"]);
let result = menu.inner_mut().run();
println!("{result:?}");
}
}