mirror of
https://github.com/Relintai/pandemonium_engine_easy_charts.git
synced 2024-11-20 10:47:22 +01:00
update Tooltip
This commit is contained in:
parent
af4389ffa6
commit
b0e786f553
@ -43,5 +43,4 @@ func _draw_lines() -> void:
|
||||
_draw_line(function_points[function][i - 1], function_points[function][i], function)
|
||||
|
||||
func _draw() -> void:
|
||||
if chart_properties.lines:
|
||||
_draw_lines()
|
||||
_draw_lines()
|
||||
|
@ -5,8 +5,13 @@ signal point_entered(point)
|
||||
|
||||
var _point_box_rad: int = 10
|
||||
|
||||
# List of all unordered points belonging to this plot
|
||||
var points: Array = []
|
||||
|
||||
# List of all points, grouped by function
|
||||
var function_points: Array = []
|
||||
|
||||
# Currently focused point
|
||||
var focused_point: Point = null
|
||||
|
||||
func _clear_points() -> void:
|
||||
@ -19,35 +24,36 @@ func _clear() -> void:
|
||||
func _get_point_box(point: Point, rad: int) -> Rect2:
|
||||
return Rect2(point.position - (Vector2.ONE * rad), (Vector2.ONE * rad * 2))
|
||||
|
||||
func _move_tooltip(position: Vector2) -> void:
|
||||
$Tooltip.set_position(position + (Vector2.ONE * 15))
|
||||
|
||||
func _show_tooltip(position: Vector2, text: String) -> void:
|
||||
_move_tooltip(position)
|
||||
$Tooltip.show()
|
||||
$Tooltip.set_text(text)
|
||||
$Tooltip.set_size(Vector2.ZERO)
|
||||
|
||||
func _hide_tooltip() -> void:
|
||||
$Tooltip.hide()
|
||||
$Tooltip.set_text("")
|
||||
$Tooltip.set_size(Vector2.ZERO)
|
||||
func _get_function_point(point: Point) -> int:
|
||||
var point_f_index: int = -1
|
||||
for f_point in function_points.size():
|
||||
var found: int = function_points[f_point].find(point)
|
||||
if found != -1:
|
||||
point_f_index = f_point
|
||||
break
|
||||
return point_f_index
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
if event is InputEventMouse:
|
||||
for point in points:
|
||||
if _get_point_box(point, _point_box_rad).abs().has_point(event.position):
|
||||
if focused_point == point:
|
||||
_move_tooltip(event.position)
|
||||
return
|
||||
else:
|
||||
focused_point = point
|
||||
_show_tooltip(event.position, str(focused_point.value))
|
||||
var func_index: int = _get_function_point(focused_point)
|
||||
$Tooltip.update_values(
|
||||
str(point.value.left),
|
||||
str(point.value.right),
|
||||
_get_function_name(func_index),
|
||||
_get_function_color(func_index)
|
||||
)
|
||||
$Tooltip.show()
|
||||
emit_signal("point_entered", point)
|
||||
return
|
||||
# Mouse is not in any point's box
|
||||
focused_point = null
|
||||
_hide_tooltip()
|
||||
$Tooltip.hide()
|
||||
|
||||
func _draw_point(point: Point, function_index: int) -> void:
|
||||
match chart_properties.get_point_shape(function_index):
|
||||
@ -107,7 +113,7 @@ func _calculate_points() -> void:
|
||||
for i in y_sampled.values.size():
|
||||
var real_point_val: Pair = Pair.new(x[i], y[i])
|
||||
var sampled_point_pos: Vector2 = Vector2(x_sampled.values[i], y_sampled.values[i])
|
||||
var point: Point = Point.news(sampled_point_pos, real_point_val)
|
||||
var point: Point = Point.new(sampled_point_pos, real_point_val)
|
||||
points.append(point)
|
||||
function_points.append(points)
|
||||
|
||||
|
@ -14,6 +14,7 @@ var y_sampled: SampledAxis = SampledAxis.new()
|
||||
|
||||
var x_labels: Array = []
|
||||
var y_labels: Array = []
|
||||
var functions_names: Array = []
|
||||
|
||||
###### STYLE
|
||||
var chart_properties: ChartProperties = ChartProperties.new()
|
||||
@ -22,12 +23,13 @@ var chart_properties: ChartProperties = ChartProperties.new()
|
||||
# The bounding_box of the chart
|
||||
var node_box: Rect2
|
||||
var bounding_box: Rect2
|
||||
var plot_offset: Vector2
|
||||
var plot_box: Rect2
|
||||
|
||||
# The Reference Rectangle to plot samples
|
||||
# It is the @bounding_box Rectangle inverted on the Y axis
|
||||
var x_sampled_domain: Pair
|
||||
var y_sampled_domain: Pair
|
||||
var sampled_domain_rect: Rect2
|
||||
|
||||
var _padding_offset: Vector2 = Vector2(20.0, 20.0)
|
||||
var _internal_offset: Vector2 = Vector2(15.0, 15.0)
|
||||
@ -51,6 +53,13 @@ func _ready() -> void:
|
||||
set_process_input(false)
|
||||
set_process(false)
|
||||
|
||||
func validate_input_samples(samples: Array) -> bool:
|
||||
if samples.size() > 1 and samples[0] is Array:
|
||||
for sample in samples:
|
||||
if (not sample is Array) or sample.size() != samples[0].size():
|
||||
return false
|
||||
return true
|
||||
|
||||
func plot(x: Array, y: Array, properties: ChartProperties = self.chart_properties) -> void:
|
||||
self.x = x
|
||||
self.y = y
|
||||
@ -71,10 +80,14 @@ func _has_decimals(values: Array) -> bool:
|
||||
if temp[0] is Array:
|
||||
for dim in temp:
|
||||
for val in dim:
|
||||
if val is String:
|
||||
return false
|
||||
if abs(fmod(val, 1)) > 0.0:
|
||||
return true
|
||||
else:
|
||||
for val in temp:
|
||||
if val is String:
|
||||
return false
|
||||
if abs(fmod(val, 1)) > 0.0:
|
||||
return true
|
||||
|
||||
@ -93,7 +106,6 @@ func _find_min_max(values: Array) -> Pair:
|
||||
max_ts.append(dim.max())
|
||||
_min = min_ts.min()
|
||||
_max = max_ts.max()
|
||||
|
||||
else:
|
||||
_min = temp.min()
|
||||
_max = temp.max()
|
||||
@ -115,6 +127,7 @@ func _sample_values(values: Array, rel_values: Pair, ref_values: Pair) -> Sample
|
||||
var temp: Array = values.duplicate(true)
|
||||
|
||||
var rels: Array = []
|
||||
var division_size: float
|
||||
if temp[0] is Array:
|
||||
for t_dim in temp:
|
||||
var rels_t: Array = []
|
||||
@ -123,8 +136,12 @@ func _sample_values(values: Array, rel_values: Pair, ref_values: Pair) -> Sample
|
||||
rels.append(rels_t)
|
||||
|
||||
else:
|
||||
for val in temp:
|
||||
rels.append(_map_pair(val, rel_values, ref_values))
|
||||
division_size = (ref_values.right - ref_values.left) / values.size()
|
||||
for val_i in temp.size():
|
||||
if temp[val_i] is String:
|
||||
rels.append(val_i * division_size)
|
||||
else:
|
||||
rels.append(_map_pair(temp[val_i], rel_values, ref_values))
|
||||
|
||||
return SampledAxis.new(rels, rel_values)
|
||||
|
||||
@ -134,20 +151,47 @@ func _round_min(val: float) -> float:
|
||||
func _round_max(val: float) -> float:
|
||||
return round(val) if abs(val) < 10 else ceil(val / 10.0) * 10.0
|
||||
|
||||
func _pre_process() -> void:
|
||||
var t_gr: Rect2 = get_global_rect()
|
||||
|
||||
#### @node_box size, which is the whole "frame"
|
||||
node_box = Rect2(Vector2.ZERO, t_gr.size - t_gr.position)
|
||||
|
||||
#### drawing size for defining @bounding_box
|
||||
|
||||
func _calc_x_domain() -> void:
|
||||
x_min_max = _find_min_max(x)
|
||||
x_domain = Pair.new(_round_min(x_min_max.left), _round_max(x_min_max.right))
|
||||
|
||||
func _sample_x() -> void:
|
||||
### @sampled_domain, which are the domain relative to the sampled values
|
||||
### x (real value) --> sampling --> x_sampled (pixel value in canvas)
|
||||
x_sampled_domain = Pair.new(plot_box.position.x, plot_box.end.x)
|
||||
|
||||
# samples
|
||||
x_sampled = _sample_values(x, x_min_max, x_sampled_domain)
|
||||
|
||||
func _calc_y_domain() -> void:
|
||||
y_min_max = _find_min_max(y)
|
||||
y_domain = Pair.new(_round_min(y_min_max.left), _round_max(y_min_max.right))
|
||||
|
||||
func _sample_y() -> void:
|
||||
### @sampled_domain, which are the domain relative to the sampled values
|
||||
### x (real value) --> sampling --> x_sampled (pixel value in canvas)
|
||||
y_sampled_domain = Pair.new(plot_box.end.y, plot_box.position.y)
|
||||
|
||||
# samples
|
||||
y_sampled = _sample_values(y, y_domain, y_sampled_domain)
|
||||
|
||||
|
||||
func _find_longest_x() -> String:
|
||||
return ("%.2f" if x_has_decimals else "%s") % x_domain.right
|
||||
|
||||
func _pre_process() -> void:
|
||||
_calc_x_domain()
|
||||
_calc_y_domain()
|
||||
|
||||
var frame: Rect2 = get_global_rect()
|
||||
|
||||
|
||||
#### @node_box size, which is the whole "frame"
|
||||
node_box = Rect2(Vector2.ZERO, frame.size - frame.position)
|
||||
|
||||
#### calculating offset from the @node_box for the @bounding_box.
|
||||
var offset: Vector2 = _padding_offset
|
||||
plot_offset = _padding_offset
|
||||
|
||||
### if @labels drawing is enabled, calcualte offsets
|
||||
if chart_properties.labels:
|
||||
@ -159,12 +203,12 @@ func _pre_process() -> void:
|
||||
|
||||
###### --- X
|
||||
x_has_decimals = _has_decimals(x)
|
||||
# calculate the string length of the largest value on the Y axis.
|
||||
# calculate the string length of the largest value on the X axis.
|
||||
# remember that "-" sign adds additional pixels, and it is relative only to negative numbers!
|
||||
var x_max_formatted: String = ("%.2f" if x_has_decimals else "%s") % x_domain.right
|
||||
var x_max_formatted: String = _find_longest_x()
|
||||
_x_ticklabel_size = chart_properties.font.get_string_size(x_max_formatted)
|
||||
|
||||
offset.y += _x_label_offset + _x_label_size.y + _x_ticklabel_offset + _x_ticklabel_size.y
|
||||
plot_offset.y += _x_label_offset + _x_label_size.y + _x_ticklabel_offset + _x_ticklabel_size.y
|
||||
|
||||
###### --- Y
|
||||
y_has_decimals = _has_decimals(y)
|
||||
@ -181,31 +225,26 @@ func _pre_process() -> void:
|
||||
else:
|
||||
_y_ticklabel_size = chart_properties.font.get_string_size(y_max_formatted)
|
||||
|
||||
offset.x += _y_label_offset + _y_label_size.y + _y_ticklabel_offset + _y_ticklabel_size.x
|
||||
plot_offset.x += _y_label_offset + _y_label_size.y + _y_ticklabel_offset + _y_ticklabel_size.x
|
||||
|
||||
### if @ticks drawing is enabled, calculate offsets
|
||||
if chart_properties.ticks:
|
||||
offset.x += _y_tick_size
|
||||
offset.y += _x_tick_size
|
||||
plot_offset.x += _y_tick_size
|
||||
plot_offset.y += _x_tick_size
|
||||
|
||||
### @bounding_box, where the points will be plotted
|
||||
bounding_box = Rect2(
|
||||
offset,
|
||||
t_gr.size - (offset * 2)
|
||||
plot_offset,
|
||||
frame.size - (plot_offset * 2)
|
||||
)
|
||||
|
||||
### @sampled_domain, which are the domain relative to the sampled values
|
||||
### x (real value) --> sampling --> x_sampled (pixel value in canvas)
|
||||
x_sampled_domain = Pair.new(bounding_box.position.x + _internal_offset.x, bounding_box.position.x + bounding_box.size.x - _internal_offset.y)
|
||||
y_sampled_domain = Pair.new(bounding_box.size.y + bounding_box.position.y - _internal_offset.x, bounding_box.position.y + _internal_offset.y)
|
||||
sampled_domain_rect = Rect2(
|
||||
Vector2(x_sampled_domain.left, y_sampled_domain.left),
|
||||
Vector2(x_sampled_domain.right, y_sampled_domain.right)
|
||||
plot_box = Rect2(
|
||||
bounding_box.position + _internal_offset,
|
||||
bounding_box.size - (_internal_offset * 2)
|
||||
)
|
||||
|
||||
# samples
|
||||
x_sampled = _sample_values(x, x_min_max, x_sampled_domain)
|
||||
y_sampled = _sample_values(y, y_domain, y_sampled_domain)
|
||||
_sample_x()
|
||||
_sample_y()
|
||||
|
||||
func _draw_borders() -> void:
|
||||
draw_rect(node_box, Color.red, false, 1, true)
|
||||
@ -233,12 +272,82 @@ func _draw_background() -> void:
|
||||
# draw_line(Vector2(half.x, node_box.position.y), Vector2(half.x, node_box.size.y), Color.red, 3, false)
|
||||
# draw_line(Vector2(node_box.position.x, half.y), Vector2(node_box.size.x, half.y), Color.red, 3, false)
|
||||
|
||||
func _draw_grid() -> void:
|
||||
var validation: int = _validate_sampled_axis(x_sampled, y_sampled)
|
||||
if not validation == OK:
|
||||
printerr("Cannot draw grid for invalid dataset! Error: %s" % validation)
|
||||
return
|
||||
func _draw_tick(from: Vector2, to: Vector2, color: Color) -> void:
|
||||
draw_line(from, to, color, 1, true)
|
||||
|
||||
|
||||
func _get_vertical_tick_label_pos(base_position: Vector2, text: String) -> Vector2:
|
||||
return base_position + Vector2(
|
||||
- chart_properties.font.get_string_size(text).x / 2,
|
||||
_x_label_size.y + _x_tick_size
|
||||
)
|
||||
|
||||
func _get_tick_label(line_index: int, line_value: float) -> String:
|
||||
var tick_lbl: String = ""
|
||||
if x_labels.empty():
|
||||
tick_lbl = ("%.2f" if x_has_decimals else "%s") % [x_min_max.left + (line_index * line_value)]
|
||||
else:
|
||||
tick_lbl = x_labels[clamp(line_value * line_index, 0, x_labels.size() - 1)]
|
||||
|
||||
return tick_lbl
|
||||
|
||||
func _draw_vertical_gridline_component(p1: Vector2, p2: Vector2, line_index: int, line_value: float) -> void:
|
||||
if chart_properties.labels:
|
||||
var tick_lbl: String = _get_tick_label(line_index, line_value)
|
||||
draw_string(
|
||||
chart_properties.font,
|
||||
_get_vertical_tick_label_pos(p2, tick_lbl),
|
||||
tick_lbl,
|
||||
chart_properties.colors.bounding_box
|
||||
)
|
||||
|
||||
# Draw V Ticks
|
||||
if chart_properties.ticks:
|
||||
_draw_tick(p2, p2 + Vector2(0, _x_tick_size), chart_properties.colors.bounding_box)
|
||||
|
||||
# Draw V Grid Lines
|
||||
if chart_properties.grid:
|
||||
draw_line(p1, p2, chart_properties.colors.grid, 1, true)
|
||||
|
||||
|
||||
func _draw_horizontal_tick_label(font: Font, position: Vector2, color: Color, line_index: int, line_value: float) -> void:
|
||||
var tick_lbl: String = ""
|
||||
if y_labels.empty():
|
||||
tick_lbl = ("%.2f" if y_has_decimals else "%s") % [y_domain.left + (line_index * line_value)]
|
||||
else:
|
||||
tick_lbl = y_labels[clamp(y_labels.size() * line_index, 0, y_labels.size() - 1)]
|
||||
|
||||
draw_string(
|
||||
chart_properties.font,
|
||||
position - Vector2(
|
||||
chart_properties.font.get_string_size(tick_lbl).x + _y_ticklabel_offset + _y_tick_size,
|
||||
- _y_ticklabel_size.y * 0.35
|
||||
),
|
||||
tick_lbl,
|
||||
chart_properties.colors.bounding_box
|
||||
)
|
||||
|
||||
|
||||
func _draw_horizontal_gridline_component(p1: Vector2, p2: Vector2, line_index: int, line_value: float) -> void:
|
||||
# Draw H labels
|
||||
if chart_properties.labels:
|
||||
_draw_horizontal_tick_label(
|
||||
chart_properties.font,
|
||||
p1,
|
||||
chart_properties.colors.bounding_box,
|
||||
line_index,
|
||||
line_value
|
||||
)
|
||||
|
||||
# Draw H Ticks
|
||||
if chart_properties.ticks:
|
||||
_draw_tick(p1, p1 - Vector2(_y_tick_size, 0), chart_properties.colors.bounding_box)
|
||||
|
||||
# Draw H Grid Lines
|
||||
if chart_properties.grid:
|
||||
draw_line(p1, p2, chart_properties.colors.grid, 1, true)
|
||||
|
||||
func _draw_vertical_grid() -> void:
|
||||
# draw vertical lines
|
||||
|
||||
# 1. the amount of lines is equals to the X_scale: it identifies in how many sectors the x domain
|
||||
@ -249,43 +358,18 @@ func _draw_grid() -> void:
|
||||
var x_lbl_val: float = (x_min_max.right - x_min_max.left) / (chart_properties.x_scale)
|
||||
for _x in chart_properties.x_scale + 1:
|
||||
var x_val: float = _x * x_pixel_dist + x_sampled.min_max.left
|
||||
var p1: Vector2 = Vector2(
|
||||
var top: Vector2 = Vector2(
|
||||
range_lerp(x_val, x_sampled.min_max.left, x_sampled.min_max.right, x_sampled_domain.left, x_sampled_domain.right),
|
||||
bounding_box.position.y
|
||||
)
|
||||
var p2: Vector2 = Vector2(
|
||||
var bottom: Vector2 = Vector2(
|
||||
range_lerp(x_val, x_sampled.min_max.left, x_sampled.min_max.right, x_sampled_domain.left, x_sampled_domain.right),
|
||||
bounding_box.size.y + bounding_box.position.y
|
||||
)
|
||||
|
||||
# Draw V labels
|
||||
if chart_properties.labels:
|
||||
var tick_lbl: String = ""
|
||||
if x_labels.empty():
|
||||
tick_lbl = ("%.2f" if x_has_decimals else "%s") % [x_min_max.left + (_x * x_lbl_val)]
|
||||
else:
|
||||
tick_lbl = x_labels[clamp(x_lbl_val * _x, 0, x_labels.size() - 1)]
|
||||
|
||||
draw_string(
|
||||
chart_properties.font,
|
||||
p2 + Vector2(
|
||||
- chart_properties.font.get_string_size(tick_lbl).x / 2,
|
||||
_x_label_size.y + _x_tick_size
|
||||
),
|
||||
tick_lbl,
|
||||
chart_properties.colors.bounding_box
|
||||
)
|
||||
|
||||
# Draw V Ticks
|
||||
if chart_properties.ticks:
|
||||
draw_line(p2, p2 + Vector2(0, _x_tick_size), chart_properties.colors.bounding_box, 1, true)
|
||||
|
||||
# Draw V Grid Lines
|
||||
if chart_properties.grid:
|
||||
draw_line(p1, p2, chart_properties.colors.grid, 1, true)
|
||||
|
||||
# draw horizontal lines
|
||||
|
||||
_draw_vertical_gridline_component(top, bottom, _x, x_lbl_val)
|
||||
|
||||
func _draw_horizontal_grid() -> void:
|
||||
# 1. the amount of lines is equals to the y_scale: it identifies in how many sectors the y domain
|
||||
# should be devided
|
||||
# 2. calculate the spacing between each line in pixel. It is equals to y_sampled_domain / y_scale
|
||||
@ -294,40 +378,25 @@ func _draw_grid() -> void:
|
||||
var y_lbl_val: float = (y_domain.right - y_domain.left) / (chart_properties.y_scale)
|
||||
for _y in chart_properties.y_scale + 1:
|
||||
var y_val: float = (_y * y_pixel_dist) + y_sampled.min_max.left
|
||||
var p1: Vector2 = Vector2(
|
||||
var left: Vector2 = Vector2(
|
||||
bounding_box.position.x,
|
||||
range_lerp(y_val, y_sampled.min_max.left, y_sampled.min_max.right, y_sampled_domain.left, y_sampled_domain.right)
|
||||
)
|
||||
var p2: Vector2 = Vector2(
|
||||
var right: Vector2 = Vector2(
|
||||
bounding_box.size.x + bounding_box.position.x,
|
||||
range_lerp(y_val, y_sampled.min_max.left, y_sampled.min_max.right, y_sampled_domain.left, y_sampled_domain.right)
|
||||
)
|
||||
|
||||
# Draw H labels
|
||||
if chart_properties.labels:
|
||||
var tick_lbl: String = ""
|
||||
if y_labels.empty():
|
||||
tick_lbl = ("%.2f" if y_has_decimals else "%s") % [y_domain.left + (_y * y_lbl_val)]
|
||||
else:
|
||||
tick_lbl = y_labels[clamp(y_labels * _y, 0, y_labels.size() - 1)]
|
||||
|
||||
draw_string(
|
||||
chart_properties.font,
|
||||
p1 - Vector2(chart_properties.font.get_string_size(tick_lbl).x + _y_ticklabel_offset + _y_tick_size, - _y_ticklabel_size.y * 0.35),
|
||||
tick_lbl,
|
||||
chart_properties.colors.bounding_box
|
||||
)
|
||||
|
||||
# Draw H Ticks
|
||||
if chart_properties.ticks:
|
||||
draw_line(
|
||||
p1,
|
||||
p1 - Vector2(_y_tick_size, 0),
|
||||
chart_properties.colors.bounding_box, 1, true)
|
||||
|
||||
# Draw H Grid Lines
|
||||
if chart_properties.grid:
|
||||
draw_line(p1, p2, chart_properties.colors.grid, 1, true)
|
||||
_draw_horizontal_gridline_component(left, right, _y, y_lbl_val)
|
||||
|
||||
func _draw_grid() -> void:
|
||||
var validation: int = _validate_sampled_axis(x_sampled, y_sampled)
|
||||
if not validation == OK:
|
||||
printerr("Cannot draw grid for invalid dataset! Error: %s" % validation)
|
||||
return
|
||||
|
||||
_draw_vertical_grid()
|
||||
_draw_horizontal_grid()
|
||||
|
||||
func _create_canvas_label(text: String, position: Vector2, rotation: float = 0.0) -> Label:
|
||||
var lbl: Label = Label.new()
|
||||
@ -383,6 +452,10 @@ func _clear() -> void:
|
||||
# The draw loop also contains the "processing loop" which is where
|
||||
# everything is calculated in a separated function.
|
||||
func _draw():
|
||||
if not (validate_input_samples(x) and validate_input_samples(y)):
|
||||
printerr("Input samples are invalid!")
|
||||
return
|
||||
|
||||
_clear()
|
||||
_pre_process()
|
||||
|
||||
@ -421,3 +494,10 @@ func _validate_sampled_axis(x_data: SampledAxis, y_data: SampledAxis) -> int:
|
||||
# X and Y samples don't have same length
|
||||
error = 2
|
||||
return error
|
||||
|
||||
# ----- utilities
|
||||
func _get_function_name(function_idx: int) -> String:
|
||||
return functions_names[function_idx] if functions_names.size() > 0 else "Function %s" % function_idx
|
||||
|
||||
func _get_function_color(function_idx: int) -> Color:
|
||||
return chart_properties.colors.functions[function_idx] if chart_properties.colors.functions.size() > 0 else Color.black
|
||||
|
@ -1,9 +1,7 @@
|
||||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://addons/easy_charts/control_charts/chart.gd" type="Script" id=1]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id=1]
|
||||
bg_color = Color( 1, 1, 1, 1 )
|
||||
[ext_resource path="res://addons/easy_charts/utilities/containers/data_tooltip/data_tooltip.tscn" type="PackedScene" id=2]
|
||||
|
||||
[node name="Chart" type="Control"]
|
||||
anchor_right = 1.0
|
||||
@ -26,9 +24,5 @@ margin_bottom = 14.0
|
||||
margin_right = 40.0
|
||||
margin_bottom = 14.0
|
||||
|
||||
[node name="Tooltip" type="Label" parent="."]
|
||||
[node name="Tooltip" parent="." instance=ExtResource( 2 )]
|
||||
visible = false
|
||||
margin_right = 40.0
|
||||
margin_bottom = 14.0
|
||||
custom_colors/font_color = Color( 0, 0, 0, 1 )
|
||||
custom_styles/normal = SubResource( 1 )
|
||||
|
Loading…
Reference in New Issue
Block a user