class_name CharacterCard extends Panel ## One character in the character select popup: its picture and name. Clicking it picks ## the character. ## Emitted with the character's picture and name when the card is clicked. signal new_character_selected(img_texture: ImageTexture, character_name: String) ## The character's name: its picture's file name, e.g. "PaperMario.png". var character_name: String = "" @onready var character_image: TextureRect = %CharacterTextureRect @onready var character_name_label: Label = %CharacterName func _ready() -> void: gui_input.connect(_on_gui_input) mouse_entered.connect(_set_hovered.bind(true)) mouse_exited.connect(_set_hovered.bind(false)) ## Shows [param character_name] and its picture. [param fetch_image] is called with the ## name and a Callable that takes the picture as an [Image], e.g. ## [method CharacterCache.fetch_image]. func set_character_name(new_name: String, fetch_image: Callable) -> void: character_name = new_name character_name_label.text = display_name(new_name) tooltip_text = character_name_label.text var image_fetched: Callable = func image_fetched(picture: Image) -> void: character_image.texture = ImageTexture.create_from_image(picture) fetch_image.call(new_name, image_fetched) ## The name to show for a picture's [param file_name]: without the file extension, and ## with words that are written together split, e.g. "PaperMario.png" is "Paper Mario". static func display_name(file_name: String) -> String: var name_part: String = file_name.get_basename() if "." in file_name else file_name var words: RegEx = RegEx.create_from_string("([a-z])([A-Z])") return words.sub(name_part, "$1 $2", true) ## Reads a PNG, JPG or WebP picture, telling them apart by their first bytes so that no ## error is printed for trying the wrong format. Returns null if it is none of them. static func image_from_bytes(bytes: PackedByteArray) -> Image: var image: Image = Image.new() var error: Error = ERR_FILE_UNRECOGNIZED if bytes.size() >= 4 && bytes.slice(0, 4) == PackedByteArray([0x89, 0x50, 0x4E, 0x47]): error = image.load_png_from_buffer(bytes) elif bytes.size() >= 3 && bytes.slice(0, 3) == PackedByteArray([0xFF, 0xD8, 0xFF]): error = image.load_jpg_from_buffer(bytes) elif bytes.size() >= 12 && bytes.slice(8, 12).get_string_from_ascii() == "WEBP": error = image.load_webp_from_buffer(bytes) return image if error == OK else null func _set_hovered(hovered: bool) -> void: theme_type_variation = &"CharacterCardHover" if hovered else &"CharacterCard" func _on_gui_input(event: InputEvent) -> void: if event is InputEventMouseButton && event.pressed \ && event.button_index == MOUSE_BUTTON_LEFT && Settings.character_select_open: accept_event() GameLog.debug(character_name_label.text) new_character_selected.emit(character_image.texture, character_name)