Initial commit: Theriapolis baseline at port/godot branch point
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>
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user