with Entities; use Entities;
with Events.Listeners; use Events.Listeners;
private with Ada.Containers.Ordered_Maps;
private with Ada.Containers.Ordered_Sets;
private with Events;
private with Events.Entities;
private with Events.World;
private with Interfaces;
private with Maps;
private with Tiles.Libraries;
private with Widgets.Sprites;
package Widgets.Containers.Scenes is
-- A Scene displays a graphical view of a game world as a layered map built
-- from tiles. As a container widget, it contains Sprite widgets, each
-- corresponding to a non-metaphysical entity in the world. The Scene's
-- viewport generally shows only a portion of the world at a time and can be
-- zoomed or scrolled, either manually or by following an entity.
type Scene is abstract new Container and Event_Listener with private;
type A_Scene is access all Scene'Class;
-- Draws the range of tiles visible in the scene's viewport for layer
-- 'layer' of the scene's map. The drawing location for the tile at
-- 'tileX1','tileY1' is given by 'startX', 'startY'. Missing tiles should
-- not drawn. All tiles in this layer are assumed to be opaque so
-- transparency doesn't need to be handled when drawin. This procedure will
-- be called per redraw per layer from background to foreground.
procedure Draw_Layer( this : access Scene;
dc : Drawing_Context;
layer : Positive; -- layer to draw
startX, -- location in content coordinates
startY : Integer; -- to start drawing
tileX1, -- range of the visible layer
tileY1, -- in tile coordinates
tileX2, --
tileY2 : Integer --
) is abstract;
-- Returns the height of the scene's map in tiles.
function Get_Height_Tiles( this : not null access Scene'Class ) return Natural;
-- Returns the width of the scene's map in tiles.
function Get_Width_Tiles( this : not null access Scene'Class ) return Natural;
-- Scrolls the viewport by x, y in world coordinates. If the scene is
-- following an entity then scrolling will be constrained to the target by
-- the slack distance.
procedure Scroll( this : not null access Scene'Class; x, y : Float );
-- Passing null in 'child' will clear the selection.
procedure Set_Selection( this : access Scene; child : A_Widget );
-- Sets the scene's target entity, 'target', by Entity_Id. The scene will
-- automatically scroll its viewport to keep the target entity in sight,
-- constrained by a slack distance from dead center. If 'target' equals
-- INVALID_ID then the scene will not follow an entity.
procedure Set_Target( this : access Scene; target : Entity_Id );
-- Unselects 'child' widget, removing it from the set of selected children.
-- This is not the same thing as input focus.
procedure Unselect( this : access Scene; child : not null A_Widget );
private
use Events;
use Events.Entities;
use Events.World;
use Interfaces;
use Maps;
use Tiles.Libraries;
use Widgets.Sprites;
-- Provides a Map to map entity id values to their respective Sprite widgets.
package Sprite_Maps is new Ada.Containers.Ordered_Maps( Entity_Id, A_Sprite, "<", "=" );
use Sprite_Maps;
-- Provides an ordered Set of widget references.
package Widget_Sets is new Ada.Containers.Ordered_Sets( A_Widget, Lt, "=" );
use Widget_Sets;
type Boolean_Array is array (Natural range <>) of Boolean;
type A_Boolean_Array is access all Boolean_Array;
type Byte_Array is array (Natural range <>) of Unsigned_8;
type A_Byte_Array is access all Byte_Array;
-- A cache record of a tile bitmap retrieved from the scene's tile library.
-- A Cached_Bitmap doesn't maintain a copy of the bitmap, but only a
-- reference. A Cached_Bitmap should not be used after the scene's tile
-- library is unloaded.
type Cached_Bitmap is
record
tileId : Natural := 0;
bmp : A_Bitmap := null;
end record;
-- An array of Cached_Bitmap records.
type Cached_Bitmap_Array is array (Natural range <>) of Cached_Bitmap;
type A_Cached_Bitmap_Array is access all Cached_Bitmap_Array;
-- An array of Cached_Bitmap_Arrays.
type Bitmap_Cache is array (Natural range <>) of A_Cached_Bitmap_Array;
type A_Bitmap_Cache is access all Bitmap_Cache;
----------------------------------------------------------------------------
type Scene is abstract new Container and Event_Listener with
record
hasData : Boolean := False;
mapWidth,
mapHeight : Natural := 0;
mapLayers : A_Layer_Array := null;
bitmapCache : A_Bitmap_Cache := null;
visibleLayers : A_Boolean_Array := null;
lightLevels : A_Byte_Array := null;
spriteLayer : Integer := Integer'Last; -- sprites draw on top of this layer
tileWidth : Positive := 1;
tileLib : A_Tile_Library := null;
target : Entity_Id := INVALID_ID; -- target entity to follow
wFocusX, -- world coords at center of scene
wFocusY : Float := 0.0; --
wSlackX, -- max pixels target can be from center
wSlackY : Float := 0.0; -- in world units (changes with zoom)
spriteMap : Sprite_Maps.Map; -- maps entity id to sprite widget
selectedSet : Widget_Sets.Set; -- set of selected widgets
waitForLoad : Boolean := False; -- waits for the tile library to
-- load completely before drawing
-- any tiles.
end record;
-- Adds a widget to the scene as a child, updating the entity id/sprite map
-- as necessary. 'child' will be consumed only if 'consume' is True.
-- However, 'child' will be owned by the scene after this call.
procedure Add( this : access Scene;
child : in out A_Widget;
consume : Boolean := True );
pragma Precondition( child /= null );
pragma Postcondition( consume xor child /= null );
-- Unselects all currently selected child widgets.
procedure Clear_Selection( this : access Scene );
procedure Construct( this : access Scene;
view : not null access Game_Views.Game_View'Class;
id : String );
pragma Precondition( id'Length > 0 );
procedure Delete( this : in out Scene );
-- Deletes child widget 'child', updating the sprite map and selection set
-- as necessary. 'child' will be consumed. Exception WIDGET_NOT_FOUND will
-- be raised if 'child' is not a child of the scene.
procedure Delete_Child( this : access Scene; child : in out A_Widget );
-- Deletes all child widgets, updating the sprite map and selection set as
-- necessary.
procedure Delete_Children( this : access Scene );
-- Draws the scene's content area, including map layers, to 'dc'. This is
-- called twice per widget redraw; once where the drawing context layer
-- equals Background and againwhen the drawing context layer equals
-- Foreground. The content drawing is split into two calls like this so that
-- the background map layers can be drawn in the first call, then after the
-- child widgets are drawn, this procedure can be called again to draw the
-- map's foreground layers and any additional overlayed graphics on top of
-- the widget's children. This makes the Scene widget special, in that it
-- can draw both below and on top (ie: behind and in front) of its children.
procedure Draw_Content( this : access Scene; dc : Drawing_Context );
-- Draws any visuals that should overlay the foreground of the scene within
-- the viewport. The signature is similar to Draw_Layer with the exception
-- of a layer parameter. The drawing location for the tile at
-- 'tileX1','tileY1' is given by 'startX', 'startY'. This procedure is
-- called once per redraw, directly after the map and sprites have been
-- drawn.
procedure Draw_Layer_Overlay( this : access Scene;
dc : Drawing_Context;
startX,
startY : Integer;
tileX1,
tileY1,
tileX2,
tileY2 : Integer );
-- Returns a reference to an entity's representative Sprite, which is a
-- child widget of the scene. If 'id' is not recognized entity then null
-- will be returned.
function Find_Sprite( this : not null access Scene'Class;
id : Entity_Id ) return A_Sprite;
-- Focus the scene on a point in world coordinates. If the point is already
-- within the slack focus area, the viewport will not change. However, if
-- centered is set to True then the viewport will ignore slack constraints
-- and attempt to center the focal point.
procedure Focus_On( this : not null access Scene'Class;
x, y : Float;
centered : Boolean := False );
-- Returns the minimum height of the scene, taking into account a previously
-- specified minimum height or the height of the scene's map in pixels.
function Get_Min_Height( this : access Scene ) return Natural;
-- Returns the minimum width of the scene, taking into account a previously
-- specified minimum width or the width of the scene's map in pixels.
function Get_Min_Width( this : access Scene ) return Natural;
-- Handles an Entity_Attribute_Changed event by calling Set_Attribute on
-- the affected entity's Sprite.
procedure Handle_Entity_Attribute_Changed( this : access Scene;
evt : not null A_Entity_Attribute_Changed_Event );
-- Handles an Entity_Created event by creating and adding a corresponding
-- Sprite child widget to represent the entity, if it is non-metaphysical.
procedure Handle_Entity_Created( this : access Scene;
evt : not null A_Entity_Created_Event );
-- Handles an Entity_Deleted event by deleting the entity's corresponding
-- Sprite, if it has one.
procedure Handle_Entity_Deleted( this : access Scene;
evt : not null A_Entity_Deleted_Event );
-- Handles an Entity_Moved event by moving the entity's corresponding Sprite
-- and focusing the viewport on the entity, if it's the scene's target.
procedure Handle_Entity_Moved( this : access Scene;
evt : not null A_Entity_Moved_Event );
-- Handles an Entity_Resized event by resizing the entity's corresponding
-- Sprite.
procedure Handle_Entity_Resized( this : access Scene;
evt : not null A_Entity_Resized_Event );
-- Handles an event received from the corral is registered with. This is the
-- same corral provided by the Game View system's Game_View object. If 'evt'
-- is returned null then the event was consumed.
procedure Handle_Event( this : access Scene;
evt : in out A_Event;
resp : out Response_Type );
pragma Precondition( evt /= null );
-- Handles a Frame_Changed event by changing the image of the entity's
-- corresponding Sprite.
procedure Handle_Frame_Changed( this : access Scene;
evt : not null A_Frame_Changed_Event );
-- Handles a New_World event by clearing the scene's current map and all
-- child widgets, and loading the new world's tile library and map. No
-- sprites will be added yet because the New_World event does not contain
-- entity information. A series of Entity_Created events will follow to
-- populate the world's entities in the scene.
procedure Handle_New_World( this : access Scene;
evt : not null A_New_World_Event );
-- Handles a widget resize, keeping the target entity in focus, if a target
-- entity has been specified.
procedure Handle_Resize( this : access Scene );
-- Handles a Tile_Changed event by updating the specified tile in the
-- scene's tile map.
procedure Handle_Tile_Changed( this : access Scene;
evt : not null A_Tile_Changed_Event );
-- Handles a World_Property_Changed event. This implementation of this
-- procedure does nothing. It is intended to be overridden as necessary,
-- to handle changes to project-specific world properties.
procedure Handle_World_Property_Changed( this : access Scene;
evt : not null A_World_Property_Changed_Event );
-- Returns True if the tile at 'x','y' in layer 'layer' of the scene's map
-- is currently visible in the scene's viewport.
function Is_Tile_Visible( this : not null access Scene'Class;
layer : Positive;
x, y : Integer ) return Boolean;
-- Removes a child widget from the scene, updating the sprite map and
-- selection set as necessary. 'child' will belong to the caller.
procedure Remove( this : access Scene; child : not null A_Widget );
----------------------------------------------------------------------------
-- Deletes a Boolean_Array.
procedure Delete( ba : in out A_Boolean_Array );
-- Deletes a Byte_Array.
procedure Delete( ba : in out A_Byte_Array );
-- Deletes a Bitmap_Cache record. The bitmap referenced by this record is
-- not owned so it will not be touched.
procedure Delete( bc : in out A_Bitmap_Cache );
end Widgets.Containers.Scenes;