/// Visual browser for decoded sprite assets and their inferred gameplay roles. library; import 'package:flutter/material.dart'; import 'package:wolf_3d_dart/wolf_3d_data_types.dart'; import 'package:wolf_3d_dart/wolf_3d_entities.dart'; import 'package:wolf_3d_flutter/wolf_3d_flutter.dart'; import 'package:wolf_3d_gui/screens/gallery_game_selector.dart'; import 'package:wolf_3d_renderer/wolf_3d_asset_painter.dart'; /// Displays every sprite frame in the active game along with enemy metadata. class SpriteGallery extends StatefulWidget { /// Shared application facade used to access the active game's sprite set. final Wolf3d wolf3d; /// Creates the sprite gallery for [wolf3d]. const SpriteGallery({super.key, required this.wolf3d}); @override State createState() => _SpriteGalleryState(); } class _SpriteGalleryState extends State { late WolfensteinData _selectedGame; @override void initState() { super.initState(); _selectedGame = widget.wolf3d.maybeActiveGame ?? widget.wolf3d.availableGames.first; } bool get isShareware => _selectedGame.version == GameVersion.shareware; List get _sprites => _selectedGame.sprites; void _selectGame(WolfensteinData game) { if (identical(_selectedGame, game)) { return; } widget.wolf3d.setActiveGame(game); setState(() { _selectedGame = game; }); } String _buildSpriteLabel(int index) { String label = 'Sprite Index: $index'; for (final enemy in EnemyType.values) { // The gallery infers likely ownership from sprite index ranges so // debugging art packs does not require cross-referencing source. if (enemy.claimsSpriteIndex(index, isShareware: isShareware)) { final EnemyAnimation? animation = enemy.getAnimationFromSprite( index, isShareware: isShareware, ); label += '\n${enemy.name}'; if (animation != null) { label += '\n${animation.name}'; } break; } } return label; } void _showImagePreviewDialog(BuildContext context, int index) { final Sprite sprite = _sprites[index]; showDialog( context: context, builder: (dialogContext) { return AlertDialog( title: Text( '${_buildSpriteLabel(index)}\n64 x 64', style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, ), ), actions: [ TextButton( onPressed: () => Navigator.of(dialogContext).pop(), child: const Text('Close'), ), ], content: Center( child: AspectRatio( aspectRatio: 1, child: WolfAssetPainter.sprite(sprite), ), ), ); }, ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Sprite Gallery'), automaticallyImplyLeading: true, actions: [ if (widget.wolf3d.availableGames.length > 1) GalleryGameSelector( wolf3d: widget.wolf3d, selectedGame: _selectedGame, onSelected: _selectGame, ), ], ), backgroundColor: Colors.black, body: GridView.builder( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 8, crossAxisSpacing: 8, mainAxisSpacing: 8, ), itemCount: _sprites.length, itemBuilder: (context, index) { final String label = _buildSpriteLabel(index); return Card( color: Colors.blueGrey, child: InkWell( onTap: () => _showImagePreviewDialog(context, index), child: Column( spacing: 8, children: [ Text( label, style: const TextStyle(color: Colors.white, fontSize: 10), textAlign: TextAlign.center, ), Expanded( child: Center( child: AspectRatio( aspectRatio: 1, child: WolfAssetPainter.sprite(_sprites[index]), ), ), ), ], ), ), ); }, ), ); } }