～GUIシステムの設計とウィジェット体系～

# 第13回：Realé - GUI/OSフレームワーク（前編）
## ～GUIシステムの設計とウィジェット体系～

### はじめに

Realéは、クロスプラットフォームに対応したGUI/OSフレームワークです。今回は基本的なGUIシステムの設計とウィジェット体系について解説します。

### GUIシステムの設計

```rust
// GUIシステムのコア
pub struct GuiSystem {
    renderer: Renderer,
    event_system: EventSystem,
    window_manager: WindowManager,
    theme_manager: ThemeManager,
}

impl GuiSystem {
    pub async fn new(config: GuiConfig) -> Result<Self> {
        let renderer = Renderer::new(&config.renderer_config)?;
        let event_system = EventSystem::new();
        let window_manager = WindowManager::new(&config.window_config)?;
        let theme_manager = ThemeManager::new(&config.theme_config)?;
        
        Ok(Self {
            renderer,
            event_system,
            window_manager,
            theme_manager,
        })
    }
    
    pub async fn run(&mut self) -> Result<()> {
        loop {
            // イベントの処理
            self.process_events().await?;
            
            // ウィンドウの更新
            self.window_manager.update().await?;
            
            // 描画
            self.render_frame().await?;
            
            // フレーム同期
            self.synchronize_frame().await?;
        }
    }
}

// レンダリングシステム
pub struct Renderer {
    graphics_context: GraphicsContext,
    render_queue: RenderQueue,
    shader_cache: ShaderCache,
}

impl Renderer {
    pub async fn render_frame(&mut self, scene: &Scene) -> Result<()> {
        // シーンの準備
        let render_commands = self.prepare_scene(scene)?;
        
        // コマンドのキューイング
        for cmd in render_commands {
            self.render_queue.push(cmd)?;
        }
        
        // 描画の実行
        self.graphics_context.execute_commands(&self.render_queue).await?;
        
        // キューのクリア
        self.render_queue.clear();
        
        Ok(())
    }
}
```

### ウィジェット体系

```rust
// ウィジェットの基本トレイト
pub trait Widget: Send + Sync {
    fn id(&self) -> WidgetId;
    fn bounds(&self) -> Rect;
    fn parent(&self) -> Option<WidgetId>;
    fn children(&self) -> &[WidgetId];
    
    fn layout(&mut self, constraints: BoxConstraints) -> Size;
    fn paint(&self, context: &mut PaintContext);
    fn handle_event(&mut self, event: &Event) -> bool;
}

// ウィジェットツリー
pub struct WidgetTree {
    root: WidgetId,
    nodes: HashMap<WidgetId, Box<dyn Widget>>,
    layout_cache: LayoutCache,
}

impl WidgetTree {
    pub fn layout(&mut self) -> Result<()> {
        // レイアウトの再計算が必要なウィジェットを特定
        let dirty_widgets = self.layout_cache.get_dirty_widgets();
        
        // レイアウトの更新
        for widget_id in dirty_widgets {
            self.update_layout(widget_id)?;
        }
        
        Ok(())
    }
    
    fn update_layout(&mut self, widget_id: WidgetId) -> Result<Size> {
        let widget = self.nodes.get_mut(&widget_id)
            .ok_or(Error::WidgetNotFound(widget_id))?;
            
        // 子ウィジェットのレイアウトを先に計算
        let mut child_sizes = Vec::new();
        for &child_id in widget.children() {
            let child_size = self.update_layout(child_id)?;
            child_sizes.push(child_size);
        }
        
        // 親ウィジェットのレイアウトを計算
        let constraints = self.get_constraints(widget_id)?;
        let size = widget.layout(constraints);
        
        // キャッシュの更新
        self.layout_cache.update(widget_id, size);
        
        Ok(size)
    }
}

// 基本的なウィジェットの実装
pub struct Container {
    id: WidgetId,
    bounds: Rect,
    parent: Option<WidgetId>,
    children: Vec<WidgetId>,
    style: ContainerStyle,
}

impl Widget for Container {
    fn layout(&mut self, constraints: BoxConstraints) -> Size {
        // コンテナのサイズを計算
        let size = if let Some(fixed_size) = self.style.fixed_size {
            constraints.constrain(fixed_size)
        } else {
            constraints.max
        };
        
        self.bounds = Rect::new(Point::origin(), size);
        size
    }
    
    fn paint(&self, context: &mut PaintContext) {
        // 背景の描画
        if let Some(background) = &self.style.background {
            context.fill_rect(self.bounds, background);
        }
        
        // 境界線の描画
        if let Some(border) = &self.style.border {
            context.stroke_rect(self.bounds, border);
        }
    }
    
    fn handle_event(&mut self, event: &Event) -> bool {
        match event {
            Event::MouseDown(position) if self.bounds.contains(*position) => {
                // クリックイベントの処理
                true
            }
            _ => false,
        }
    }
}
```

### イベント処理

```rust
// イベントシステム
pub struct EventSystem {
    listeners: HashMap<EventType, Vec<Box<dyn EventListener>>>,
    event_queue: EventQueue,
}

impl EventSystem {
    pub async fn process_events(&mut self) -> Result<()> {
        while let Some(event) = self.event_queue.pop() {
            // イベントタイプに対応するリスナーを取得
            let listeners = self.listeners.get(&event.event_type())
                .ok_or(Error::NoListenerFound)?;
                
            // リスナーに通知
            for listener in listeners {
                listener.handle_event(&event).await?;
            }
        }
        Ok(())
    }
    
    pub fn register_listener<L: EventListener + 'static>(
        &mut self,
        event_type: EventType,
        listener: L,
    ) {
        self.listeners.entry(event_type)
            .or_default()
            .push(Box::new(listener));
    }
}

// イベントリスナーの実装例
pub struct ButtonListener {
    button_id: WidgetId,
    callback: Box<dyn Fn() + Send + Sync>,
}

impl EventListener for ButtonListener {
    async fn handle_event(&self, event: &Event) -> bool {
        match event {
            Event::MouseClick(position) => {
                if self.is_within_bounds(*position) {
                    (self.callback)();
                    true
                } else {
                    false
                }
            }
            _ => false,
        }
    }
}
```

### 実装例：カスタムウィジェットの実装

```rust
// カスタムウィジェットの実装例
pub struct CustomButton {
    id: WidgetId,
    bounds: Rect,
    label: String,
    state: ButtonState,
    style: ButtonStyle,
}

impl Widget for CustomButton {
    fn layout(&mut self, constraints: BoxConstraints) -> Size {
        // テキストサイズに基づいたレイアウト計算
        let text_size = self.measure_text(&self.label);
        let padding = self.style.padding;
        
        let size = Size::new(
            text_size.width + padding.horizontal(),
            text_size.height + padding.vertical(),
        );
        
        let constrained_size = constraints.constrain(size);
        self.bounds = Rect::new(Point::origin(), constrained_size);
        constrained_size
    }
    
    fn paint(&self, context: &mut PaintContext) {
        // 背景の描画
        let background_color = match self.state {
            ButtonState::Normal => self.style.normal_color,
            ButtonState::Hovered => self.style.hover_color,
            ButtonState::Pressed => self.style.pressed_color,
        };
        
        context.fill_rounded_rect(self.bounds, self.style.corner_radius, background_color);
        
        // テキストの描画
        let text_layout = context.create_text_layout(&self.label, self.style.font)?;
        let text_position = self.calculate_text_position(&text_layout);
        context.draw_text(&text_layout, text_position, self.style.text_color);
    }
    
    fn handle_event(&mut self, event: &Event) -> bool {
        match event {
            Event::MouseEnter => {
                self.state = ButtonState::Hovered;
                true
            }
            Event::MouseLeave => {
                self.state = ButtonState::Normal;
                true
            }
            Event::MouseDown if self.bounds.contains(event.position()) => {
                self.state = ButtonState::Pressed;
                true
            }
            Event::MouseUp if self.state == ButtonState::Pressed => {
                self.state = ButtonState::Hovered;
                // クリックイベントの発火
                true
            }
            _ => false,
        }
    }
}

// 使用例
fn create_custom_ui() -> Result<WidgetTree> {
    let mut tree = WidgetTree::new();
    
    // ルートコンテナの作成
    let root = Container::new()
        .with_style(ContainerStyle {
            background: Some(Color::WHITE),
            padding: Padding::all(16.0),
            ..Default::default()
        });
    
    // カスタムボタンの追加
    let button = CustomButton::new()
        .with_label("Click me!")
        .with_style(ButtonStyle {
            normal_color: Color::BLUE,
            hover_color: Color::LIGHT_BLUE,
            pressed_color: Color::DARK_BLUE,
            text_color: Color::WHITE,
            corner_radius: 8.0,
            padding: Padding::symmetric(16.0, 8.0),
            font: Font::default(),
        });
    
    tree.add_widget(button, Some(root.id()))?;
    
    Ok(tree)
}
```

### 今回のまとめ

1. 柔軟なGUIシステムの基本設計
2. 拡張可能なウィジェット体系
3. 効率的なイベント処理システム
4. カスタムウィジェットの実装例

### 次回予告

第14回では、realeのOS抽象化レイヤーとプロセス制御について解説します。クロスプラットフォーム対応とリソース管理の実装について詳しく見ていきます。

### 参考資料
- GUI Framework Design
- Widget System Architecture
- Event-Driven Programming
- Cross-Platform UI Development