smokes: add curated LLVM runner; archive legacy smokes; PHI-off unified across Bridge/Builder; LLVM resolver tracing; minimal Throw lowering; config env getters; dev profile and root cleaner; docs updated; CI workflow runs curated LLVM (PHI-on/off)

This commit is contained in:
Selfhosting Dev
2025-09-16 23:49:36 +09:00
parent 97a76c0571
commit 5c9213cd03
104 changed files with 8094 additions and 2930 deletions

View File

@ -3,14 +3,14 @@ use eframe::egui;
fn main() -> eframe::Result {
env_logger::init(); // Enable logging
let options = eframe::NativeOptions {
viewport: egui::ViewportBuilder::default()
.with_inner_size([640.0, 480.0])
.with_title("Debug Notepad"),
..Default::default()
};
eframe::run_native(
"Debug Notepad",
options,
@ -29,32 +29,34 @@ impl eframe::App for DebugApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("Debug Text Input Test");
// Single line input
ui.horizontal(|ui| {
ui.label("Single Line:");
let response = ui.text_edit_singleline(&mut self.single_line);
if response.changed() {
self.event_log.push(format!("Single line changed: '{}'", self.single_line));
self.event_log
.push(format!("Single line changed: '{}'", self.single_line));
}
});
ui.separator();
// Multi line input
ui.label("Multi Line:");
let response = ui.add(
egui::TextEdit::multiline(&mut self.text)
.desired_width(f32::INFINITY)
.desired_rows(10)
.desired_rows(10),
);
if response.changed() {
self.event_log.push(format!("Multi line changed: {} chars", self.text.len()));
self.event_log
.push(format!("Multi line changed: {} chars", self.text.len()));
}
ui.separator();
// Show input events
ui.label("Event Log:");
egui::ScrollArea::vertical()
@ -64,18 +66,18 @@ impl eframe::App for DebugApp {
ui.label(event);
}
});
// Debug info
ui.separator();
ui.label(format!("Text length: {}", self.text.len()));
ui.label(format!("Single line length: {}", self.single_line.len()));
// Test buttons
if ui.button("Add Test Text").clicked() {
self.text.push_str("Test ");
self.event_log.push("Button: Added test text".to_string());
}
if ui.button("Clear All").clicked() {
self.text.clear();
self.single_line.clear();
@ -83,4 +85,4 @@ impl eframe::App for DebugApp {
}
});
}
}
}

View File

@ -8,11 +8,8 @@ use std::path::PathBuf;
use windows::{
core::*,
Win32::{
Foundation::*,
Storage::FileSystem::*,
UI::Shell::*,
Foundation::*, Storage::FileSystem::*, System::Com::*, UI::Shell::*,
UI::WindowsAndMessaging::*,
System::Com::*,
},
};
@ -23,7 +20,7 @@ fn main() -> eframe::Result {
.with_title("Nyash Explorer - ドライブ情報ビューアー"),
..Default::default()
};
eframe::run_native(
"Nyash Explorer",
options,
@ -37,24 +34,25 @@ fn main() -> eframe::Result {
// フォント設定
fn setup_custom_fonts(ctx: &egui::Context) {
let mut fonts = egui::FontDefinitions::default();
fonts.font_data.insert(
"noto_sans_jp".to_owned(),
egui::FontData::from_static(include_bytes!("../assets/NotoSansJP-VariableFont_wght.ttf")).into(),
egui::FontData::from_static(include_bytes!("../assets/NotoSansJP-VariableFont_wght.ttf"))
.into(),
);
fonts
.families
.entry(FontFamily::Proportional)
.or_default()
.insert(0, "noto_sans_jp".to_owned());
fonts
.families
.entry(FontFamily::Monospace)
.or_default()
.push("noto_sans_jp".to_owned());
ctx.set_fonts(fonts);
}
@ -84,22 +82,22 @@ impl NyashExplorer {
explorer.refresh_drives();
explorer
}
fn refresh_drives(&mut self) {
self.drives.clear();
self.status = "ドライブ情報を取得中...".to_string();
#[cfg(windows)]
{
unsafe {
// 論理ドライブのビットマスクを取得
let drives_mask = GetLogicalDrives();
for i in 0..26 {
if drives_mask & (1 << i) != 0 {
let drive_letter = format!("{}:", (b'A' + i) as char);
let drive_path = format!("{}\\", drive_letter);
// ドライブ情報を取得
let mut drive_info = DriveInfo {
letter: drive_letter.clone(),
@ -109,12 +107,15 @@ impl NyashExplorer {
free_bytes: 0,
icon_data: None,
};
// ドライブタイプを取得
let drive_type_code = GetDriveTypeW(PCWSTR::from_raw(
format!("{}\0", drive_path).encode_utf16().collect::<Vec<u16>>().as_ptr()
format!("{}\0", drive_path)
.encode_utf16()
.collect::<Vec<u16>>()
.as_ptr(),
));
drive_info.drive_type = match drive_type_code {
DRIVE_REMOVABLE => "リムーバブル".to_string(),
DRIVE_FIXED => "ハードディスク".to_string(),
@ -123,22 +124,29 @@ impl NyashExplorer {
DRIVE_RAMDISK => "RAMディスク".to_string(),
_ => "不明".to_string(),
};
// ボリューム情報を取得
let mut volume_name = vec![0u16; 256];
let mut file_system = vec![0u16; 256];
let mut serial_number = 0u32;
let mut max_component_len = 0u32;
let mut file_system_flags = 0u32;
if GetVolumeInformationW(
PCWSTR::from_raw(format!("{}\0", drive_path).encode_utf16().collect::<Vec<u16>>().as_ptr()),
PCWSTR::from_raw(
format!("{}\0", drive_path)
.encode_utf16()
.collect::<Vec<u16>>()
.as_ptr(),
),
Some(&mut volume_name),
Some(&mut serial_number),
Some(&mut max_component_len),
Some(&mut file_system_flags),
Some(&mut file_system),
).is_ok() {
)
.is_ok()
{
let volume_name_str = String::from_utf16_lossy(&volume_name)
.trim_end_matches('\0')
.to_string();
@ -150,28 +158,35 @@ impl NyashExplorer {
} else {
drive_info.name = format!("ドライブ ({})", drive_letter);
}
// 空き容量を取得
let mut free_bytes_available = 0u64;
let mut total_bytes = 0u64;
let mut total_free_bytes = 0u64;
if GetDiskFreeSpaceExW(
PCWSTR::from_raw(format!("{}\0", drive_path).encode_utf16().collect::<Vec<u16>>().as_ptr()),
PCWSTR::from_raw(
format!("{}\0", drive_path)
.encode_utf16()
.collect::<Vec<u16>>()
.as_ptr(),
),
Some(&mut free_bytes_available),
Some(&mut total_bytes),
Some(&mut total_free_bytes),
).is_ok() {
)
.is_ok()
{
drive_info.total_bytes = total_bytes;
drive_info.free_bytes = total_free_bytes;
}
self.drives.push(drive_info);
}
}
}
}
#[cfg(not(windows))]
{
// Windows以外の環境ではダミーデータ
@ -184,20 +199,20 @@ impl NyashExplorer {
icon_data: None,
});
}
self.status = format!("{}個のドライブを検出しました", self.drives.len());
}
fn format_bytes(bytes: u64) -> String {
const UNITS: &[&str] = &["B", "KB", "MB", "GB", "TB"];
let mut size = bytes as f64;
let mut unit_index = 0;
while size >= 1024.0 && unit_index < UNITS.len() - 1 {
size /= 1024.0;
unit_index += 1;
}
format!("{:.2} {}", size, UNITS[unit_index])
}
}
@ -216,7 +231,7 @@ impl eframe::App for NyashExplorer {
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
}
});
ui.menu_button("表示", |ui| {
if ui.button("大きいアイコン").clicked() {
self.status = "表示モード: 大きいアイコン".to_string();
@ -225,7 +240,7 @@ impl eframe::App for NyashExplorer {
self.status = "表示モード: 詳細".to_string();
}
});
ui.menu_button("ヘルプ", |ui| {
if ui.button("Nyash Explorerについて").clicked() {
self.status = "Nyash Explorer - Everything is Box! 🐱".to_string();
@ -233,7 +248,7 @@ impl eframe::App for NyashExplorer {
});
});
});
// ツールバー
egui::TopBottomPanel::top("toolbar").show(ctx, |ui| {
ui.horizontal(|ui| {
@ -244,7 +259,7 @@ impl eframe::App for NyashExplorer {
ui.label("Nyash Explorer - ドライブ情報ビューアー");
});
});
// ステータスバー
egui::TopBottomPanel::bottom("status_bar").show(ctx, |ui| {
ui.horizontal(|ui| {
@ -254,27 +269,27 @@ impl eframe::App for NyashExplorer {
});
});
});
// メインパネル - ドライブ一覧
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("💾 ドライブ一覧");
ui.separator();
egui::ScrollArea::vertical().show(ui, |ui| {
for (index, drive) in self.drives.iter().enumerate() {
let is_selected = self.selected_drive == Some(index);
ui.group(|ui| {
let response = ui.allocate_response(
egui::vec2(ui.available_width(), 100.0),
egui::Sense::click(),
);
if response.clicked() {
self.selected_drive = Some(index);
self.status = format!("{} を選択しました", drive.name);
}
// 背景色
if is_selected {
ui.painter().rect_filled(
@ -283,7 +298,7 @@ impl eframe::App for NyashExplorer {
egui::Color32::from_rgb(100, 149, 237).gamma_multiply(0.2),
);
}
ui.allocate_ui_at_rect(response.rect, |ui| {
ui.horizontal(|ui| {
// ドライブアイコン(仮)
@ -298,19 +313,20 @@ impl eframe::App for NyashExplorer {
};
ui.label(egui::RichText::new(icon_text).size(40.0));
});
ui.add_space(20.0);
// ドライブ情報
ui.vertical(|ui| {
ui.add_space(10.0);
ui.label(egui::RichText::new(&drive.name).size(16.0).strong());
ui.label(format!("種類: {}", drive.drive_type));
if drive.total_bytes > 0 {
let used_bytes = drive.total_bytes - drive.free_bytes;
let usage_percent = (used_bytes as f32 / drive.total_bytes as f32) * 100.0;
let usage_percent =
(used_bytes as f32 / drive.total_bytes as f32) * 100.0;
ui.horizontal(|ui| {
ui.label(format!(
"使用領域: {} / {} ({:.1}%)",
@ -319,7 +335,7 @@ impl eframe::App for NyashExplorer {
usage_percent
));
});
// 使用率バー
let bar_width = 200.0;
let bar_height = 10.0;
@ -327,14 +343,14 @@ impl eframe::App for NyashExplorer {
egui::vec2(bar_width, bar_height),
egui::Sense::hover(),
);
// 背景
ui.painter().rect_filled(
rect,
2.0,
egui::Color32::from_gray(60),
);
// 使用領域
let used_width = bar_width * (usage_percent / 100.0);
let used_rect = egui::Rect::from_min_size(
@ -354,18 +370,19 @@ impl eframe::App for NyashExplorer {
});
});
});
ui.add_space(5.0);
}
});
// クイックアクション
ui.separator();
ui.horizontal(|ui| {
if ui.button("🐱 Nyashについて").clicked() {
self.status = "Nyash - Everything is Box! Windows APIも吸収できる化け物言語".to_string();
self.status = "Nyash - Everything is Box! Windows APIも吸収できる化け物言語"
.to_string();
}
if ui.button("📊 システム情報").clicked() {
let total: u64 = self.drives.iter().map(|d| d.total_bytes).sum();
let free: u64 = self.drives.iter().map(|d| d.free_bytes).sum();
@ -378,4 +395,4 @@ impl eframe::App for NyashExplorer {
});
});
}
}
}

View File

@ -1,7 +1,7 @@
// Nyash Explorer with Icons - Windows API Drive Icon Viewer
// エクスプローラー風ドライブアイコン付きビューアー
use eframe::egui::{self, FontFamily, ColorImage, TextureHandle};
use eframe::egui::{self, ColorImage, FontFamily, TextureHandle};
use std::fs::File;
use std::io::Read;
// use std::collections::HashMap;
@ -10,12 +10,7 @@ use std::io::Read;
#[cfg(windows)]
use windows::{
core::*,
Win32::{
Storage::FileSystem::*,
UI::Shell::*,
UI::WindowsAndMessaging::*,
System::Com::*,
},
Win32::{Storage::FileSystem::*, System::Com::*, UI::Shell::*, UI::WindowsAndMessaging::*},
};
fn main() -> eframe::Result {
@ -24,14 +19,14 @@ fn main() -> eframe::Result {
unsafe {
let _ = CoInitializeEx(None, COINIT_APARTMENTTHREADED);
}
let options = eframe::NativeOptions {
viewport: egui::ViewportBuilder::default()
.with_inner_size([1024.0, 768.0])
.with_title("Nyash Explorer with Icons - アイコン付きドライブビューアー"),
..Default::default()
};
eframe::run_native(
"Nyash Explorer Icons",
options,
@ -45,24 +40,25 @@ fn main() -> eframe::Result {
// フォント設定
fn setup_custom_fonts(ctx: &egui::Context) {
let mut fonts = egui::FontDefinitions::default();
fonts.font_data.insert(
"noto_sans_jp".to_owned(),
egui::FontData::from_static(include_bytes!("../assets/NotoSansJP-VariableFont_wght.ttf")).into(),
egui::FontData::from_static(include_bytes!("../assets/NotoSansJP-VariableFont_wght.ttf"))
.into(),
);
fonts
.families
.entry(FontFamily::Proportional)
.or_default()
.insert(0, "noto_sans_jp".to_owned());
fonts
.families
.entry(FontFamily::Monospace)
.or_default()
.push("noto_sans_jp".to_owned());
ctx.set_fonts(fonts);
}
@ -93,13 +89,16 @@ impl NyashExplorer {
explorer.refresh_drives();
explorer
}
#[cfg(windows)]
fn get_drive_icon(&self, drive_path: &str) -> Option<ColorImage> {
unsafe {
let mut shfi = SHFILEINFOW::default();
let drive_path_wide: Vec<u16> = drive_path.encode_utf16().chain(std::iter::once(0)).collect();
let drive_path_wide: Vec<u16> = drive_path
.encode_utf16()
.chain(std::iter::once(0))
.collect();
// アイコンを取得
let result = SHGetFileInfoW(
PCWSTR::from_raw(drive_path_wide.as_ptr()),
@ -108,25 +107,25 @@ impl NyashExplorer {
std::mem::size_of::<SHFILEINFOW>() as u32,
SHGFI_ICON | SHGFI_LARGEICON | SHGFI_USEFILEATTRIBUTES,
);
if result == 0 || shfi.hIcon.is_invalid() {
return None;
}
// アイコンからビットマップを取得
let icon_info = ICONINFO::default();
if GetIconInfo(shfi.hIcon, &icon_info as *const _ as *mut _).is_ok() {
// ビットマップからピクセルデータを取得する処理
// アイコンを破棄
let _ = DestroyIcon(shfi.hIcon);
// C:ドライブの場合は保存済みBMPファイルを読み込む
if drive_path.contains("C:") {
if let Some(icon) = Self::load_bmp_icon("c_drive_icon.bmp") {
return Some(icon);
}
}
// それ以外はダミーアイコンを返す
Some(Self::create_dummy_icon(&drive_path))
} else {
@ -135,44 +134,46 @@ impl NyashExplorer {
}
}
}
#[cfg(not(windows))]
fn get_drive_icon(&self, drive_path: &str) -> Option<ColorImage> {
Some(Self::create_dummy_icon(drive_path))
}
// BMPファイルを読み込んでColorImageに変換
fn load_bmp_icon(file_path: &str) -> Option<ColorImage> {
let mut file = File::open(file_path).ok()?;
let mut buffer = Vec::new();
file.read_to_end(&mut buffer).ok()?;
// BMPヘッダーをパース簡易版
if buffer.len() < 54 {
return None;
}
// BMPマジックナンバーをチェック
if &buffer[0..2] != b"BM" {
return None;
}
// ヘッダーから情報を読み取る
let data_offset = u32::from_le_bytes([buffer[10], buffer[11], buffer[12], buffer[13]]) as usize;
let data_offset =
u32::from_le_bytes([buffer[10], buffer[11], buffer[12], buffer[13]]) as usize;
let width = i32::from_le_bytes([buffer[18], buffer[19], buffer[20], buffer[21]]) as usize;
let height = i32::from_le_bytes([buffer[22], buffer[23], buffer[24], buffer[25]]).abs() as usize;
let height =
i32::from_le_bytes([buffer[22], buffer[23], buffer[24], buffer[25]]).abs() as usize;
let bits_per_pixel = u16::from_le_bytes([buffer[28], buffer[29]]);
// 32ビットBMPのみサポート
if bits_per_pixel != 32 {
println!("Unsupported BMP format: {} bits per pixel", bits_per_pixel);
return None;
}
// ピクセルデータを読み取る
let mut pixels = Vec::with_capacity(width * height);
let pixel_data = &buffer[data_offset..];
// BMPは下から上に格納されているので、反転しながら読み取る
for y in (0..height).rev() {
for x in 0..width {
@ -188,18 +189,18 @@ impl NyashExplorer {
}
}
}
Some(ColorImage {
size: [width, height],
pixels,
})
}
// ダミーアイコンを生成(実際のアイコン取得が複雑なため)
fn create_dummy_icon(drive_path: &str) -> ColorImage {
let size = 48;
let mut pixels = vec![egui::Color32::TRANSPARENT; size * size];
// ドライブタイプに応じた色を設定
let color = if drive_path.contains("C:") {
egui::Color32::from_rgb(100, 149, 237) // コーンフラワーブルー
@ -208,17 +209,17 @@ impl NyashExplorer {
} else {
egui::Color32::from_rgb(255, 182, 193) // ライトピンク
};
// シンプルな円形アイコンを描画
let center = size as f32 / 2.0;
let radius = (size as f32 / 2.0) - 4.0;
for y in 0..size {
for x in 0..size {
let dx = x as f32 - center;
let dy = y as f32 - center;
let distance = (dx * dx + dy * dy).sqrt();
if distance <= radius {
pixels[y * size + x] = color;
} else if distance <= radius + 2.0 {
@ -227,13 +228,13 @@ impl NyashExplorer {
}
}
}
// ドライブ文字を中央に配置(簡易版)
if let Some(_letter) = drive_path.chars().next() {
// 文字の位置(中央)
let text_x = size / 2 - 8;
let text_y = size / 2 - 8;
// 白い文字で描画
for dy in 0..16 {
for dx in 0..16 {
@ -246,28 +247,28 @@ impl NyashExplorer {
}
}
}
ColorImage {
size: [size, size],
pixels,
}
}
fn refresh_drives(&mut self) {
self.drives.clear();
self.status = "ドライブ情報を取得中...".to_string();
#[cfg(windows)]
{
unsafe {
// 論理ドライブのビットマスクを取得
let drives_mask = GetLogicalDrives();
for i in 0..26 {
if drives_mask & (1 << i) != 0 {
let drive_letter = format!("{}:", (b'A' + i) as char);
let drive_path = format!("{}\\", drive_letter);
// ドライブ情報を取得
let mut drive_info = DriveInfo {
letter: drive_letter.clone(),
@ -277,12 +278,15 @@ impl NyashExplorer {
free_bytes: 0,
icon_texture: None,
};
// ドライブタイプを取得
let drive_type_code = GetDriveTypeW(PCWSTR::from_raw(
format!("{}\0", drive_path).encode_utf16().collect::<Vec<u16>>().as_ptr()
format!("{}\0", drive_path)
.encode_utf16()
.collect::<Vec<u16>>()
.as_ptr(),
));
drive_info.drive_type = match drive_type_code {
DRIVE_REMOVABLE => "リムーバブル".to_string(),
DRIVE_FIXED => "ハードディスク".to_string(),
@ -291,22 +295,29 @@ impl NyashExplorer {
DRIVE_RAMDISK => "RAMディスク".to_string(),
_ => "不明".to_string(),
};
// ボリューム情報を取得
let mut volume_name = vec![0u16; 256];
let mut file_system = vec![0u16; 256];
let mut serial_number = 0u32;
let mut max_component_len = 0u32;
let mut file_system_flags = 0u32;
if GetVolumeInformationW(
PCWSTR::from_raw(format!("{}\0", drive_path).encode_utf16().collect::<Vec<u16>>().as_ptr()),
PCWSTR::from_raw(
format!("{}\0", drive_path)
.encode_utf16()
.collect::<Vec<u16>>()
.as_ptr(),
),
Some(&mut volume_name),
Some(&mut serial_number),
Some(&mut max_component_len),
Some(&mut file_system_flags),
Some(&mut file_system),
).is_ok() {
)
.is_ok()
{
let volume_name_str = String::from_utf16_lossy(&volume_name)
.trim_end_matches('\0')
.to_string();
@ -318,38 +329,45 @@ impl NyashExplorer {
} else {
drive_info.name = format!("ドライブ ({})", drive_letter);
}
// 空き容量を取得
let mut free_bytes_available = 0u64;
let mut total_bytes = 0u64;
let mut total_free_bytes = 0u64;
if GetDiskFreeSpaceExW(
PCWSTR::from_raw(format!("{}\0", drive_path).encode_utf16().collect::<Vec<u16>>().as_ptr()),
PCWSTR::from_raw(
format!("{}\0", drive_path)
.encode_utf16()
.collect::<Vec<u16>>()
.as_ptr(),
),
Some(&mut free_bytes_available),
Some(&mut total_bytes),
Some(&mut total_free_bytes),
).is_ok() {
)
.is_ok()
{
drive_info.total_bytes = total_bytes;
drive_info.free_bytes = total_free_bytes;
}
// アイコンを取得してテクスチャに変換
if let Some(icon_image) = self.get_drive_icon(&drive_path) {
let texture = self.ctx.load_texture(
format!("drive_icon_{}", drive_letter),
icon_image,
Default::default()
Default::default(),
);
drive_info.icon_texture = Some(texture);
}
self.drives.push(drive_info);
}
}
}
}
#[cfg(not(windows))]
{
// Windows以外の環境ではダミーデータ
@ -361,32 +379,33 @@ impl NyashExplorer {
free_bytes: 250_000_000_000,
icon_texture: None,
};
if let Some(icon_image) = self.get_drive_icon("C:") {
let texture = self.ctx.load_texture(
"drive_icon_C:",
icon_image,
Default::default()
);
let texture =
self.ctx
.load_texture("drive_icon_C:", icon_image, Default::default());
drive_info.icon_texture = Some(texture);
}
self.drives.push(drive_info);
}
self.status = format!("{}個のドライブを検出しました(アイコン付き)", self.drives.len());
self.status = format!(
"{}個のドライブを検出しました(アイコン付き)",
self.drives.len()
);
}
fn format_bytes(bytes: u64) -> String {
const UNITS: &[&str] = &["B", "KB", "MB", "GB", "TB"];
let mut size = bytes as f64;
let mut unit_index = 0;
while size >= 1024.0 && unit_index < UNITS.len() - 1 {
size /= 1024.0;
unit_index += 1;
}
format!("{:.2} {}", size, UNITS[unit_index])
}
}
@ -422,7 +441,7 @@ impl eframe::App for NyashExplorer {
});
});
});
// ツールバー
egui::TopBottomPanel::top("toolbar").show(ctx, |ui| {
ui.horizontal(|ui| {
@ -433,7 +452,7 @@ impl eframe::App for NyashExplorer {
ui.label("Nyash Explorer - アイコン付きドライブビューアー");
});
});
// ステータスバー
egui::TopBottomPanel::bottom("status_bar").show(ctx, |ui| {
ui.horizontal(|ui| {
@ -443,27 +462,27 @@ impl eframe::App for NyashExplorer {
});
});
});
// メインパネル - ドライブ一覧
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("💾 ドライブ一覧(アイコン付き)");
ui.separator();
egui::ScrollArea::vertical().show(ui, |ui| {
for (index, drive) in self.drives.iter().enumerate() {
let is_selected = self.selected_drive == Some(index);
ui.group(|ui| {
let response = ui.allocate_response(
egui::vec2(ui.available_width(), 100.0),
egui::Sense::click(),
);
if response.clicked() {
self.selected_drive = Some(index);
self.status = format!("{} を選択しました", drive.name);
}
// 背景色
if is_selected {
ui.painter().rect_filled(
@ -472,13 +491,13 @@ impl eframe::App for NyashExplorer {
egui::Color32::from_rgb(100, 149, 237).gamma_multiply(0.2),
);
}
ui.allocate_new_ui(egui::UiBuilder::new().max_rect(response.rect), |ui| {
ui.horizontal(|ui| {
// ドライブアイコン
ui.vertical(|ui| {
ui.add_space(10.0);
if let Some(texture) = &drive.icon_texture {
ui.image((texture.id(), egui::vec2(48.0, 48.0)));
} else {
@ -493,19 +512,20 @@ impl eframe::App for NyashExplorer {
ui.label(egui::RichText::new(icon_text).size(40.0));
}
});
ui.add_space(20.0);
// ドライブ情報
ui.vertical(|ui| {
ui.add_space(10.0);
ui.label(egui::RichText::new(&drive.name).size(16.0).strong());
ui.label(format!("種類: {}", drive.drive_type));
if drive.total_bytes > 0 {
let used_bytes = drive.total_bytes - drive.free_bytes;
let usage_percent = (used_bytes as f32 / drive.total_bytes as f32) * 100.0;
let usage_percent =
(used_bytes as f32 / drive.total_bytes as f32) * 100.0;
ui.horizontal(|ui| {
ui.label(format!(
"使用領域: {} / {} ({:.1}%)",
@ -514,7 +534,7 @@ impl eframe::App for NyashExplorer {
usage_percent
));
});
// 使用率バー
let bar_width = 200.0;
let bar_height = 10.0;
@ -522,14 +542,14 @@ impl eframe::App for NyashExplorer {
egui::vec2(bar_width, bar_height),
egui::Sense::hover(),
);
// 背景
ui.painter().rect_filled(
rect,
2.0,
egui::Color32::from_gray(60),
);
// 使用領域
let used_width = bar_width * (usage_percent / 100.0);
let used_rect = egui::Rect::from_min_size(
@ -549,18 +569,20 @@ impl eframe::App for NyashExplorer {
});
});
});
ui.add_space(5.0);
}
});
// クイックアクション
ui.separator();
ui.horizontal(|ui| {
if ui.button("🐱 Nyashについて").clicked() {
self.status = "Nyash - Everything is Box! Windows APIでアイコンも取得できる化け物言語".to_string();
self.status =
"Nyash - Everything is Box! Windows APIでアイコンも取得できる化け物言語"
.to_string();
}
if ui.button("📊 システム情報").clicked() {
let total: u64 = self.drives.iter().map(|d| d.total_bytes).sum();
let free: u64 = self.drives.iter().map(|d| d.free_bytes).sum();
@ -573,4 +595,4 @@ impl eframe::App for NyashExplorer {
});
});
}
}
}

View File

@ -10,7 +10,7 @@ fn main() -> eframe::Result {
.with_title("Nyash Notepad - にゃっしゅメモ帳"),
..Default::default()
};
eframe::run_native(
"Nyash Notepad JP",
options,
@ -26,27 +26,28 @@ fn main() -> eframe::Result {
fn setup_custom_fonts(ctx: &egui::Context) {
// フォント設定を取得
let mut fonts = egui::FontDefinitions::default();
// 日本語フォント(可変ウェイト)を追加
fonts.font_data.insert(
"noto_sans_jp".to_owned(),
egui::FontData::from_static(include_bytes!("../assets/NotoSansJP-VariableFont_wght.ttf")).into(),
egui::FontData::from_static(include_bytes!("../assets/NotoSansJP-VariableFont_wght.ttf"))
.into(),
);
// フォントファミリーに追加
fonts
.families
.entry(FontFamily::Proportional)
.or_default()
.insert(0, "noto_sans_jp".to_owned()); // 一番優先度高く追加
// モノスペースフォントにも日本語フォントを追加
fonts
.families
.entry(FontFamily::Monospace)
.or_default()
.push("noto_sans_jp".to_owned());
// フォント設定を適用
ctx.set_fonts(fonts);
}
@ -76,7 +77,7 @@ impl eframe::App for NyashNotepad {
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
}
});
ui.menu_button("編集", |ui| {
if ui.button("すべて選択").clicked() {
self.status = "すべて選択(未実装)".to_string();
@ -85,31 +86,33 @@ impl eframe::App for NyashNotepad {
self.status = "検索機能(未実装)".to_string();
}
});
ui.menu_button("ヘルプ", |ui| {
if ui.button("Nyashについて").clicked() {
self.status = "Nyash - Everything is Box! 🐱".to_string();
}
if ui.button("使い方").clicked() {
self.status = "テキストを入力して、にゃっしゅプログラムを書こう!".to_string();
self.status =
"テキストを入力して、にゃっしゅプログラムを書こう!".to_string();
}
});
});
});
// ステータスバー
egui::TopBottomPanel::bottom("status_bar").show(ctx, |ui| {
ui.horizontal(|ui| {
ui.label(&self.status);
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
ui.label(format!("文字数: {} | 行数: {}",
ui.label(format!(
"文字数: {} | 行数: {}",
self.text.chars().count(),
self.text.lines().count()
));
});
});
});
// メインのテキストエディタ
egui::CentralPanel::default().show(ctx, |ui| {
// ツールバー
@ -118,39 +121,39 @@ impl eframe::App for NyashNotepad {
self.text.clear();
self.status = "テキストをクリアしました".to_string();
}
ui.separator();
if ui.button("📋 コピー").clicked() {
ui.output_mut(|o| o.copied_text = self.text.clone());
self.status = "テキストをコピーしました".to_string();
}
if ui.button("✂️ カット").clicked() {
ui.output_mut(|o| o.copied_text = self.text.clone());
self.text.clear();
self.status = "テキストをカットしました".to_string();
}
if ui.button("📄 ペースト").clicked() {
self.status = "ペースト機能(簡易版)".to_string();
}
ui.separator();
if ui.button("🔤 フォント大").clicked() {
ctx.set_zoom_factor(ctx.zoom_factor() * 1.1);
self.status = "フォントサイズを拡大しました".to_string();
}
if ui.button("🔡 フォント小").clicked() {
ctx.set_zoom_factor(ctx.zoom_factor() * 0.9);
self.status = "フォントサイズを縮小しました".to_string();
}
});
ui.separator();
// テキストエディタ本体
egui::ScrollArea::vertical().show(ui, |ui| {
ui.add(
@ -158,22 +161,26 @@ impl eframe::App for NyashNotepad {
.font(egui::TextStyle::Monospace)
.desired_width(f32::INFINITY)
.desired_rows(20)
.hint_text("ここにテキストを入力してください... にゃ!🐱")
.hint_text("ここにテキストを入力してください... にゃ!🐱"),
);
});
// サンプルボタン
ui.separator();
ui.horizontal(|ui| {
ui.label("クイック挿入: ");
if ui.button("📝 Nyashサンプル").clicked() {
self.text.push_str("\n// Nyash - Everything is Box! すべてがBoxの世界へようこそ\n");
self.text.push_str(
"\n// Nyash - Everything is Box! すべてがBoxの世界へようこそ\n",
);
self.text.push_str("box こんにちは世界 {\n");
self.text.push_str(" init { メッセージ }\n");
self.text.push_str(" \n");
self.text.push_str(" こんにちは世界() {\n");
self.text.push_str(" me.メッセージ = \"こんにちは、Nyashの世界にゃ〜🐱\"\n");
self.text.push_str(
" me.メッセージ = \"こんにちは、Nyashの世界にゃ〜🐱\"\n",
);
self.text.push_str(" }\n");
self.text.push_str(" \n");
self.text.push_str(" 挨拶() {\n");
@ -186,13 +193,16 @@ impl eframe::App for NyashNotepad {
self.text.push_str("hello.挨拶()\n");
self.status = "Nyashサンプルコードを挿入しました".to_string();
}
if ui.button("🕐 現在時刻").clicked() {
let now = chrono::Local::now();
self.text.push_str(&format!("\n// 挿入時刻: {}\n", now.format("%Y年%m月%d日 %H時%M分%S秒")));
self.text.push_str(&format!(
"\n// 挿入時刻: {}\n",
now.format("%Y年%m月%d日 %H時%M分%S秒")
));
self.status = "現在時刻を挿入しました".to_string();
}
if ui.button("🐱 ASCIIにゃんこ").clicked() {
self.text.push_str("\n/*\n");
self.text.push_str(" /\\_/\\ \n");
@ -205,4 +215,4 @@ impl eframe::App for NyashNotepad {
});
});
}
}
}

View File

@ -11,7 +11,7 @@ fn main() -> eframe::Result {
.with_title("Nyash Notepad"),
..Default::default()
};
eframe::run_native(
"Nyash Notepad",
options,
@ -44,14 +44,14 @@ impl eframe::App for NyashNotepad {
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
}
});
ui.menu_button("編集", |ui| {
if ui.button("すべて選択").clicked() {
// TODO: テキストエリア全選択
self.status = "すべて選択(未実装)".to_string();
}
});
ui.menu_button("ヘルプ", |ui| {
if ui.button("Nyashについて").clicked() {
self.status = "Nyash - Everything is Box! 🐱".to_string();
@ -59,7 +59,7 @@ impl eframe::App for NyashNotepad {
});
});
});
// ステータスバー
egui::TopBottomPanel::bottom("status_bar").show(ctx, |ui| {
ui.horizontal(|ui| {
@ -69,7 +69,7 @@ impl eframe::App for NyashNotepad {
});
});
});
// メインのテキストエディタ
egui::CentralPanel::default().show(ctx, |ui| {
// ツールバー
@ -78,28 +78,28 @@ impl eframe::App for NyashNotepad {
self.text.clear();
self.status = "テキストをクリアしました".to_string();
}
ui.separator();
if ui.button("📋 コピー").clicked() {
ui.output_mut(|o| o.copied_text = self.text.clone());
self.status = "テキストをコピーしました".to_string();
}
if ui.button("✂️ カット").clicked() {
ui.output_mut(|o| o.copied_text = self.text.clone());
self.text.clear();
self.status = "テキストをカットしました".to_string();
}
if ui.button("📄 ペースト").clicked() {
// egui 0.29ではクリップボードAPIが変更されている
self.status = "ペースト機能(簡易版)".to_string();
}
});
ui.separator();
// テキストエディタ本体
egui::ScrollArea::vertical().show(ui, |ui| {
ui.add(
@ -107,10 +107,10 @@ impl eframe::App for NyashNotepad {
.font(egui::TextStyle::Monospace)
.desired_width(f32::INFINITY)
.desired_rows(20)
.hint_text("ここにテキストを入力してください... にゃ!")
.hint_text("ここにテキストを入力してください... にゃ!"),
);
});
// サンプルボタン
ui.separator();
ui.horizontal(|ui| {
@ -120,18 +120,20 @@ impl eframe::App for NyashNotepad {
self.text.push_str(" init { message }\n");
self.text.push_str(" \n");
self.text.push_str(" HelloWorld() {\n");
self.text.push_str(" me.message = \"Hello, Nyash World! にゃ!\"\n");
self.text
.push_str(" me.message = \"Hello, Nyash World! にゃ!\"\n");
self.text.push_str(" }\n");
self.text.push_str("}\n");
self.status = "Nyashサンプルコードを挿入しました".to_string();
}
if ui.button("時刻挿入").clicked() {
let now = chrono::Local::now();
self.text.push_str(&format!("\n{}\n", now.format("%Y-%m-%d %H:%M:%S")));
self.text
.push_str(&format!("\n{}\n", now.format("%Y-%m-%d %H:%M:%S")));
self.status = "現在時刻を挿入しました".to_string();
}
});
});
}
}
}

View File

@ -10,7 +10,7 @@ fn main() -> eframe::Result {
.with_title("Nyash Notepad - ASCII Version"),
..Default::default()
};
eframe::run_native(
"Nyash Notepad",
options,
@ -43,13 +43,13 @@ impl eframe::App for NyashNotepad {
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
}
});
ui.menu_button("Edit", |ui| {
if ui.button("Select All").clicked() {
self.status = "Select All (not implemented)".to_string();
}
});
ui.menu_button("Help", |ui| {
if ui.button("About Nyash").clicked() {
self.status = "Nyash - Everything is Box! (^-^)".to_string();
@ -57,7 +57,7 @@ impl eframe::App for NyashNotepad {
});
});
});
// Status bar
egui::TopBottomPanel::bottom("status_bar").show(ctx, |ui| {
ui.horizontal(|ui| {
@ -67,45 +67,45 @@ impl eframe::App for NyashNotepad {
});
});
});
// Main text editor
egui::CentralPanel::default().show(ctx, |ui| {
// Title
ui.heading("=== Nyash Text Editor ===");
// Toolbar without emojis
ui.horizontal(|ui| {
if ui.button("[X] Clear").clicked() {
self.text.clear();
self.status = "Text cleared".to_string();
}
ui.separator();
if ui.button("[C] Copy").clicked() {
ui.output_mut(|o| o.copied_text = self.text.clone());
self.status = "Text copied to clipboard".to_string();
}
if ui.button("[X] Cut").clicked() {
ui.output_mut(|o| o.copied_text = self.text.clone());
self.text.clear();
self.status = "Text cut to clipboard".to_string();
}
if ui.button("[V] Paste").clicked() {
self.status = "Paste (simplified version)".to_string();
}
ui.separator();
if ui.button("[?] Help").clicked() {
self.status = "Nyash Notepad v1.0 - Everything is Box!".to_string();
}
});
ui.separator();
// Text editor body
egui::ScrollArea::vertical().show(ui, |ui| {
ui.add(
@ -113,22 +113,23 @@ impl eframe::App for NyashNotepad {
.font(egui::TextStyle::Monospace)
.desired_width(f32::INFINITY)
.desired_rows(20)
.hint_text("Type your text here... nya!")
.hint_text("Type your text here... nya!"),
);
});
// Sample buttons
ui.separator();
ui.horizontal(|ui| {
ui.label("Quick Insert: ");
if ui.button("Nyash Sample Code").clicked() {
self.text.push_str("\n// Nyash - Everything is Box!\n");
self.text.push_str("box HelloWorld {\n");
self.text.push_str(" init { message }\n");
self.text.push_str(" \n");
self.text.push_str(" HelloWorld() {\n");
self.text.push_str(" me.message = \"Hello, Nyash World! nya!\"\n");
self.text
.push_str(" me.message = \"Hello, Nyash World! nya!\"\n");
self.text.push_str(" }\n");
self.text.push_str(" \n");
self.text.push_str(" greet() {\n");
@ -141,13 +142,14 @@ impl eframe::App for NyashNotepad {
self.text.push_str("hello.greet()\n");
self.status = "Nyash sample code inserted".to_string();
}
if ui.button("Current Time").clicked() {
let now = chrono::Local::now();
self.text.push_str(&format!("\n[{}]\n", now.format("%Y-%m-%d %H:%M:%S")));
self.text
.push_str(&format!("\n[{}]\n", now.format("%Y-%m-%d %H:%M:%S")));
self.status = "Timestamp inserted".to_string();
}
if ui.button("ASCII Art Cat").clicked() {
self.text.push_str("\n");
self.text.push_str(" /\\_/\\ \n");
@ -160,4 +162,4 @@ impl eframe::App for NyashNotepad {
});
});
}
}
}

View File

@ -10,7 +10,7 @@ fn main() -> eframe::Result {
.with_title("Nyash Notepad"),
..Default::default()
};
eframe::run_native(
"Nyash Notepad",
options,
@ -43,13 +43,13 @@ impl eframe::App for NyashNotepad {
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
}
});
ui.menu_button("Edit", |ui| {
if ui.button("Select All").clicked() {
self.status = "Select All (not implemented)".to_string();
}
});
ui.menu_button("Help", |ui| {
if ui.button("About Nyash").clicked() {
self.status = "Nyash - Everything is Box!".to_string();
@ -57,7 +57,7 @@ impl eframe::App for NyashNotepad {
});
});
});
// Status bar
egui::TopBottomPanel::bottom("status_bar").show(ctx, |ui| {
ui.horizontal(|ui| {
@ -67,7 +67,7 @@ impl eframe::App for NyashNotepad {
});
});
});
// Main text editor
egui::CentralPanel::default().show(ctx, |ui| {
// Toolbar
@ -76,27 +76,27 @@ impl eframe::App for NyashNotepad {
self.text.clear();
self.status = "Text cleared".to_string();
}
ui.separator();
if ui.button("Copy").clicked() {
ui.output_mut(|o| o.copied_text = self.text.clone());
self.status = "Text copied to clipboard".to_string();
}
if ui.button("Cut").clicked() {
ui.output_mut(|o| o.copied_text = self.text.clone());
self.text.clear();
self.status = "Text cut to clipboard".to_string();
}
if ui.button("Paste").clicked() {
self.status = "Paste (simplified version)".to_string();
}
});
ui.separator();
// Text editor body
egui::ScrollArea::vertical().show(ui, |ui| {
ui.add(
@ -104,10 +104,10 @@ impl eframe::App for NyashNotepad {
.font(egui::TextStyle::Monospace)
.desired_width(f32::INFINITY)
.desired_rows(20)
.hint_text("Type your text here... nya!")
.hint_text("Type your text here... nya!"),
);
});
// Sample buttons
ui.separator();
ui.horizontal(|ui| {
@ -117,18 +117,20 @@ impl eframe::App for NyashNotepad {
self.text.push_str(" init { message }\n");
self.text.push_str(" \n");
self.text.push_str(" HelloWorld() {\n");
self.text.push_str(" me.message = \"Hello, Nyash World! nya!\"\n");
self.text
.push_str(" me.message = \"Hello, Nyash World! nya!\"\n");
self.text.push_str(" }\n");
self.text.push_str("}\n");
self.status = "Nyash sample code inserted".to_string();
}
if ui.button("Insert Timestamp").clicked() {
let now = chrono::Local::now();
self.text.push_str(&format!("\n{}\n", now.format("%Y-%m-%d %H:%M:%S")));
self.text
.push_str(&format!("\n{}\n", now.format("%Y-%m-%d %H:%M:%S")));
self.status = "Timestamp inserted".to_string();
}
});
});
}
}
}

View File

@ -12,7 +12,7 @@ fn main() -> eframe::Result {
.with_title("Nyash Notepad"),
..Default::default()
};
eframe::run_native(
"Nyash Notepad",
options,
@ -28,10 +28,10 @@ fn main() -> eframe::Result {
fn setup_custom_fonts(ctx: &egui::Context) {
// Start with the default fonts
let mut fonts = egui::FontDefinitions::default();
// Use built-in fonts for cross-platform compatibility
// Note: On Windows, egui will automatically use system fonts
// Tell egui to use these fonts
ctx.set_fonts(fonts);
}
@ -71,13 +71,13 @@ impl eframe::App for NyashNotepad {
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
}
});
ui.menu_button("Edit", |ui| {
if ui.button("Select All").clicked() {
self.status = "Select All (not implemented)".to_string();
}
});
ui.menu_button("Help", |ui| {
if ui.button("About Nyash").clicked() {
self.status = "Nyash - Everything is Box!".to_string();
@ -85,7 +85,7 @@ impl eframe::App for NyashNotepad {
});
});
});
// Status bar
egui::TopBottomPanel::bottom("status_bar").show(ctx, |ui| {
ui.horizontal(|ui| {
@ -95,7 +95,7 @@ impl eframe::App for NyashNotepad {
});
});
});
// Main text editor
egui::CentralPanel::default().show(ctx, |ui| {
// Toolbar with ASCII-only labels
@ -104,27 +104,27 @@ impl eframe::App for NyashNotepad {
self.text.clear();
self.status = "Text cleared".to_string();
}
ui.separator();
if ui.button("[Copy]").clicked() {
ui.output_mut(|o| o.copied_text = self.text.clone());
self.status = "Text copied to clipboard".to_string();
}
if ui.button("[Cut]").clicked() {
ui.output_mut(|o| o.copied_text = self.text.clone());
self.text.clear();
self.status = "Text cut to clipboard".to_string();
}
if ui.button("[Paste]").clicked() {
self.status = "Paste (simplified version)".to_string();
}
});
ui.separator();
// Text editor body
egui::ScrollArea::vertical().show(ui, |ui| {
ui.add(
@ -132,10 +132,10 @@ impl eframe::App for NyashNotepad {
.font(egui::TextStyle::Monospace)
.desired_width(f32::INFINITY)
.desired_rows(20)
.hint_text("Type your text here... nya!")
.hint_text("Type your text here... nya!"),
);
});
// Sample buttons
ui.separator();
ui.horizontal(|ui| {
@ -145,15 +145,17 @@ impl eframe::App for NyashNotepad {
self.text.push_str(" init { message }\n");
self.text.push_str(" \n");
self.text.push_str(" HelloWorld() {\n");
self.text.push_str(" me.message = \"Hello, Nyash World! nya!\"\n");
self.text
.push_str(" me.message = \"Hello, Nyash World! nya!\"\n");
self.text.push_str(" }\n");
self.text.push_str("}\n");
self.status = "Nyash sample code inserted".to_string();
}
if ui.button("Insert Timestamp").clicked() {
let now = chrono::Local::now();
self.text.push_str(&format!("\n{}\n", now.format("%Y-%m-%d %H:%M:%S")));
self.text
.push_str(&format!("\n{}\n", now.format("%Y-%m-%d %H:%M:%S")));
self.status = "Timestamp inserted".to_string();
}
});

View File

@ -4,25 +4,23 @@
#[cfg(windows)]
use windows::{
core::*,
Win32::{
Storage::FileSystem::*,
UI::Shell::*,
UI::WindowsAndMessaging::*,
Graphics::Gdi::*,
},
Win32::{Graphics::Gdi::*, Storage::FileSystem::*, UI::Shell::*, UI::WindowsAndMessaging::*},
};
fn main() {
#[cfg(windows)]
unsafe {
println!("Windows Icon Extraction Test");
// C:ドライブのアイコンを取得
let drive_path = "C:\\";
let drive_path_wide: Vec<u16> = drive_path.encode_utf16().chain(std::iter::once(0)).collect();
let drive_path_wide: Vec<u16> = drive_path
.encode_utf16()
.chain(std::iter::once(0))
.collect();
let mut shfi = SHFILEINFOW::default();
let result = SHGetFileInfoW(
PCWSTR::from_raw(drive_path_wide.as_ptr()),
FILE_ATTRIBUTE_NORMAL,
@ -30,74 +28,80 @@ fn main() {
std::mem::size_of::<SHFILEINFOW>() as u32,
SHGFI_ICON | SHGFI_LARGEICON | SHGFI_USEFILEATTRIBUTES,
);
println!("SHGetFileInfoW result: {}", result);
if result != 0 && !shfi.hIcon.is_invalid() {
println!("Icon handle obtained!");
// アイコン情報を取得
let mut icon_info = ICONINFO::default();
if GetIconInfo(shfi.hIcon, &mut icon_info).is_ok() {
println!("GetIconInfo success!");
println!("fIcon: {}", icon_info.fIcon.as_bool());
// ビットマップ情報を取得
if !icon_info.hbmColor.is_invalid() {
println!("Color bitmap handle obtained!");
// ビットマップ情報を取得
let mut bitmap = BITMAP::default();
let size = GetObjectW(
icon_info.hbmColor.into(),
icon_info.hbmColor.into(),
std::mem::size_of::<BITMAP>() as i32,
Some(&mut bitmap as *mut _ as *mut _)
Some(&mut bitmap as *mut _ as *mut _),
);
if size > 0 {
println!("Bitmap info:");
println!(" Width: {}", bitmap.bmWidth);
println!(" Height: {}", bitmap.bmHeight);
println!(" Bits per pixel: {}", bitmap.bmBitsPixel);
println!(" Planes: {}", bitmap.bmPlanes);
// ピクセルデータを取得
let pixel_count = (bitmap.bmWidth * bitmap.bmHeight) as usize;
let bytes_per_pixel = (bitmap.bmBitsPixel / 8) as usize;
let mut pixels = vec![0u8; pixel_count * bytes_per_pixel];
let copied = GetBitmapBits(
icon_info.hbmColor,
pixels.len() as i32,
pixels.as_mut_ptr() as *mut _
pixels.as_mut_ptr() as *mut _,
);
println!("Copied {} bytes of pixel data", copied);
// 簡易的にBMPファイルとして保存
if copied > 0 {
save_as_bmp("c_drive_icon.bmp", &pixels, bitmap.bmWidth, bitmap.bmHeight, bitmap.bmBitsPixel);
save_as_bmp(
"c_drive_icon.bmp",
&pixels,
bitmap.bmWidth,
bitmap.bmHeight,
bitmap.bmBitsPixel,
);
println!("Saved as c_drive_icon.bmp");
}
}
// ビットマップを削除
let _ = DeleteObject(icon_info.hbmColor.into());
}
if !icon_info.hbmMask.is_invalid() {
println!("Mask bitmap handle obtained!");
let _ = DeleteObject(icon_info.hbmMask.into());
}
}
// アイコンを破棄
let _ = DestroyIcon(shfi.hIcon);
} else {
println!("Failed to get icon");
}
}
#[cfg(not(windows))]
println!("This test only works on Windows");
}
@ -106,17 +110,17 @@ fn main() {
fn save_as_bmp(filename: &str, pixels: &[u8], width: i32, height: i32, bits_per_pixel: u16) {
use std::fs::File;
use std::io::Write;
// 簡易BMPヘッダー実際の実装はもっと複雑
let file_size = 54 + pixels.len() as u32;
let mut file = File::create(filename).unwrap();
// BMPファイルヘッダー
file.write_all(b"BM").unwrap(); // マジックナンバー
file.write_all(&file_size.to_le_bytes()).unwrap();
file.write_all(&0u32.to_le_bytes()).unwrap(); // 予約
file.write_all(&54u32.to_le_bytes()).unwrap(); // データオフセット
// BMPインフォヘッダー
file.write_all(&40u32.to_le_bytes()).unwrap(); // ヘッダーサイズ
file.write_all(&width.to_le_bytes()).unwrap();
@ -124,14 +128,15 @@ fn save_as_bmp(filename: &str, pixels: &[u8], width: i32, height: i32, bits_per_
file.write_all(&1u16.to_le_bytes()).unwrap(); // プレーン数
file.write_all(&bits_per_pixel.to_le_bytes()).unwrap();
file.write_all(&0u32.to_le_bytes()).unwrap(); // 圧縮なし
file.write_all(&(pixels.len() as u32).to_le_bytes()).unwrap();
file.write_all(&(pixels.len() as u32).to_le_bytes())
.unwrap();
file.write_all(&0i32.to_le_bytes()).unwrap(); // X解像度
file.write_all(&0i32.to_le_bytes()).unwrap(); // Y解像度
file.write_all(&0u32.to_le_bytes()).unwrap(); // カラーテーブル数
file.write_all(&0u32.to_le_bytes()).unwrap(); // 重要な色数
// ピクセルデータ
file.write_all(pixels).unwrap();
println!("BMP file saved: {}", filename);
}
}