РВП. Переход на godot4
This commit is contained in:
35
scenes/nine-patch-button.gd
Normal file
35
scenes/nine-patch-button.gd
Normal file
@@ -0,0 +1,35 @@
|
||||
@tool
|
||||
|
||||
extends PanelContainer
|
||||
|
||||
@export var text: String = '': get = get_text, set = set_text
|
||||
@export var texture_state0: Texture2D = preload('res://data/кнопка-квадрат-0.png'): set = _state_set_texture
|
||||
@export var texture_state1: Texture2D = preload('res://data/кнопка-квадрат-1.png'): set = _state_set_texture
|
||||
@export var pressed: bool = false: get = is_pressed, set = set_pressed
|
||||
@export var toggle_mode: bool = false: get = is_toggle_mode, set = set_toggle_mode
|
||||
|
||||
func _state_set_texture(val: Texture2D): $state.set_texture(val)
|
||||
func _state_get_texture(): return $state.get_texture()
|
||||
|
||||
func set_text (val: String): $button.set_text(val)
|
||||
func set_pressed (val: bool): $button.set_pressed(val)
|
||||
|
||||
|
||||
func set_toggle_mode (val: bool):
|
||||
if is_inside_tree():
|
||||
$button.set_toggle_mode(val)
|
||||
|
||||
|
||||
func get_text(): return $button.get_text()
|
||||
func is_pressed(): return $button.is_pressed()
|
||||
func is_toggle_mode(): return $button.is_toggle_mode()
|
||||
|
||||
|
||||
|
||||
func _on_button_toggled(val: bool):
|
||||
if val: $state.set_texture(texture_state1)
|
||||
else: $state.set_texture(texture_state0)
|
||||
|
||||
|
||||
func button_connect(button_signal: String, proc: Callable):
|
||||
$button.connect(button_signal, proc)
|
||||
4
scenes/node.tscn
Normal file
4
scenes/node.tscn
Normal file
@@ -0,0 +1,4 @@
|
||||
[gd_scene format=3 uid="uid://fp6utm5jmlj2"]
|
||||
|
||||
[node name="Label" type="Label"]
|
||||
clip_text = true
|
||||
10
scenes/selector.tscn
Normal file
10
scenes/selector.tscn
Normal file
@@ -0,0 +1,10 @@
|
||||
[gd_scene format=3 uid="uid://dhdiy3lgtt8v3"]
|
||||
|
||||
[node name="NinePatchRect" type="NinePatchRect"]
|
||||
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
|
||||
509
scenes/table.gd
Normal file
509
scenes/table.gd
Normal file
@@ -0,0 +1,509 @@
|
||||
extends GridContainer
|
||||
|
||||
@export var _selector_color: Color = Color(1.0, 1.0, 1.0, 1.0)
|
||||
@export_file ('*.tscn') var node_type_file: String = 'res://scenes/node.tscn'
|
||||
@export_file ('*.tscn') var selector_type_file: String = 'res://scenes/selector.tscn'
|
||||
|
||||
const MAX_INDEX = 99 # Максимальное значение индекса для колонки и строки. Связано с форматом индекса ключа
|
||||
const INDEX_FORMAT = '%02d_%02d' # Формат индекса
|
||||
const NODE_PREFIX = 'NODE_' # Префикс ключа ячейки таблицы
|
||||
const HEAD_PREFIX = 'HEAD_' # Префикс ключа заголовка таблицы
|
||||
const DATA_PREFIX = 'DATA_' # Префикс ключа данных ячейки таблицы
|
||||
const CONN_PREFIX = 'CONN_' # Префикс ключа обработчиков событий ячейки таблицы
|
||||
const SLCT_PREFIX = 'SLCT_' # Префикс ключа индикатора выбранного ряда таблицы
|
||||
|
||||
const NODE_KEY_FORMAT = NODE_PREFIX + INDEX_FORMAT
|
||||
const HEAD_KEY_FORMAT = HEAD_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
|
||||
|
||||
const SLCT_KEY_UP = KEY_UP # Клавиша уменьшения индекса выбранного ряда
|
||||
const SLCT_KEY_DOWN = KEY_DOWN # Клавиша увеличения индекса выбранного ряда
|
||||
|
||||
var nodes: = {} # Все ячейки таблицы и дополнительные элементы
|
||||
var selector_color_proc: Callable # Ссылка на процедуру генератора цвета индикатора выбранного ряда
|
||||
var selector_size_proc: Callable # Ссылка на процедуру генератора размера индикатора выбранного ряда
|
||||
var ScnSelector: PackedScene # Прототип индикатора выбранного ряда
|
||||
var ScnNode: PackedScene # Прототип ячейки таблицы
|
||||
var in_focus: = false # Фокус пользовательского ввода
|
||||
var header: GridContainer # Заголовок таблицы
|
||||
|
||||
signal row_pressed(i_row) # Вызывается при нажатии кнопкой мыши на строку
|
||||
signal selected_changed(i_row) # Вызывается при изменении выбранного ряда. i_row - текущий выбранный ряд
|
||||
|
||||
|
||||
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 _ready():
|
||||
ScnSelector = load(selector_type_file)
|
||||
ScnNode = load(node_type_file)
|
||||
assert(ScnSelector)
|
||||
assert(ScnNode)
|
||||
|
||||
|
||||
func align_to_left_bottom(header, gap: = Vector2(0, 0)):
|
||||
""" Выравнивает по нижнему левому углу. Используется для выравнивания по заголовку """
|
||||
position.x = header.position.x + gap.x
|
||||
position.y = header.position.y + header.rect_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_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:
|
||||
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.scancode == SLCT_KEY_UP:
|
||||
selector_up()
|
||||
elif event.scancode == SLCT_KEY_DOWN:
|
||||
selector_down()
|
||||
elif event is InputEventMouseButton:
|
||||
if not event.pressed:
|
||||
return
|
||||
if (event.position.x < position.x) \
|
||||
or (event.position.x > (position.x + size.x)) \
|
||||
or (event.position.y < position.y) \
|
||||
or (event.position.y > (position.y + size.y)):
|
||||
in_focus = false
|
||||
emit_signal('focus_exited')
|
||||
return
|
||||
var rows_count: = get_rows_count()
|
||||
in_focus = true
|
||||
emit_signal('focus_entered')
|
||||
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
|
||||
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 = ScnSelector.instantiate()
|
||||
var rect: = [0, 0, 0, 0]
|
||||
selector_size_proc.call(i_row, rect)
|
||||
selector.rect_position.x = rect[0]
|
||||
selector.rect_position.y = rect[1]
|
||||
selector.rect_size.x = rect[2]
|
||||
selector.rect_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))
|
||||
if columns == 1:
|
||||
set_columns(row_types.size())
|
||||
else:
|
||||
assert(columns == row_types.size(), 'ошибка: %s количество колонок установлено ранее - %d, но требуется %d' % [self, 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 set_header(header_types: Array):
|
||||
assert(header_types.size() < MAX_INDEX, 'ошибка: слишком много колонок, больше %d' % (MAX_INDEX + 1))
|
||||
if columns == 1:
|
||||
set_columns(header_types.size())
|
||||
else:
|
||||
assert(columns == header_types.size())
|
||||
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 = get_parent()
|
||||
parent.add_child(header)
|
||||
do_adj = true
|
||||
else:
|
||||
var nodes = header.get_children()
|
||||
for node in nodes:
|
||||
nodes.erase(node.name)
|
||||
header.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 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]
|
||||
var callback = conn[0]
|
||||
var dest_node = conn[1]
|
||||
node.disconnect('pressed', dest_node, callback)
|
||||
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]
|
||||
swaps.append([slct_key0, slct_key1])
|
||||
|
||||
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]
|
||||
swaps.append([conn_key0, conn_key1])
|
||||
|
||||
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]
|
||||
swaps.append([data_key0, data_key1])
|
||||
|
||||
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]
|
||||
var prev_callback = conn[0]
|
||||
var prev_dest_node = conn[1]
|
||||
node.disconnect(event_name, prev_dest_node, prev_callback)
|
||||
assert (OK == node.connect(event_name, dest_node, callback, [node] + user_data))
|
||||
nodes[conn_key] = [callback, dest_node]
|
||||
|
||||
|
||||
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.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].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].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, key_format: String = NODE_KEY_FORMAT) -> void:
|
||||
for i_col in row.size():
|
||||
var key: = get_node_key(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, 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
|
||||
49
scenes/кнопка-помеха.tscn
Normal file
49
scenes/кнопка-помеха.tscn
Normal file
@@ -0,0 +1,49 @@
|
||||
[gd_scene load_steps=9 format=3 uid="uid://da7w3vkhadfwe"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://ct0ajcwno03h7" path="res://data/кнопка-квадрат-0.png" id="1"]
|
||||
[ext_resource type="Script" path="res://scenes/nine-patch-button.gd" id="2"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="1"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="6"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="2"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="3"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="5"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="4"]
|
||||
|
||||
[node name="container" type="PanelContainer"]
|
||||
offset_right = 30.0
|
||||
offset_bottom = 30.0
|
||||
theme_override_styles/panel = SubResource("1")
|
||||
script = ExtResource("2")
|
||||
toggle_mode = true
|
||||
|
||||
[node name="state" type="NinePatchRect" parent="."]
|
||||
show_behind_parent = true
|
||||
layout_mode = 2
|
||||
texture = ExtResource("1")
|
||||
patch_margin_left = 10
|
||||
patch_margin_top = 10
|
||||
patch_margin_right = 10
|
||||
patch_margin_bottom = 10
|
||||
axis_stretch_horizontal = 1
|
||||
axis_stretch_vertical = 1
|
||||
|
||||
[node name="button" type="Button" parent="."]
|
||||
layout_mode = 2
|
||||
theme_override_styles/normal = SubResource("6")
|
||||
theme_override_styles/hover = SubResource("2")
|
||||
theme_override_styles/pressed = SubResource("3")
|
||||
theme_override_styles/disabled = SubResource("5")
|
||||
theme_override_styles/focus = SubResource("4")
|
||||
toggle_mode = true
|
||||
clip_text = true
|
||||
|
||||
[node name="label" type="Label" parent="."]
|
||||
layout_mode = 2
|
||||
|
||||
[connection signal="toggled" from="button" to="." method="_on_button_toggled"]
|
||||
18
scenes/рамка.gd
Normal file
18
scenes/рамка.gd
Normal file
@@ -0,0 +1,18 @@
|
||||
@tool
|
||||
|
||||
extends NinePatchRect
|
||||
|
||||
|
||||
@export var horizontal_alignment: HorizontalAlignment = HorizontalAlignment.HORIZONTAL_ALIGNMENT_CENTER:
|
||||
get: return $header.horizontal_alignment
|
||||
set(align): $header.horizontal_alignment = align
|
||||
|
||||
|
||||
@export var vertical_alignment: VerticalAlignment = VerticalAlignment.VERTICAL_ALIGNMENT_CENTER:
|
||||
get: return $header.vertical_alignment
|
||||
set(align): $header.vertical_alignment = align
|
||||
|
||||
|
||||
@export var text: String = 'caption text':
|
||||
get: return $header.text
|
||||
set(text): $header.text = text
|
||||
26
scenes/рамка.tscn
Normal file
26
scenes/рамка.tscn
Normal file
@@ -0,0 +1,26 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://bq7haw1ypiv48"]
|
||||
|
||||
[ext_resource type="Script" path="res://scenes/рамка.gd" id="1"]
|
||||
[ext_resource type="Texture2D" uid="uid://cs6i1xwx0pmdk" path="res://data/рамка-панели.png" id="2"]
|
||||
|
||||
[node name="ramka" type="NinePatchRect"]
|
||||
offset_right = 150.0
|
||||
offset_bottom = 100.0
|
||||
texture = ExtResource("2")
|
||||
patch_margin_left = 15
|
||||
patch_margin_top = 30
|
||||
patch_margin_right = 15
|
||||
patch_margin_bottom = 10
|
||||
script = ExtResource("1")
|
||||
|
||||
[node name="header" type="Label" parent="."]
|
||||
clip_contents = true
|
||||
layout_mode = 1
|
||||
anchors_preset = 10
|
||||
anchor_right = 1.0
|
||||
offset_bottom = 22.0
|
||||
grow_horizontal = 2
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 1)
|
||||
text = "caption text"
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
8
scenes/ячейка-1.tscn
Normal file
8
scenes/ячейка-1.tscn
Normal file
@@ -0,0 +1,8 @@
|
||||
[gd_scene format=2]
|
||||
|
||||
[node name="Label" type="Label"]
|
||||
margin_right = 122.0
|
||||
margin_bottom = 34.0
|
||||
custom_colors/font_color = Color( 1, 0.596078, 0.4, 1 )
|
||||
valign = 1
|
||||
clip_text = true
|
||||
Reference in New Issue
Block a user