146 lines
4.7 KiB
GDScript
146 lines
4.7 KiB
GDScript
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)
|