equipment ui layout

Guide for equipment ui layout

Equipment UI Layout

Design

Side-by-side layout with equipment slots on the left and inventory grid on the right.
┌────────────────────────────────────────┐
│  Equipment      │     Backpack         │
│  ─────────      │     ────────         │
│  Head: [Item]   │  [▪][▪][▪][▪]       │
│  Cape: [Empty]  │  [▪][▪][▪][▪]       │
│  Neck: [Item]   │  [▪][▪][▪][▪]       │
│  Weapon: [Item] │  [▪][▪][▪][▪]       │
│  Body: [Item]   │  [▪][▪][▪][▪]       │
│  Shield: [Empty]│  [▪][▪][▪][▪]       │
│  Legs: [Item]   │  [▪][▪][▪][▪]       │
│  Hands: [Empty] │                      │
│  Feet: [Item]   │                      │
│  Ring: [Empty]  │                      │
│  Ammo: [Item]   │                      │
└────────────────────────────────────────┘

Implementation

Updated Function Signature

File: src/systems/ui/inventory_ui.rs
pub fn render_inventory_tab(
    ui: &mut egui::Ui,
    player_entity: Entity,
    inventory_query: &Query<&Inventory>,
    equipment_query: &Query<&Equipment>,  // NEW
    use_events: &mut EventWriter<UseItemEvent>,
    unequip_events: &mut EventWriter<UnequipItemEvent>,  // NEW
)

Layout Structure

ui.horizontal(|ui| {
    // LEFT: Equipment Panel
    ui.vertical(|ui| {
        ui.label(egui::RichText::new("Equipment").strong());
        ui.separator();
        if let Some(equip) = equipment {
            render_equipment_slots(ui, equip, player_entity, unequip_events);
        }
    });

    ui.separator();

    // RIGHT: Inventory Panel
    ui.vertical(|ui| {
        ui.label(egui::RichText::new("Backpack").strong());
        ui.separator();
        
        egui::ScrollArea::vertical().show(ui, |ui| {
            egui::Grid::new("inventory_grid")
                .spacing(egui::vec2(8.0, 8.0))
                .min_col_width(40.0)
                .show(ui, |ui| {
                    for (i, slot) in inventory.items.iter().enumerate() {
                        render_inventory_slot(ui, slot, i, player_entity, use_events);
                        if (i + 1) % 4 == 0 { ui.end_row(); }
                    }
                });
        });
    });
});

Equipment Slots Rendering

fn render_equipment_slots(
    ui: &mut egui::Ui,
    equip: &Equipment,
    player_entity: Entity,
    unequip_events: &mut EventWriter<UnequipItemEvent>,
) {
    let slot_size = egui::vec2(32.0, 32.0);
    
    let render_slot = |ui: &mut egui::Ui, name: &str, slot: &Option<ItemSlot>, slot_id: &str| {
        ui.horizontal(|ui| {
            ui.label(format!("{}: ", name));
            let btn_text = if let Some(item) = slot {
                format!("{}", item.id.0)  // TODO: Use item name from GameData
            } else {
                "Empty".to_string()
            };
            
            let btn = ui.add(egui::Button::new(btn_text).min_size(slot_size));
            if let Some(_item) = slot {
                if btn.clicked() {
                    unequip_events.send(UnequipItemEvent {
                        entity: player_entity,
                        slot: slot_id.to_string(),
                    });
                }
                btn.on_hover_text("Click to unequip");
            }
        });
    };

    // Render all slots
    render_slot(ui, "Head", &equip.head, "head");
    render_slot(ui, "Cape", &equip.cape, "cape");
    render_slot(ui, "Neck", &equip.neck, "neck");
    render_slot(ui, "Weapon", &equip.weapon, "weapon");
    render_slot(ui, "Body", &equip.body, "body");
    render_slot(ui, "Shield", &equip.shield, "shield");
    render_slot(ui, "Legs", &equip.legs, "legs");
    render_slot(ui, "Hands", &equip.hands, "hands");
    render_slot(ui, "Feet", &equip.feet, "feet");
    render_slot(ui, "Ring", &equip.ring, "ring");
    render_slot(ui, "Ammo", &equip.ammo, "ammo");
}

Inventory Slot Context Menu

response.context_menu(|ui| {
    ui.label(format!("Item: {}", item.id.0));
    if ui.button("Use / Equip").clicked() {  // Changed from "Use"
        use_events.send(UseItemEvent {
            entity: player_entity,
            item: item.id,
        });
        ui.close_menu();
    }
    if ui.button("Drop").clicked() {
        // TODO: Drop item logic
        ui.close_menu();
    }
});

UI Integration

File: src/systems/ui/mod.rs

1. Add Equipment Query to UiParams

#[derive(bevy::ecs::system::SystemParam)]
pub struct UiParams<'w, 's> {
    // ... existing fields
    pub equipment_q: Query<'w, 's, &'static crate::systems::player::equipment::Equipment>,
}

2. Add UnequipItemEvent Writer

fn ui_main_layout(
    // ... existing params
    mut unequip_item_writer: EventWriter<crate::systems::player::equipment::UnequipItemEvent>,
) {
    // ... unpack params
    let equipment_q = params.equipment_q;
    
    // ... in Inventory tab case:
    UiTab::Inventory => {
        if let Ok((player_entity, _, _)) = player_q.get_single() {
            inventory_ui::render_inventory_tab(
                ui, 
                player_entity, 
                &inventory_q, 
                &equipment_q,           // NEW
                &mut use_item_writer, 
                &mut unequip_item_writer  // NEW
            );
        }
    }
}

Future Enhancements

  1. Item Icons: Replace item IDs with actual icons from GameData
  2. Drag-and-Drop: Allow dragging items from inventory to equipment slots
  3. Stat Preview: Show stat changes when hovering over equippable items
  4. Visual Feedback: Highlight compatible equipment slots when selecting an item
  5. Equipment Sets: Show set bonuses when wearing matching items