285 lines
7.4 KiB
GDScript3
285 lines
7.4 KiB
GDScript3
|
extends Control
|
||
|
|
||
|
var boxes = [];
|
||
|
var used = [];
|
||
|
var notused = [];
|
||
|
var layout := true;
|
||
|
var _layout := VBoxContainer.new();
|
||
|
|
||
|
var _last_control;
|
||
|
|
||
|
var _default = {
|
||
|
Control:{
|
||
|
"size_flags_horizontal":0,
|
||
|
"size_flags_vertical":0,
|
||
|
},
|
||
|
BaseButton:{
|
||
|
"action_mode":BaseButton.ACTION_MODE_BUTTON_PRESS,
|
||
|
"mouse_default_cursor_shape":CURSOR_POINTING_HAND,
|
||
|
},
|
||
|
ColorPickerButton:{
|
||
|
"rect_min_size":Vector2(20, 20),
|
||
|
},
|
||
|
};
|
||
|
var property = {};
|
||
|
|
||
|
func clear_default():
|
||
|
_default.clear();
|
||
|
# warning-ignore:shadowed_variable
|
||
|
func add_default(type, property, value):
|
||
|
var props = _default.get(type);
|
||
|
if props == null:
|
||
|
props = {};
|
||
|
_default[type] = props;
|
||
|
props[property] = value;
|
||
|
# warning-ignore:shadowed_variable
|
||
|
func remove_default(type, property=null):
|
||
|
var props = _default.get(type);
|
||
|
assert(props != null, str("There is no default values for type \"", type, "\""));
|
||
|
if property == null:
|
||
|
_default.erase(type);
|
||
|
return;
|
||
|
var has_property = props.has(property);
|
||
|
assert(has_property, str("Can't remove property \"", property, "\" from type \"", type, "\", property not set"));
|
||
|
if has_property:
|
||
|
props.erase(property);
|
||
|
|
||
|
func _init():
|
||
|
mouse_filter = MOUSE_FILTER_IGNORE;
|
||
|
_layout.mouse_filter = MOUSE_FILTER_IGNORE;
|
||
|
|
||
|
func _ready():
|
||
|
add_child(_layout);
|
||
|
set_anchors_and_margins_preset(PRESET_WIDE);
|
||
|
_layout.set_anchors_and_margins_preset(PRESET_WIDE);
|
||
|
|
||
|
func _process(delta):
|
||
|
get_parent().propagate_call("_gui", [delta]);
|
||
|
|
||
|
raise();
|
||
|
layout = true;
|
||
|
assert(boxes.size() == 0, "Not all containers are closed. Use GUI.end() to close containers.");
|
||
|
boxes.clear();
|
||
|
|
||
|
for c in notused:
|
||
|
c.queue_free();
|
||
|
notused.clear();
|
||
|
|
||
|
var t = notused;
|
||
|
notused = used;
|
||
|
used = t;
|
||
|
|
||
|
func printvar(node, v):
|
||
|
label(str(node.name, " ", "[", node.get_instance_id(), "] ", v, ": ", node.get(v)));
|
||
|
|
||
|
func _get_control(type, text=null):
|
||
|
var _c;
|
||
|
for c in notused:
|
||
|
if c is type:
|
||
|
_c = c;
|
||
|
c.base.revert();
|
||
|
notused.erase(c);
|
||
|
break;
|
||
|
if _c == null:
|
||
|
_c = type.new();
|
||
|
used.append(_c);
|
||
|
# warning-ignore:incompatible_ternary
|
||
|
# warning-ignore:incompatible_ternary
|
||
|
reparent(_c, (_layout if layout else self) if boxes.size() == 0 else boxes[-1]);
|
||
|
if text != null:
|
||
|
_c.text = str(text);
|
||
|
|
||
|
_c.rect_size = Vector2();
|
||
|
|
||
|
for type in _default.keys():
|
||
|
if _c is type:
|
||
|
var defs = _default[type];
|
||
|
for p in defs.keys():
|
||
|
_c.base.set_property(p, defs[p]);
|
||
|
for p in property.keys():
|
||
|
_c.base.set_property(p, property[p]);
|
||
|
property.clear();
|
||
|
|
||
|
_last_control = _c;
|
||
|
return _c;
|
||
|
func reparent(node:Node, new_parent:Node):
|
||
|
var p = node.get_parent();
|
||
|
if p == new_parent:
|
||
|
node.raise();
|
||
|
return;
|
||
|
if p != null:
|
||
|
p.remove_child(node);
|
||
|
if new_parent != null:
|
||
|
new_parent.add_child(node);
|
||
|
|
||
|
func _toggle(type, text, state):
|
||
|
var b = _get_control(type, text);
|
||
|
b.pressed = !state if b.base.get_changed() else state;
|
||
|
return b.pressed;
|
||
|
|
||
|
func label(text):
|
||
|
_get_control(GUILabel, text);
|
||
|
func button(text):
|
||
|
return _get_control(GUIButton, text).base.get_changed();
|
||
|
func buttonpress(text):
|
||
|
var b = _get_control(GUIButton, text);
|
||
|
b.base.get_changed();
|
||
|
return b.pressed;
|
||
|
|
||
|
func toggle(text, state:bool):
|
||
|
return _toggle(GUIToggle, text, state);
|
||
|
func checkbox(text, state:bool):
|
||
|
return _toggle(GUICheckBox, text, state);
|
||
|
func checkbutton(text, state:bool):
|
||
|
return _toggle(GUICheckButton, text, state);
|
||
|
|
||
|
func options(selected:int, options:Array):
|
||
|
var b = _get_control(GUIOptions);
|
||
|
b.set_options(options);
|
||
|
if !b.base.get_changed():
|
||
|
b.selected = selected;
|
||
|
return b.selected;
|
||
|
|
||
|
func pickcolor(color:Color, edit_alpha:bool=true):
|
||
|
var c = _get_control(GUIPickColor);
|
||
|
c.edit_alpha = edit_alpha;
|
||
|
c.get_popup().rect_global_position = c.rect_global_position + Vector2(0, c.rect_size.y);
|
||
|
if !c.base.get_changed():
|
||
|
c.color = color;
|
||
|
return c.color;
|
||
|
func progress(value:float, percent_visible:bool=true):
|
||
|
var c = _get_control(GUIProgress);
|
||
|
c.percent_visible = percent_visible;
|
||
|
c.min_value = 0;
|
||
|
c.max_value = 100;
|
||
|
c.value = value*100;
|
||
|
func spin(value, min_value, max_value, step=null):
|
||
|
var c = _get_control(GUISpin);
|
||
|
c.min_value = min_value;
|
||
|
c.max_value = max_value;
|
||
|
c.step = (1.0 if value is int else 0.001) if step == null else step;
|
||
|
if !c.base.get_changed() && c.value != value:
|
||
|
c.value = value;
|
||
|
return c.value;
|
||
|
func line(text:String):
|
||
|
var l = _get_control(GUILine);
|
||
|
if !l.base.get_changed() && l.text != text:
|
||
|
l.text = text;
|
||
|
return l.text;
|
||
|
|
||
|
func _get_box(type):
|
||
|
var box = _get_control(type);
|
||
|
boxes.append(box);
|
||
|
return box;
|
||
|
func control():
|
||
|
_get_box(GUIControl);
|
||
|
return true;
|
||
|
func hbox(separation=null):
|
||
|
var box = _get_box(GUIHBox);
|
||
|
box.set("custom_constants/separation", separation);
|
||
|
return true;
|
||
|
func vbox(separation=null):
|
||
|
var box = _get_box(GUIVBox);
|
||
|
box.set("custom_constants/separation", separation);
|
||
|
return true;
|
||
|
func grid(columns:int, vseparation=null, hseparation=null):
|
||
|
var box = _get_box(GUIGrid);
|
||
|
box.columns = columns;
|
||
|
box.set("custom_constants/vseparation", vseparation);
|
||
|
box.set("custom_constants/hseparation", hseparation);
|
||
|
return true;
|
||
|
func panel():
|
||
|
_get_box(GUIPanel);
|
||
|
return true;
|
||
|
func margin(left:int=0, top:int=0, right:int=0, bottom:int=0):
|
||
|
var box = _get_box(GUIMargin);
|
||
|
box.set("custom_constants/margin_left", left);
|
||
|
box.set("custom_constants/margin_top", top);
|
||
|
box.set("custom_constants/margin_right", right);
|
||
|
box.set("custom_constants/margin_bottom", bottom);
|
||
|
return true;
|
||
|
func center():
|
||
|
_get_box(GUICenter);
|
||
|
return true;
|
||
|
func scroll():
|
||
|
_get_box(GUIScroll);
|
||
|
return true;
|
||
|
func end():
|
||
|
boxes.pop_back();
|
||
|
|
||
|
class GUIControl extends Control:
|
||
|
var base = GUIBase.new(self);
|
||
|
class GUIVBox extends VBoxContainer:
|
||
|
var base = GUIBase.new(self);
|
||
|
class GUIHBox extends HBoxContainer:
|
||
|
var base = GUIBase.new(self);
|
||
|
class GUIGrid extends GridContainer:
|
||
|
var base = GUIBase.new(self);
|
||
|
class GUIPanel extends PanelContainer:
|
||
|
var base = GUIBase.new(self);
|
||
|
class GUIMargin extends MarginContainer:
|
||
|
var base = GUIBase.new(self);
|
||
|
class GUICenter extends CenterContainer:
|
||
|
var base = GUIBase.new(self);
|
||
|
class GUIScroll extends ScrollContainer:
|
||
|
var base = GUIBase.new(self);
|
||
|
|
||
|
class GUILabel extends Label:
|
||
|
var base = GUIBase.new(self);
|
||
|
class GUIBaseButton extends Button:
|
||
|
var base = GUIBase.new(self, "pressed");
|
||
|
class GUIButton extends GUIBaseButton:
|
||
|
pass
|
||
|
class GUIToggle extends GUIBaseButton:
|
||
|
func _init():
|
||
|
toggle_mode = true;
|
||
|
class GUICheckBox extends CheckBox:
|
||
|
var base = GUIBase.new(self, "pressed");
|
||
|
class GUICheckButton extends CheckButton:
|
||
|
var base = GUIBase.new(self, "pressed");
|
||
|
class GUIOptions extends OptionButton:
|
||
|
var base = GUIBase.new(self, "item_selected");
|
||
|
var options = [];
|
||
|
func set_options(_options):
|
||
|
if options != _options:
|
||
|
options = _options;
|
||
|
clear();
|
||
|
for text in options:
|
||
|
add_item(str(text));
|
||
|
class GUILine extends LineEdit:
|
||
|
var base = GUIBase.new(self, "text_changed");
|
||
|
class GUIPickColor extends ColorPickerButton:
|
||
|
var base = GUIBase.new(self, "color_changed");
|
||
|
class GUIProgress extends ProgressBar:
|
||
|
var base = GUIBase.new(self);
|
||
|
class GUISpin extends SpinBox:
|
||
|
var base = GUIBase.new(self, "value_changed");
|
||
|
|
||
|
class GUIBase:
|
||
|
var node;
|
||
|
var changed:bool;
|
||
|
func _changed(_v=null):
|
||
|
changed = true;
|
||
|
func get_changed():
|
||
|
if changed:
|
||
|
changed = false;
|
||
|
return true;
|
||
|
return false;
|
||
|
var defs = {};
|
||
|
var edited = [];
|
||
|
func _init(_node, _signal=null):
|
||
|
node = _node;
|
||
|
if _signal != null:
|
||
|
node.connect(_signal, self, "_changed");
|
||
|
func set_property(p, v):
|
||
|
if !defs.has(p):
|
||
|
defs[p] = node.get(p);
|
||
|
edited.append(p);
|
||
|
node.set(p, v);
|
||
|
func revert():
|
||
|
for p in edited:
|
||
|
var def = defs.get(p);
|
||
|
if node.get(p) != def:
|
||
|
node.set(p, def);
|
||
|
edited.clear();
|