Refactor menu structure and add Flutter-specific input and persistence layers
- Moved menu-related classes to a new structure under `src/menu/`. - Introduced `WolfMenuPresentation` to handle menu art and mappings. - Added `MenuManager` tests to ensure menu state reflects game status. - Implemented `FlutterRendererSettingsPersistence` and `FlutterSaveGamePersistence` for managing settings and save files on desktop platforms. - Created `Wolf3dFlutterInput` to handle keyboard and mouse input in a Flutter environment. - Updated README to reflect new package structure and usage instructions. Signed-off-by: Hans Kokx <hans.d.kokx@gmail.com>
This commit is contained in:
@@ -1,218 +1,5 @@
|
||||
/// Shared menu helpers for Wolf3D hosts.
|
||||
library;
|
||||
|
||||
import 'package:wolf_3d_dart/wolf_3d_data_types.dart';
|
||||
|
||||
/// Known VGA picture indexes used by the original Wolf3D control-panel menus.
|
||||
///
|
||||
/// Values below are picture-table indexes (not raw chunk ids).
|
||||
/// For example, `C_CONTROLPIC` is chunk 26 in `GFXV_WL6.H`, so its picture
|
||||
/// index is `26 - STARTPICS(3) = 23`.
|
||||
abstract class WolfMenuPic {
|
||||
static const int hBj = 0; // H_BJPIC
|
||||
static const int hTopWindow = 3; // H_TOPWINDOWPIC
|
||||
static const int cOptions = 7; // C_OPTIONSPIC
|
||||
static const int cCursor1 = 8; // C_CURSOR1PIC
|
||||
static const int cCursor2 = 9; // C_CURSOR2PIC
|
||||
static const int cNotSelected = 10; // C_NOTSELECTEDPIC
|
||||
static const int cSelected = 11; // C_SELECTEDPIC
|
||||
static const int cBabyMode = 16; // C_BABYMODEPIC
|
||||
static const int cEasy = 17; // C_EASYPIC
|
||||
static const int cNormal = 18; // C_NORMALPIC
|
||||
static const int cHard = 19; // C_HARDPIC
|
||||
static const int cControl = 23; // C_CONTROLPIC
|
||||
static const int cCustomize = 24; // C_CUSTOMIZEPIC
|
||||
static const int cEpisode1 = 27; // C_EPISODE1PIC
|
||||
static const int cEpisode2 = 28; // C_EPISODE2PIC
|
||||
static const int cEpisode3 = 29; // C_EPISODE3PIC
|
||||
static const int cEpisode4 = 30; // C_EPISODE4PIC
|
||||
static const int cEpisode5 = 31; // C_EPISODE5PIC
|
||||
static const int cEpisode6 = 32; // C_EPISODE6PIC
|
||||
static const int statusBar = 83; // STATUSBARPIC
|
||||
static const int title = 84; // TITLEPIC
|
||||
static const int pg13 = 85; // PG13PIC
|
||||
static const int credits = 86; // CREDITSPIC
|
||||
static const int highScores = 87; // HIGHSCORESPIC
|
||||
|
||||
static const List<int> episodePics = [
|
||||
cEpisode1,
|
||||
cEpisode2,
|
||||
cEpisode3,
|
||||
cEpisode4,
|
||||
cEpisode5,
|
||||
cEpisode6,
|
||||
];
|
||||
}
|
||||
|
||||
/// Shared menu text colors resolved from the VGA palette.
|
||||
///
|
||||
/// Keep menu color choices centralized so renderers don't duplicate
|
||||
/// hard-coded palette slots or RGB conversion logic.
|
||||
abstract class WolfMenuPalette {
|
||||
static const int backgroundIndex = 111;
|
||||
static const int panelIndex = 103;
|
||||
static const int borderIndex = 87;
|
||||
static const int emphasisIndex = 10;
|
||||
static const int warningIndex = 14;
|
||||
static const int mutedIndex = 8;
|
||||
|
||||
static const int selectedTextIndex = 19;
|
||||
static const int unselectedTextIndex = 23;
|
||||
static const int disabledTextIndex = 4;
|
||||
static const int _headerTargetRgb = 0xFFF700;
|
||||
|
||||
static int? _cachedHeaderTextIndex;
|
||||
|
||||
static int get headerTextIndex => _cachedHeaderTextIndex ??=
|
||||
ColorPalette.findClosestPaletteIndex(_headerTargetRgb);
|
||||
|
||||
/// Standard ARGB colors (`0xAARRGGBB`) for UI consumers.
|
||||
static int get backgroundColor =>
|
||||
ColorPalette.argbFromVgaIndex(backgroundIndex);
|
||||
|
||||
static int get panelColor => ColorPalette.argbFromVgaIndex(panelIndex);
|
||||
|
||||
static int get borderColor => ColorPalette.argbFromVgaIndex(borderIndex);
|
||||
|
||||
static int get titleColor => ColorPalette.argbFromVgaIndex(headerTextIndex);
|
||||
|
||||
static int get bodyColor =>
|
||||
ColorPalette.argbFromVgaIndex(unselectedTextIndex);
|
||||
|
||||
static int get emphasisColor => ColorPalette.argbFromVgaIndex(emphasisIndex);
|
||||
|
||||
static int get warningColor => ColorPalette.argbFromVgaIndex(warningIndex);
|
||||
|
||||
static int get mutedColor => ColorPalette.argbFromVgaIndex(mutedIndex);
|
||||
|
||||
static int get selectedTextColor => ColorPalette.vga32Bit[selectedTextIndex];
|
||||
|
||||
static int get unselectedTextColor =>
|
||||
ColorPalette.vga32Bit[unselectedTextIndex];
|
||||
|
||||
static int get disabledTextColor => ColorPalette.vga32Bit[disabledTextIndex];
|
||||
|
||||
static int get headerTextColor => ColorPalette.vga32Bit[headerTextIndex];
|
||||
}
|
||||
|
||||
/// Structured accessors for classic Wolf3D menu art.
|
||||
class WolfClassicMenuArt {
|
||||
final WolfensteinData data;
|
||||
|
||||
WolfClassicMenuArt(this.data);
|
||||
|
||||
VgaImage? get controlBackground {
|
||||
return _imageForKey(MenuPicKey.controlBackground);
|
||||
}
|
||||
|
||||
VgaImage? get title => _imageForKey(MenuPicKey.title);
|
||||
|
||||
VgaImage? get heading => _imageForKey(MenuPicKey.heading);
|
||||
|
||||
VgaImage? get selectedMarker => _imageForKey(MenuPicKey.markerSelected);
|
||||
|
||||
VgaImage? get unselectedMarker => _imageForKey(MenuPicKey.markerUnselected);
|
||||
|
||||
VgaImage? get optionsLabel => _imageForKey(MenuPicKey.optionsLabel);
|
||||
|
||||
VgaImage? get customizeLabel => _imageForKey(MenuPicKey.customizeLabel);
|
||||
|
||||
VgaImage? get credits => _imageForKey(MenuPicKey.credits);
|
||||
|
||||
VgaImage? episodeOption(int episodeIndex) {
|
||||
if (episodeIndex < 0) {
|
||||
return null;
|
||||
}
|
||||
final key = data.registry.menu.episodeKey(episodeIndex);
|
||||
return _imageForKey(key);
|
||||
}
|
||||
|
||||
VgaImage? difficultyOption(Difficulty difficulty) {
|
||||
final key = data.registry.menu.difficultyKey(difficulty);
|
||||
return _imageForKey(key);
|
||||
}
|
||||
|
||||
/// Legacy numeric lookup API retained for existing renderer call sites.
|
||||
///
|
||||
/// Known legacy indices are mapped through symbolic registry keys first.
|
||||
/// Unknown indices fall back to direct picture-table indexing.
|
||||
VgaImage? mappedPic(int index) {
|
||||
final key = _legacyKeyForIndex(index);
|
||||
if (key != null) {
|
||||
return _imageForKey(key);
|
||||
}
|
||||
return pic(index);
|
||||
}
|
||||
|
||||
VgaImage? pic(int index) {
|
||||
if (index < 0 || index >= data.vgaImages.length) {
|
||||
return null;
|
||||
}
|
||||
final image = data.vgaImages[index];
|
||||
|
||||
if (image.width <= 0 || image.height <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
VgaImage? _imageForKey(MenuPicKey key) {
|
||||
final ref = data.registry.menu.resolve(key);
|
||||
if (ref == null) {
|
||||
return null;
|
||||
}
|
||||
return pic(ref.pictureIndex);
|
||||
}
|
||||
|
||||
MenuPicKey? _legacyKeyForIndex(int index) {
|
||||
switch (index) {
|
||||
case WolfMenuPic.hTopWindow:
|
||||
return MenuPicKey.heading;
|
||||
case WolfMenuPic.cOptions:
|
||||
return MenuPicKey.optionsLabel;
|
||||
case WolfMenuPic.cCursor1:
|
||||
return MenuPicKey.cursorActive;
|
||||
case WolfMenuPic.cCursor2:
|
||||
return MenuPicKey.cursorInactive;
|
||||
case WolfMenuPic.cNotSelected:
|
||||
return MenuPicKey.markerUnselected;
|
||||
case WolfMenuPic.cSelected:
|
||||
return MenuPicKey.markerSelected;
|
||||
case 15:
|
||||
return MenuPicKey.footer;
|
||||
case WolfMenuPic.cBabyMode:
|
||||
return MenuPicKey.difficultyBaby;
|
||||
case WolfMenuPic.cEasy:
|
||||
return MenuPicKey.difficultyEasy;
|
||||
case WolfMenuPic.cNormal:
|
||||
return MenuPicKey.difficultyNormal;
|
||||
case WolfMenuPic.cHard:
|
||||
return MenuPicKey.difficultyHard;
|
||||
case WolfMenuPic.cControl:
|
||||
return MenuPicKey.controlBackground;
|
||||
case WolfMenuPic.cCustomize:
|
||||
return MenuPicKey.customizeLabel;
|
||||
case WolfMenuPic.cEpisode1:
|
||||
return MenuPicKey.episode1;
|
||||
case WolfMenuPic.cEpisode2:
|
||||
return MenuPicKey.episode2;
|
||||
case WolfMenuPic.cEpisode3:
|
||||
return MenuPicKey.episode3;
|
||||
case WolfMenuPic.cEpisode4:
|
||||
return MenuPicKey.episode4;
|
||||
case WolfMenuPic.cEpisode5:
|
||||
return MenuPicKey.episode5;
|
||||
case WolfMenuPic.cEpisode6:
|
||||
return MenuPicKey.episode6;
|
||||
case WolfMenuPic.title:
|
||||
return MenuPicKey.title;
|
||||
case WolfMenuPic.pg13:
|
||||
return MenuPicKey.pg13;
|
||||
case WolfMenuPic.credits:
|
||||
return MenuPicKey.credits;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
export 'src/menu/wolf_menu_pic.dart';
|
||||
export 'src/menu/wolf_menu_presentation.dart';
|
||||
|
||||
Reference in New Issue
Block a user