From cf32b2f09c40161bbdbf49aacbc4851494fad060 Mon Sep 17 00:00:00 2001 From: frisk-V3 <260639938+frisk-V3@users.noreply.github.com> Date: Fri, 5 Jun 2026 19:29:40 +0900 Subject: [PATCH] Refactor dock rendering and input handling --- src/main.rs | 63 ++++++++++++++++++++++++++--------------------------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/src/main.rs b/src/main.rs index 083a6c5..d18b31e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,16 +4,15 @@ use swiftlib::{ process, task::yield_now, }; -use viewkit::{ipc_proto, render_component_to_pixmap, Window, VComponent}; +use viewkit::{ipc_proto, render_component_to_pixmap, VComponent, Window}; fn main() { println!("[Dock] start"); println!("[Dock] listing apps..."); let apps = list_app_bundles(); - println!("[Dock] apps count={}", apps.len()); - let (width, height) = dock_window_size(apps.len()); + let (width, height) = dock_window_size(apps.len()); let mut window = match Window::new(width, height, ipc_proto::LAYER_STATUS) { Ok(w) => w, Err(e) => { @@ -24,9 +23,9 @@ fn main() { println!("[Dock] window ready id={}", window.id()); let mut sel = 0usize; - println!("[Dock] rendering..."); let dock = render_dock_component(&apps, sel); + println!("[Dock] presenting..."); let pixels = render_component_to_pixmap(&dock, width as u32, height as u32); if let Err(e) = window.present(&pixels) { @@ -35,36 +34,39 @@ fn main() { } println!("[Dock] shown"); + // 描画ロジックの重複を避けるためのクロージャ + let mut redraw = |current_sel: usize| { + let dock = render_dock_component(&apps, current_sel); + let pixels = render_component_to_pixmap(&dock, width as u32, height as u32); + let _ = window.present(&pixels); + }; + loop { let sc_opt = match read_scancode_tap() { Ok(Some(sc)) => Some(sc), Ok(None) => read_scancode(), Err(_) => read_scancode(), }; + if let Some(sc) = sc_opt { // ESC if sc == 0x01 || sc == 0x81 { println!("[Dock] exit"); return; } + // Left arrow (press) - if sc == 0x4B { - if sel > 0 { - sel -= 1; - } - let dock = render_dock_component(&apps, sel); - let pixels = render_component_to_pixmap(&dock, width as u32, height as u32); - let _ = window.present(&pixels); + if sc == 0x4B && sel > 0 { + sel -= 1; + redraw(sel); } + // Right arrow (press) - if sc == 0x4D { - if sel + 1 < apps.len() { - sel += 1; - } - let dock = render_dock_component(&apps, sel); - let pixels = render_component_to_pixmap(&dock, width as u32, height as u32); - let _ = window.present(&pixels); + if sc == 0x4D && sel + 1 < apps.len() { + sel += 1; + redraw(sel); } + // Enter (press) if sc == 0x1C { if let Some((app, _icon)) = apps.get(sel) { @@ -85,24 +87,22 @@ fn render_dock_component( selected: usize, ) -> VComponent { let appicon_template = include_str!("components/appicon.html"); - let mut icons = Vec::new(); + for (i, (name, icon_opt)) in apps.iter().enumerate() { let mut appicon = VComponent::from_str(appicon_template); - if let Some(path) = icon_opt { - println!("[Dokc] loading icon for {} from {}", name, path); + println!("[Dock] loading icon for {} from {}", name, path); // タイポを修正 appicon = appicon.image(path.clone()); } else { println!("[Dock] no icon for {}, using default", name); let label = name.trim_end_matches(".app"); appicon = appicon.text(label.to_string()); } - + if i == selected { appicon = appicon.class("selected"); } - icons.push(appicon); } @@ -114,11 +114,13 @@ fn dock_window_size(app_count: usize) -> (u16, u16) { let icon_width = 40usize; let gap = 10usize; let padding = 18usize; + let content_width = if app_count == 0 { 0 } else { app_count * icon_width + app_count.saturating_sub(1) * gap }; + let width = content_width + padding * 2; (width.max(120).min(u16::MAX as usize) as u16, 75) } @@ -133,19 +135,14 @@ fn read_file(path: &str, max_size: usize) -> Option> { fn list_app_bundles() -> Vec<(String, Option)> { let mut apps = Vec::new(); let dir_path = "/applications/"; - + match fs::open_via_fs(dir_path) { Ok(fd) => { let mut buf = vec![0u8; 16 * 1024]; let n = fs::readdir(fd, &mut buf); - fs::close_via_fs(fd); - if n == 0 { - return apps; - } - - if n > buf.len() as u64 { + if n == 0 || n > buf.len() as u64 { return apps; } @@ -153,12 +150,13 @@ fn list_app_bundles() -> Vec<(String, Option)> { Ok(t) => t, Err(_) => return apps, }; - + for line in text.lines() { let name_str = line.trim(); if name_str.is_empty() || !name_str.ends_with(".app") { continue; } + let app_path = format!("{}{}", dir_path, name_str); let about_toml_path = format!("{}/about.toml", app_path); let icon = read_icon_from_about_toml(&about_toml_path); @@ -167,7 +165,7 @@ fn list_app_bundles() -> Vec<(String, Option)> { } Err(_) => {} } - + apps.sort_by(|a, b| a.0.cmp(&b.0)); apps } @@ -183,6 +181,7 @@ fn read_icon_from_about_toml(path: &str) -> Option { let value = value .trim() .trim_matches(|c| c == '"' || c == '\'' || c == ' '); + if !value.is_empty() { if value.starts_with('/') { return Some(value.to_string());