b451f83174
Captures the pre-Godot-port state of the codebase. This is the rollback anchor for the Godot port (M0 of theriapolis-rpg-implementation-plan-godot-port.md). All Phase 0 through Phase 6.5 work is included; Phase 7 is in flight. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
110 lines
3.8 KiB
C#
110 lines
3.8 KiB
C#
using Microsoft.Xna.Framework;
|
|
using Microsoft.Xna.Framework.Graphics;
|
|
using Theriapolis.Game.CodexUI.Drag;
|
|
using Theriapolis.Game.Screens;
|
|
|
|
namespace Theriapolis.Game.CodexUI.Core;
|
|
|
|
/// <summary>
|
|
/// Base class for screens implemented in CodexUI. Owns the input snapshot,
|
|
/// the root widget, the parchment background tiling, the drag-drop
|
|
/// controller, and the popover layer. Concrete screens override
|
|
/// <see cref="BuildRoot"/> to populate the widget tree.
|
|
///
|
|
/// Implements <see cref="IScreen"/> so the existing <c>ScreenManager</c>
|
|
/// can treat CodexUI screens identically to Myra-based ones.
|
|
/// </summary>
|
|
public abstract class CodexScreen : IScreen
|
|
{
|
|
protected Game1 Game = null!;
|
|
protected CodexInput Input { get; } = new();
|
|
protected CodexWidget? Root;
|
|
protected CodexAtlas Atlas { get; private set; } = null!;
|
|
protected DragDropController DragDrop { get; } = new();
|
|
|
|
/// <summary>The popover layer is painted last so floating panels stay above the page.</summary>
|
|
protected Widgets.CodexHoverPopover? Popover { get; set; }
|
|
|
|
private System.EventHandler<TextInputEventArgs>? _textInputHandler;
|
|
private bool _layoutDirty = true;
|
|
|
|
public virtual void Initialize(Game1 game)
|
|
{
|
|
Game = game;
|
|
Atlas = game.CodexAtlas;
|
|
if (CodexFonts.DisplayLarge is null)
|
|
throw new System.InvalidOperationException("CodexFonts.LoadAll must be called before any CodexScreen is initialized.");
|
|
|
|
_textInputHandler = (_, e) =>
|
|
{
|
|
// Filter out non-printable controls so backspace etc. routes via
|
|
// KeyJustPressed instead of pushing into the text buffer.
|
|
if (e.Character >= 32 && e.Character != 127) Input.OnTextInput(e.Character);
|
|
};
|
|
game.Window.TextInput += _textInputHandler;
|
|
|
|
Root = BuildRoot();
|
|
_layoutDirty = true;
|
|
}
|
|
|
|
public virtual void Deactivate()
|
|
{
|
|
if (_textInputHandler is not null) Game.Window.TextInput -= _textInputHandler;
|
|
}
|
|
|
|
public virtual void Reactivate() { _layoutDirty = true; }
|
|
|
|
/// <summary>Concrete screens build the entire widget tree here. Called once after Initialize.</summary>
|
|
protected abstract CodexWidget BuildRoot();
|
|
|
|
/// <summary>Force a re-measure on next frame (e.g. step changed).</summary>
|
|
public void InvalidateLayout()
|
|
{
|
|
Root = BuildRoot();
|
|
_layoutDirty = true;
|
|
}
|
|
|
|
public virtual void Update(GameTime gameTime)
|
|
{
|
|
Input.Tick();
|
|
if (Root is null) return;
|
|
|
|
if (_layoutDirty)
|
|
{
|
|
var vp = Game.GraphicsDevice.Viewport;
|
|
Root.Measure(new Point(vp.Width, vp.Height));
|
|
Root.Arrange(new Rectangle(0, 0, vp.Width, vp.Height));
|
|
_layoutDirty = false;
|
|
}
|
|
Root.Update(gameTime, Input);
|
|
Popover?.Update(gameTime, Input);
|
|
DragDrop.Update(gameTime, Input);
|
|
}
|
|
|
|
public virtual void Draw(GameTime gameTime, SpriteBatch sb)
|
|
{
|
|
Game.GraphicsDevice.Clear(CodexColors.BgDeep);
|
|
sb.Begin();
|
|
DrawBackground(sb);
|
|
Root?.Draw(sb, gameTime);
|
|
Popover?.Draw(sb, gameTime);
|
|
DragDrop.Draw(sb);
|
|
sb.End();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Paint a flat <see cref="CodexColors.BgDeep"/> across the full viewport.
|
|
/// The body widget paints its own lighter <see cref="CodexColors.Bg"/>
|
|
/// fill on top so cards (which use the slightly-darker
|
|
/// <see cref="CodexColors.Bg2"/>) read clearly against their immediate
|
|
/// background. We don't tile a parchment-grain texture: a 256-px tile
|
|
/// produces visible seams, and the procedural radial gradients made
|
|
/// some areas brighter than the cards on top of them.
|
|
/// </summary>
|
|
private void DrawBackground(SpriteBatch sb)
|
|
{
|
|
var vp = Game.GraphicsDevice.Viewport;
|
|
sb.Draw(Atlas.Pixel, vp.Bounds, CodexColors.BgDeep);
|
|
}
|
|
}
|