use std::{error::Error, num::NonZero, rc::Rc};
use winit::{
application::ApplicationHandler,
dpi::PhysicalSize,
event::{Modifiers, WindowEvent},
event_loop::{ActiveEventLoop, ControlFlow, EventLoop, EventLoopProxy, OwnedDisplayHandle},
keyboard::{Key, ModifiersState, NamedKey},
window::Window,
};
use crate::{
json_ui::{Config, Request, Response, Rpc},
kakoune::Kakoune,
render::{Rasterizer, Shaper, Target},
};
const WIDTH: u32 = 600;
const HEIGHT: u32 = 400;
mod json_ui;
mod kakoune;
mod render;
anchor: json_ui::Coord,
face: json_ui::Face,
style: json_ui::InfoShowStyle,
title: RcLine,
content: Vec<RcLine>,
}
struct Info {
menus: Vec<Menu>,
infos: Vec<Info>,
}
#[derive(Default)]
struct Render {
pub shaper: Shaper,
pub rasterizer: Rasterizer,
line_face: json_ui::Face,
}
modifiers: Modifiers,
kakoune: Kakoune,
ui: Ui,
config: Config,
configured: bool,
render: Render,
pixels: Option<(
softbuffer::Context<OwnedDisplayHandle>,
softbuffer::Surface<OwnedDisplayHandle, Window>,
)>,
struct App {
ui: Default::default(),
let window = event_loop
.create_window(
Window::default_attributes()
.with_inner_size(PhysicalSize::new(WIDTH as f64, HEIGHT as f64))
.with_title("Kakoune Client"),
)
.unwrap();
let context = softbuffer::Context::new(event_loop.owned_display_handle()).unwrap();
let mut surface = softbuffer::Surface::new(&context, window).unwrap();
surface
.resize(NonZero::new(WIDTH).unwrap(), NonZero::new(HEIGHT).unwrap())
.unwrap();
self.pixels = Some((context, surface));
_ = self.kakoune.send_response(Response::Resize(lines, cols));
let cols = u16::MAX as u32;
let lines = (size.height
/ render::line_height(self.config.font_size as f32) as u32)
- 1;
surface.window().request_redraw();
}
}
WindowEvent::Destroyed => {
event_loop.exit();
}
self.kakoune
.send_response(Response::Keys(vec![key]))
.unwrap();
WindowEvent::ModifiersChanged(modifiers) => {
self.modifiers = modifiers;
}
WindowEvent::KeyboardInput { event, .. } => {
if !event.state.is_pressed() {
return;
}
if let Some(key) = make_kakoune_key(event.logical_key, self.modifiers.state()) {
}
}
AppMessage::Exit => {
event_loop.exit();
}
},
}
Request::MenuSelect(index) => {
if let Some(menu) = self.ui.menus.last_mut() {
menu.selected = index[0] as usize;
}
}
Request::MenuShow(content, anchor, selected_face, menu_face, style) => {
self.ui.menus.retain(|menu| menu.style != style);
self.ui.menus.push(Menu {
content: content.into_iter().map(From::from).collect(),
anchor,
selected_face,
menu_face,
style,
selected: 0,
});
}
anchor,
face,
style,
});
title: title.into(),
content: content.into_iter().map(From::from).collect(),
Request::InfoShow(title, content, anchor, face, style) => {
self.ui.infos.push(Info {
Request::MenuHide(_) => {
self.ui.menus.clear();
}
}
Request::InfoHide(_) => {
self.ui.infos.clear();
}
}
if let Some((_, surface)) = &self.pixels {
surface.window().request_redraw();
}
Request::SetCursor(_, _) => {}
Request::Refresh(_) => {
self.config = config;
self.configured = true;
}
let cols = u16::MAX as u32;
_ = self.kakoune.send_response(Response::Resize(lines, cols));
render::load_fonts(
&config.fonts,
&mut self.render.shaper,
&mut self.render.rasterizer,
)
.expect("Failed to load font");
if let Some((_, surface)) = &mut self.pixels {
let buf = surface.buffer_mut().unwrap();
let lines = (buf.height().get() as u32
/ render::line_height(config.font_size as f32) as u32)
- 1;
}
Request::SetUiOptions([config]) => {
self.ui.line_face = default_face;
self.ui.prompt_line = prompt_line.into();
self.ui.mode_line = mode_line.into();
Request::DrawStatus(prompt_line, mode_line, default_face) => {
}
self.ui.default_face = default_face;
self.ui.lines = lines.into_iter().map(From::from).collect();
AppMessage::Kakoune(kak) => match kak {
Request::Draw(lines, default_face, _padding_face) => {
match event {
fn user_event(&mut self, event_loop: &ActiveEventLoop, event: AppMessage) {
}
app.kakoune.join();
event_loop.run_app(&mut app).unwrap();
let mut app = App::new(event_loop.create_proxy()).unwrap();
event_loop.set_control_flow(ControlFlow::Wait);
let event_loop = EventLoop::<AppMessage>::with_user_event().build().unwrap();
}
fn main() {
_ => {}
}
}
}
}
.unwrap();
surface
.resize(
NonZero::new(size.width).unwrap(),
NonZero::new(size.height).unwrap(),
)
if let Some((_, surface)) = self.pixels.as_mut() {
WindowEvent::Resized(size) => {
}
}
WindowEvent::CloseRequested => {
event_loop.exit();
}
buf.present().expect("Failed to present surface");
let width = buf.width().get() as usize;
let height = buf.height().get() as usize;
let mut target = Target::new(&mut buf, width, height);
render::render(
&mut target,
&mut self.render.shaper,
&mut self.render.rasterizer,
&self.ui,
&self.config,
)
.unwrap();
let mut buf = surface.buffer_mut().expect("Failed to get buffer");
if let Some((_, surface)) = self.pixels.as_mut()
&& self.configured
{
_window_id: winit::window::WindowId,
event: winit::event::WindowEvent,
) {
match event {
WindowEvent::RedrawRequested => {
event_loop: &ActiveEventLoop,
}
fn window_event(
&mut self,
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
impl ApplicationHandler<AppMessage> for App {
_ => None,
}
}
Key::Character(c) if c == "+" => Some(add_modifiers("plus", state, false)),
Key::Character(c) if c == "-" => Some(add_modifiers("minus", state, false)),
Key::Character(c) if c == "<" => Some(add_modifiers("lt", state, false)),
Key::Character(c) if c == ">" => Some(add_modifiers("gt", state, false)),
Key::Character(c) => Some(add_modifiers(&c, state, false)),
Key::Named(NamedKey::F1) => Some(add_modifiers("F1", state, true)),
Key::Named(NamedKey::F2) => Some(add_modifiers("F2", state, true)),
Key::Named(NamedKey::F3) => Some(add_modifiers("F3", state, true)),
Key::Named(NamedKey::F4) => Some(add_modifiers("F4", state, true)),
Key::Named(NamedKey::F5) => Some(add_modifiers("F5", state, true)),
Key::Named(NamedKey::F6) => Some(add_modifiers("F6", state, true)),
Key::Named(NamedKey::F7) => Some(add_modifiers("F7", state, true)),
Key::Named(NamedKey::F8) => Some(add_modifiers("F8", state, true)),
Key::Named(NamedKey::F9) => Some(add_modifiers("F9", state, true)),
Key::Named(NamedKey::F10) => Some(add_modifiers("F10", state, true)),
Key::Named(NamedKey::F11) => Some(add_modifiers("F11", state, true)),
Key::Named(NamedKey::F12) => Some(add_modifiers("F12", state, true)),
Key::Named(NamedKey::PageUp) => Some(add_modifiers("pageup", state, true)),
Key::Named(NamedKey::PageDown) => Some(add_modifiers("pagedown", state, true)),
Key::Named(NamedKey::Home) => Some(add_modifiers("home", state, true)),
Key::Named(NamedKey::End) => Some(add_modifiers("end", state, true)),
Key::Named(NamedKey::Insert) => Some(add_modifiers("ins", state, true)),
Key::Named(NamedKey::ArrowUp) => Some(add_modifiers("up", state, true)),
Key::Named(NamedKey::ArrowDown) => Some(add_modifiers("down", state, true)),
Key::Named(NamedKey::ArrowLeft) => Some(add_modifiers("left", state, true)),
Key::Named(NamedKey::ArrowRight) => Some(add_modifiers("right", state, true)),
Key::Named(NamedKey::Space) => Some(add_modifiers("space", state, true)),
Key::Named(NamedKey::Enter) => Some(add_modifiers("ret", state, true)),
Key::Named(NamedKey::Tab) => Some(add_modifiers("tab", state, true)),
Key::Named(NamedKey::Backspace) => Some(add_modifiers("backspace", state, true)),
Key::Named(NamedKey::Delete) => Some(add_modifiers("del", state, true)),
Key::Named(NamedKey::Escape) => Some(add_modifiers("esc", state, true)),
fn make_kakoune_key(key: Key, state: ModifiersState) -> Option<String> {
match key {
}
res.push('>');
res
res.push_str(key_name);
}
res.push_str("s-");
}
if state.alt_key() {
res.push_str("a-")
if use_shift && state.shift_key() {
let mut res = String::new();
res.push('<');
if state.control_key() {
res.push_str("c-");
}
fn add_modifiers(key_name: &str, state: ModifiersState, use_shift: bool) -> String {
}
}
})
modifiers: Modifiers::default(),
kakoune: Kakoune::new(evp),
config: Default::default(),
configured: false,
render: Default::default(),
pixels: None,
Ok(Self {
fn new(evp: EventLoopProxy<AppMessage>) -> Result<Self, Box<dyn Error>> {
impl App {
}
default_face: json_ui::Face,
lines: Vec<RcLine>,
prompt_line: RcLine,
mode_line: RcLine,
#[derive(Default)]
struct Ui {
struct Menu {
content: Vec<RcLine>,
anchor: json_ui::Coord,
selected_face: json_ui::Face,
menu_face: json_ui::Face,
style: json_ui::MenuShowStyle,
selected: usize,
}
}
Exit,
Kakoune(Request),
#[derive(Debug)]
enum AppMessage {
type RcLine = Rc<[json_ui::Atom]>;