150 lines
4.4 KiB
GDScript
150 lines
4.4 KiB
GDScript
class_name PauseModal
|
|
extends Control
|
|
## Модальное окно «ПАУЗА»: продолжить, настройки, выход в главное меню.
|
|
##
|
|
## Только UI и сигналы. «Настройки» и «В главное меню» не закрывают окно сами:
|
|
## интеграция решает, показать ли поверх настройки или подтверждение выхода.
|
|
|
|
signal resumed
|
|
signal settings_requested
|
|
signal menu_requested
|
|
signal closed
|
|
|
|
const W := 440.0
|
|
const H := 224.0
|
|
const TITLE_H := 20.0
|
|
const DIM := Color(0.0, 0.0, 0.0, 0.35)
|
|
|
|
var _btn_resume: Button90
|
|
var _btn_settings: Button90
|
|
var _btn_menu: Button90
|
|
var _btn_x: Button90
|
|
|
|
|
|
func _ready() -> void:
|
|
process_mode = Node.PROCESS_MODE_ALWAYS
|
|
mouse_filter = Control.MOUSE_FILTER_STOP
|
|
focus_mode = Control.FOCUS_ALL
|
|
set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
|
_build()
|
|
resized.connect(_layout)
|
|
_layout()
|
|
visible = false
|
|
|
|
|
|
func open() -> void:
|
|
visible = true
|
|
_layout()
|
|
queue_redraw()
|
|
if _btn_resume != null:
|
|
_btn_resume.grab_focus()
|
|
|
|
|
|
func close() -> void:
|
|
if not visible:
|
|
return
|
|
visible = false
|
|
closed.emit()
|
|
|
|
|
|
func _build() -> void:
|
|
_btn_resume = _make_button(_tr("btn.continue", "Продолжить"), true)
|
|
_btn_resume.pressed.connect(_resume)
|
|
_btn_settings = _make_button(_tr("btn.settings", "Настройки"), false)
|
|
_btn_settings.pressed.connect(func() -> void: settings_requested.emit())
|
|
_btn_menu = _make_button("В главное меню", false)
|
|
_btn_menu.danger = true
|
|
_btn_menu.pressed.connect(func() -> void: menu_requested.emit())
|
|
|
|
_btn_x = Button90.new()
|
|
_btn_x.icon = Button90.Icon.X
|
|
_btn_x.tooltip_text = "Продолжить"
|
|
_btn_x.pressed.connect(_resume)
|
|
add_child(_btn_x)
|
|
|
|
|
|
func _make_button(caption: String, accent: bool) -> Button90:
|
|
var b := Button90.new()
|
|
b.caption = caption
|
|
b.accent = accent
|
|
b.caption_size = Theme90.FS_BODY
|
|
add_child(b)
|
|
return b
|
|
|
|
|
|
func _tr(key: String, fallback: String) -> String:
|
|
var data := get_node_or_null("/root/Data")
|
|
if data != null and data.has_method("has_string") and data.has_string(key):
|
|
var value := str(data.tr(key))
|
|
if not value.is_empty() and value != key:
|
|
return value
|
|
return fallback
|
|
|
|
|
|
func _resume() -> void:
|
|
resumed.emit()
|
|
close()
|
|
|
|
|
|
func _window_rect() -> Rect2:
|
|
var s := size
|
|
if s.x <= 0.0 or s.y <= 0.0:
|
|
s = Vector2(1280, 720)
|
|
return Rect2(((s - Vector2(W, H)) * 0.5).round(), Vector2(W, H))
|
|
|
|
|
|
func _layout() -> void:
|
|
var r := _window_rect()
|
|
var x := r.position.x + 70.0
|
|
var y := r.position.y + 96.0
|
|
for b in [_btn_resume, _btn_settings, _btn_menu]:
|
|
if b != null:
|
|
b.position = Vector2(x, y)
|
|
b.size = Vector2(300, 24)
|
|
y += 32.0
|
|
if _btn_x != null:
|
|
_btn_x.position = r.position + Vector2(W - 22, 4)
|
|
_btn_x.size = Vector2(16, 16)
|
|
|
|
|
|
func _unhandled_input(event: InputEvent) -> void:
|
|
if not visible:
|
|
return
|
|
if event is InputEventKey and event.pressed and not event.echo and event.keycode == KEY_ESCAPE:
|
|
_resume()
|
|
get_viewport().set_input_as_handled()
|
|
|
|
|
|
# --- отрисовка -------------------------------------------------------------
|
|
|
|
func _draw() -> void:
|
|
var full := Rect2(Vector2.ZERO, size)
|
|
if size.x <= 0.0 or size.y <= 0.0:
|
|
full = Rect2(0, 0, 1280, 720)
|
|
draw_rect(full, DIM)
|
|
_draw_frame(_window_rect())
|
|
|
|
|
|
func _draw_frame(r: Rect2) -> void:
|
|
Theme90.draw_bevel(self, r, false, Theme90.BEVEL, Theme90.WHITE)
|
|
Theme90.modal_header(self, r, _tr("ui.pause_title", "Пауза").to_upper(), "ЧАС 3 · 03:42")
|
|
|
|
# информационная плашка
|
|
var well := Rect2(r.position + Vector2(14, 28), Vector2(r.size.x - 28, 56))
|
|
Theme90.draw_sunken(self, well)
|
|
var bx := well.position.x + 14.0
|
|
var by := well.position.y + 18.0
|
|
draw_rect(Rect2(bx, by, 9, 20), Theme90.NAVY)
|
|
draw_rect(Rect2(bx + 14, by, 9, 20), Theme90.NAVY)
|
|
draw_rect(Rect2(bx, by, 9, 2), Theme90.ACCENT_LIGHT)
|
|
draw_rect(Rect2(bx + 14, by, 9, 2), Theme90.ACCENT_LIGHT)
|
|
var f := Theme90.ui()
|
|
Theme90.text(self, f, Vector2(well.position.x + 44, well.position.y + 10),
|
|
"СМЕНА ПРИОСТАНОВЛЕНА", Theme90.FS_BODY, Theme90.INK)
|
|
Theme90.text(self, f, Vector2(well.position.x + 44, well.position.y + 27),
|
|
"Таймеры, касса и канал ждут оператора", Theme90.FS_MICRO, Theme90.SHADE)
|
|
|
|
Theme90.text_vcenter(self, f, Rect2(r.position.x + 10, r.position.y + 194, r.size.x - 20, 12),
|
|
"ESC — ПРОДОЛЖИТЬ СМЕНУ", Theme90.FS_MICRO, Theme90.SHADE,
|
|
-1, HORIZONTAL_ALIGNMENT_CENTER)
|