refactor: 拆分 claude-dev-stack 为 windows-dev-stack 和 wsl-dev-stack
将原 claude-dev-stack 目录拆分为独立的 Windows 和 WSL 部署栈,便于分别维护和使用。 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,424 @@
|
||||
@tool
|
||||
extends "res://addons/godot_mcp/commands/base_command.gd"
|
||||
|
||||
|
||||
func get_commands() -> Dictionary:
|
||||
return {
|
||||
"create_theme": _create_theme,
|
||||
"set_theme_color": _set_theme_color,
|
||||
"set_theme_constant": _set_theme_constant,
|
||||
"set_theme_font_size": _set_theme_font_size,
|
||||
"set_theme_stylebox": _set_theme_stylebox,
|
||||
"setup_control": _setup_control,
|
||||
"get_theme_info": _get_theme_info,
|
||||
}
|
||||
|
||||
|
||||
func _create_theme(params: Dictionary) -> Dictionary:
|
||||
var result := require_string(params, "path")
|
||||
if result[1] != null:
|
||||
return result[1]
|
||||
var path: String = result[0]
|
||||
|
||||
var theme := Theme.new()
|
||||
|
||||
# Optionally set default font size
|
||||
var font_size: int = optional_int(params, "default_font_size", 0)
|
||||
if font_size > 0:
|
||||
theme.default_font_size = font_size
|
||||
|
||||
var scene_guard := guard_offline_scene_save(path)
|
||||
if scene_guard != null:
|
||||
return scene_guard
|
||||
|
||||
var err := ResourceSaver.save(theme, path)
|
||||
if err != OK:
|
||||
return error_internal("Failed to save theme: %s" % error_string(err))
|
||||
|
||||
EditorInterface.get_resource_filesystem().scan()
|
||||
return success({"path": path, "created": true})
|
||||
|
||||
|
||||
func _set_theme_color(params: Dictionary) -> Dictionary:
|
||||
var result := require_string(params, "node_path")
|
||||
if result[1] != null:
|
||||
return result[1]
|
||||
var node_path: String = result[0]
|
||||
|
||||
var result2 := require_string(params, "name")
|
||||
if result2[1] != null:
|
||||
return result2[1]
|
||||
var color_name: String = result2[0]
|
||||
|
||||
var result3 := require_string(params, "color")
|
||||
if result3[1] != null:
|
||||
return result3[1]
|
||||
var color_str: String = result3[0]
|
||||
|
||||
var node := find_node_by_path(node_path)
|
||||
if node == null or not (node is Control):
|
||||
return error_not_found("Control node at '%s'" % node_path)
|
||||
|
||||
var control: Control = node
|
||||
var color := Color(color_str)
|
||||
|
||||
var theme_type: String = optional_string(params, "theme_type", "")
|
||||
if theme_type.is_empty():
|
||||
theme_type = control.get_class()
|
||||
|
||||
var had_old := control.has_theme_color_override(color_name)
|
||||
var old_value: Variant = control.get("theme_override_colors/" + color_name) if had_old else null
|
||||
var undo_redo := get_undo_redo()
|
||||
undo_redo.create_action("MCP: Set theme color override")
|
||||
undo_redo.add_do_method(control, "add_theme_color_override", color_name, color)
|
||||
undo_redo.add_undo_method(self, "_restore_theme_override", control, "color", color_name, had_old, old_value)
|
||||
undo_redo.commit_action()
|
||||
|
||||
return success({"node_path": node_path, "name": color_name, "color": color_str})
|
||||
|
||||
|
||||
func _set_theme_constant(params: Dictionary) -> Dictionary:
|
||||
var result := require_string(params, "node_path")
|
||||
if result[1] != null:
|
||||
return result[1]
|
||||
var node_path: String = result[0]
|
||||
|
||||
var result2 := require_string(params, "name")
|
||||
if result2[1] != null:
|
||||
return result2[1]
|
||||
var const_name: String = result2[0]
|
||||
|
||||
var node := find_node_by_path(node_path)
|
||||
if node == null or not (node is Control):
|
||||
return error_not_found("Control node at '%s'" % node_path)
|
||||
|
||||
var control: Control = node
|
||||
var value: int = int(params.get("value", 0))
|
||||
|
||||
var had_old := control.has_theme_constant_override(const_name)
|
||||
var old_value: Variant = control.get("theme_override_constants/" + const_name) if had_old else null
|
||||
var undo_redo := get_undo_redo()
|
||||
undo_redo.create_action("MCP: Set theme constant override")
|
||||
undo_redo.add_do_method(control, "add_theme_constant_override", const_name, value)
|
||||
undo_redo.add_undo_method(self, "_restore_theme_override", control, "constant", const_name, had_old, old_value)
|
||||
undo_redo.commit_action()
|
||||
|
||||
return success({"node_path": node_path, "name": const_name, "value": value})
|
||||
|
||||
|
||||
func _set_theme_font_size(params: Dictionary) -> Dictionary:
|
||||
var result := require_string(params, "node_path")
|
||||
if result[1] != null:
|
||||
return result[1]
|
||||
var node_path: String = result[0]
|
||||
|
||||
var result2 := require_string(params, "name")
|
||||
if result2[1] != null:
|
||||
return result2[1]
|
||||
var font_name: String = result2[0]
|
||||
|
||||
var node := find_node_by_path(node_path)
|
||||
if node == null or not (node is Control):
|
||||
return error_not_found("Control node at '%s'" % node_path)
|
||||
|
||||
var control: Control = node
|
||||
var size: int = int(params.get("size", 16))
|
||||
|
||||
var had_old := control.has_theme_font_size_override(font_name)
|
||||
var old_value: Variant = control.get("theme_override_font_sizes/" + font_name) if had_old else null
|
||||
var undo_redo := get_undo_redo()
|
||||
undo_redo.create_action("MCP: Set theme font size override")
|
||||
undo_redo.add_do_method(control, "add_theme_font_size_override", font_name, size)
|
||||
undo_redo.add_undo_method(self, "_restore_theme_override", control, "font_size", font_name, had_old, old_value)
|
||||
undo_redo.commit_action()
|
||||
|
||||
return success({"node_path": node_path, "name": font_name, "size": size})
|
||||
|
||||
|
||||
func _set_theme_stylebox(params: Dictionary) -> Dictionary:
|
||||
var result := require_string(params, "node_path")
|
||||
if result[1] != null:
|
||||
return result[1]
|
||||
var node_path: String = result[0]
|
||||
|
||||
var result2 := require_string(params, "name")
|
||||
if result2[1] != null:
|
||||
return result2[1]
|
||||
var style_name: String = result2[0]
|
||||
|
||||
var node := find_node_by_path(node_path)
|
||||
if node == null or not (node is Control):
|
||||
return error_not_found("Control node at '%s'" % node_path)
|
||||
|
||||
var control: Control = node
|
||||
|
||||
var stylebox := StyleBoxFlat.new()
|
||||
|
||||
var bg_color: String = optional_string(params, "bg_color", "")
|
||||
if not bg_color.is_empty():
|
||||
stylebox.bg_color = Color(bg_color)
|
||||
|
||||
var border_color: String = optional_string(params, "border_color", "")
|
||||
if not border_color.is_empty():
|
||||
stylebox.border_color = Color(border_color)
|
||||
|
||||
var border_width: int = optional_int(params, "border_width", 0)
|
||||
if border_width > 0:
|
||||
stylebox.border_width_left = border_width
|
||||
stylebox.border_width_top = border_width
|
||||
stylebox.border_width_right = border_width
|
||||
stylebox.border_width_bottom = border_width
|
||||
|
||||
var corner_radius: int = optional_int(params, "corner_radius", 0)
|
||||
if corner_radius > 0:
|
||||
stylebox.corner_radius_top_left = corner_radius
|
||||
stylebox.corner_radius_top_right = corner_radius
|
||||
stylebox.corner_radius_bottom_left = corner_radius
|
||||
stylebox.corner_radius_bottom_right = corner_radius
|
||||
|
||||
var padding: int = optional_int(params, "padding", 0)
|
||||
if padding > 0:
|
||||
stylebox.content_margin_left = padding
|
||||
stylebox.content_margin_top = padding
|
||||
stylebox.content_margin_right = padding
|
||||
stylebox.content_margin_bottom = padding
|
||||
|
||||
var had_old := control.has_theme_stylebox_override(style_name)
|
||||
var old_value: Variant = control.get("theme_override_styles/" + style_name) if had_old else null
|
||||
var undo_redo := get_undo_redo()
|
||||
undo_redo.create_action("MCP: Set theme stylebox override")
|
||||
undo_redo.add_do_method(control, "add_theme_stylebox_override", style_name, stylebox)
|
||||
undo_redo.add_do_reference(stylebox)
|
||||
undo_redo.add_undo_method(self, "_restore_theme_override", control, "stylebox", style_name, had_old, old_value)
|
||||
if old_value is Resource:
|
||||
undo_redo.add_undo_reference(old_value)
|
||||
undo_redo.commit_action()
|
||||
|
||||
return success({"node_path": node_path, "name": style_name, "type": "StyleBoxFlat"})
|
||||
|
||||
|
||||
func _setup_control(params: Dictionary) -> Dictionary:
|
||||
var result := require_string(params, "node_path")
|
||||
if result[1] != null:
|
||||
return result[1]
|
||||
var node_path: String = result[0]
|
||||
|
||||
var node := find_node_by_path(node_path)
|
||||
if node == null or not (node is Control):
|
||||
return error_not_found("Control node at '%s'" % node_path)
|
||||
|
||||
var control: Control = node
|
||||
var applied: Array = []
|
||||
var old_state := _capture_control_setup_state(control)
|
||||
var target: Control = control.duplicate() as Control
|
||||
|
||||
# Anchor preset
|
||||
var anchor_preset: String = optional_string(params, "anchor_preset", "")
|
||||
if not anchor_preset.is_empty():
|
||||
var preset_map := {
|
||||
"top_left": Control.PRESET_TOP_LEFT,
|
||||
"top_right": Control.PRESET_TOP_RIGHT,
|
||||
"bottom_left": Control.PRESET_BOTTOM_LEFT,
|
||||
"bottom_right": Control.PRESET_BOTTOM_RIGHT,
|
||||
"center_left": Control.PRESET_CENTER_LEFT,
|
||||
"center_top": Control.PRESET_CENTER_TOP,
|
||||
"center_right": Control.PRESET_CENTER_RIGHT,
|
||||
"center_bottom": Control.PRESET_CENTER_BOTTOM,
|
||||
"center": Control.PRESET_CENTER,
|
||||
"left_wide": Control.PRESET_LEFT_WIDE,
|
||||
"top_wide": Control.PRESET_TOP_WIDE,
|
||||
"right_wide": Control.PRESET_RIGHT_WIDE,
|
||||
"bottom_wide": Control.PRESET_BOTTOM_WIDE,
|
||||
"vcenter_wide": Control.PRESET_VCENTER_WIDE,
|
||||
"hcenter_wide": Control.PRESET_HCENTER_WIDE,
|
||||
"full_rect": Control.PRESET_FULL_RECT,
|
||||
}
|
||||
if preset_map.has(anchor_preset):
|
||||
target.set_anchors_and_offsets_preset(preset_map[anchor_preset])
|
||||
applied.append("anchor_preset=%s" % anchor_preset)
|
||||
|
||||
# Min size
|
||||
var min_size_str: String = optional_string(params, "min_size", "")
|
||||
if not min_size_str.is_empty():
|
||||
var expr := Expression.new()
|
||||
if expr.parse(min_size_str) == OK:
|
||||
var val = expr.execute()
|
||||
if val is Vector2:
|
||||
target.custom_minimum_size = val
|
||||
applied.append("min_size=%s" % min_size_str)
|
||||
|
||||
# Size flags horizontal
|
||||
var sf_h: String = optional_string(params, "size_flags_h", "")
|
||||
if not sf_h.is_empty():
|
||||
var flags_map := {
|
||||
"fill": Control.SIZE_FILL,
|
||||
"expand": Control.SIZE_EXPAND,
|
||||
"fill_expand": Control.SIZE_EXPAND_FILL,
|
||||
"shrink_center": Control.SIZE_SHRINK_CENTER,
|
||||
"shrink_end": Control.SIZE_SHRINK_END,
|
||||
}
|
||||
if flags_map.has(sf_h):
|
||||
target.size_flags_horizontal = flags_map[sf_h]
|
||||
applied.append("size_flags_h=%s" % sf_h)
|
||||
|
||||
# Size flags vertical
|
||||
var sf_v: String = optional_string(params, "size_flags_v", "")
|
||||
if not sf_v.is_empty():
|
||||
var flags_map := {
|
||||
"fill": Control.SIZE_FILL,
|
||||
"expand": Control.SIZE_EXPAND,
|
||||
"fill_expand": Control.SIZE_EXPAND_FILL,
|
||||
"shrink_center": Control.SIZE_SHRINK_CENTER,
|
||||
"shrink_end": Control.SIZE_SHRINK_END,
|
||||
}
|
||||
if flags_map.has(sf_v):
|
||||
target.size_flags_vertical = flags_map[sf_v]
|
||||
applied.append("size_flags_v=%s" % sf_v)
|
||||
|
||||
# Margins (for MarginContainer)
|
||||
if params.has("margins") and params["margins"] is Dictionary:
|
||||
var margins: Dictionary = params["margins"]
|
||||
if target is MarginContainer:
|
||||
if margins.has("left"):
|
||||
target.add_theme_constant_override("margin_left", int(margins["left"]))
|
||||
if margins.has("top"):
|
||||
target.add_theme_constant_override("margin_top", int(margins["top"]))
|
||||
if margins.has("right"):
|
||||
target.add_theme_constant_override("margin_right", int(margins["right"]))
|
||||
if margins.has("bottom"):
|
||||
target.add_theme_constant_override("margin_bottom", int(margins["bottom"]))
|
||||
applied.append("margins=%s" % str(margins))
|
||||
|
||||
# Separation (for VBox/HBoxContainer)
|
||||
if params.has("separation"):
|
||||
var sep: int = int(params["separation"])
|
||||
if target is BoxContainer:
|
||||
target.add_theme_constant_override("separation", sep)
|
||||
applied.append("separation=%d" % sep)
|
||||
|
||||
# Grow direction horizontal
|
||||
var grow_h: String = optional_string(params, "grow_h", "")
|
||||
if not grow_h.is_empty():
|
||||
var grow_map := {
|
||||
"begin": Control.GROW_DIRECTION_BEGIN,
|
||||
"end": Control.GROW_DIRECTION_END,
|
||||
"both": Control.GROW_DIRECTION_BOTH,
|
||||
}
|
||||
if grow_map.has(grow_h):
|
||||
target.grow_horizontal = grow_map[grow_h]
|
||||
applied.append("grow_h=%s" % grow_h)
|
||||
|
||||
# Grow direction vertical
|
||||
var grow_v: String = optional_string(params, "grow_v", "")
|
||||
if not grow_v.is_empty():
|
||||
var grow_map := {
|
||||
"begin": Control.GROW_DIRECTION_BEGIN,
|
||||
"end": Control.GROW_DIRECTION_END,
|
||||
"both": Control.GROW_DIRECTION_BOTH,
|
||||
}
|
||||
if grow_map.has(grow_v):
|
||||
target.grow_vertical = grow_map[grow_v]
|
||||
applied.append("grow_v=%s" % grow_v)
|
||||
|
||||
if not applied.is_empty():
|
||||
var new_state := _capture_control_setup_state(target)
|
||||
_register_control_setup_undo(control, old_state, new_state)
|
||||
target.free()
|
||||
return success({"node_path": node_path, "applied": applied, "count": applied.size()})
|
||||
|
||||
|
||||
func _restore_theme_override(control: Control, kind: String, override_name: String, had_old: bool, old_value: Variant) -> void:
|
||||
match kind:
|
||||
"color":
|
||||
if had_old:
|
||||
control.add_theme_color_override(override_name, old_value)
|
||||
else:
|
||||
control.remove_theme_color_override(override_name)
|
||||
"constant":
|
||||
if had_old:
|
||||
control.add_theme_constant_override(override_name, old_value)
|
||||
else:
|
||||
control.remove_theme_constant_override(override_name)
|
||||
"font_size":
|
||||
if had_old:
|
||||
control.add_theme_font_size_override(override_name, old_value)
|
||||
else:
|
||||
control.remove_theme_font_size_override(override_name)
|
||||
"stylebox":
|
||||
if had_old:
|
||||
control.add_theme_stylebox_override(override_name, old_value)
|
||||
else:
|
||||
control.remove_theme_stylebox_override(override_name)
|
||||
|
||||
|
||||
func _capture_control_setup_state(control: Control) -> Dictionary:
|
||||
var state := {"properties": {}, "theme_constants": {}}
|
||||
for property: String in [
|
||||
"anchor_left", "anchor_top", "anchor_right", "anchor_bottom",
|
||||
"offset_left", "offset_top", "offset_right", "offset_bottom",
|
||||
"custom_minimum_size", "size_flags_horizontal", "size_flags_vertical",
|
||||
"grow_horizontal", "grow_vertical",
|
||||
]:
|
||||
state["properties"][property] = control.get(property)
|
||||
for constant_name: String in ["margin_left", "margin_top", "margin_right", "margin_bottom", "separation"]:
|
||||
var had_override := control.has_theme_constant_override(constant_name)
|
||||
state["theme_constants"][constant_name] = {
|
||||
"had": had_override,
|
||||
"value": control.get("theme_override_constants/" + constant_name) if had_override else null,
|
||||
}
|
||||
return state
|
||||
|
||||
|
||||
func _register_control_setup_undo(control: Control, old_state: Dictionary, new_state: Dictionary) -> void:
|
||||
var undo_redo := get_undo_redo()
|
||||
undo_redo.create_action("MCP: Setup Control")
|
||||
for property: String in new_state["properties"]:
|
||||
undo_redo.add_do_property(control, property, new_state["properties"][property])
|
||||
undo_redo.add_undo_property(control, property, old_state["properties"][property])
|
||||
for constant_name: String in new_state["theme_constants"]:
|
||||
var new_constant: Dictionary = new_state["theme_constants"][constant_name]
|
||||
var old_constant: Dictionary = old_state["theme_constants"][constant_name]
|
||||
undo_redo.add_do_method(self, "_restore_theme_override", control, "constant", constant_name, new_constant["had"], new_constant["value"])
|
||||
undo_redo.add_undo_method(self, "_restore_theme_override", control, "constant", constant_name, old_constant["had"], old_constant["value"])
|
||||
undo_redo.commit_action()
|
||||
|
||||
|
||||
func _get_theme_info(params: Dictionary) -> Dictionary:
|
||||
var result := require_string(params, "node_path")
|
||||
if result[1] != null:
|
||||
return result[1]
|
||||
var node_path: String = result[0]
|
||||
|
||||
var node := find_node_by_path(node_path)
|
||||
if node == null or not (node is Control):
|
||||
return error_not_found("Control node at '%s'" % node_path)
|
||||
|
||||
var control: Control = node
|
||||
var info := {"node_path": node_path, "class": control.get_class()}
|
||||
|
||||
# Check if node has a theme
|
||||
var theme := control.theme
|
||||
if theme:
|
||||
info["theme_path"] = theme.resource_path
|
||||
info["type_list"] = Array(theme.get_type_list())
|
||||
|
||||
# List overrides
|
||||
var overrides := {"colors": {}, "constants": {}, "font_sizes": {}, "styleboxes": {}}
|
||||
for prop in control.get_property_list():
|
||||
var pname: String = prop["name"]
|
||||
if pname.begins_with("theme_override_colors/"):
|
||||
var key := pname.substr(22)
|
||||
overrides["colors"][key] = "#" + (control.get(pname) as Color).to_html()
|
||||
elif pname.begins_with("theme_override_constants/"):
|
||||
var key := pname.substr(25)
|
||||
overrides["constants"][key] = control.get(pname)
|
||||
elif pname.begins_with("theme_override_font_sizes/"):
|
||||
var key := pname.substr(26)
|
||||
overrides["font_sizes"][key] = control.get(pname)
|
||||
elif pname.begins_with("theme_override_styles/"):
|
||||
var key := pname.substr(22)
|
||||
var style = control.get(pname)
|
||||
overrides["styleboxes"][key] = style.get_class() if style else null
|
||||
|
||||
info["overrides"] = overrides
|
||||
return success(info)
|
||||
Reference in New Issue
Block a user