class_name OperationsCameraControls extends HBoxContainer ## Presentation-only camera and navigation controls providing click alternatives ## for pointer drag, wheel scroll, and modifier-based navigation. ## Does not alter the underlying simulation model or game state. const LayerSkin := preload("res://scripts/ui/layer_interface_skin.gd") signal zoom_in_requested signal zoom_out_requested signal reset_view_requested signal pan_requested(direction: Vector2) signal grid_toggle_requested signal layer_toggle_requested var zoom_in_button: Button var zoom_out_button: Button var reset_button: Button var pan_up_button: Button var pan_down_button: Button var pan_left_button: Button var pan_right_button: Button var grid_button: Button var layer_button: Button var _world_preview: Variant var _main_scene: Variant var _buttons: Array[Button] = [] func _init() -> void: name = "OperationsCameraControls" add_theme_constant_override("separation", 4) func _ready() -> void: _build_ui() func configure(preview: Variant, main_scene: Variant = null) -> void: _world_preview = preview _main_scene = main_scene func _build_ui() -> void: # Navigation Pan Buttons pan_left_button = _create_button("◀", "左へ移動", func() -> void: _on_pan_step(Vector2(1, 0))) pan_up_button = _create_button("▲", "上へ移動", func() -> void: _on_pan_step(Vector2(0, 1))) pan_down_button = _create_button("▼", "下へ移動", func() -> void: _on_pan_step(Vector2(0, -1))) pan_right_button = _create_button("▶", "右へ移動", func() -> void: _on_pan_step(Vector2(-1, 0))) # Zoom Buttons zoom_in_button = _create_button("+", "拡大表示", _on_zoom_in) zoom_out_button = _create_button("-", "縮小表示", _on_zoom_out) # Reset / Focus reset_button = _create_button("全体", "表示範囲全体を収める", _on_reset_view) # Grid & Layer Toggle grid_button = _create_button("マス目", "グリッド線の表示/非表示を切り替え", _on_grid_toggle) layer_button = _create_button("表/裏", "フロアの表層/裏層を切り替え", _on_layer_toggle) func _create_button(text_label: String, tooltip: String, callback: Callable) -> Button: var btn := Button.new() btn.text = text_label btn.tooltip_text = tooltip btn.custom_minimum_size = Vector2(30, 26) btn.focus_mode = Control.FOCUS_NONE btn.add_theme_font_size_override("font_size", 11) btn.pressed.connect(callback) add_child(btn) _buttons.append(btn) return btn func _on_zoom_in() -> void: if _world_preview != null and _world_preview.has_method(&"set_zoom"): var current: float = float(_world_preview.get("zoom_level")) _world_preview.set_zoom(current + 0.5) zoom_in_requested.emit() func _on_zoom_out() -> void: if _world_preview != null and _world_preview.has_method(&"set_zoom"): var current: float = float(_world_preview.get("zoom_level")) _world_preview.set_zoom(current - 0.5) zoom_out_requested.emit() func _on_pan_step(direction: Vector2) -> void: var delta := Vector2(32, 48) * direction if _world_preview != null: if _world_preview.has_method(&"_cell_dimensions"): var dims: Vector2 = _world_preview.call(&"_cell_dimensions") delta = direction * dims var offset: Vector2 = _world_preview.get("pan_offset") _world_preview.set("pan_offset", offset + delta) if _world_preview.has_method(&"_clamp_pan"): _world_preview.call(&"_clamp_pan") _world_preview.queue_redraw() pan_requested.emit(delta) func _on_pan(delta: Vector2) -> void: if _world_preview != null: var offset: Vector2 = _world_preview.get("pan_offset") _world_preview.set("pan_offset", offset + delta) if _world_preview.has_method(&"_clamp_pan"): _world_preview.call(&"_clamp_pan") _world_preview.queue_redraw() pan_requested.emit(delta) func _on_reset_view() -> void: if _world_preview != null: if _world_preview.has_method(&"focus_operating_area"): _world_preview.call(&"focus_operating_area") elif _world_preview.has_method(&"reset_view"): _world_preview.call(&"reset_view") reset_view_requested.emit() func _on_grid_toggle() -> void: if _world_preview != null: var current_grid: bool = bool(_world_preview.get("show_grid")) _world_preview.set("show_grid", not current_grid) _world_preview.queue_redraw() grid_toggle_requested.emit() func _on_layer_toggle() -> void: if _main_scene != null and _main_scene.has_method(&"_toggle_layer"): _main_scene.call(&"_toggle_layer") elif _world_preview != null: var current_mode: int = int(_world_preview.get("layer_mode")) _world_preview.set("layer_mode", 1 if current_mode == 0 else 0) layer_toggle_requested.emit() func apply_layer_skin(layer: int) -> void: for btn: Button in _buttons: LayerSkin.register_toggle_text(btn, layer) LayerSkin.apply_tree(self, layer)