└── addons └── godot-immediate-gui └── GUI.gd /addons/godot-immediate-gui/GUI.gd: -------------------------------------------------------------------------------- 1 | extends Control 2 | 3 | var boxes = []; 4 | var used = []; 5 | var notused = []; 6 | var layout := true; 7 | var _layout := VBoxContainer.new(); 8 | 9 | var _last_control; 10 | 11 | var _default = { 12 | Control:{ 13 | "size_flags_horizontal":0, 14 | "size_flags_vertical":0, 15 | }, 16 | BaseButton:{ 17 | "action_mode":BaseButton.ACTION_MODE_BUTTON_PRESS, 18 | "mouse_default_cursor_shape":CURSOR_POINTING_HAND, 19 | }, 20 | ColorPickerButton:{ 21 | "rect_min_size":Vector2(20, 20), 22 | }, 23 | }; 24 | var property = {}; 25 | 26 | func clear_default(): 27 | _default.clear(); 28 | # warning-ignore:shadowed_variable 29 | func add_default(type, property, value): 30 | var props = _default.get(type); 31 | if props == null: 32 | props = {}; 33 | _default[type] = props; 34 | props[property] = value; 35 | # warning-ignore:shadowed_variable 36 | func remove_default(type, property=null): 37 | var props = _default.get(type); 38 | assert(props != null, str("There is no default values for type \"", type, "\"")); 39 | if property == null: 40 | _default.erase(type); 41 | return; 42 | var has_property = props.has(property); 43 | assert(has_property, str("Can't remove property \"", property, "\" from type \"", type, "\", property not set")); 44 | if has_property: 45 | props.erase(property); 46 | 47 | func _init(): 48 | mouse_filter = MOUSE_FILTER_IGNORE; 49 | _layout.mouse_filter = MOUSE_FILTER_IGNORE; 50 | 51 | func _ready(): 52 | add_child(_layout); 53 | set_anchors_and_margins_preset(PRESET_WIDE); 54 | _layout.set_anchors_and_margins_preset(PRESET_WIDE); 55 | 56 | func _process(delta): 57 | get_parent().propagate_call("_gui", [delta]); 58 | 59 | raise(); 60 | layout = true; 61 | assert(boxes.size() == 0, "Not all containers are closed. Use GUI.end() to close containers."); 62 | boxes.clear(); 63 | 64 | for c in notused: 65 | c.queue_free(); 66 | notused.clear(); 67 | 68 | var t = notused; 69 | notused = used; 70 | used = t; 71 | 72 | func printvar(node, v): 73 | label(str(node.name, " ", "[", node.get_instance_id(), "] ", v, ": ", node.get(v))); 74 | 75 | func _get_control(type, text=null): 76 | var _c; 77 | for c in notused: 78 | if c is type: 79 | _c = c; 80 | c.base.revert(); 81 | notused.erase(c); 82 | break; 83 | if _c == null: 84 | _c = type.new(); 85 | used.append(_c); 86 | # warning-ignore:incompatible_ternary 87 | # warning-ignore:incompatible_ternary 88 | reparent(_c, (_layout if layout else self) if boxes.size() == 0 else boxes[-1]); 89 | if text != null: 90 | _c.text = str(text); 91 | 92 | _c.rect_size = Vector2(); 93 | 94 | for type in _default.keys(): 95 | if _c is type: 96 | var defs = _default[type]; 97 | for p in defs.keys(): 98 | _c.base.set_property(p, defs[p]); 99 | for p in property.keys(): 100 | _c.base.set_property(p, property[p]); 101 | property.clear(); 102 | 103 | _last_control = _c; 104 | return _c; 105 | func reparent(node:Node, new_parent:Node): 106 | var p = node.get_parent(); 107 | if p == new_parent: 108 | node.raise(); 109 | return; 110 | if p != null: 111 | p.remove_child(node); 112 | if new_parent != null: 113 | new_parent.add_child(node); 114 | 115 | func _toggle(type, text, state): 116 | var b = _get_control(type, text); 117 | b.pressed = !state if b.base.get_changed() else state; 118 | return b.pressed; 119 | 120 | func label(text): 121 | _get_control(GUILabel, text); 122 | func button(text): 123 | return _get_control(GUIButton, text).base.get_changed(); 124 | func buttonpress(text): 125 | var b = _get_control(GUIButton, text); 126 | b.base.get_changed(); 127 | return b.pressed; 128 | 129 | func toggle(text, state:bool): 130 | return _toggle(GUIToggle, text, state); 131 | func checkbox(text, state:bool): 132 | return _toggle(GUICheckBox, text, state); 133 | func checkbutton(text, state:bool): 134 | return _toggle(GUICheckButton, text, state); 135 | 136 | func options(selected:int, options:Array): 137 | var b = _get_control(GUIOptions); 138 | b.set_options(options); 139 | if !b.base.get_changed(): 140 | b.selected = selected; 141 | return b.selected; 142 | 143 | func pickcolor(color:Color, edit_alpha:bool=true): 144 | var c = _get_control(GUIPickColor); 145 | c.edit_alpha = edit_alpha; 146 | c.get_popup().rect_global_position = c.rect_global_position + Vector2(0, c.rect_size.y); 147 | if !c.base.get_changed(): 148 | c.color = color; 149 | return c.color; 150 | func progress(value:float, percent_visible:bool=true): 151 | var c = _get_control(GUIProgress); 152 | c.percent_visible = percent_visible; 153 | c.min_value = 0; 154 | c.max_value = 100; 155 | c.value = value*100; 156 | func spin(value, min_value, max_value, step=null): 157 | var c = _get_control(GUISpin); 158 | c.min_value = min_value; 159 | c.max_value = max_value; 160 | c.step = (1.0 if value is int else 0.001) if step == null else step; 161 | if !c.base.get_changed() && c.value != value: 162 | c.value = value; 163 | return c.value; 164 | func line(text:String): 165 | var l = _get_control(GUILine); 166 | if !l.base.get_changed() && l.text != text: 167 | l.text = text; 168 | return l.text; 169 | 170 | func _get_box(type): 171 | var box = _get_control(type); 172 | boxes.append(box); 173 | return box; 174 | func control(): 175 | _get_box(GUIControl); 176 | return true; 177 | func hbox(separation=null): 178 | var box = _get_box(GUIHBox); 179 | box.set("custom_constants/separation", separation); 180 | return true; 181 | func vbox(separation=null): 182 | var box = _get_box(GUIVBox); 183 | box.set("custom_constants/separation", separation); 184 | return true; 185 | func grid(columns:int, vseparation=null, hseparation=null): 186 | var box = _get_box(GUIGrid); 187 | box.columns = columns; 188 | box.set("custom_constants/vseparation", vseparation); 189 | box.set("custom_constants/hseparation", hseparation); 190 | return true; 191 | func panel(): 192 | _get_box(GUIPanel); 193 | return true; 194 | func margin(left:int=0, top:int=0, right:int=0, bottom:int=0): 195 | var box = _get_box(GUIMargin); 196 | box.set("custom_constants/margin_left", left); 197 | box.set("custom_constants/margin_top", top); 198 | box.set("custom_constants/margin_right", right); 199 | box.set("custom_constants/margin_bottom", bottom); 200 | return true; 201 | func center(): 202 | _get_box(GUICenter); 203 | return true; 204 | func scroll(): 205 | _get_box(GUIScroll); 206 | return true; 207 | func end(): 208 | boxes.pop_back(); 209 | 210 | class GUIControl extends Control: 211 | var base = GUIBase.new(self); 212 | class GUIVBox extends VBoxContainer: 213 | var base = GUIBase.new(self); 214 | class GUIHBox extends HBoxContainer: 215 | var base = GUIBase.new(self); 216 | class GUIGrid extends GridContainer: 217 | var base = GUIBase.new(self); 218 | class GUIPanel extends PanelContainer: 219 | var base = GUIBase.new(self); 220 | class GUIMargin extends MarginContainer: 221 | var base = GUIBase.new(self); 222 | class GUICenter extends CenterContainer: 223 | var base = GUIBase.new(self); 224 | class GUIScroll extends ScrollContainer: 225 | var base = GUIBase.new(self); 226 | 227 | class GUILabel extends Label: 228 | var base = GUIBase.new(self); 229 | class GUIBaseButton extends Button: 230 | var base = GUIBase.new(self, "pressed"); 231 | class GUIButton extends GUIBaseButton: 232 | pass 233 | class GUIToggle extends GUIBaseButton: 234 | func _init(): 235 | toggle_mode = true; 236 | class GUICheckBox extends CheckBox: 237 | var base = GUIBase.new(self, "pressed"); 238 | class GUICheckButton extends CheckButton: 239 | var base = GUIBase.new(self, "pressed"); 240 | class GUIOptions extends OptionButton: 241 | var base = GUIBase.new(self, "item_selected"); 242 | var options = []; 243 | func set_options(_options): 244 | if options != _options: 245 | options = _options; 246 | clear(); 247 | for text in options: 248 | add_item(str(text)); 249 | class GUILine extends LineEdit: 250 | var base = GUIBase.new(self, "text_changed"); 251 | class GUIPickColor extends ColorPickerButton: 252 | var base = GUIBase.new(self, "color_changed"); 253 | class GUIProgress extends ProgressBar: 254 | var base = GUIBase.new(self); 255 | class GUISpin extends SpinBox: 256 | var base = GUIBase.new(self, "value_changed"); 257 | 258 | class GUIBase: 259 | var node; 260 | var changed:bool; 261 | func _changed(_v=null): 262 | changed = true; 263 | func get_changed(): 264 | if changed: 265 | changed = false; 266 | return true; 267 | return false; 268 | var defs = {}; 269 | var edited = []; 270 | func _init(_node, _signal=null): 271 | node = _node; 272 | if _signal != null: 273 | node.connect(_signal, self, "_changed"); 274 | func set_property(p, v): 275 | if !defs.has(p): 276 | defs[p] = node.get(p); 277 | edited.append(p); 278 | node.set(p, v); 279 | func revert(): 280 | for p in edited: 281 | var def = defs.get(p); 282 | if node.get(p) != def: 283 | node.set(p, def); 284 | edited.clear(); 285 | --------------------------------------------------------------------------------