cwensley on develop
Mac: Check for null Handler whe… Merge pull request #2385 from c… (compare)
cwensley on develop
Add Control.TriggerStyleChanged… Merge pull request #2384 from c… (compare)
cwensley on develop
Gtk: Fix crash when setting Tre… Merge pull request #2383 from c… (compare)
using BitmapData data = imageWidget.Lock();
Stopwatch stop = Stopwatch.StartNew();
int xSize = imageWidget.Width, ySize = imageWidget.Height;
Image<Rgb24> renderBuffer = renderJob.ImageBuffer;
Verbose("Updating image");
IntPtr offset = data.Data;
for (int y = 0; y < ySize; y++)
unsafe
{
Span<Rgb24> renderBufRow = renderBuffer.GetPixelRowSpan(y);
void* destPtr = offset.ToPointer();
Span<Rgb24> destRow = new(destPtr, xSize);
renderBufRow.CopyTo(destRow);
offset += data.ScanWidth;
}
imageContainer.MinimumSize = new Size(160, 90);
imageView.Size = new Size(-1, -1);
previewImage = new Bitmap(renderJob.RenderOptions.Width, renderJob.RenderOptions.Height, PixelFormat.Format24bppRgb);
imageView = new ImageView { Image = previewImage};
imageContainer = new GroupBox { Text = "Preview", Content = imageView };
using Eto.Drawing;
using Eto.Forms;
using RayTracer.Core.Graphics;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using static Serilog.Log;
using Size = Eto.Drawing.Size;
namespace RayTracer.Display.EtoForms;
internal sealed class RenderProgressDisplayPanel : Panel
{
private readonly GroupBox imageContainer;
private readonly ImageView imageView;
private readonly Bitmap previewImage;
private readonly AsyncRenderJob renderJob;
private readonly GroupBox statsContainer;
private readonly TableLayout statsTable;
public RenderProgressDisplayPanel(AsyncRenderJob renderJob)
{
//TODO
this.renderJob = renderJob;
Verbose("Creating StackPanelLayout for content");
statsTable = new TableLayout();
statsContainer = new GroupBox { Text = "Statistics", Content = statsTable };
previewImage = new Bitmap(renderJob.RenderOptions.Width, renderJob.RenderOptions.Height, PixelFormat.Format24bppRgb);
imageView = new ImageView { Image = previewImage};
imageContainer = new GroupBox { Text = "Preview", Content = imageView };
Content = new StackLayout
{
Items = { statsContainer, imageContainer },
Orientation = Orientation.Horizontal,
Spacing = 10
};
Task.Run(UpdatePreviewWorker);
}
private async Task UpdatePreviewWorker()
{
while (!renderJob.RenderCompleted)
{
UpdateImagePreview();
UpdateStatsTable();
await Task.Delay(1000);
}
UpdateImagePreview(); //Do final run to ensure image isn't half updated (if render completed partway through update)
UpdateStatsTable();
}
private void UpdateImagePreview()
{
imageContainer.MinimumSize = new Size(160, 90);
imageView.Size = new Size(-1, -1);
using BitmapData data = previewImage.Lock();
Stopwatch stop = Stopwatch.StartNew();
int xSize = previewImage.Width, ySize = previewImage.Height;
Image<Rgb24> renderBuffer = renderJob.ImageBuffer;
Verbose("Updating image");
IntPtr offset = data.Data;
for (int y = 0; y < ySize; y++)
unsafe
{
Span<Rgb24> renderBufRow = renderBuffer.GetPixelRowSpan(y);
void* destPtr = offset.ToPointer();
Span<Rgb24> destRow = new(destPtr, xSize);
renderBufRow.CopyTo(destRow);
offset += data.ScanWidth;
}
//Mark this object as requiring a redraw
Invalidate();
Verbose("Finished updating image in {Elapsed}", stop.Elapsed);
}
private void UpdateStatsTable()
{
/*Unrelated*/
}
}
@cwensley Really sorry to keep bothering you, but I've had a look through the repo issues and done some googling, and I can't find a solution.
I followed what you said, and I set the sizes like so:
this.MinimumSize = new Size(160, 90);
imageContainer.MinimumSize = new Size(160, 90);
imageContainer.Size = new Size(-1, -1);
imageContainer.ClientSize = new Size(-1, -1);
imageView.Size = new Size(-1, -1);
But the image still scales itself to 1920*1080 not the available space.
new Size(100,100)
, then it's too small. What I want is for it to go as big as it can, just not outside the available space it has. So if the available space is 19201080, then it will be 19201080. If the screen is half the size, it'll be 960*540, etc. Like i need auto scaling that changes when i resize the app window, not a fixed size
GroupBox
right?
using Eto.Drawing;
using Eto.Forms;
using Gtk;
using LibEternal.ObjectPools;
using RayTracer.Core.Graphics;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using static Serilog.Log;
using Application = Eto.Forms.Application;
using Orientation = Eto.Forms.Orientation;
using Size = Eto.Drawing.Size;
namespace RayTracer.Display.EtoForms;
internal sealed class RenderProgressDisplayPanel : Panel
{
/*Properties storing sub-controls*/
public RenderProgressDisplayPanel(AsyncRenderJob renderJob)
{
//TODO
this.renderJob = renderJob;
Verbose("Creating StackPanelLayout for content");
statsTable = new TableLayout
{ ID = "Stats Table" };
statsContainer = new GroupBox
{ ID = "Stats Container", Text = "Statistics", Content = statsTable };
previewImage = new Bitmap(renderJob.RenderOptions.Width, renderJob.RenderOptions.Height, PixelFormat.Format24bppRgb)
{ ID = "Preview Image" };
imageView = new ImageView
{ ID = "Image View", Image = previewImage };
imageContainer = new GroupBox
{ Text = "Preview", Content = imageView, ID = "Image Container" };
Content = new StackLayout
{
Items = { statsContainer, imageContainer },
Orientation = Orientation.Horizontal,
Spacing = 10,
ID = "Main Content StackLayout"
};
TaskWatcher.Watch(Task.Run(UpdatePreviewWorker), false);
}
private async Task UpdatePreviewWorker()
{
//Updates the content of the image and table
}
private void UpdateImagePreview()
{
//HACK WARN: Auto sizing doesn't work so need to manually set it
imageView.Size = new Size(1000, 700);
using BitmapData data = previewImage.Lock();
Stopwatch stop = Stopwatch.StartNew();
int xSize = previewImage.Width, ySize = previewImage.Height;
Image<Rgb24> renderBuffer = renderJob.ImageBuffer;
Verbose("Updating image");
IntPtr offset = data.Data;
for (int y = 0; y < ySize; y++)
unsafe
{
Span<Rgb24> renderBufRow = renderBuffer.GetPixelRowSpan(y);
void* destPtr = offset.ToPointer();
Span<Rgb24> destRow = new(destPtr, xSize);
renderBufRow.CopyTo(destRow);
offset += data.ScanWidth;
}
Verbose("Finished updating image in {Elapsed}", stop.Elapsed);
}
private void UpdateStatsTable()
{
//...
}
using Eto.Drawing;
using Eto.Forms;
using RayTracer.Core.Graphics;
using RayTracer.Core.Scenes;
using System;
using System.Reflection;
using System.Threading.Tasks;
using static Serilog.Log;
namespace RayTracer.Display.EtoForms;
public sealed class MainForm : Form
{
private readonly RenderOptionSelectorPanel? selectorPanel = null;
private readonly Label titleLabel;
private AsyncRenderJob? renderJob = null;
public MainForm()
{
Verbose("MainForm.Ctor()");
string title = $"RayTracer.Display - v{Assembly.GetEntryAssembly()!.GetName().Version}";
Title = title;
Verbose("Title is {Title}", Title);
MinimumSize = new Size(200, 200);
Verbose("Minimum app size set to {MinSize}", MinimumSize);
Padding = 10;
Verbose("Creating UI elements");
titleLabel = new Label { Text = title, Font = new Font(FontFamilies.Sans!, 32f, FontStyle.Bold) };
StackLayoutItem displayedWindowItem = new() { HorizontalAlignment = HorizontalAlignment.Stretch, Expand = true };
StackLayoutItem titleItem = new(titleLabel, HorizontalAlignment.Center);
Content = new StackLayout
{
Items = { titleItem, displayedWindowItem },
Spacing = 10
};
Verbose("Generating commands");
Command quitCommand = new() { MenuText = "Quit", Shortcut = Application.Instance!.CommonModifier | Keys.Q };
quitCommand.Executed += (_, _) => Application.Instance.Quit();
Command aboutCommand = new() { MenuText = "About..." };
aboutCommand.Executed += (_, _) => new AboutDialog().ShowDialog(this);
// create menu
Verbose("Creating menu bar");
Menu = new MenuBar
{
Items =
{
// File submenu
// new SubMenuItem { Text = "&File", Items = { clickMe } }
// new SubMenuItem { Text = "&Edit", Items = { /* commands/items */ } },
// new SubMenuItem { Text = "&View", Items = { /* commands/items */ } },
},
ApplicationItems =
{
// application (OS X) or file menu (others)
// new ButtonMenuItem { Text = "&Preferences..." }
},
QuitItem = quitCommand,
AboutItem = aboutCommand
};
const string iconPath = "RayTracer.Display.EtoForms.Appearance.icon.png";
Verbose("Loading and setting icon from {IconPath}", iconPath);
Icon = Icon.FromResource(iconPath);
Verbose("Toolbar disabled");
ToolBar = null; //new ToolBar { Items = { clickMe } };
//We start off with an options selection panel, then once the user clicks the 'continue' button, we start the render and change it to the render progress panel
Verbose("Initializing render options selector subview");
selectorPanel = new RenderOptionSelectorPanel((_, _) => StartRenderButtonClicked());
displayedWindowItem.Control = selectorPanel;
}
private void StartRenderButtonClicked()
{
//Assume that the sender is the same selector panel we have stored
//Might be bad practice but hey who cares it's easier
RenderOptions options = selectorPanel!.RenderOptions;
Scene scene = selectorPanel.Scene;
Information("Render start button clicked");
Debug("Scene is {Scene}, Options are {Options}", scene, options);
Debug("Creating render job");
renderJob = new AsyncRenderJob(scene, options);
Debug("Starting render job");
Task renderTask = renderJob.TryStartAsync();
TaskWatcher.Watch(renderTask, true);
//Create the display panel
//TODO: Honestly this is a really bad way to do it and I don't like it, but for some reason removing the children from the stack panel
// does not work (some weird logical child not equal behaviour) so i gotta create a new layout instead :(
Verbose("Creating render progress display panel");
RenderProgressDisplayPanel displayPanel = new(renderJob);
StackLayoutItem titleItem = new(titleLabel, HorizontalAlignment.Center);
Content = new StackLayout
{
Items = { titleItem, displayPanel },
Spacing = 10
};
}
}
new StackLayoutItem(displayPanel, HorizontalAlignment.Stretch, true)
, and new StackLayoutItem(imageContainer, VerticalAlignment.Stretch, true)
for the respective places those are added to the StackLayout.Items.
NullReferenceExcetpions
to be thrown by GTK (see picoe/Eto#2181)