new features, play menu, deck builder, deck selection
This commit is contained in:
355
scripts/ui/CardDetailViewer.gd
Normal file
355
scripts/ui/CardDetailViewer.gd
Normal file
@@ -0,0 +1,355 @@
|
||||
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)
|
||||
Reference in New Issue
Block a user