feat: Windows GUI development with egui - simple notepad example

- Fixed EguiBox Send+Sync trait bounds for thread safety
- Added missing Arc import for EguiBox implementation
- Simplified font setup in Windows notepad example
- Successfully built 4.5MB Windows GUI executable
- Nyash can now create native Windows desktop applications! 🎉
This commit is contained in:
Moe Charm
2025-08-20 08:03:36 +09:00
parent 670615d1de
commit 8f82437c58
9 changed files with 140 additions and 33 deletions

0
build_wasm_errors.txt Normal file
View File

View File

@ -29,26 +29,8 @@ fn setup_custom_fonts(ctx: &egui::Context) {
// Start with the default fonts
let mut fonts = egui::FontDefinitions::default();
// Use default system fonts for better Windows compatibility
fonts.font_data.insert(
"system".to_owned(),
std::sync::Arc::new(egui::FontData::from_static(include_bytes!(
"C:/Windows/Fonts/arial.ttf"
))),
);
// Configure font families
fonts
.families
.entry(egui::FontFamily::Proportional)
.or_default()
.push("system".to_owned());
fonts
.families
.entry(egui::FontFamily::Monospace)
.or_default()
.push("system".to_owned());
// 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);

View File

@ -0,0 +1,13 @@
// 最もシンプルなWindowsテスト
print("Hello Windows!")
print("1 + 1 = " + (1 + 1))
print("Nyash is running!")
// ループテスト
local i = 0
loop(i < 3) {
print("Count: " + i)
i = i + 1
}
print("Done!")

View File

@ -0,0 +1,15 @@
// Windows実行テスト
local console = new ConsoleBox()
console.log("🎉 Hello from Windows Nyash!")
console.log("Everything is Box on Windows too! 🐱")
// 基本的な計算テスト
local math = new MathBox()
local result = math.add(10, 32)
console.log("10 + 32 = " + result)
// StringBoxテスト
local str = new StringBox("Windows")
console.log("Running on: " + str.value)
print("✨ Nyash works perfectly on Windows! ✨")

View File

@ -0,0 +1,26 @@
// シンプルなWindowsテスト
print("🎉 Nyash on Windows!")
print("Everything is Box!")
// 基本的な文字列操作
local str1 = new StringBox("Hello")
local str2 = new StringBox("Windows")
print(str1.value + " " + str2.value + "!")
// 数値演算(直接)
local num1 = new IntegerBox(42)
local num2 = new IntegerBox(8)
print("Answer: " + num1.value + " + " + num2.value + " = " + (num1.value + num2.value))
// ArrayBoxテスト
local arr = new ArrayBox()
arr.push("First")
arr.push("Second")
arr.push("Third")
print("Array length: " + arr.length())
// MapBoxテスト
local map = new MapBox()
map.set("os", "Windows")
map.set("arch", "x86_64")
print("Running on: " + map.get("os"))

View File

@ -36,8 +36,8 @@
use crate::box_trait::{NyashBox, StringBox, BoolBox, BoxCore, BoxBase};
use crate::interpreter::RuntimeError;
use std::any::Any;
use std::sync::RwLock;
use eframe::{self, epaint::Vec2};
use std::sync::{Arc, RwLock};
use eframe::{self, egui, epaint::Vec2};
/// EguiBox - GUI アプリケーションを包むBox
///
@ -52,8 +52,8 @@ pub struct EguiBox {
base: BoxBase,
title: String,
size: Vec2,
app_state: RwLock<Box<dyn Any + Send>>,
update_fn: Option<Arc<dyn Fn(&mut Box<dyn Any + Send>, &egui::Context) + Send + Sync>>,
app_state: RwLock<Box<dyn Any + Send + Sync>>,
update_fn: Option<Arc<dyn Fn(&mut Box<dyn Any + Send + Sync>, &egui::Context) + Send + Sync>>,
}
impl std::fmt::Debug for EguiBox {
@ -73,7 +73,7 @@ impl Clone for EguiBox {
base: BoxBase::new(), // New unique ID for clone
title: self.title.clone(),
size: self.size,
app_state: RwLock::new(Box::new(()) as Box<dyn Any + Send>),
app_state: RwLock::new(Box::new(()) as Box<dyn Any + Send + Sync>),
update_fn: self.update_fn.clone(), // Arc is cloneable
}
}
@ -85,20 +85,20 @@ impl EguiBox {
base: BoxBase::new(),
title: "Nyash GUI Application".to_string(),
size: Vec2::new(800.0, 600.0),
app_state: RwLock::new(Box::new(()) as Box<dyn Any + Send>),
app_state: RwLock::new(Box::new(()) as Box<dyn Any + Send + Sync>),
update_fn: None,
}
}
/// アプリケーション状態を設定
pub fn set_app_state<T: Any + Send + 'static>(&mut self, state: T) {
pub fn set_app_state<T: Any + Send + Sync + 'static>(&mut self, state: T) {
*self.app_state.write().unwrap() = Box::new(state);
}
/// 更新関数を設定
pub fn set_update_fn<F>(&mut self, f: F)
where
F: Fn(&mut Box<dyn Any + Send>, &egui::Context) + Send + Sync + 'static
F: Fn(&mut Box<dyn Any + Send + Sync>, &egui::Context) + Send + Sync + 'static
{
self.update_fn = Some(Arc::new(f));
}
@ -106,8 +106,8 @@ impl EguiBox {
// NyashApp - eframe::Appを実装する内部構造体
struct NyashApp {
app_state: Arc<RwLock<Box<dyn Any + Send>>>,
update_fn: Arc<dyn Fn(&mut Box<dyn Any + Send>, &egui::Context) + Send + Sync>,
app_state: Arc<RwLock<Box<dyn Any + Send + Sync>>>,
update_fn: Arc<dyn Fn(&mut Box<dyn Any + Send + Sync>, &egui::Context) + Send + Sync>,
}
impl eframe::App for NyashApp {
@ -185,7 +185,7 @@ impl EguiBox {
let state_snapshot = self.app_state.read().unwrap();
// Note: This is a simplified approach - in a full implementation,
// we would need a more sophisticated state sharing mechanism
let app_state = Arc::new(RwLock::new(Box::new(()) as Box<dyn Any + Send>));
let app_state = Arc::new(RwLock::new(Box::new(()) as Box<dyn Any + Send + Sync>));
drop(state_snapshot);
let update_fn = Arc::clone(update_fn);

View File

@ -734,7 +734,7 @@ impl NyashInterpreter {
// 🔥 Phase 8.8: pack透明化システム - ビルトインBox判定
use crate::box_trait::is_builtin_box;
let is_builtin = is_builtin_box(parent);
let mut is_builtin = is_builtin_box(parent);
// GUI機能が有効な場合はEguiBoxも追加判定
#[cfg(all(feature = "gui", not(target_arch = "wasm32")))]

View File

@ -1106,7 +1106,7 @@ impl NyashInterpreter {
// 🔥 Phase 8.8: pack透明化システム - ビルトインBox判定
use crate::box_trait::is_builtin_box;
let is_builtin = is_builtin_box(parent_name);
let mut is_builtin = is_builtin_box(parent_name);
// GUI機能が有効な場合はEguiBoxも追加判定
#[cfg(all(feature = "gui", not(target_arch = "wasm32")))]

71
test_results.txt Normal file
View File

@ -0,0 +1,71 @@
running 8 tests
test mir::instruction_v2::tests::test_instruction_count ... ok
test mir::instruction_v2::tests::test_ownership_operations ... ok
test mir::instruction_v2::tests::test_effect_categories ... ok
test instance_v2::tests::test_from_declaration_creation ... ok
test instance_v2::tests::test_from_any_box_creation ... ok
test instance_v2::tests::test_unified_approach ... ok
test instance_v2::tests::test_field_operations ... ok
test config::nyash_toml_v2::tests::test_parse_v2_config ... ok
test result: ok. 8 passed; 0 failed; 0 ignored; 0 measured; 148 filtered out; finished in 0.04s
running 8 tests
test mir::instruction_v2::tests::test_ownership_operations ... ok
test mir::instruction_v2::tests::test_instruction_count ... ok
test mir::instruction_v2::tests::test_effect_categories ... ok
test instance_v2::tests::test_field_operations ... ok
test instance_v2::tests::test_from_declaration_creation ... ok
test instance_v2::tests::test_from_any_box_creation ... ok
test instance_v2::tests::test_unified_approach ... ok
test config::nyash_toml_v2::tests::test_parse_v2_config ... ok
test result: ok. 8 passed; 0 failed; 0 ignored; 0 measured; 137 filtered out; finished in 0.04s
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 3 filtered out; finished in 0.00s
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 16 filtered out; finished in 0.00s
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out; finished in 0.00s
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 3 filtered out; finished in 0.00s
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 3 filtered out; finished in 0.00s
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s