## 🔧 言語機能改善 - from予約語問題を解決する":"継承演算子を実装 - box Child : Parent 構文でより直感的な継承表現 - tokenizer/parserを更新、from を変数名として使用可能に ## 📚 ドキュメント大改善(1000行以上追加) 全14Box型に包括的なJavaDoc風ドキュメントを追加: - StringBox: 文字列操作メソッド群 - IntegerBox/BoolBox: 基本データ型と演算子 - MathBox/RandomBox/TimeBox: 計算・ユーティリティ - ConsoleBox/DebugBox/SoundBox: システムIO - MapBox/NullBox: データ構造 - EguiBox: デスクトップGUI - SimpleIntentBox: P2P通信 各Boxに概要・メソッド一覧・使用例・実用例・注意事項を完備 ## 🧹 プロジェクト整理 - ルートディレクトリから60個のテストファイルを削除 (development/root_tests/に移動済み) - 不要ファイル削除: bmp, tar.xz, html, 空フォルダ等 - examplesフォルダへ適切なファイルを移動 ## 📝 その他の更新 - CLAUDE.md: パーサーデバッグ機能の説明追加 - sessions/: AI相談記録2件を保存 - from予約語問題の解決策検討 - 標準Box型(ArrayBox等)の設計相談
194 lines
5.7 KiB
Rust
194 lines
5.7 KiB
Rust
/*! 🖼️ EguiBox - デスクトップGUIアプリBox
|
||
* Everything is Box哲学によるGUIフレームワーク統合
|
||
* 「なんでもBoxにできる」化け物言語の第一歩!
|
||
*
|
||
* ## 📝 概要
|
||
* Rustの人気GUI框架eframeを使ったネイティブデスクトップアプリ作成。
|
||
* Nyashコードから直接GUI操作が可能!
|
||
*
|
||
* ## 🛠️ 利用可能メソッド
|
||
* - `setTitle(title)` - ウィンドウタイトル設定
|
||
* - `setSize(width, height)` - ウィンドウサイズ設定
|
||
* - `run()` - GUIアプリ実行開始
|
||
* - `addText(text)` - テキスト表示追加
|
||
* - `addButton(label)` - ボタン追加
|
||
* - `close()` - ウィンドウ閉じる
|
||
*
|
||
* ## 💡 使用例
|
||
* ```nyash
|
||
* // 基本的なGUIアプリ
|
||
* local app
|
||
* app = new EguiBox()
|
||
* app.setTitle("Nyash GUI Demo")
|
||
* app.setSize(800, 600)
|
||
* app.addText("Welcome to Nyash!")
|
||
* app.addButton("Click Me")
|
||
* app.run() // GUIアプリ開始
|
||
* ```
|
||
*
|
||
* ## ⚠️ 注意
|
||
* - デスクトップ環境でのみ利用可能(WASM環境では無効)
|
||
* - `run()`はブロッキング動作(アプリ終了まで制御を返さない)
|
||
*/
|
||
|
||
use crate::box_trait::{NyashBox, StringBox, BoolBox};
|
||
use crate::interpreter::RuntimeError;
|
||
use std::any::Any;
|
||
use std::sync::{Arc, Mutex};
|
||
use eframe::{self, epaint::Vec2};
|
||
|
||
/// EguiBox - GUI アプリケーションを包むBox
|
||
///
|
||
/// # 使用例
|
||
/// ```nyash
|
||
/// app = new EguiBox()
|
||
/// app.setTitle("My Nyash App")
|
||
/// app.setSize(800, 600)
|
||
/// app.run()
|
||
/// ```
|
||
pub struct EguiBox {
|
||
title: String,
|
||
size: Vec2,
|
||
app_state: Arc<Mutex<Box<dyn Any + Send>>>,
|
||
update_fn: Option<Arc<dyn Fn(&mut Box<dyn Any + Send>, &egui::Context) + Send + Sync>>,
|
||
}
|
||
|
||
impl std::fmt::Debug for EguiBox {
|
||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||
f.debug_struct("EguiBox")
|
||
.field("title", &self.title)
|
||
.field("size", &self.size)
|
||
.finish()
|
||
}
|
||
}
|
||
|
||
impl EguiBox {
|
||
pub fn new() -> Self {
|
||
Self {
|
||
title: "Nyash GUI Application".to_string(),
|
||
size: Vec2::new(800.0, 600.0),
|
||
app_state: Arc::new(Mutex::new(Box::new(()) as Box<dyn Any + Send>)),
|
||
update_fn: None,
|
||
}
|
||
}
|
||
|
||
/// アプリケーション状態を設定
|
||
pub fn set_app_state<T: Any + Send + 'static>(&mut self, state: T) {
|
||
self.app_state = Arc::new(Mutex::new(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
|
||
{
|
||
self.update_fn = Some(Arc::new(f));
|
||
}
|
||
}
|
||
|
||
// NyashApp - eframe::Appを実装する内部構造体
|
||
struct NyashApp {
|
||
app_state: Arc<Mutex<Box<dyn Any + Send>>>,
|
||
update_fn: Arc<dyn Fn(&mut Box<dyn Any + Send>, &egui::Context) + Send + Sync>,
|
||
}
|
||
|
||
impl eframe::App for NyashApp {
|
||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||
if let Ok(mut state) = self.app_state.lock() {
|
||
(self.update_fn)(&mut *state, ctx);
|
||
}
|
||
}
|
||
}
|
||
|
||
impl NyashBox for EguiBox {
|
||
fn to_string_box(&self) -> StringBox {
|
||
StringBox::new(
|
||
format!("EguiBox('{}', {}x{})", self.title, self.size.x, self.size.y)
|
||
)
|
||
}
|
||
|
||
fn clone_box(&self) -> Box<dyn NyashBox> {
|
||
// GUI Boxはクローン不可(単一インスタンス)
|
||
Box::new(Self {
|
||
title: self.title.clone(),
|
||
size: self.size,
|
||
app_state: Arc::new(Mutex::new(Box::new(()) as Box<dyn Any + Send>)),
|
||
update_fn: None,
|
||
})
|
||
}
|
||
|
||
fn as_any(&self) -> &dyn Any {
|
||
self
|
||
}
|
||
|
||
fn equals(&self, other: &dyn NyashBox) -> BoolBox {
|
||
if let Some(other_egui) = other.as_any().downcast_ref::<EguiBox>() {
|
||
BoolBox::new(self.title == other_egui.title && self.size == other_egui.size)
|
||
} else {
|
||
BoolBox::new(false)
|
||
}
|
||
}
|
||
|
||
fn type_name(&self) -> &'static str {
|
||
"EguiBox"
|
||
}
|
||
|
||
fn box_id(&self) -> u64 {
|
||
// 簡易的なIDとしてポインタアドレスを使用
|
||
self as *const _ as u64
|
||
}
|
||
}
|
||
|
||
// EguiBoxのメソッド実装(実際にはインタープリターから呼ばれない)
|
||
impl EguiBox {
|
||
pub fn run_gui(&self) -> Result<(), RuntimeError> {
|
||
if let Some(update_fn) = &self.update_fn {
|
||
let app_state = Arc::clone(&self.app_state);
|
||
let update_fn = Arc::clone(update_fn);
|
||
|
||
let options = eframe::NativeOptions {
|
||
viewport: egui::ViewportBuilder::default()
|
||
.with_inner_size(self.size)
|
||
.with_title(&self.title),
|
||
..Default::default()
|
||
};
|
||
|
||
let app = NyashApp {
|
||
app_state,
|
||
update_fn,
|
||
};
|
||
|
||
// 注意: これはブロッキング呼び出し
|
||
let _ = eframe::run_native(
|
||
&self.title,
|
||
options,
|
||
Box::new(|_cc| Ok(Box::new(app))),
|
||
);
|
||
|
||
Ok(())
|
||
} else {
|
||
Err(RuntimeError::InvalidOperation {
|
||
message: "No update function set for EguiBox".to_string(),
|
||
})
|
||
}
|
||
}
|
||
}
|
||
|
||
#[cfg(test)]
|
||
mod tests {
|
||
use super::*;
|
||
|
||
#[test]
|
||
fn test_egui_box_creation() {
|
||
let gui = EguiBox::new();
|
||
assert_eq!(gui.title, "Nyash GUI Application");
|
||
assert_eq!(gui.size, Vec2::new(800.0, 600.0));
|
||
}
|
||
|
||
#[test]
|
||
fn test_egui_box_to_string() {
|
||
let gui = EguiBox::new();
|
||
let s = gui.to_string_box();
|
||
assert_eq!(s.value, "EguiBox('Nyash GUI Application', 800x600)");
|
||
}
|
||
} |