Merge remote-tracking branch 'origin/master' into sasha80
# Conflicts: # Selector.tscn # main.gd # pomehi.gd # table.gd # threats.gd
This commit is contained in:
@@ -1,15 +0,0 @@
|
|||||||
[gd_scene load_steps=2 format=3 uid="uid://bapeyu5wapuhv"]
|
|
||||||
|
|
||||||
[ext_resource type="Texture2D" uid="uid://bkjlwivmtq1rp" path="res://nine-patch.png" id="1_kvh2c"]
|
|
||||||
|
|
||||||
[node name="NinePatchRect" type="NinePatchRect"]
|
|
||||||
offset_right = 42.0
|
|
||||||
offset_bottom = 33.0
|
|
||||||
texture = ExtResource("1_kvh2c")
|
|
||||||
draw_center = false
|
|
||||||
patch_margin_left = 8
|
|
||||||
patch_margin_top = 8
|
|
||||||
patch_margin_right = 8
|
|
||||||
patch_margin_bottom = 8
|
|
||||||
axis_stretch_horizontal = 1
|
|
||||||
axis_stretch_vertical = 1
|
|
||||||
BIN
bin/imi_skysens.x86_64
Normal file
BIN
bin/imi_skysens.x86_64
Normal file
Binary file not shown.
13
main.gd
13
main.gd
@@ -7,17 +7,14 @@ var sock = PacketPeerUDP.new()
|
|||||||
@onready var btn_del_threads = get_node('tabs/threats/btn_del')
|
@onready var btn_del_threads = get_node('tabs/threats/btn_del')
|
||||||
|
|
||||||
@onready var header_pomehi = get_node('tabs/pomehi/header_p')
|
@onready var header_pomehi = get_node('tabs/pomehi/header_p')
|
||||||
@onready var table_pomehi = get_node('tabs/pomehi/table_p')
|
@onready var table_pomehi = get_node('tabs/pomehi/table_p')
|
||||||
|
|
||||||
# Called when the node enters the scene tree for the first time.
|
# Called when the node enters the scene tree for the first time.
|
||||||
func _ready():
|
func _ready():
|
||||||
call_deferred('_redy_defered')
|
|
||||||
|
|
||||||
func _redy_defered():
|
|
||||||
sock.bind(Consts.MAIN_ADDR[1], Consts.MAIN_ADDR[0])
|
sock.bind(Consts.MAIN_ADDR[1], Consts.MAIN_ADDR[0])
|
||||||
sock.set_dest_address(Consts.DST_ADDR[0], Consts.DST_ADDR[1])
|
sock.set_dest_address(Consts.DST_ADDR[0], Consts.DST_ADDR[1])
|
||||||
Threats.init_treats(header_threads, table_threads, btn_add_threads, btn_del_threads)
|
Threats.init_treats(table_threads, btn_add_threads, btn_del_threads)
|
||||||
Pomehi.init_pomehi(header_pomehi, table_pomehi)
|
Pomehi.init_pomehi(table_pomehi)
|
||||||
var timer = Timer.new()
|
var timer = Timer.new()
|
||||||
timer.connect('timeout', Callable(self, 'on_timeout').bind())
|
timer.connect('timeout', Callable(self, 'on_timeout').bind())
|
||||||
add_child(timer) #to process
|
add_child(timer) #to process
|
||||||
@@ -27,3 +24,7 @@ func _redy_defered():
|
|||||||
func on_timeout():
|
func on_timeout():
|
||||||
sock.put_packet(Threats.get_threats_data())
|
sock.put_packet(Threats.get_threats_data())
|
||||||
|
|
||||||
|
|
||||||
|
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||||
|
#func _process(delta):
|
||||||
|
# pass
|
||||||
|
|||||||
40
main.tscn
40
main.tscn
@@ -1,12 +1,12 @@
|
|||||||
[gd_scene load_steps=5 format=3 uid="uid://87gtvqd7bbje"]
|
[gd_scene load_steps=5 format=3 uid="uid://87gtvqd7bbje"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://main.gd" id="1_qcx24"]
|
[ext_resource type="Script" path="res://main.gd" id="1_o7op8"]
|
||||||
[ext_resource type="Script" path="res://table.gd" id="2_y3x5h"]
|
[ext_resource type="Script" path="res://table/table.gd" id="2_nv8t5"]
|
||||||
[ext_resource type="Texture2D" uid="uid://cex4jiu1pcj3x" path="res://edit-add-0.png" id="3_5pb81"]
|
[ext_resource type="Texture2D" uid="uid://cex4jiu1pcj3x" path="res://edit-add-0.png" id="3_g7h67"]
|
||||||
[ext_resource type="Texture2D" uid="uid://cx746np1wexnd" path="res://edit-add-1.png" id="4_i1fqu"]
|
[ext_resource type="Texture2D" uid="uid://cx746np1wexnd" path="res://edit-add-1.png" id="4_75pij"]
|
||||||
|
|
||||||
[node name="main" type="Node2D"]
|
[node name="main" type="Node2D"]
|
||||||
script = ExtResource("1_qcx24")
|
script = ExtResource("1_o7op8")
|
||||||
|
|
||||||
[node name="tabs" type="TabContainer" parent="."]
|
[node name="tabs" type="TabContainer" parent="."]
|
||||||
offset_right = 1594.0
|
offset_right = 1594.0
|
||||||
@@ -16,20 +16,18 @@ offset_bottom = 897.0
|
|||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
|
|
||||||
[node name="table_t" type="GridContainer" parent="tabs/threats"]
|
[node name="table_t" type="GridContainer" parent="tabs/threats"]
|
||||||
layout_mode = 0
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
anchor_right = 1.0
|
anchor_right = 1.0
|
||||||
anchor_bottom = 1.0
|
anchor_bottom = 1.0
|
||||||
|
offset_left = 11.0
|
||||||
offset_top = 100.0
|
offset_top = 100.0
|
||||||
offset_right = 1.0
|
offset_right = 1.0
|
||||||
offset_bottom = 10.0
|
offset_bottom = 10.0
|
||||||
script = ExtResource("2_y3x5h")
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
[node name="header_t" type="GridContainer" parent="tabs/threats"]
|
script = ExtResource("2_nv8t5")
|
||||||
layout_mode = 0
|
node_type_file = "res://ячейка-1.tscn"
|
||||||
offset_top = 57.0
|
|
||||||
offset_right = 1584.0
|
|
||||||
offset_bottom = 96.0
|
|
||||||
script = ExtResource("2_y3x5h")
|
|
||||||
|
|
||||||
[node name="btn_add" type="TextureButton" parent="tabs/threats"]
|
[node name="btn_add" type="TextureButton" parent="tabs/threats"]
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
@@ -37,8 +35,8 @@ offset_left = 1533.0
|
|||||||
offset_top = -2.0
|
offset_top = -2.0
|
||||||
offset_right = 1581.0
|
offset_right = 1581.0
|
||||||
offset_bottom = 46.0
|
offset_bottom = 46.0
|
||||||
texture_normal = ExtResource("3_5pb81")
|
texture_normal = ExtResource("3_g7h67")
|
||||||
texture_pressed = ExtResource("4_i1fqu")
|
texture_pressed = ExtResource("4_75pij")
|
||||||
|
|
||||||
[node name="btn_del" type="TextureButton" parent="tabs/threats"]
|
[node name="btn_del" type="TextureButton" parent="tabs/threats"]
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
@@ -56,11 +54,5 @@ layout_mode = 0
|
|||||||
offset_top = 100.0
|
offset_top = 100.0
|
||||||
offset_right = 1587.0
|
offset_right = 1587.0
|
||||||
offset_bottom = 861.0
|
offset_bottom = 861.0
|
||||||
script = ExtResource("2_y3x5h")
|
script = ExtResource("2_nv8t5")
|
||||||
|
node_type_file = "res://ячейка-1.tscn"
|
||||||
[node name="header_p" type="GridContainer" parent="tabs/pomehi"]
|
|
||||||
layout_mode = 0
|
|
||||||
offset_top = 57.0
|
|
||||||
offset_right = 32.0
|
|
||||||
offset_bottom = 96.0
|
|
||||||
script = ExtResource("2_y3x5h")
|
|
||||||
|
|||||||
20
pomehi.gd
20
pomehi.gd
@@ -10,10 +10,11 @@ const TableCellType3 = preload('res://кнопка-4.tscn')
|
|||||||
const TableCellType4 = preload('res://заголовок.tscn')
|
const TableCellType4 = preload('res://заголовок.tscn')
|
||||||
const TableCellType5 = preload('res://ячейка-2.tscn')
|
const TableCellType5 = preload('res://ячейка-2.tscn')
|
||||||
const TableCellType6 = preload('res://кнопка-5.tscn')
|
const TableCellType6 = preload('res://кнопка-5.tscn')
|
||||||
|
const TableHeader = preload('res://table/header.tscn')
|
||||||
|
|
||||||
# Индекс колонки: 0 1 2 3 4 5 6
|
# Индекс колонки: 0 1 2 3 4 5 6
|
||||||
const TABLE_HEADERS = [ 'Индекс', 'Состояние', 'Помеха', 'Мощность', 'Кур. уг.', 'Частота', 'Ш. диап.']
|
const TABLE_HEADERS = [ 'Индекс', 'Состояние', 'Помеха', 'Мощность', 'Кур. уг.', 'Частота', 'Ш. диап.']
|
||||||
const TABLE_HEADER_TYPES = [ TableCellType4, TableCellType4, TableCellType4, TableCellType4, TableCellType4, TableCellType4, TableCellType4]
|
const TABLE_HEADER_TYPES = [ TableHeader, TableHeader, TableHeader, TableHeader, TableHeader, TableHeader, TableHeader]
|
||||||
const TABLE_HEADER_ALIGNMENTS = [ HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER]
|
const TABLE_HEADER_ALIGNMENTS = [ HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER]
|
||||||
const TABLE_ROW_TYPES = [ TableCellType1, TableCellType6, TableCellType1, TableCellType1, TableCellType1, TableCellType1, TableCellType1]
|
const TABLE_ROW_TYPES = [ TableCellType1, TableCellType6, TableCellType1, TableCellType1, TableCellType1, TableCellType1, TableCellType1]
|
||||||
const TABLE_ROW_ALIGNMENTS = [ HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER]
|
const TABLE_ROW_ALIGNMENTS = [ HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER]
|
||||||
@@ -78,14 +79,9 @@ class Pomeha:
|
|||||||
return new_rows
|
return new_rows
|
||||||
|
|
||||||
|
|
||||||
func selector_color_proc(_i_row: int):
|
|
||||||
return Consts.COLOR_ACCENT * Consts.COLOR_HALF_ALPHA
|
|
||||||
|
|
||||||
|
|
||||||
func init_table(table: Table, sizes: Array):
|
func init_table(table: Table, sizes: Array):
|
||||||
for i_row in table.get_rows_count():
|
for i_row in table.get_rows_count():
|
||||||
table.set_nodes_min_size(i_row, sizes)
|
table.set_nodes_min_size(i_row, sizes)
|
||||||
table.set_selector_color_proc(self, 'selector_color_proc')
|
|
||||||
|
|
||||||
|
|
||||||
func init_opt_btns(row : int, table):
|
func init_opt_btns(row : int, table):
|
||||||
@@ -98,14 +94,13 @@ func init_opt_btns(row : int, table):
|
|||||||
cell.select(0)
|
cell.select(0)
|
||||||
|
|
||||||
|
|
||||||
func init_pomehi(header, table): # Инициализация вкладки с целями
|
func init_pomehi(table): # Инициализация вкладки с целями
|
||||||
header.add_row(TABLE_HEADER_TYPES)
|
table.set_header(TABLE_HEADER_TYPES)
|
||||||
header.set_rows_text([TABLE_HEADERS])
|
table.set_header_text(TABLE_HEADERS)
|
||||||
on_btn_add(table)
|
on_btn_add(table)
|
||||||
init_table(header, TABLE_COLUMN_SIZES)
|
|
||||||
init_table(table, TABLE_COLUMN_SIZES)
|
init_table(table, TABLE_COLUMN_SIZES)
|
||||||
table.align_to_left_bottom(header, Vector2(0, 2))
|
|
||||||
table.connect('row_pressed', Callable(self, 'on_row_pressed').bind(table))
|
table.connect('row_pressed', Callable(self, 'on_row_pressed').bind(table))
|
||||||
|
table.connect_columns(self, 'item_selected', 'on_item_selected', COLUMN_OPT_BTN, [table])
|
||||||
|
|
||||||
|
|
||||||
func on_btn_add(table):
|
func on_btn_add(table):
|
||||||
@@ -114,8 +109,9 @@ func on_btn_add(table):
|
|||||||
var row = pomeha.update_rows()
|
var row = pomeha.update_rows()
|
||||||
table.add_row(TABLE_ROW_TYPES)
|
table.add_row(TABLE_ROW_TYPES)
|
||||||
table.set_row_text(table.get_rows_count()-1, row)
|
table.set_row_text(table.get_rows_count()-1, row)
|
||||||
|
table.set_columns_min_size(TABLE_COLUMN_SIZES)
|
||||||
init_opt_btns(table.get_rows_count()-1, table)
|
init_opt_btns(table.get_rows_count()-1, table)
|
||||||
table.set_callbacks(self, 'item_selected', 'on_item_selected', COLUMN_OPT_BTN, [])
|
table.connect_columns(self, 'item_selected', 'on_item_selected', COLUMN_OPT_BTN, [])
|
||||||
|
|
||||||
|
|
||||||
func on_row_pressed(i_row: int, table):
|
func on_row_pressed(i_row: int, table):
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ Consts="*res://consts.gd"
|
|||||||
Threats="*res://threats.gd"
|
Threats="*res://threats.gd"
|
||||||
Pomehi="*res://pomehi.gd"
|
Pomehi="*res://pomehi.gd"
|
||||||
Tools="*res://tools.gd"
|
Tools="*res://tools.gd"
|
||||||
Table="*res://table.gd"
|
Table="*res://table/table.gd"
|
||||||
|
|
||||||
[display]
|
[display]
|
||||||
|
|
||||||
|
|||||||
418
table.gd
418
table.gd
@@ -1,418 +0,0 @@
|
|||||||
@tool
|
|
||||||
extends GridContainer
|
|
||||||
|
|
||||||
@export var _selector_color: Color = Color(1.0, 1.0, 1.0, 1.0)
|
|
||||||
@export var columns_count: int = 1: set = _set_columns_count
|
|
||||||
@export var rows_count: int = 1: set = _set_rows_count
|
|
||||||
@export var node_type_file: String = 'res://ячейка-1.tscn'
|
|
||||||
const Selector = preload('res://Selector.tscn')
|
|
||||||
const INDEX_FORMAT = '%02d_%02d'
|
|
||||||
const NODE_PREFIX = 'NODE_'
|
|
||||||
const DATA_PREFIX = 'DATA_'
|
|
||||||
const CONN_PREFIX = 'CONN_'
|
|
||||||
const SLCT_PREFIX = 'SLCT_'
|
|
||||||
|
|
||||||
const NODE_KEY_FORMAT = NODE_PREFIX + INDEX_FORMAT
|
|
||||||
const DATA_KEY_FORMAT = DATA_PREFIX + INDEX_FORMAT
|
|
||||||
const CONNECTED_KEY_FORMAT = CONN_PREFIX + INDEX_FORMAT
|
|
||||||
const ROW_SELECTOR_KEY_FORMAT = SLCT_PREFIX + INDEX_FORMAT
|
|
||||||
|
|
||||||
var nodes: = {}
|
|
||||||
var selector_color_proc: Callable
|
|
||||||
var selector_size_proc: Callable
|
|
||||||
signal row_pressed(i_row) # Вызывается при нажатии кнопкой мыши на строку
|
|
||||||
const MAX_INDEX = 99 # Максимальное значение индекса для колонки и строки. Связано с форматом ключа
|
|
||||||
|
|
||||||
|
|
||||||
func align_to_left_bottom(header, gap: = Vector2(0, 0)):
|
|
||||||
""" Выравнивает по нижнему левому углу. Используется для выравнивания по заголовку """
|
|
||||||
position.x = header.position.x + gap.x
|
|
||||||
position.y = header.position.y + header.size.y + gap.y
|
|
||||||
|
|
||||||
|
|
||||||
func _assert_meta(i_col: int, i_row: int, pname: String, node):
|
|
||||||
assert(node.has_meta(pname)) #,'ошибка: нет мета-свойства \"%s\" у ячейки (%s): колонка:%d ряд:%d' % [pname, typeof(node), i_col, i_row])
|
|
||||||
|
|
||||||
|
|
||||||
func _set_columns_count(cc: int):
|
|
||||||
columns_count = cc
|
|
||||||
|
|
||||||
|
|
||||||
func _set_rows_count(rc: int):
|
|
||||||
rows_count = rc
|
|
||||||
|
|
||||||
|
|
||||||
func set_node_meta(i_col: int, i_row: int, pname: String, val) -> void:
|
|
||||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
|
||||||
var node = nodes[key]
|
|
||||||
node.set_meta(pname, val)
|
|
||||||
|
|
||||||
|
|
||||||
func get_node_meta(i_col: int, i_row: int, pname: String):
|
|
||||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
|
||||||
var node = nodes[key]
|
|
||||||
_assert_meta(i_col, i_row, pname, node)
|
|
||||||
return node.get_meta(pname)
|
|
||||||
|
|
||||||
|
|
||||||
func set_node_property(i_col: int, i_row: int, pname: String, val) -> void:
|
|
||||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
|
||||||
var node = nodes[key]
|
|
||||||
node.set(pname, val)
|
|
||||||
|
|
||||||
|
|
||||||
func get_node_property(i_col: int, i_row: int, pname: String):
|
|
||||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
|
||||||
var node = nodes[key]
|
|
||||||
return node.get(pname)
|
|
||||||
|
|
||||||
|
|
||||||
func get_node_key(format: String, i_col: int, i_row: int) -> String:
|
|
||||||
var key: String = format % [i_row, i_col]
|
|
||||||
assert(nodes.has(key)) #,'ошибка: нет такой ячейки: колонка:%d ряд:%d' % [i_col, i_row])
|
|
||||||
return key
|
|
||||||
|
|
||||||
|
|
||||||
func get_key_indexes(key: String) -> Array:
|
|
||||||
var tokens: = key.split('_')
|
|
||||||
assert(tokens.size() == 3) #,'ошибка: неверный ключ: \"%s\"' % key)
|
|
||||||
return [int(tokens[2]), int(tokens[1])]
|
|
||||||
|
|
||||||
|
|
||||||
func set_columns_min_size(sizes: Array) -> void:
|
|
||||||
for i_row in get_rows_count():
|
|
||||||
set_nodes_min_size(i_row, sizes)
|
|
||||||
|
|
||||||
|
|
||||||
func set_columns_aligment(alignments: Array) -> void:
|
|
||||||
for i_row in get_rows_count():
|
|
||||||
for i_col in alignments.size():
|
|
||||||
set_node_alligment(i_col, i_row, alignments[i_col])
|
|
||||||
|
|
||||||
|
|
||||||
func _input(event) -> void:
|
|
||||||
if event is InputEventMouseButton:
|
|
||||||
if not event.pressed:
|
|
||||||
return
|
|
||||||
if event.position.x < position.x:
|
|
||||||
emit_signal('focus_exited')
|
|
||||||
return
|
|
||||||
if event.position.x > (position.x + size.x):
|
|
||||||
emit_signal('focus_exited')
|
|
||||||
return
|
|
||||||
if event.position.y < position.y:
|
|
||||||
emit_signal('focus_exited')
|
|
||||||
return
|
|
||||||
if event.position.y > (position.y + size.y):
|
|
||||||
emit_signal('focus_exited')
|
|
||||||
return
|
|
||||||
var rows_count: = get_rows_count()
|
|
||||||
var parent = get_parent()
|
|
||||||
var y0 = parent.position.y
|
|
||||||
for i_row in rows_count:
|
|
||||||
var rect = [0, 0, 0, 0]
|
|
||||||
get_node_rect(0, i_row, rect)
|
|
||||||
var y = rect[1] + position.y + y0
|
|
||||||
if event.position.y < y:
|
|
||||||
continue
|
|
||||||
if event.position.y > (y + rect[3]):
|
|
||||||
continue
|
|
||||||
emit_signal('row_pressed', i_row)
|
|
||||||
break
|
|
||||||
|
|
||||||
|
|
||||||
func _init() -> void:
|
|
||||||
selector_color_proc = Callable(self, 'default_selector_color_proc')
|
|
||||||
assert(selector_color_proc.is_valid())
|
|
||||||
selector_size_proc = Callable(self, 'default_selector_size_proc')
|
|
||||||
assert(selector_size_proc.is_valid())
|
|
||||||
|
|
||||||
|
|
||||||
func default_selector_color_proc(i_row: int):
|
|
||||||
return _selector_color
|
|
||||||
|
|
||||||
|
|
||||||
func set_selector_color_proc(instance: Object, function: String) -> void:
|
|
||||||
selector_color_proc = Callable(instance, function)
|
|
||||||
assert(selector_color_proc.is_valid())
|
|
||||||
|
|
||||||
|
|
||||||
func set_selector_size_proc(instance: Object, function: String) -> void:
|
|
||||||
selector_size_proc = Callable(instance, function)
|
|
||||||
assert(selector_size_proc.is_valid())
|
|
||||||
|
|
||||||
|
|
||||||
func default_selector_size_proc(i_row: int, rect: Array) -> void:
|
|
||||||
get_node_rect(0, i_row, rect)
|
|
||||||
rect[0] = rect[0] + position.x - 1
|
|
||||||
rect[1] = rect[1] + position.y - 4
|
|
||||||
rect[2] = size.x + 2
|
|
||||||
rect[3] = rect[3] + 8
|
|
||||||
|
|
||||||
|
|
||||||
func clear_rows_selected():
|
|
||||||
var rows_count: = get_rows_count()
|
|
||||||
for i_row in rows_count:
|
|
||||||
set_row_selected(i_row, false)
|
|
||||||
|
|
||||||
|
|
||||||
func set_row_selected(i_row: int, selected: bool = true) -> void:
|
|
||||||
var key: = ROW_SELECTOR_KEY_FORMAT % [i_row, 0]
|
|
||||||
var parent = get_parent()
|
|
||||||
if nodes.has(key) and (not selected):
|
|
||||||
var selector = nodes[key]
|
|
||||||
parent.remove_child(selector)
|
|
||||||
selector.queue_free()
|
|
||||||
nodes.erase(key)
|
|
||||||
elif (not nodes.has(key)) and selected:
|
|
||||||
var selector = Selector.instantiate()
|
|
||||||
var rect: = [0, 0, 0, 0]
|
|
||||||
selector_size_proc.call(i_row, rect)
|
|
||||||
selector.position.x = rect[0]
|
|
||||||
selector.position.y = rect[1]
|
|
||||||
selector.size.x = rect[2]
|
|
||||||
selector.size.y = rect[3]
|
|
||||||
selector.modulate = selector_color_proc.call(i_row)
|
|
||||||
nodes[key] = selector
|
|
||||||
parent.add_child(selector)
|
|
||||||
|
|
||||||
|
|
||||||
func is_row_selected(i_row: int) -> bool:
|
|
||||||
var key: = get_node_key(ROW_SELECTOR_KEY_FORMAT, 0, i_row)
|
|
||||||
return nodes.has(key)
|
|
||||||
|
|
||||||
|
|
||||||
func get_selected_rows(rows: Array) -> void:
|
|
||||||
for key in nodes.keys():
|
|
||||||
if SLCT_PREFIX in key:
|
|
||||||
var indexes = get_key_indexes(key)
|
|
||||||
rows.append(indexes[1])
|
|
||||||
|
|
||||||
|
|
||||||
func get_rows_count() -> int:
|
|
||||||
var rows_count: int = 0
|
|
||||||
for key in nodes:
|
|
||||||
rows_count += int(NODE_PREFIX in key)
|
|
||||||
return rows_count / columns
|
|
||||||
|
|
||||||
|
|
||||||
func get_node2(i_col: int, i_row: int) -> Node:
|
|
||||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
|
||||||
return nodes[key]
|
|
||||||
|
|
||||||
|
|
||||||
func set_node_user_data(i_col: int, i_row: int, user_data: Object) -> void:
|
|
||||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
|
||||||
nodes[key] = user_data
|
|
||||||
|
|
||||||
|
|
||||||
func add_row(row_types: Array) -> void:
|
|
||||||
assert(row_types.size() < MAX_INDEX, 'ошибка: слишком много колонок, больше %d' % (MAX_INDEX + 1))
|
|
||||||
set_columns(row_types.size())
|
|
||||||
var rows_count: int = get_rows_count()
|
|
||||||
assert(rows_count < MAX_INDEX, 'ошибка: слишком много рядов, больше %d' % (MAX_INDEX + 1))
|
|
||||||
for i_col in columns:
|
|
||||||
var node = row_types[i_col].instantiate()
|
|
||||||
var key: String = NODE_KEY_FORMAT % [rows_count, i_col]
|
|
||||||
node.name = key
|
|
||||||
add_child(node)
|
|
||||||
nodes[key] = node
|
|
||||||
|
|
||||||
|
|
||||||
func get_node_user_data(i_col: int, i_row: int) -> Object:
|
|
||||||
var key: = get_node_key(DATA_KEY_FORMAT, i_col, i_row)
|
|
||||||
return nodes[key]
|
|
||||||
|
|
||||||
|
|
||||||
func remove_row(i_row: int):
|
|
||||||
|
|
||||||
var sel_key: String = ROW_SELECTOR_KEY_FORMAT % [i_row, 0]
|
|
||||||
if nodes.has(sel_key):
|
|
||||||
var selector = nodes[sel_key]
|
|
||||||
get_parent().remove_child(selector)
|
|
||||||
selector.queue_free()
|
|
||||||
nodes.erase(sel_key)
|
|
||||||
for i_col in columns:
|
|
||||||
var node_key: String = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
|
||||||
var conn_key: String = CONNECTED_KEY_FORMAT % [i_row, i_col]
|
|
||||||
var data_key: String = DATA_KEY_FORMAT % [i_row, i_col]
|
|
||||||
var node = nodes[node_key]
|
|
||||||
nodes.erase(node_key)
|
|
||||||
remove_child(node)
|
|
||||||
node.queue_free()
|
|
||||||
|
|
||||||
if nodes.has(data_key):
|
|
||||||
nodes.erase(data_key)
|
|
||||||
|
|
||||||
if nodes.has(conn_key):
|
|
||||||
var conn = nodes[conn_key]
|
|
||||||
if node.is_connected(conn):
|
|
||||||
node.disconnect('pressed', conn)
|
|
||||||
nodes.erase(conn_key)
|
|
||||||
|
|
||||||
|
|
||||||
func rehash(swaps: Array):
|
|
||||||
""" Переназначает ключи в соответствии с размерами таблицы.
|
|
||||||
После вызова swaps содержит массив пар [<прежний ключ>, <текущий ключ>] """
|
|
||||||
assert(not swaps.size()) #,'ошибка: swaps не пустой')
|
|
||||||
var nodes_copy = {}
|
|
||||||
var i_col = 0
|
|
||||||
var i_row = 0
|
|
||||||
for key0 in nodes:
|
|
||||||
if NODE_PREFIX in key0:
|
|
||||||
var node_key1: String = NODE_KEY_FORMAT % [i_row, i_col]
|
|
||||||
nodes_copy[node_key1] = nodes[key0]
|
|
||||||
swaps.append([key0, node_key1])
|
|
||||||
|
|
||||||
var indxs = get_key_indexes(key0)
|
|
||||||
|
|
||||||
var slct_key0: String = ROW_SELECTOR_KEY_FORMAT % [indxs[1], indxs[0]]
|
|
||||||
if nodes.has(slct_key0):
|
|
||||||
var slct_key1: String = ROW_SELECTOR_KEY_FORMAT % [i_row, i_col]
|
|
||||||
nodes_copy[slct_key1] = nodes[slct_key0]
|
|
||||||
|
|
||||||
var conn_key0: String = CONNECTED_KEY_FORMAT % [indxs[1], indxs[0]]
|
|
||||||
if nodes.has(conn_key0):
|
|
||||||
var conn_key1: String = CONNECTED_KEY_FORMAT % [i_row, i_col]
|
|
||||||
nodes_copy[conn_key1] = nodes[conn_key0]
|
|
||||||
|
|
||||||
var data_key0: String = DATA_KEY_FORMAT % [indxs[1], indxs[0]]
|
|
||||||
if nodes.has(data_key0):
|
|
||||||
var data_key1: String = DATA_KEY_FORMAT % [i_row, i_col]
|
|
||||||
nodes_copy[data_key1] = nodes[data_key0]
|
|
||||||
|
|
||||||
i_col += 1
|
|
||||||
if i_col == columns:
|
|
||||||
i_col = 0
|
|
||||||
i_row += 1
|
|
||||||
nodes.clear()
|
|
||||||
nodes.merge(nodes_copy)
|
|
||||||
|
|
||||||
|
|
||||||
func clear_rows() -> void:
|
|
||||||
""" Удаляет все строки таблицы """
|
|
||||||
var rows_count: int = get_rows_count()
|
|
||||||
for i_row in rows_count:
|
|
||||||
remove_row(i_row)
|
|
||||||
|
|
||||||
|
|
||||||
func set_callbacks(dest_node: Node, event_name: String, callback: String, clmns: Array, user_data: Array) -> void:
|
|
||||||
""" Настраивает обратные вызовы для колонок.
|
|
||||||
:dest_node: Получатель события
|
|
||||||
:event_name: Имя события
|
|
||||||
:callback: Имя функции получателя события
|
|
||||||
:clmns: Индексы колонок
|
|
||||||
:user_data: Аргументы функции получателя события """
|
|
||||||
var rows_count = get_rows_count()
|
|
||||||
for i_row in rows_count:
|
|
||||||
for i_col in clmns:
|
|
||||||
assert(i_col >= 0 and i_col < columns,'ошибка: нет колонки %d' % i_col)
|
|
||||||
var node_key: String = NODE_KEY_FORMAT % [i_row, i_col]
|
|
||||||
var conn_key: String = CONNECTED_KEY_FORMAT % [i_row, i_col]
|
|
||||||
var node = nodes[node_key]
|
|
||||||
if nodes.has(conn_key):
|
|
||||||
var conn = nodes[conn_key]
|
|
||||||
if node.is_connected(event_name, conn):
|
|
||||||
node.disconnect(event_name, conn)
|
|
||||||
nodes.erase(conn_key)
|
|
||||||
|
|
||||||
var conn = Callable(dest_node, callback).bind([node])
|
|
||||||
assert (OK == node.connect(event_name, conn))
|
|
||||||
nodes[conn_key] = conn
|
|
||||||
|
|
||||||
|
|
||||||
func set_rows_text(rows: Array) -> void:
|
|
||||||
for i_row in rows.size():
|
|
||||||
for i_col in columns:
|
|
||||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
|
||||||
var node = nodes[key]
|
|
||||||
node.text = rows[i_row][i_col]
|
|
||||||
|
|
||||||
|
|
||||||
func set_nodes_min_size(i_row: int, sizes: Array) -> void:
|
|
||||||
for i_col in columns:
|
|
||||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
|
||||||
var node = nodes[key]
|
|
||||||
node.custom_minimum_size.x = sizes[i_col]
|
|
||||||
node.size.x = sizes[i_col]
|
|
||||||
|
|
||||||
|
|
||||||
func set_node_text(i_col: int, i_row: int, val: String) -> void:
|
|
||||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
|
||||||
nodes[key].text = val
|
|
||||||
|
|
||||||
|
|
||||||
func set_rows_state(rows: Array) -> void:
|
|
||||||
for i_row in rows.size():
|
|
||||||
for i_col in columns:
|
|
||||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
|
||||||
nodes[name].button_pressed = rows[i_row][i_col]
|
|
||||||
|
|
||||||
|
|
||||||
func set_node_state(i_col: int, i_row: int, val: bool) -> void:
|
|
||||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
|
||||||
nodes[key].button_pressed = val
|
|
||||||
|
|
||||||
|
|
||||||
func set_node_frame(i_col: int, i_row: int, name: String, val: int) -> void:
|
|
||||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
|
||||||
var node = nodes[key]
|
|
||||||
var sprite = node.get_node(name)
|
|
||||||
sprite.frame = val
|
|
||||||
|
|
||||||
|
|
||||||
func set_node_editable(i_col: int, i_row: int, val: bool) -> void:
|
|
||||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
|
||||||
nodes[key].editable = val
|
|
||||||
|
|
||||||
|
|
||||||
func set_node_alligment(i_col: int, i_row: int, val: int) -> void:
|
|
||||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
|
||||||
nodes[key].align = val
|
|
||||||
|
|
||||||
|
|
||||||
func set_row_alligments(i_row: int, aligns: Array) -> void:
|
|
||||||
for i_col in columns:
|
|
||||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
|
||||||
nodes[key].align = aligns[i_col]
|
|
||||||
|
|
||||||
|
|
||||||
func get_row_text(i_row: int) -> Array:
|
|
||||||
var row: = []
|
|
||||||
for i_col in columns:
|
|
||||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
|
||||||
row.append(nodes[key].text)
|
|
||||||
return row
|
|
||||||
|
|
||||||
|
|
||||||
func set_row_text(i_row: int, row: Array, i_begin: int = 0) -> void:
|
|
||||||
for i_col in row.size():
|
|
||||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
|
||||||
nodes[key].text = row[i_col]
|
|
||||||
|
|
||||||
|
|
||||||
func get_rows_text() -> Array:
|
|
||||||
var rows_count: = get_rows_count()
|
|
||||||
var rows: = []
|
|
||||||
for i_row in rows_count:
|
|
||||||
var row = get_row_text(i_row)
|
|
||||||
rows.append(row)
|
|
||||||
return rows
|
|
||||||
|
|
||||||
|
|
||||||
func get_row(i_row: int) -> Array:
|
|
||||||
var row: = []
|
|
||||||
for i_col in columns:
|
|
||||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
|
||||||
row.append(nodes[key])
|
|
||||||
return row
|
|
||||||
|
|
||||||
|
|
||||||
func get_node_rect(i_col: int, i_row: int, rect: Array) -> void:
|
|
||||||
assert(rect.size() >= 4) #,'ошибка: мало элементов для возврата результата')
|
|
||||||
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
|
||||||
var cell = nodes[key]
|
|
||||||
rect[0] = cell.position.x
|
|
||||||
rect[1] = cell.position.y
|
|
||||||
rect[2] = cell.size.x
|
|
||||||
rect[3] = cell.size.y
|
|
||||||
12
table/header.tscn
Normal file
12
table/header.tscn
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://ch14g46swx74h"]
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_2thpi"]
|
||||||
|
bg_color = Color(0.8, 0.533333, 0.27451, 1)
|
||||||
|
|
||||||
|
[node name="header" type="Label"]
|
||||||
|
offset_right = 128.0
|
||||||
|
offset_bottom = 23.0
|
||||||
|
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||||
|
theme_override_styles/normal = SubResource("StyleBoxFlat_2thpi")
|
||||||
|
horizontal_alignment = 1
|
||||||
|
vertical_alignment = 1
|
||||||
BIN
table/nine-patch.png
Normal file
BIN
table/nine-patch.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 125 B |
34
table/nine-patch.png.import
Normal file
34
table/nine-patch.png.import
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://bw3yv3smvaxqn"
|
||||||
|
path="res://.godot/imported/nine-patch.png-798f7950fb3126b4e1ed0c39d9e4beba.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://table/nine-patch.png"
|
||||||
|
dest_files=["res://.godot/imported/nine-patch.png-798f7950fb3126b4e1ed0c39d9e4beba.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
10
table/node.tscn
Normal file
10
table/node.tscn
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
[gd_scene format=3 uid="uid://c1i4rwaajq7d5"]
|
||||||
|
|
||||||
|
[node name="Label" type="LineEdit"]
|
||||||
|
offset_right = 121.0
|
||||||
|
offset_bottom = 23.0
|
||||||
|
theme_override_colors/font_color = Color(1, 0.596078, 0.4, 1)
|
||||||
|
editable = false
|
||||||
|
context_menu_enabled = false
|
||||||
|
caret_blink = true
|
||||||
|
caret_blink_interval = 0.1
|
||||||
15
table/selector.tscn
Normal file
15
table/selector.tscn
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://pd3fcx55duj2"]
|
||||||
|
|
||||||
|
[ext_resource type="Texture2D" uid="uid://bw3yv3smvaxqn" path="res://table/nine-patch.png" id="1_ik10p"]
|
||||||
|
|
||||||
|
[node name="NinePatchRect" type="NinePatchRect"]
|
||||||
|
offset_right = 17.0
|
||||||
|
offset_bottom = 16.0
|
||||||
|
texture = ExtResource("1_ik10p")
|
||||||
|
draw_center = false
|
||||||
|
patch_margin_left = 8
|
||||||
|
patch_margin_top = 8
|
||||||
|
patch_margin_right = 8
|
||||||
|
patch_margin_bottom = 8
|
||||||
|
axis_stretch_horizontal = 1
|
||||||
|
axis_stretch_vertical = 1
|
||||||
594
table/table.gd
Normal file
594
table/table.gd
Normal file
@@ -0,0 +1,594 @@
|
|||||||
|
extends GridContainer
|
||||||
|
|
||||||
|
## Виджет "Таблица"
|
||||||
|
|
||||||
|
@export var node_gap: = Vector2(0.0, 0.0) ## Зазор между ячейками, который не возможно вычислить или получить
|
||||||
|
@export var selector_color: = Color(1.0, 1.0, 1.0, 1.0) ## Окрашивающий цвет для индикатора выбранного ряда
|
||||||
|
@export var selector_key_down: Key = KEY_DOWN ## Клавиша увеличения индекса выбранного ряда
|
||||||
|
@export var selector_key_up: Key = KEY_UP ## Клавиша уменьшения индекса выбранного ряда
|
||||||
|
@export_file var node_type_file: = 'res://table/node.tscn': get = get_node_scene, set = load_node_scene ## Сцена ячейки устанавливаемая по умолчанию
|
||||||
|
@export_file var selector_type_file: = 'res://table/selector.tscn': set = load_selector_scene ## Сцена индикатора для выбранного ряда
|
||||||
|
|
||||||
|
const HEAD_PREFIX = 'HEAD_' ## Префикс ключа заголовка таблицы
|
||||||
|
const INDEX_FORMAT = '%02d_%02d' ## Формат индекса ключа
|
||||||
|
const MAX_INDEX = 99 ## Максимальное значение индекса для колонки и строки. Связано с форматом индекса ключа
|
||||||
|
const NODE_PREFIX = 'NODE_' ## Префикс ключа ячейки таблицы
|
||||||
|
const SLCT_PREFIX = 'SLCT_' ## Префикс ключа индикатора выбранного ряда таблицы
|
||||||
|
|
||||||
|
const HEAD_KEY_FORMAT = HEAD_PREFIX + INDEX_FORMAT ## Формат ключа заголовка
|
||||||
|
const NODE_KEY_FORMAT = NODE_PREFIX + INDEX_FORMAT ## Формат ключа ячейки
|
||||||
|
const ROW_SELECTOR_KEY_FORMAT = SLCT_PREFIX + INDEX_FORMAT ## Формат ключа индикаторов выбранного ряда
|
||||||
|
const META_NAME_USER_DATA = 'user_data'
|
||||||
|
const META_NAME_CALLEBLE = 'calleble'
|
||||||
|
|
||||||
|
var header: GridContainer ## Заголовок таблицы
|
||||||
|
var in_focus: = false ## Фокус пользовательского ввода
|
||||||
|
var nodes: = {} ## Все ячейки таблицы и дополнительные элементы
|
||||||
|
var ScnNode: PackedScene ## Прототип ячейки таблицы
|
||||||
|
var ScnSelector: PackedScene ## Прототип индикатора выбранного ряда
|
||||||
|
var selector_color_proc: Callable ## Ссылка на процедуру генератора цвета индикатора выбранного ряда
|
||||||
|
var selector_size_proc: Callable ## Ссылка на процедуру генератора размера индикатора выбранного ряда
|
||||||
|
|
||||||
|
signal row_pressed(i_row: int) ## Вызывается при нажатии кнопкой мыши на строку
|
||||||
|
signal selected_changed(i_row: int) ## Вызывается при изменении выбранного ряда. i_row - текущий выбранный ряд
|
||||||
|
|
||||||
|
var scroll: Control
|
||||||
|
var scroll_adj: = Vector2(0, 0)
|
||||||
|
|
||||||
|
|
||||||
|
func get_node_scene(): return node_type_file
|
||||||
|
func _assert_meta(i_col: int, i_row: int, pname: String, node): assert(node.has_meta(pname), 'ошибка: нет мета-свойства \"%s\" у ячейки колонка:%d ряд:%d' % [pname, i_col, i_row])
|
||||||
|
func get_node_user_data(i_col: int, i_row: int): return get_node_meta(i_col, i_row, META_NAME_USER_DATA)
|
||||||
|
func set_node_user_data(i_col: int, i_row: int, val) -> void: set_node_meta(i_col, i_row, META_NAME_USER_DATA, val)
|
||||||
|
|
||||||
|
|
||||||
|
## Закрепляет заголовок таблицы. [param scrl] - Прокрутка,
|
||||||
|
## [param prnt] - Родитель прокрутки заданный в редакторе
|
||||||
|
func pin_header(scrl: ScrollContainer, prnt: Control):
|
||||||
|
scrl.remove_child(header)
|
||||||
|
prnt.add_child(header)
|
||||||
|
## TODO: Это значение следует получить из темы
|
||||||
|
var v_separation: = 3.0
|
||||||
|
header.position = scrl.position - Vector2(0, header.size.y + v_separation)
|
||||||
|
scroll = scrl
|
||||||
|
scroll_adj = scrl.position
|
||||||
|
|
||||||
|
|
||||||
|
## Перемещает указатель на одну строку вверх
|
||||||
|
func selector_up():
|
||||||
|
var i_rows: = []
|
||||||
|
get_selected_rows(i_rows)
|
||||||
|
for i in i_rows:
|
||||||
|
set_row_selected(i, false)
|
||||||
|
var rows_count: = get_rows_count()
|
||||||
|
if not (i_rows.size() and (rows_count > 1)):
|
||||||
|
return
|
||||||
|
var i_row = i_rows[0]
|
||||||
|
i_row -= 1
|
||||||
|
if i_row < 0:
|
||||||
|
i_row = rows_count - 1
|
||||||
|
set_row_selected(i_row, true)
|
||||||
|
emit_signal('selected_changed', i_row)
|
||||||
|
|
||||||
|
|
||||||
|
## Перемещает указатель на одну строку вниз
|
||||||
|
func selector_down():
|
||||||
|
var i_rows: = []
|
||||||
|
get_selected_rows(i_rows)
|
||||||
|
for i in i_rows:
|
||||||
|
set_row_selected(i, false)
|
||||||
|
var rows_count: = get_rows_count()
|
||||||
|
if not (i_rows.size() and (rows_count > 1)):
|
||||||
|
return
|
||||||
|
var i_row = i_rows[0]
|
||||||
|
i_row += 1
|
||||||
|
i_row %= rows_count
|
||||||
|
set_row_selected(i_row, true)
|
||||||
|
emit_signal('selected_changed', i_row)
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
func set_columns_alignments(alignments):
|
||||||
|
assert(columns == alignments.size())
|
||||||
|
var rows_count: = get_rows_count()
|
||||||
|
for i_row in rows_count:
|
||||||
|
for i_col in alignments.size():
|
||||||
|
set_node_alligment(i_col, i_row, alignments[i_col])
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
func load_selector_scene(file_name: String):
|
||||||
|
selector_type_file = file_name
|
||||||
|
ScnSelector = load(file_name)
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
func load_node_scene(file_name: String):
|
||||||
|
node_type_file = file_name
|
||||||
|
ScnNode = load(file_name)
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
func _ready():
|
||||||
|
ScnSelector = load(selector_type_file)
|
||||||
|
ScnNode = load(node_type_file)
|
||||||
|
assert(ScnSelector)
|
||||||
|
assert(ScnNode)
|
||||||
|
|
||||||
|
|
||||||
|
## Выравнивает по нижнему левому углу. Используется для выравнивания по заголовку
|
||||||
|
func align_to_left_bottompos(hdr: Control, gap: = Vector2(0, 0)):
|
||||||
|
position.x = hdr.position.x + gap.x
|
||||||
|
position.y = hdr.position.y + hdr.size.y + gap.y
|
||||||
|
|
||||||
|
|
||||||
|
## [param i_col] - индекс колонки. [param i_row] - индекс ряда.
|
||||||
|
func set_node_meta(i_col: int, i_row: int, pname: String, val) -> void:
|
||||||
|
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||||
|
var node = nodes[key]
|
||||||
|
node.set_meta(pname, val)
|
||||||
|
|
||||||
|
|
||||||
|
## [param i_col] - индекс колонки. [param i_row] - индекс ряда.
|
||||||
|
func get_node_meta(i_col: int, i_row: int, pname: String):
|
||||||
|
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||||
|
var node = nodes[key]
|
||||||
|
_assert_meta(i_col, i_row, pname, node)
|
||||||
|
return node.get_meta(pname)
|
||||||
|
|
||||||
|
|
||||||
|
## [param i_col] - индекс колонки. [param i_row] - индекс ряда.
|
||||||
|
func set_node_property(i_col: int, i_row: int, pname: String, val) -> void:
|
||||||
|
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||||
|
var node = nodes[key]
|
||||||
|
node.set(pname, val)
|
||||||
|
|
||||||
|
|
||||||
|
## [param i_col] - индекс колонки. [param i_row] - индекс ряда.
|
||||||
|
func get_node_property(i_col: int, i_row: int, pname: String):
|
||||||
|
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||||
|
var node = nodes[key]
|
||||||
|
return node.get(pname)
|
||||||
|
|
||||||
|
|
||||||
|
## [param i_col] - индекс колонки. [param i_row] - индекс ряда
|
||||||
|
func get_node_key(format: String, i_col: int, i_row: int) -> String:
|
||||||
|
var key: String = format % [i_row, i_col]
|
||||||
|
assert(nodes.has(key), 'ошибка: нет такой ячейки - колонка:%d ряд:%d' % [i_col, i_row])
|
||||||
|
return key
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
func get_key_indexes(key: String) -> Array:
|
||||||
|
var tokens: = key.split('_')
|
||||||
|
assert(tokens.size() == 3, 'ошибка: неверный ключ: \"%s\"' % key)
|
||||||
|
return [int(tokens[2]), int(tokens[1])]
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
func set_columns_min_size(sizes: Array) -> void:
|
||||||
|
var rows_count: = get_rows_count()
|
||||||
|
for i_row in rows_count:
|
||||||
|
set_nodes_min_size(i_row, sizes)
|
||||||
|
set_nodes_min_size(0, sizes, HEAD_KEY_FORMAT)
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
func set_columns_aligment(alignments: Array) -> void:
|
||||||
|
var rows_count: = get_rows_count()
|
||||||
|
for i_row in rows_count:
|
||||||
|
for i_col in alignments.size():
|
||||||
|
set_node_alligment(i_col, i_row, alignments[i_col])
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
func _input(event) -> void:
|
||||||
|
if event is InputEventKey:
|
||||||
|
if in_focus and event.pressed:
|
||||||
|
if event.keycode == selector_key_up:
|
||||||
|
selector_up()
|
||||||
|
elif event.keycode == selector_key_down:
|
||||||
|
selector_down()
|
||||||
|
elif event is InputEventMouseButton:
|
||||||
|
if not event.pressed:
|
||||||
|
return
|
||||||
|
if check_event_pos(event.position, scroll):
|
||||||
|
if not in_focus:
|
||||||
|
in_focus = true
|
||||||
|
emit_signal('focus_entered')
|
||||||
|
elif not check_event_pos(event.position, scroll):
|
||||||
|
if in_focus:
|
||||||
|
in_focus = false
|
||||||
|
emit_signal('focus_exited')
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
func _init() -> void:
|
||||||
|
selector_color_proc = Callable(self, 'defaultselector_color_proc')
|
||||||
|
assert(selector_color_proc.is_valid())
|
||||||
|
selector_size_proc = Callable(self, 'default_selector_size_proc')
|
||||||
|
assert(selector_size_proc.is_valid())
|
||||||
|
scroll = self
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
func check_event_pos(event_pos: Vector2, obj: Control):
|
||||||
|
return \
|
||||||
|
(event_pos.x > obj.position.x) \
|
||||||
|
and (event_pos.x < (obj.position.x + obj.size.x)) \
|
||||||
|
and (event_pos.y > obj.position.y) \
|
||||||
|
and (event_pos.y < (obj.position.y + obj.size.y))
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
func defaultselector_color_proc(_i_row: int):
|
||||||
|
return selector_color
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
func setselector_color_proc(instance: Object, function: String) -> void:
|
||||||
|
selector_color_proc = Callable(instance, function)
|
||||||
|
assert(selector_color_proc.is_valid())
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
func set_selector_size_proc(instance: Object, function: String) -> void:
|
||||||
|
selector_size_proc = Callable(instance, function)
|
||||||
|
assert(selector_size_proc.is_valid())
|
||||||
|
|
||||||
|
|
||||||
|
## [param i_row] - Индекс ряда
|
||||||
|
func default_selector_size_proc(i_row: int, rect: Array) -> void:
|
||||||
|
get_row_rect(i_row, rect)
|
||||||
|
rect[0] += position.x - node_gap.x / 2.0
|
||||||
|
rect[1] += position.y - node_gap.y / 2.0
|
||||||
|
rect[2] += node_gap.x
|
||||||
|
rect[3] += node_gap.y
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
func clear_rows_selected():
|
||||||
|
var rows_count: = get_rows_count()
|
||||||
|
for i_row in rows_count:
|
||||||
|
set_row_selected(i_row, false)
|
||||||
|
|
||||||
|
|
||||||
|
## [param i_row] - Индекс ряда.
|
||||||
|
func set_row_selected(i_row: int, selected: bool = true) -> void:
|
||||||
|
var key: = ROW_SELECTOR_KEY_FORMAT % [i_row, 0]
|
||||||
|
var node = nodes[NODE_KEY_FORMAT % [i_row, 0]]
|
||||||
|
if nodes.has(key) and (not selected):
|
||||||
|
var selector = nodes[key]
|
||||||
|
node.remove_child(selector)
|
||||||
|
selector.queue_free()
|
||||||
|
nodes.erase(key)
|
||||||
|
elif (not nodes.has(key)) and selected:
|
||||||
|
var selector = ScnSelector.instantiate()
|
||||||
|
var rect: = [0, 0, 0, 0]
|
||||||
|
selector_size_proc.call(i_row, rect)
|
||||||
|
selector.size.x = rect[2]
|
||||||
|
selector.size.y = rect[3]
|
||||||
|
selector.modulate = selector_color_proc.call(i_row)
|
||||||
|
selector.z_index = z_index + 1
|
||||||
|
nodes[key] = selector
|
||||||
|
node.add_child(selector)
|
||||||
|
|
||||||
|
|
||||||
|
## [param i_row] - Индекс ряда.
|
||||||
|
func is_row_selected(i_row: int) -> bool:
|
||||||
|
var key: = ROW_SELECTOR_KEY_FORMAT % [i_row, 0]
|
||||||
|
return nodes.has(key)
|
||||||
|
|
||||||
|
|
||||||
|
## [param i_row] - Индексы рядов.
|
||||||
|
func get_selected_rows(i_rows: Array) -> void:
|
||||||
|
for key in nodes.keys():
|
||||||
|
if SLCT_PREFIX in key:
|
||||||
|
var indexes = get_key_indexes(key)
|
||||||
|
i_rows.append(indexes[1])
|
||||||
|
|
||||||
|
|
||||||
|
## Возвращает количество рядов
|
||||||
|
func get_rows_count() -> int:
|
||||||
|
var nodes_count: int = 0
|
||||||
|
for key in nodes:
|
||||||
|
nodes_count += int(NODE_PREFIX in key)
|
||||||
|
return nodes_count / columns
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
func get_node2(i_col: int, i_row: int) -> Node:
|
||||||
|
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||||
|
return nodes[key]
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
func add_row(row_types: Array) -> void:
|
||||||
|
assert(row_types.size() < MAX_INDEX, 'ошибка: слишком много колонок, больше %d' % (MAX_INDEX + 1))
|
||||||
|
if columns == 1:
|
||||||
|
set_columns(row_types.size())
|
||||||
|
else:
|
||||||
|
assert(columns == row_types.size(), 'ошибка: %s количество колонок установлено ранее - %d, но требуется %d' % [self, columns, row_types.size()])
|
||||||
|
var i_row: int = get_rows_count()
|
||||||
|
assert(i_row < MAX_INDEX, 'ошибка: слишком много рядов, больше %d' % (MAX_INDEX + 1))
|
||||||
|
for i_col in columns:
|
||||||
|
var node_type = row_types[i_col]
|
||||||
|
var node = node_type.instantiate()
|
||||||
|
assert(node.name == node.name, 'ошибка: экземпляр не имеет поля \"name\"')
|
||||||
|
var head = nodes[HEAD_KEY_FORMAT % [0, i_col]]
|
||||||
|
node.custom_minimum_size.x = head.custom_minimum_size.x
|
||||||
|
node.set_deferred('size.x', head.size.x)
|
||||||
|
var node_key: String = NODE_KEY_FORMAT % [i_row, i_col]
|
||||||
|
node.name = node_key
|
||||||
|
add_child(node)
|
||||||
|
nodes[node_key] = node
|
||||||
|
var conn = Callable(self, '_on_focus_entered').bind(node)
|
||||||
|
node.connect('focus_entered', conn)
|
||||||
|
set_node_meta(i_col, i_row, 'callable_focus_entered', conn)
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
func _on_focus_entered(node):
|
||||||
|
var indexes = get_key_indexes(node.name)
|
||||||
|
emit_signal('row_pressed', indexes[1])
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
func set_header(header_types: Array):
|
||||||
|
assert(header_types.size() < MAX_INDEX, 'ошибка: количество колонок в заголовке: %d больше допустимого: %d' % [header_types.size(), MAX_INDEX + 1])
|
||||||
|
if columns == 1:
|
||||||
|
set_columns(header_types.size())
|
||||||
|
else:
|
||||||
|
assert(columns == header_types.size(), 'ошибка: количество колонок в заголовке %d, но ранее установлено: %d' % [header_types.size(), columns])
|
||||||
|
var do_adj: = false
|
||||||
|
if not header:
|
||||||
|
header = GridContainer.new()
|
||||||
|
header.position = position
|
||||||
|
header.columns = header_types.size()
|
||||||
|
header.size.x = size.x
|
||||||
|
var parent = scroll.get_parent()
|
||||||
|
parent.add_child(header)
|
||||||
|
do_adj = true
|
||||||
|
else:
|
||||||
|
var childrens = header.get_children()
|
||||||
|
for node in childrens:
|
||||||
|
childrens.erase(node.name)
|
||||||
|
childrens.remove_child(node)
|
||||||
|
node.queue_free()
|
||||||
|
for i_col in columns:
|
||||||
|
var node = header_types[i_col].instantiate()
|
||||||
|
var key: String = HEAD_KEY_FORMAT % [0, i_col]
|
||||||
|
node.name = key
|
||||||
|
nodes[key] = node
|
||||||
|
header.add_child(node)
|
||||||
|
if do_adj:
|
||||||
|
var rect = [0, 0, 0, 0]
|
||||||
|
get_node_rect(0, 0, rect, HEAD_KEY_FORMAT)
|
||||||
|
position.y += rect[3]
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
func set_header_text(headers: Array):
|
||||||
|
assert(columns == headers.size())
|
||||||
|
set_row_text(0, headers, 0, HEAD_KEY_FORMAT)
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
func remove_row(i_row: int):
|
||||||
|
var sel_key: String = ROW_SELECTOR_KEY_FORMAT % [i_row, 0]
|
||||||
|
|
||||||
|
if nodes.has(sel_key):
|
||||||
|
var selector = nodes[sel_key]
|
||||||
|
var prnt = selector.get_parent()
|
||||||
|
prnt.remove_child(selector)
|
||||||
|
selector.queue_free()
|
||||||
|
nodes.erase(sel_key)
|
||||||
|
|
||||||
|
for i_col in columns:
|
||||||
|
|
||||||
|
var node_key: String = NODE_KEY_FORMAT % [i_row, i_col]
|
||||||
|
var node = nodes[node_key]
|
||||||
|
|
||||||
|
var conn = get_node_meta(i_col, i_row, 'callable_focus_entered')
|
||||||
|
node.disconnect('focus_entered', conn)
|
||||||
|
|
||||||
|
if node.has_meta(META_NAME_CALLEBLE):
|
||||||
|
conn = node.get_meta(META_NAME_CALLEBLE)
|
||||||
|
node.disconnect('pressed', conn)
|
||||||
|
|
||||||
|
remove_child(node)
|
||||||
|
nodes.erase(node_key)
|
||||||
|
node.queue_free()
|
||||||
|
rehash()
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
func next_index(indexes: Array) -> void:
|
||||||
|
indexes[0].x += 1
|
||||||
|
if indexes[0].x == columns:
|
||||||
|
indexes[0].x = 0
|
||||||
|
indexes[0].y += 1
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
func swap_nodes(nodes_copy, node_key_format, i0, i1) -> void:
|
||||||
|
var key0 = node_key_format % [i0.y, i0.x]
|
||||||
|
var key1 = node_key_format % [i1.y, i1.x]
|
||||||
|
nodes_copy[key1] = nodes[key0]
|
||||||
|
nodes_copy[key1].name = key1
|
||||||
|
|
||||||
|
|
||||||
|
## Переназначает ключи в соответствии с размерами таблицы.
|
||||||
|
func rehash():
|
||||||
|
var i_node: = [Vector2i()]
|
||||||
|
var i_hdr: = [Vector2i()]
|
||||||
|
var i_slct: = [Vector2i()]
|
||||||
|
var nodes_copy = {}
|
||||||
|
for key in nodes:
|
||||||
|
var iv = get_key_indexes(key)
|
||||||
|
var i0 = Vector2(iv[0], iv[1])
|
||||||
|
if HEAD_PREFIX in key:
|
||||||
|
swap_nodes(nodes_copy, HEAD_KEY_FORMAT, i0, i_hdr[0])
|
||||||
|
next_index(i_hdr)
|
||||||
|
elif NODE_PREFIX in key:
|
||||||
|
swap_nodes(nodes_copy, NODE_KEY_FORMAT, i0, i_node[0])
|
||||||
|
next_index(i_node)
|
||||||
|
elif SLCT_PREFIX in key:
|
||||||
|
swap_nodes(nodes_copy, ROW_SELECTOR_KEY_FORMAT, i0, i_slct[0])
|
||||||
|
next_index(i_slct)
|
||||||
|
nodes.clear()
|
||||||
|
nodes.merge(nodes_copy)
|
||||||
|
|
||||||
|
|
||||||
|
## Удаляет все строки таблицы
|
||||||
|
func clear_rows() -> void:
|
||||||
|
var rows_count: int = get_rows_count()
|
||||||
|
for i_row in range(rows_count - 1, -1, -1):
|
||||||
|
remove_row(i_row)
|
||||||
|
|
||||||
|
|
||||||
|
## Настраевает обратные вызовы для колонок.
|
||||||
|
## [param dest_node] - Получатель события[br]
|
||||||
|
## [param event_name] - Имя события[br]
|
||||||
|
## [param callback] - Имя функции получателя события[br]
|
||||||
|
## [param clmns] - Индексы колонок[br]
|
||||||
|
## [param user_data] - Аргументы функции получателя события[br]
|
||||||
|
func connect_columns(dest_node: Node, event_name: String, callback: String, clmns: Array, user_data: Array) -> void:
|
||||||
|
var rows_count = get_rows_count()
|
||||||
|
for i_row in rows_count:
|
||||||
|
for i_col in clmns:
|
||||||
|
assert(i_col >= 0 and i_col < columns, 'ошибка: нет такой колонки: %d' % i_col)
|
||||||
|
var node = get_node2(i_col, i_row)
|
||||||
|
if node.has_meta(META_NAME_CALLEBLE):
|
||||||
|
var conn = node.get_meta(META_NAME_CALLEBLE)
|
||||||
|
node.disconnect(event_name, conn)
|
||||||
|
var conn = Callable(dest_node, callback).bind([node] + user_data)
|
||||||
|
assert (OK == node.connect(event_name, conn))
|
||||||
|
node.set_meta(META_NAME_CALLEBLE, conn)
|
||||||
|
|
||||||
|
##
|
||||||
|
func set_rows_text(rows: Array) -> void:
|
||||||
|
for i_row in rows.size():
|
||||||
|
for i_col in columns:
|
||||||
|
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||||
|
var node = nodes[key]
|
||||||
|
node.text = rows[i_row][i_col]
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
func set_nodes_min_size(i_row: int, sizes: Array, key_format: String = NODE_KEY_FORMAT) -> void:
|
||||||
|
for i_col in columns:
|
||||||
|
var key: = get_node_key(key_format, i_col, i_row)
|
||||||
|
var node = nodes[key]
|
||||||
|
node.custom_minimum_size.x = sizes[i_col]
|
||||||
|
node.set_deferred('size.x', sizes[i_col])
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
func set_node_text(i_col: int, i_row: int, val: String) -> void:
|
||||||
|
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||||
|
nodes[key].text = val
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
func set_rows_state(rows: Array) -> void:
|
||||||
|
for i_row in rows.size():
|
||||||
|
for i_col in columns:
|
||||||
|
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||||
|
nodes[key].button_pressed = rows[i_row][i_col]
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
func set_node_state(i_col: int, i_row: int, val: bool) -> void:
|
||||||
|
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||||
|
nodes[key].button_pressed = val
|
||||||
|
|
||||||
|
|
||||||
|
## [param i_col] - индекс колонки. [param i_row] - индекс ряда.
|
||||||
|
func set_node_frame(i_col: int, i_row: int, node_name: String, val: int) -> void:
|
||||||
|
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||||
|
var node = nodes[key]
|
||||||
|
var sprite = node.get_node(node_name)
|
||||||
|
sprite.frame = val
|
||||||
|
|
||||||
|
|
||||||
|
## [param i_col] - индекс колонки. [param i_row] - индекс ряда.
|
||||||
|
func set_node_editable(i_col: int, i_row: int, val: bool) -> void:
|
||||||
|
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||||
|
nodes[key].editable = val
|
||||||
|
|
||||||
|
|
||||||
|
## [param i_col] - индекс колонки. [param i_row] - индекс ряда.
|
||||||
|
func set_node_alligment(i_col: int, i_row: int, val: int) -> void:
|
||||||
|
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||||
|
if 'horizontal_alignment' in nodes[key]:
|
||||||
|
nodes[key].horizontal_alignment = val
|
||||||
|
elif 'alignment' in nodes[key]:
|
||||||
|
nodes[key].alignment = val
|
||||||
|
|
||||||
|
|
||||||
|
## [param i_row] - индекс ряда.
|
||||||
|
func set_row_alligments(i_row: int, aligns: Array) -> void:
|
||||||
|
for i_col in columns:
|
||||||
|
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||||
|
nodes[key].align = aligns[i_col]
|
||||||
|
|
||||||
|
|
||||||
|
## [param i_row] - индекс ряда.
|
||||||
|
func get_row_text(i_row: int) -> Array:
|
||||||
|
var row: = []
|
||||||
|
for i_col in columns:
|
||||||
|
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||||
|
row.append(nodes[key].text)
|
||||||
|
return row
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
func set_row_text(i_row: int, row: Array, i_begin: int = 0, key_format: String = NODE_KEY_FORMAT) -> void:
|
||||||
|
assert(i_begin >= 0)
|
||||||
|
assert((columns - i_begin) <= row.size())
|
||||||
|
for i_col in columns - i_begin:
|
||||||
|
var key: = get_node_key(key_format, i_col + i_begin, i_row)
|
||||||
|
nodes[key].text = row[i_col]
|
||||||
|
|
||||||
|
|
||||||
|
## Возвращает все строки таблицы в двумерном массиве
|
||||||
|
func get_rows_text() -> Array:
|
||||||
|
var rows_count: = get_rows_count()
|
||||||
|
var rows: = []
|
||||||
|
for i_row in rows_count:
|
||||||
|
var row = get_row_text(i_row)
|
||||||
|
rows.append(row)
|
||||||
|
return rows
|
||||||
|
|
||||||
|
|
||||||
|
## Возвращает массив ячеек из ряда [param i_row]
|
||||||
|
func get_row(i_row: int) -> Array:
|
||||||
|
var row: = []
|
||||||
|
for i_col in columns:
|
||||||
|
var key: = get_node_key(NODE_KEY_FORMAT, i_col, i_row)
|
||||||
|
row.append(nodes[key])
|
||||||
|
return row
|
||||||
|
|
||||||
|
|
||||||
|
## Возвращает прямоугольник [param rect] занимаемый ячейкой в ряду [param i_row] и колонке [param i_col].
|
||||||
|
## [param key_format] - Формат ключа ячейки
|
||||||
|
func get_node_rect(i_col: int, i_row: int, rect: Array, key_format: String = NODE_KEY_FORMAT) -> void:
|
||||||
|
assert(rect.size() >= 4, 'ошибка: мало элементов для возврата результата')
|
||||||
|
var key: = get_node_key(key_format, i_col, i_row)
|
||||||
|
var cell = nodes[key]
|
||||||
|
rect[0] = cell.position.x
|
||||||
|
rect[1] = cell.position.y
|
||||||
|
rect[2] = cell.size.x
|
||||||
|
rect[3] = cell.size.y
|
||||||
|
|
||||||
|
|
||||||
|
## Возвращает прямоугольник [param rect] занимаемый рядом [param i_row]. [param key_format] - Формат ключа ячейки
|
||||||
|
func get_row_rect(i_row: int, rect: Array, key_format: String = NODE_KEY_FORMAT) -> void:
|
||||||
|
assert(rect.size() >= 4, 'ошибка: мало элементов для возврата результата')
|
||||||
|
var cell0 = nodes[get_node_key(key_format, 0, i_row)]
|
||||||
|
var cell1 = nodes[get_node_key(key_format, columns - 1, i_row)]
|
||||||
|
rect[0] = cell0.position.x + scroll_adj.x
|
||||||
|
rect[1] = cell0.position.y + scroll_adj.y
|
||||||
|
rect[2] = (cell1.position.x - cell0.position.x) + cell1.size.x
|
||||||
|
rect[3] = cell0.size.y
|
||||||
30
threats.gd
30
threats.gd
@@ -12,10 +12,11 @@ const TableCellType3 = preload('res://кнопка-4.tscn')
|
|||||||
const TableCellType4 = preload('res://заголовок.tscn')
|
const TableCellType4 = preload('res://заголовок.tscn')
|
||||||
const TableCellType5 = preload('res://ячейка-2.tscn')
|
const TableCellType5 = preload('res://ячейка-2.tscn')
|
||||||
const TableCellType6 = preload('res://кнопка-5.tscn')
|
const TableCellType6 = preload('res://кнопка-5.tscn')
|
||||||
|
const TableHeader = preload('res://table/header.tscn')
|
||||||
|
|
||||||
# Индекс колонки: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
# Индекс колонки: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||||
const TABLE_HEADERS = ['ID Цели', 'Курc.град', 'Частота', 'Ш. диап.', 'Ампл.', 'T обнар.', 'Мод.', 'Реж. см. F', 'Ск. пер.', 'Протокол', 'Ст. дол.', 'Ст. шир.', 'Cт. выс.', 'Тек. дол.', 'Тек. шир.', 'Тек. выс.', ]
|
const TABLE_HEADERS = ['ID Цели', 'Курc.град', 'Частота', 'Ш. диап.', 'Ампл.', 'T обнар.', 'Мод.', 'Реж. см. F', 'Ск. пер.', 'Протокол', 'Ст. дол.', 'Ст. шир.', 'Cт. выс.', 'Тек. дол.', 'Тек. шир.', 'Тек. выс.', ]
|
||||||
const TABLE_HEADER_TYPES = [ TableCellType4, TableCellType4, TableCellType4, TableCellType4, TableCellType4, TableCellType4, TableCellType4, TableCellType4, TableCellType4, TableCellType4, TableCellType4, TableCellType4, TableCellType4, TableCellType4, TableCellType4, TableCellType4]
|
const TABLE_HEADER_TYPES = [ TableHeader, TableHeader, TableHeader, TableHeader, TableHeader, TableHeader, TableHeader, TableHeader, TableHeader, TableHeader, TableHeader, TableHeader, TableHeader, TableHeader, TableHeader, TableHeader]
|
||||||
const TABLE_HEADER_ALIGNMENTS = [ HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER]
|
const TABLE_HEADER_ALIGNMENTS = [ HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER]
|
||||||
const TABLE_ROW_TYPES = [ TableCellType1, TableCellType5, TableCellType5, TableCellType5, TableCellType5, TableCellType5, TableCellType6, TableCellType6, TableCellType5, TableCellType6, TableCellType5, TableCellType5, TableCellType5, TableCellType5, TableCellType5, TableCellType5]
|
const TABLE_ROW_TYPES = [ TableCellType1, TableCellType5, TableCellType5, TableCellType5, TableCellType5, TableCellType5, TableCellType6, TableCellType6, TableCellType5, TableCellType6, TableCellType5, TableCellType5, TableCellType5, TableCellType5, TableCellType5, TableCellType5]
|
||||||
const TABLE_ROW_ALIGNMENTS = [ HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_LEFT, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER]
|
const TABLE_ROW_ALIGNMENTS = [ HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_LEFT, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER, HORIZONTAL_ALIGNMENT_CENTER]
|
||||||
@@ -262,31 +263,26 @@ class Threat:
|
|||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
func init_treats(header, table, btn_add, btn_del): # Инициализация вкладки с целями
|
func init_treats(table, btn_add, btn_del): # Инициализация вкладки с целями
|
||||||
for i in range(ID_ARRAY_LEN): # Заполняет массив ID целей
|
for i in range(ID_ARRAY_LEN): # Заполняет массив ID целей
|
||||||
id_array.append(i+1)
|
id_array.append(i+1)
|
||||||
header.add_row(TABLE_HEADER_TYPES)
|
table.set_header(TABLE_HEADER_TYPES)
|
||||||
header.set_rows_text([TABLE_HEADERS])
|
table.set_header_text(TABLE_HEADERS)
|
||||||
on_btn_add(table)
|
on_btn_add(table)
|
||||||
init_table(header, TABLE_COLUMN_SIZES)
|
|
||||||
init_table(table, TABLE_COLUMN_SIZES)
|
init_table(table, TABLE_COLUMN_SIZES)
|
||||||
g_table = table
|
g_table = table
|
||||||
table.align_to_left_bottom(header, Vector2(0, 2))
|
table.set_columns_min_size(TABLE_COLUMN_SIZES)
|
||||||
table.connect('row_pressed', Callable(self, 'on_row_pressed').bind(table))
|
table.connect('row_pressed', Callable(self, 'on_row_pressed').bind(table))
|
||||||
#table.set_callbacks(self, 'text_submitted', 'on_edit_entry', TABLE_ENTRY_COLUMNS, [])
|
table.connect_columns(self, 'text_submitted', 'on_edit_entry', TABLE_ENTRY_COLUMNS, [])
|
||||||
#table.set_callbacks(self, 'item_selected', 'on_item_selected', COLUMN_OPT_BTN, [])
|
table.connect_columns(self, 'item_selected', 'on_item_selected', COLUMN_OPT_BTN, [])
|
||||||
btn_add.connect('button_up', Callable(self, 'on_btn_add').bind(table))
|
btn_add.connect('button_up', Callable(self, 'on_btn_add').bind(table))
|
||||||
btn_del.connect('button_up', Callable(self, 'on_btn_del').bind(table))
|
btn_del.connect('button_up', Callable(self, 'on_btn_del').bind(table))
|
||||||
|
|
||||||
|
|
||||||
func selector_color_proc(_i_row: int):
|
|
||||||
return Consts.COLOR_ACCENT * Consts.COLOR_HALF_ALPHA
|
|
||||||
|
|
||||||
|
|
||||||
func init_table(table: Table, sizes: Array):
|
func init_table(table: Table, sizes: Array):
|
||||||
for i_row in table.get_rows_count():
|
for i_row in table.get_rows_count():
|
||||||
table.set_nodes_min_size(i_row, sizes)
|
#table.set_nodes_min_size(i_row, sizes)
|
||||||
table.set_selector_color_proc(self, 'selector_color_proc')
|
pass
|
||||||
|
|
||||||
|
|
||||||
func init_opt_btns(row : int, table):
|
func init_opt_btns(row : int, table):
|
||||||
@@ -365,8 +361,8 @@ func on_btn_add(table):
|
|||||||
table.add_row(TABLE_ROW_TYPES)
|
table.add_row(TABLE_ROW_TYPES)
|
||||||
table.set_row_text(table.get_rows_count()-1, row)
|
table.set_row_text(table.get_rows_count()-1, row)
|
||||||
init_opt_btns(table.get_rows_count()-1, table)
|
init_opt_btns(table.get_rows_count()-1, table)
|
||||||
table.set_callbacks(self, 'text_submitted', 'on_edit_entry', TABLE_ENTRY_COLUMNS, [])
|
table.connect_columns(self, 'text_submitted', 'on_edit_entry', TABLE_ENTRY_COLUMNS, [])
|
||||||
table.set_callbacks(self, 'item_selected', 'on_item_selected', COLUMN_OPT_BTN, [])
|
table.connect_columns(self, 'item_selected', 'on_item_selected', COLUMN_OPT_BTN, [])
|
||||||
|
|
||||||
|
|
||||||
func on_btn_del(table):
|
func on_btn_del(table):
|
||||||
@@ -376,7 +372,6 @@ func on_btn_del(table):
|
|||||||
var cell = table.get_node2(0, row_i[0])
|
var cell = table.get_node2(0, row_i[0])
|
||||||
treats.erase(cell.text)
|
treats.erase(cell.text)
|
||||||
table.remove_row(row_i[0])
|
table.remove_row(row_i[0])
|
||||||
table.rehash([])
|
|
||||||
|
|
||||||
|
|
||||||
func pop_id():
|
func pop_id():
|
||||||
@@ -402,6 +397,5 @@ func get_threats_data():
|
|||||||
var data = treats[key].get_data()
|
var data = treats[key].get_data()
|
||||||
data_to_json['mis'].append(data)
|
data_to_json['mis'].append(data)
|
||||||
var json = JSON.new().stringify(data_to_json)
|
var json = JSON.new().stringify(data_to_json)
|
||||||
print_debug(json)
|
|
||||||
var pac = json.to_utf8_buffer()
|
var pac = json.to_utf8_buffer()
|
||||||
return pac
|
return pac
|
||||||
|
|||||||
38
tools.gd
38
tools.gd
@@ -2,29 +2,29 @@ extends Node
|
|||||||
|
|
||||||
|
|
||||||
func check_low_high(val, low, high): # Проверка min/max значений
|
func check_low_high(val, low, high): # Проверка min/max значений
|
||||||
if val > high:
|
if val > high:
|
||||||
return high
|
return high
|
||||||
elif val < low:
|
elif val < low:
|
||||||
return low
|
return low
|
||||||
else:
|
else:
|
||||||
return val
|
return val
|
||||||
|
|
||||||
func check_negative(val): # Проверка на отрицательное
|
func check_negative(val): # Проверка на отрицательное
|
||||||
if val < 0:
|
if val < 0:
|
||||||
return 0
|
return 0
|
||||||
else:
|
else:
|
||||||
return val
|
return val
|
||||||
|
|
||||||
func check_len(val, value):
|
func check_len(val, value):
|
||||||
if len(val) < 1:
|
if len(val) < 1:
|
||||||
return ''
|
return ''
|
||||||
else:
|
else:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
func check_empty(val):
|
func check_empty(val):
|
||||||
|
|
||||||
if str(val) == '':
|
if str(val) == '':
|
||||||
return false
|
return false
|
||||||
else:
|
else:
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[gd_scene load_steps=3 format=3 uid="uid://ccxre8mwhndjk"]
|
[gd_scene load_steps=3 format=3 uid="uid://ccxre8mwhndjk"]
|
||||||
|
|
||||||
[ext_resource type="Texture2D" uid="uid://b3ext3w4ftgg2" path="res://индикатор-1-1.png" id="1"]
|
[ext_resource type="Texture2D" uid="uid://dag8n0gknjwak" path="res://индикатор-1-0.png" id="1_1mkdt"]
|
||||||
[ext_resource type="Texture2D" uid="uid://dag8n0gknjwak" path="res://индикатор-1-0.png" id="2"]
|
[ext_resource type="Texture2D" uid="uid://b3ext3w4ftgg2" path="res://индикатор-1-1.png" id="2_21ih5"]
|
||||||
|
|
||||||
[node name="indicator_1" type="TextureButton"]
|
[node name="indicator_1" type="TextureButton"]
|
||||||
modulate = Color(1, 0.596078, 0.4, 1)
|
modulate = Color(1, 0.596078, 0.4, 1)
|
||||||
@@ -9,5 +9,5 @@ offset_right = 35.0
|
|||||||
offset_bottom = 29.0
|
offset_bottom = 29.0
|
||||||
toggle_mode = true
|
toggle_mode = true
|
||||||
button_mask = 0
|
button_mask = 0
|
||||||
texture_normal = ExtResource("2")
|
texture_normal = ExtResource("1_1mkdt")
|
||||||
texture_pressed = ExtResource("1")
|
texture_pressed = ExtResource("2_21ih5")
|
||||||
|
|||||||
Reference in New Issue
Block a user