356 lines
11 KiB
GDScript
356 lines
11 KiB
GDScript
class_name CardDetailViewer
|
|
extends Control
|
|
|
|
## CardDetailViewer - Left panel showing enlarged card with details and add-to-deck controls
|
|
|
|
signal add_to_deck_requested(card: CardDatabase.CardData, quantity: int)
|
|
signal card_info_requested(card: CardDatabase.CardData)
|
|
|
|
const CARD_WIDTH: float = 405.0
|
|
const CARD_HEIGHT: float = 567.0
|
|
const PANEL_WIDTH: float = 450.0
|
|
|
|
var current_card: CardDatabase.CardData = null
|
|
var current_deck_count: int = 0
|
|
var quantity_to_add: int = 1
|
|
|
|
# UI elements
|
|
var card_image: TextureRect
|
|
var fallback_rect: ColorRect
|
|
var fallback_label: Label
|
|
var name_label: Label
|
|
var type_label: Label
|
|
var element_label: Label
|
|
var cost_label: Label
|
|
var power_label: Label
|
|
var job_label: Label
|
|
var category_label: Label
|
|
var abilities_label: Label
|
|
var quantity_label: Label
|
|
var decrease_btn: Button
|
|
var increase_btn: Button
|
|
var add_button: Button
|
|
var no_card_label: Label
|
|
|
|
|
|
func _ready() -> void:
|
|
custom_minimum_size = Vector2(PANEL_WIDTH, 0)
|
|
_create_ui()
|
|
|
|
|
|
func _create_ui() -> void:
|
|
# Main panel
|
|
var panel = PanelContainer.new()
|
|
panel.set_anchors_preset(Control.PRESET_FULL_RECT)
|
|
panel.add_theme_stylebox_override("panel", _create_panel_style())
|
|
add_child(panel)
|
|
|
|
var main_vbox = VBoxContainer.new()
|
|
main_vbox.add_theme_constant_override("separation", 12)
|
|
panel.add_child(main_vbox)
|
|
|
|
# Card image container
|
|
var image_container = Control.new()
|
|
image_container.custom_minimum_size = Vector2(CARD_WIDTH, CARD_HEIGHT)
|
|
main_vbox.add_child(image_container)
|
|
|
|
# Actual card image
|
|
card_image = TextureRect.new()
|
|
card_image.set_anchors_preset(Control.PRESET_FULL_RECT)
|
|
card_image.expand_mode = TextureRect.EXPAND_FIT_WIDTH_PROPORTIONAL
|
|
card_image.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
|
image_container.add_child(card_image)
|
|
|
|
# Fallback colored rect (when no image)
|
|
fallback_rect = ColorRect.new()
|
|
fallback_rect.set_anchors_preset(Control.PRESET_FULL_RECT)
|
|
fallback_rect.visible = false
|
|
image_container.add_child(fallback_rect)
|
|
|
|
fallback_label = Label.new()
|
|
fallback_label.set_anchors_preset(Control.PRESET_CENTER)
|
|
fallback_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
|
fallback_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
|
fallback_label.add_theme_font_size_override("font_size", 18)
|
|
fallback_label.visible = false
|
|
image_container.add_child(fallback_label)
|
|
|
|
# No card selected label
|
|
no_card_label = Label.new()
|
|
no_card_label.text = "Select a card to view details"
|
|
no_card_label.set_anchors_preset(Control.PRESET_CENTER)
|
|
no_card_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
|
no_card_label.add_theme_color_override("font_color", Color(0.5, 0.5, 0.5))
|
|
image_container.add_child(no_card_label)
|
|
|
|
# Card info section
|
|
var info_vbox = VBoxContainer.new()
|
|
info_vbox.add_theme_constant_override("separation", 4)
|
|
main_vbox.add_child(info_vbox)
|
|
|
|
name_label = _create_info_label("", 20, Color(1.0, 0.95, 0.8))
|
|
info_vbox.add_child(name_label)
|
|
|
|
var details_grid = GridContainer.new()
|
|
details_grid.columns = 2
|
|
details_grid.add_theme_constant_override("h_separation", 12)
|
|
details_grid.add_theme_constant_override("v_separation", 4)
|
|
info_vbox.add_child(details_grid)
|
|
|
|
type_label = _create_info_label("")
|
|
cost_label = _create_info_label("")
|
|
element_label = _create_info_label("")
|
|
power_label = _create_info_label("")
|
|
job_label = _create_info_label("")
|
|
category_label = _create_info_label("")
|
|
|
|
details_grid.add_child(_create_info_label("Type:", 14, Color(0.6, 0.6, 0.6)))
|
|
details_grid.add_child(type_label)
|
|
details_grid.add_child(_create_info_label("Cost:", 14, Color(0.6, 0.6, 0.6)))
|
|
details_grid.add_child(cost_label)
|
|
details_grid.add_child(_create_info_label("Element:", 14, Color(0.6, 0.6, 0.6)))
|
|
details_grid.add_child(element_label)
|
|
details_grid.add_child(_create_info_label("Power:", 14, Color(0.6, 0.6, 0.6)))
|
|
details_grid.add_child(power_label)
|
|
details_grid.add_child(_create_info_label("Job:", 14, Color(0.6, 0.6, 0.6)))
|
|
details_grid.add_child(job_label)
|
|
details_grid.add_child(_create_info_label("Category:", 14, Color(0.6, 0.6, 0.6)))
|
|
details_grid.add_child(category_label)
|
|
|
|
# Abilities section
|
|
var abilities_header = _create_info_label("Abilities", 16, Color(0.8, 0.75, 0.6))
|
|
info_vbox.add_child(abilities_header)
|
|
|
|
var abilities_scroll = ScrollContainer.new()
|
|
abilities_scroll.custom_minimum_size = Vector2(0, 80)
|
|
abilities_scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
|
|
info_vbox.add_child(abilities_scroll)
|
|
|
|
abilities_label = Label.new()
|
|
abilities_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
|
abilities_label.add_theme_font_size_override("font_size", 12)
|
|
abilities_label.add_theme_color_override("font_color", Color(0.8, 0.8, 0.8))
|
|
abilities_scroll.add_child(abilities_label)
|
|
|
|
# Quantity selector
|
|
var qty_hbox = HBoxContainer.new()
|
|
qty_hbox.add_theme_constant_override("separation", 10)
|
|
qty_hbox.alignment = BoxContainer.ALIGNMENT_CENTER
|
|
main_vbox.add_child(qty_hbox)
|
|
|
|
quantity_label = Label.new()
|
|
quantity_label.text = "In deck: 0/3"
|
|
quantity_label.add_theme_font_size_override("font_size", 14)
|
|
qty_hbox.add_child(quantity_label)
|
|
|
|
decrease_btn = _create_quantity_button("-")
|
|
decrease_btn.pressed.connect(_on_decrease_quantity)
|
|
qty_hbox.add_child(decrease_btn)
|
|
|
|
var qty_display = Label.new()
|
|
qty_display.text = "1"
|
|
qty_display.name = "QtyDisplay"
|
|
qty_display.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
|
qty_display.custom_minimum_size = Vector2(30, 0)
|
|
qty_hbox.add_child(qty_display)
|
|
|
|
increase_btn = _create_quantity_button("+")
|
|
increase_btn.pressed.connect(_on_increase_quantity)
|
|
qty_hbox.add_child(increase_btn)
|
|
|
|
# Add to deck button
|
|
add_button = _create_styled_button("Add to Deck")
|
|
add_button.pressed.connect(_on_add_to_deck)
|
|
main_vbox.add_child(add_button)
|
|
|
|
# Initial state
|
|
_update_ui_state()
|
|
|
|
|
|
func _create_panel_style() -> StyleBoxFlat:
|
|
var style = StyleBoxFlat.new()
|
|
style.bg_color = Color(0.08, 0.08, 0.12, 0.95)
|
|
style.border_color = Color(0.5, 0.4, 0.2)
|
|
style.set_border_width_all(2)
|
|
style.set_corner_radius_all(6)
|
|
style.content_margin_left = 15
|
|
style.content_margin_right = 15
|
|
style.content_margin_top = 15
|
|
style.content_margin_bottom = 15
|
|
return style
|
|
|
|
|
|
func _create_info_label(text: String, font_size: int = 14, color: Color = Color(0.9, 0.9, 0.9)) -> Label:
|
|
var label = Label.new()
|
|
label.text = text
|
|
label.add_theme_font_size_override("font_size", font_size)
|
|
label.add_theme_color_override("font_color", color)
|
|
return label
|
|
|
|
|
|
func _create_quantity_button(text: String) -> Button:
|
|
var button = Button.new()
|
|
button.text = text
|
|
button.custom_minimum_size = Vector2(36, 36)
|
|
|
|
var style_normal = StyleBoxFlat.new()
|
|
style_normal.bg_color = Color(0.2, 0.2, 0.25)
|
|
style_normal.border_color = Color(0.4, 0.4, 0.5)
|
|
style_normal.set_border_width_all(1)
|
|
style_normal.set_corner_radius_all(4)
|
|
button.add_theme_stylebox_override("normal", style_normal)
|
|
|
|
var style_hover = StyleBoxFlat.new()
|
|
style_hover.bg_color = Color(0.3, 0.3, 0.4)
|
|
style_hover.border_color = Color(0.6, 0.5, 0.3)
|
|
style_hover.set_border_width_all(1)
|
|
style_hover.set_corner_radius_all(4)
|
|
button.add_theme_stylebox_override("hover", style_hover)
|
|
|
|
button.add_theme_font_size_override("font_size", 18)
|
|
return button
|
|
|
|
|
|
func _create_styled_button(text: String) -> Button:
|
|
var button = Button.new()
|
|
button.text = text
|
|
button.custom_minimum_size = Vector2(0, 44)
|
|
|
|
var style_normal = StyleBoxFlat.new()
|
|
style_normal.bg_color = Color(0.25, 0.25, 0.3)
|
|
style_normal.border_color = Color(0.5, 0.5, 0.6)
|
|
style_normal.set_border_width_all(1)
|
|
style_normal.set_corner_radius_all(5)
|
|
button.add_theme_stylebox_override("normal", style_normal)
|
|
|
|
var style_hover = StyleBoxFlat.new()
|
|
style_hover.bg_color = Color(0.35, 0.35, 0.45)
|
|
style_hover.border_color = Color(0.7, 0.6, 0.3)
|
|
style_hover.set_border_width_all(2)
|
|
style_hover.set_corner_radius_all(5)
|
|
button.add_theme_stylebox_override("hover", style_hover)
|
|
|
|
var style_disabled = StyleBoxFlat.new()
|
|
style_disabled.bg_color = Color(0.15, 0.15, 0.18)
|
|
style_disabled.border_color = Color(0.3, 0.3, 0.35)
|
|
style_disabled.set_border_width_all(1)
|
|
style_disabled.set_corner_radius_all(5)
|
|
button.add_theme_stylebox_override("disabled", style_disabled)
|
|
|
|
button.add_theme_font_size_override("font_size", 16)
|
|
return button
|
|
|
|
|
|
## Show a card in the detail viewer
|
|
func show_card(card: CardDatabase.CardData, deck_count: int = 0) -> void:
|
|
current_card = card
|
|
current_deck_count = deck_count
|
|
quantity_to_add = 1
|
|
_update_ui_state()
|
|
|
|
|
|
## Update deck count for current card
|
|
func update_deck_count(count: int) -> void:
|
|
current_deck_count = count
|
|
_update_ui_state()
|
|
|
|
|
|
## Clear the detail viewer
|
|
func clear() -> void:
|
|
current_card = null
|
|
current_deck_count = 0
|
|
_update_ui_state()
|
|
|
|
|
|
func _update_ui_state() -> void:
|
|
var has_card = current_card != null
|
|
no_card_label.visible = not has_card
|
|
card_image.visible = has_card
|
|
add_button.disabled = not has_card
|
|
|
|
if not has_card:
|
|
name_label.text = ""
|
|
type_label.text = ""
|
|
cost_label.text = ""
|
|
element_label.text = ""
|
|
power_label.text = ""
|
|
job_label.text = ""
|
|
category_label.text = ""
|
|
abilities_label.text = ""
|
|
quantity_label.text = "In deck: 0/3"
|
|
fallback_rect.visible = false
|
|
fallback_label.visible = false
|
|
return
|
|
|
|
# Load card image
|
|
var texture = CardDatabase.get_card_texture(current_card)
|
|
if texture:
|
|
card_image.texture = texture
|
|
card_image.visible = true
|
|
fallback_rect.visible = false
|
|
fallback_label.visible = false
|
|
else:
|
|
card_image.visible = false
|
|
fallback_rect.visible = true
|
|
fallback_label.visible = true
|
|
fallback_rect.color = Enums.element_to_color(current_card.get_primary_element())
|
|
fallback_label.text = current_card.name
|
|
|
|
# Update info labels
|
|
name_label.text = current_card.name
|
|
type_label.text = Enums.card_type_to_string(current_card.type)
|
|
cost_label.text = str(current_card.cost)
|
|
|
|
var elements_str = ""
|
|
for i in range(current_card.elements.size()):
|
|
if i > 0:
|
|
elements_str += " / "
|
|
elements_str += Enums.element_to_string(current_card.elements[i])
|
|
element_label.text = elements_str
|
|
|
|
power_label.text = str(current_card.power) if current_card.power > 0 else "-"
|
|
job_label.text = current_card.job if not current_card.job.is_empty() else "-"
|
|
category_label.text = current_card.category if not current_card.category.is_empty() else "-"
|
|
|
|
# Update abilities
|
|
var abilities_text = ""
|
|
for ability in current_card.abilities:
|
|
if not abilities_text.is_empty():
|
|
abilities_text += "\n\n"
|
|
var ability_type = Enums.ability_type_to_string(ability.type)
|
|
abilities_text += "[%s]" % ability_type
|
|
if not ability.trigger.is_empty():
|
|
abilities_text += " %s:" % ability.trigger
|
|
abilities_text += " %s" % ability.effect
|
|
abilities_label.text = abilities_text if not abilities_text.is_empty() else "No abilities"
|
|
|
|
# Update quantity display
|
|
var max_addable = Deck.MAX_COPIES - current_deck_count
|
|
quantity_label.text = "In deck: %d/%d" % [current_deck_count, Deck.MAX_COPIES]
|
|
|
|
var qty_display = get_node_or_null("PanelContainer/VBoxContainer/HBoxContainer/QtyDisplay")
|
|
if qty_display:
|
|
qty_display.text = str(quantity_to_add)
|
|
|
|
decrease_btn.disabled = quantity_to_add <= 1
|
|
increase_btn.disabled = quantity_to_add >= max_addable or max_addable <= 0
|
|
add_button.disabled = max_addable <= 0
|
|
|
|
|
|
func _on_decrease_quantity() -> void:
|
|
if quantity_to_add > 1:
|
|
quantity_to_add -= 1
|
|
_update_ui_state()
|
|
|
|
|
|
func _on_increase_quantity() -> void:
|
|
var max_addable = Deck.MAX_COPIES - current_deck_count
|
|
if quantity_to_add < max_addable:
|
|
quantity_to_add += 1
|
|
_update_ui_state()
|
|
|
|
|
|
func _on_add_to_deck() -> void:
|
|
if current_card:
|
|
add_to_deck_requested.emit(current_card, quantity_to_add)
|