Play mode: re-add game view resolution/ratio dropdown functionality

This commit is contained in:
Tony Ferguson
2025-11-25 21:51:54 +00:00
committed by GitHub
parent 350b15e623
commit 77cc796498
5 changed files with 189 additions and 33 deletions

View File

@@ -24,6 +24,8 @@ public partial class SceneViewWidget
_gameViewport = _viewports.FirstOrDefault().Value;
_gameViewport.StartPlay();
_viewportTools.UpdateViewportFromCookie();
}
[Event( "scene.stop" )]
@@ -65,10 +67,44 @@ public partial class SceneViewWidget
_sidePanel?.Visible = CurrentView != ViewMode.Game;
}
// The first viewport is our target for now - we could probably do something smarter
// in future, like using the last focused viewport
public SceneViewportWidget GetGameTarget()
{
return _gameViewport;
}
/// <summary>
/// Set the game viewport to free sizing mode
/// </summary>
public void SetFreeSize()
{
var viewport = GetGameTarget();
if ( viewport.IsValid() )
{
viewport.SetDefaultSize();
}
}
/// <summary>
/// Set the game viewport to a specific aspect ratio
/// </summary>
public void SetForceAspect( float aspect )
{
var viewport = GetGameTarget();
if ( viewport.IsValid() )
{
viewport.SetAspectRatio( aspect );
}
}
/// <summary>
/// Set the game viewport to a specific resolution
/// </summary>
public void SetForceResolution( Vector2 resolution )
{
var viewport = GetGameTarget();
if ( viewport.IsValid() )
{
viewport.SetResolution( resolution );
}
}
}

View File

@@ -263,7 +263,9 @@ public partial class SceneViewWidget : Widget
}
default:
case ViewportLayoutMode.One:
Layout.AddStretchCell();
viewportLayout.Add( CreateViewport() );
Layout.AddStretchCell();
break;
}
}

View File

@@ -19,6 +19,7 @@ public partial class SceneViewportWidget
Renderer.Camera = _activeCamera;
Renderer.EnableEngineOverlays = false;
ViewportOptions.Visible = true;
SetDefaultSize();
}
public void EjectGameCamera()
@@ -40,6 +41,7 @@ public partial class SceneViewportWidget
Renderer.Camera = _activeCamera;
Renderer.EnableEngineOverlays = false;
ViewportOptions.Visible = true;
SetDefaultSize();
}
public void PossesGameCamera()

View File

@@ -0,0 +1,108 @@
namespace Editor;
public partial class SceneViewportWidget
{
Vector2? ForcedSize { get; set; }
float? ForcedAspectRatio { get; set; }
//
// Qt constraint -- unsets FixedSize when set to this value
//
const float QT_MAX_SIZE = (1 << 24) - 1;
/// <summary>
/// Set the forced size to defaults (free size)
/// </summary>
public void SetDefaultSize()
{
ForcedSize = null;
ForcedAspectRatio = null;
MinimumSize = Vector2.Zero;
MaximumSize = QT_MAX_SIZE;
FixedSize = QT_MAX_SIZE;
SetSizeMode( SizeMode.CanGrow, SizeMode.CanGrow );
}
/// <summary>
/// Set the viewport to a specific aspect ratio
/// </summary>
/// <param name="aspectRatio"></param>
public void SetAspectRatio( float aspectRatio )
{
ForcedAspectRatio = aspectRatio;
ForcedSize = null;
UpdateSizeConstraints();
}
/// <summary>
/// Tries to set the viewport to a specific resolution
/// </summary>
/// <param name="resolution"></param>
public void SetResolution( Vector2 resolution )
{
ForcedSize = resolution;
ForcedAspectRatio = null;
UpdateSizeConstraints();
}
private void UpdateSizeConstraints()
{
if ( ForcedSize.HasValue )
{
var size = ForcedSize.Value;
// For fixed resolution, use exact size constraints
MaximumSize = size;
FixedSize = size;
}
else
{
// For aspect ratio mode or free, don't lock the size - let it be dynamic
MaximumSize = new Vector2( QT_MAX_SIZE, QT_MAX_SIZE );
FixedSize = QT_MAX_SIZE;
}
Layout.SizeConstraint = SizeConstraint.SetDefaultConstraint;
SetSizeMode( SizeMode.Expand, SizeMode.Expand );
UpdateGeometry();
AdjustSize();
}
protected override Vector2 SizeHint()
{
// Exact size, easy
if ( ForcedSize.HasValue )
{
return ForcedSize.Value;
}
// Free
if ( !ForcedAspectRatio.HasValue )
{
return base.SizeHint();
}
// Dynamically calculate size based on current parent size
var parentSize = Parent?.Size ?? base.SizeHint();
var parentAspect = parentSize.x / parentSize.y;
var aspectRatio = ForcedAspectRatio.Value;
if ( aspectRatio > parentAspect )
{
// Fit to width
return new Vector2( parentSize.x, parentSize.x / aspectRatio );
}
else
{
// Fit to height
return new Vector2( parentSize.y * aspectRatio, parentSize.y );
}
}
}

View File

@@ -8,6 +8,9 @@ partial class ViewportTools
private Label FrameRateLabel;
private ResolutionModeButton ResolutionComboBox;
/// <inheritdoc cref="ResolutionModeButton.UpdateViewportFromCookie"/>
public void UpdateViewportFromCookie() => ResolutionComboBox.UpdateViewportFromCookie();
private void BuildToolbarGame( Layout layout )
{
{
@@ -66,8 +69,7 @@ partial class ViewportTools
}
}
internal class ResolutionModeButton : Button
class ResolutionModeButton : Button
{
private int _selectedIndex = 0;
private List<Option> _options;
@@ -76,8 +78,16 @@ internal class ResolutionModeButton : Button
private SceneViewWidget _sceneViewWidget;
static string EditorDisplayMode
{
get => ProjectCookie.Get( "EditorDisplayMode", "Free Size" );
set => ProjectCookie.Set( "EditorDisplayMode", value );
}
public ResolutionModeButton( SceneViewWidget sceneViewWidget ) : base( null )
{
_sceneViewWidget = sceneViewWidget;
SetStyles( $"padding-left: 32px; padding-right: 32px; font-family: '{Theme.DefaultFont}'; padding-top: 6px; padding-bottom: 6px;" );
FixedWidth = 210;
FixedHeight = Theme.RowHeight + 6;
@@ -86,48 +96,45 @@ internal class ResolutionModeButton : Button
UpdateButtonText();
Clicked = Click;
_sceneViewWidget = sceneViewWidget;
}
private void InitializeOptions()
{
var view = _sceneViewWidget;
_options =
[
new Option( "Free Size", "fit_screen", () => SetFreeSize() ),
new Option( "16:9 Aspect", "aspect_ratio", () => SetForceAspect( 16.0f / 9.0f ) ),
new Option( "21:9 Aspect", "aspect_ratio", () => SetForceAspect( 21.0f / 9.0f ) ),
new Option( "4:3 Aspect", "aspect_ratio", () => SetForceAspect( 4.0f / 3.0f ) ),
new Option( "9:16 Aspect", "aspect_ratio", () => SetForceAspect( 9.0f / 16.0f ) ),
new Option( "Steam Deck", "stay_current_landscape", () => SetForceResolution( new( 1280, 800 ) ) ),
new Option( "720p", "laptop_windows", () => SetForceResolution( new( 1280, 720 ) ) ),
new Option( "1080p", "desktop_windows", () => SetForceResolution( new( 1920, 1080 ) ) ),
new Option( "Free Size", "fit_screen", () => view.SetFreeSize() ),
new Option( "16:9 Aspect", "aspect_ratio", () => view.SetForceAspect( 16.0f / 9.0f ) ),
new Option( "21:9 Aspect", "aspect_ratio", () => view.SetForceAspect( 21.0f / 9.0f ) ),
new Option( "4:3 Aspect", "aspect_ratio", () => view.SetForceAspect( 4.0f / 3.0f ) ),
new Option( "9:16 Aspect", "aspect_ratio", () => view.SetForceAspect( 9.0f / 16.0f ) ),
new Option( "Steam Deck", "stay_current_landscape", () => view.SetForceResolution( new( 1280, 800 ) ) ),
new Option( "720p", "laptop_windows", () => view.SetForceResolution( new( 1280, 720 ) ) ),
new Option( "1080p", "desktop_windows", () => view.SetForceResolution( new( 1920, 1080 ) ) ),
];
}
void SetForceAspect( float aspect )
/// <summary>
/// Updates the viewport from the <see cref="EditorDisplayMode"/> cookie
/// </summary>
public void UpdateViewportFromCookie()
{
var viewport = _sceneViewWidget.GetGameTarget();
// viewport.SetForceAspect( aspect );
var storedMode = EditorDisplayMode;
var option = _options.FirstOrDefault( o => o.Text == storedMode );
UpdateButtonText();
if ( option != null )
{
_selectedIndex = _options.IndexOf( option );
option.Triggered?.Invoke();
}
else
{
// Fallback to first option if not found
_selectedIndex = 0;
_options[0].Triggered?.Invoke();
}
}
void SetFreeSize()
{
var viewport = _sceneViewWidget.GetGameTarget();
// viewport.SetFreeSize();
UpdateButtonText();
}
void SetForceResolution( Vector2 res )
{
var viewport = _sceneViewWidget.GetGameTarget();
// viewport.SetForceResolution( res );
UpdateButtonText();
}
public string GetSizeString()
{
@@ -159,6 +166,7 @@ internal class ResolutionModeButton : Button
menu.AddOption( option.Text, option.Icon, () =>
{
EditorDisplayMode = option.Text;
_selectedIndex = index;
option.Triggered?.Invoke();
} );