aboutsummaryrefslogtreecommitdiffstatsci
diff options
context:
space:
mode:
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>2021-11-24 23:50:38 +0100
committerJean-Philippe Bruyère <jp_bruyere@hotmail.com>2021-11-24 23:50:38 +0100
commitb25ad7a6e15a7284e40407377a1624747ffe42e5 (patch)
treef53a12fb2120eb7f1b82ccfbda37a2430c5be330
parent09026f4328d0e578823062d6506ffdacac457b25 (diff)
IBackend instead of IDevice to bind to Interface
-rw-r--r--Backends/CairoBackend/src/DefaultBackend.cs16
-rw-r--r--Backends/CairoBackend/src/Device.cs94
-rw-r--r--Backends/CairoBackend/src/EGLDevice.cs7
-rw-r--r--Backends/CairoBackend/src/GLSurface.cs2
-rw-r--r--Backends/CairoBackend/src/ImageBackend.cs179
-rw-r--r--Crow/src/Fill/BmpPicture.cs10
-rw-r--r--Crow/src/Fill/Gradient.cs2
-rw-r--r--Crow/src/Fill/SvgPicture.cs8
-rw-r--r--Crow/src/Interface.cs615
-rw-r--r--Crow/src/Widgets/DockWindow.cs4
-rw-r--r--Crow/src/Widgets/GroupBase.cs2
-rw-r--r--Crow/src/Widgets/Label.cs4
-rw-r--r--Crow/src/Widgets/PrivateContainer.cs2
-rw-r--r--Crow/src/Widgets/ScrollingStack.cs2
-rw-r--r--Crow/src/Widgets/Shape.cs2
-rw-r--r--Crow/src/Widgets/Widget.cs7
-rw-r--r--Drawing2D/src/Enums.cs6
-rw-r--r--Drawing2D/src/IBackend.cs37
-rw-r--r--Drawing2D/src/IDevice.cs10
-rw-r--r--Samples/HelloWorld/main.cs8
-rw-r--r--Samples/PerfTests/Program.cs22
-rw-r--r--Samples/common/src/SampleBase.cs5
22 files changed, 559 insertions, 485 deletions
diff --git a/Backends/CairoBackend/src/DefaultBackend.cs b/Backends/CairoBackend/src/DefaultBackend.cs
new file mode 100644
index 00000000..9ef04b33
--- /dev/null
+++ b/Backends/CairoBackend/src/DefaultBackend.cs
@@ -0,0 +1,16 @@
+using System;
+using Crow.CairoBackend;
+
+namespace Crow.Backends
+{
+ public class DefaultBackend : ImageBackend {
+ /// <summary>
+ /// Create a new generic backend bound to the application surface
+ /// </summary>
+ /// <param name="width">backend surface width</param>
+ /// <param name="height">backend surface height</param>
+ public DefaultBackend (IntPtr nativeWindoPointer, int width, int height)
+ : base (nativeWindoPointer, width, height) { }
+ }
+}
+
diff --git a/Backends/CairoBackend/src/Device.cs b/Backends/CairoBackend/src/Device.cs
index c87b494b..2efe76ec 100644
--- a/Backends/CairoBackend/src/Device.cs
+++ b/Backends/CairoBackend/src/Device.cs
@@ -77,18 +77,9 @@ namespace Crow.CairoBackend
}
public class Device : IDevice
{
- /// <summary> Global font rendering settings for Cairo </summary>
- FontOptions FontRenderingOptions;
- /// <summary> Global font rendering settings for Cairo </summary>
- Antialias Antialias = Antialias.Subpixel;
public Device()
{
- FontRenderingOptions = new FontOptions ();
- FontRenderingOptions.Antialias = Antialias.Subpixel;
- FontRenderingOptions.HintMetrics = HintMetrics.On;
- FontRenderingOptions.HintStyle = HintStyle.Full;
- FontRenderingOptions.SubpixelOrder = SubpixelOrder.Default;
}
~Device ()
@@ -106,87 +97,12 @@ namespace Crow.CairoBackend
{
throw new NotImplementedException();
}
- public IRegion CreateRegion () => new Region ();
- public virtual ISurface CreateSurface(int width, int height)
- => new ImageSurface (Format.ARGB32, width, height);
- public virtual ISurface CreateSurface(byte[] data, int width, int height)
- => new ImageSurface (data, Format.ARGB32, width, height, 4 * width);
- public virtual ISurface CreateSurface (IntPtr nativeWindoPointer, int width, int height) {
- switch (Environment.OSVersion.Platform) {
- case PlatformID.Unix:
- IntPtr disp = Glfw3.GetX11Display ();
- IntPtr nativeWin = Glfw3.GetX11Window (nativeWindoPointer);
- Int32 scr = Glfw3.GetX11DefaultScreen (disp);
- IntPtr visual = Glfw3.GetX11DefaultVisual (disp, scr);
- return new XlibSurface (disp, nativeWin, visual, width, height);
- case PlatformID.Win32NT:
- case PlatformID.Win32S:
- case PlatformID.Win32Windows:
- IntPtr hWin32 = Glfw3.GetWin32Window (nativeWindoPointer);
- IntPtr hdc = Glfw3.GetWin32DC (hWin32);
- return new Win32Surface (hdc);
- }
- throw new PlatformNotSupportedException ("Unable to create cairo surface.");
- }
- public virtual IContext CreateContext(ISurface surf)
- {
- Context gr = new Context (surf);
- gr.FontOptions = FontRenderingOptions;
- gr.Antialias = Antialias;
- return gr;
- }
- public byte[] LoadBitmap (Stream stream, out Size dimensions) {
- byte[] image;
-#if STB_SHARP
- StbImageSharp.ImageResult stbi = StbImageSharp.ImageResult.FromStream (stream, StbImageSharp.ColorComponents.RedGreenBlueAlpha);
- image = new byte[stbi.Data.Length];
- //rgba to argb for cairo.
- for (int i = 0; i < stbi.Data.Length; i += 4) {
- image[i] = stbi.Data[i + 2];
- image[i + 1] = stbi.Data[i + 1];
- image[i + 2] = stbi.Data[i];
- image[i + 3] = stbi.Data[i + 3];
- }
- dimensions = new Size (stbi.Width, stbi.Height);
-#else
- using (StbImage stbi = new StbImage (stream)) {
- image = new byte [stbi.Size];
- for (int i = 0; i < stbi.Size; i+=4) {
- //rgba to argb for cairo. ???? looks like bgra to me.
- image [i] = Marshal.ReadByte (stbi.Handle, i + 2);
- image [i + 1] = Marshal.ReadByte (stbi.Handle, i + 1);
- image [i + 2] = Marshal.ReadByte (stbi.Handle, i);
- image [i + 3] = Marshal.ReadByte (stbi.Handle, i + 3);
- }
- dimensions = new Size (stbi.Width, stbi.Height);
- }
-#endif
- return image;
- }
- public ISvgHandle LoadSvg(Stream stream)
- {
- using (BinaryReader sr = new BinaryReader (stream))
- return new SvgHandle (sr.ReadBytes ((int)stream.Length));
- }
- public ISvgHandle LoadSvg(string svgFragment) =>
- new SvgHandle (System.Text.Encoding.Unicode.GetBytes (svgFragment));
- public IGradient CreateGradient (GradientType gradientType, Rectangle bounds) {
- switch (gradientType) {
- case GradientType.Vertical:
- return new LinearGradient (bounds.Left, bounds.Top, bounds.Left, bounds.Bottom);
- case GradientType.Horizontal:
- return new LinearGradient (bounds.Left, bounds.Top, bounds.Right, bounds.Top);
- case GradientType.Oblic:
- return new LinearGradient (bounds.Left, bounds.Top, bounds.Right, bounds.Bottom);
- case GradientType.Radial:
- throw new NotImplementedException ();
- }
- return null;
- }
+
+
#endregion
#region IDispose implementation
@@ -198,8 +114,10 @@ namespace Crow.CairoBackend
protected virtual void Dispose (bool disposing)
{
- if (disposing)
- FontRenderingOptions.Dispose ();
+ if (disposing){
+
+ }
+
}
#endregion
}
diff --git a/Backends/CairoBackend/src/EGLDevice.cs b/Backends/CairoBackend/src/EGLDevice.cs
index 83629374..d9296b74 100644
--- a/Backends/CairoBackend/src/EGLDevice.cs
+++ b/Backends/CairoBackend/src/EGLDevice.cs
@@ -34,15 +34,16 @@ namespace Crow.CairoBackend
{
public class EGLDevice : GLDevice
{
- public EGLDevice (IntPtr dpy, IntPtr gl_ctx, bool threadAwayre = false) : base (NativeMethods.cairo_egl_device_create (dpy, gl_ctx), true)
+ public EGLDevice (IntPtr dpy, IntPtr gl_ctx, bool threadAwayre = false)
+ : base (NativeMethods.cairo_egl_device_create (dpy, gl_ctx), true)
{
SetThreadAware(threadAwayre);
}
- public override ISurface CreateSurface(int width, int height)
+ /*public override ISurface CreateSurface(int width, int height)
=> new ImageSurface (Format.ARGB32, width, height);
public override ISurface CreateSurface (IntPtr nativeWindoPointer, int width, int height) {
return new GLSurface (this, Glfw.Glfw3.GetEGLSurface (nativeWindoPointer), width, height);
- }
+ }*/
}
}
diff --git a/Backends/CairoBackend/src/GLSurface.cs b/Backends/CairoBackend/src/GLSurface.cs
index c7959dc3..1f486c50 100644
--- a/Backends/CairoBackend/src/GLSurface.cs
+++ b/Backends/CairoBackend/src/GLSurface.cs
@@ -54,7 +54,7 @@ namespace Crow.CairoBackend {
{}
public override void Flush ()
{
- base.Flush ();
+ //base.Flush ();
SwapBuffers ();
}
public override int Width => NativeMethods.cairo_gl_surface_get_width (handle);
diff --git a/Backends/CairoBackend/src/ImageBackend.cs b/Backends/CairoBackend/src/ImageBackend.cs
new file mode 100644
index 00000000..e390ca98
--- /dev/null
+++ b/Backends/CairoBackend/src/ImageBackend.cs
@@ -0,0 +1,179 @@
+using System;
+using System.IO;
+using Drawing2D;
+using Glfw;
+
+namespace Crow.CairoBackend
+{
+ public class ImageBackend : IBackend {
+ ISurface surf;
+ /// <summary> Global font rendering settings for Cairo </summary>
+ FontOptions FontRenderingOptions;
+ /// <summary> Global font rendering settings for Cairo </summary>
+ Antialias Antialias = Antialias.Subpixel;
+ protected ImageBackend ()
+ {
+ FontRenderingOptions = new FontOptions ();
+ FontRenderingOptions.Antialias = Antialias.Subpixel;
+ FontRenderingOptions.HintMetrics = HintMetrics.On;
+ FontRenderingOptions.HintStyle = HintStyle.Full;
+ FontRenderingOptions.SubpixelOrder = SubpixelOrder.Default;
+ }
+ /// <summary>
+ /// Create a new generic backend bound to the application surface
+ /// </summary>
+ /// <param name="width">backend surface width</param>
+ /// <param name="height">backend surface height</param>
+ public ImageBackend (IntPtr nativeWindoPointer, int width, int height) : this () {
+
+ switch (Environment.OSVersion.Platform) {
+ case PlatformID.Unix:
+ IntPtr disp = Glfw3.GetX11Display ();
+ IntPtr nativeWin = Glfw3.GetX11Window (nativeWindoPointer);
+ Int32 scr = Glfw3.GetX11DefaultScreen (disp);
+ IntPtr visual = Glfw3.GetX11DefaultVisual (disp, scr);
+ surf = new XlibSurface (disp, nativeWin, visual, width, height);
+ break;
+ case PlatformID.Win32NT:
+ case PlatformID.Win32S:
+ case PlatformID.Win32Windows:
+ IntPtr hWin32 = Glfw3.GetWin32Window (nativeWindoPointer);
+ IntPtr hdc = Glfw3.GetWin32DC (hWin32);
+ surf = new Win32Surface (hdc);
+ break;
+ default:
+ throw new PlatformNotSupportedException ("Unable to create cairo image backend.");
+ }
+ }
+ /// <summary>
+ /// Create a new offscreen backend, used in perfTests
+ /// </summary>
+ /// <param name="width">backend surface width</param>
+ /// <param name="height">backend surface height</param>
+ public ImageBackend (int width, int height) : this () {
+ surf = new ImageSurface (Format.ARGB32, width, height);
+ }
+ ~ImageBackend ()
+ {
+ Dispose (false);
+ }
+ public virtual ISurface CreateSurface(int width, int height)
+ => new ImageSurface (Format.ARGB32, width, height);
+ public virtual ISurface CreateSurface(byte[] data, int width, int height)
+ => new ImageSurface (data, Format.ARGB32, width, height, 4 * width);
+ public ISurface MainSurface => surf;
+ public IRegion CreateRegion () => new Region ();
+ public IContext CreateContext (ISurface surf)
+ {
+ Context gr = new Context (surf);
+ gr.FontOptions = FontRenderingOptions;
+ gr.Antialias = Antialias;
+ return gr;
+ }
+ //IPattern CreatePattern (PatternType patternType);
+ public IGradient CreateGradient (GradientType gradientType, Rectangle bounds)
+ {
+ switch (gradientType) {
+ case GradientType.Vertical:
+ return new LinearGradient (bounds.Left, bounds.Top, bounds.Left, bounds.Bottom);
+ case GradientType.Horizontal:
+ return new LinearGradient (bounds.Left, bounds.Top, bounds.Right, bounds.Top);
+ case GradientType.Oblic:
+ return new LinearGradient (bounds.Left, bounds.Top, bounds.Right, bounds.Bottom);
+ case GradientType.Radial:
+ throw new NotImplementedException ();
+ }
+ return null;
+ }
+ public byte[] LoadBitmap (Stream stream, out Size dimensions)
+ {
+ byte[] image;
+#if STB_SHARP
+ StbImageSharp.ImageResult stbi = StbImageSharp.ImageResult.FromStream (stream, StbImageSharp.ColorComponents.RedGreenBlueAlpha);
+ image = new byte[stbi.Data.Length];
+ //rgba to argb for cairo.
+ for (int i = 0; i < stbi.Data.Length; i += 4) {
+ image[i] = stbi.Data[i + 2];
+ image[i + 1] = stbi.Data[i + 1];
+ image[i + 2] = stbi.Data[i];
+ image[i + 3] = stbi.Data[i + 3];
+ }
+ dimensions = new Size (stbi.Width, stbi.Height);
+#else
+ using (StbImage stbi = new StbImage (stream)) {
+ image = new byte [stbi.Size];
+ for (int i = 0; i < stbi.Size; i+=4) {
+ //rgba to argb for cairo. ???? looks like bgra to me.
+ image [i] = Marshal.ReadByte (stbi.Handle, i + 2);
+ image [i + 1] = Marshal.ReadByte (stbi.Handle, i + 1);
+ image [i + 2] = Marshal.ReadByte (stbi.Handle, i);
+ image [i + 3] = Marshal.ReadByte (stbi.Handle, i + 3);
+ }
+ dimensions = new Size (stbi.Width, stbi.Height);
+ }
+#endif
+ return image;
+ }
+ public ISvgHandle LoadSvg(Stream stream)
+ {
+ using (BinaryReader sr = new BinaryReader (stream))
+ return new SvgHandle (sr.ReadBytes ((int)stream.Length));
+ }
+ public ISvgHandle LoadSvg(string svgFragment) =>
+ new SvgHandle (System.Text.Encoding.Unicode.GetBytes (svgFragment));
+ bool disposeContextOnFlush;
+ IRegion clipping;
+ protected void clear(IContext ctx) {
+ for (int i = 0; i < clipping.NumRectangles; i++)
+ ctx.Rectangle (clipping.GetRectangle (i));
+
+ ctx.ClipPreserve ();
+ ctx.Operator = Operator.Clear;
+ ctx.Fill ();
+ ctx.Operator = Operator.Over;
+ }
+ public IContext PrepareUIFrame(IContext existingContext, IRegion clipping)
+ {
+ this.clipping = clipping;
+ IContext ctx = existingContext;
+ if (ctx == null) {
+ disposeContextOnFlush = true;
+ ctx = new Context (MainSurface);
+ } else
+ disposeContextOnFlush = false;
+
+ clear (ctx);
+ ctx.PushGroup ();
+
+ return ctx;
+ }
+ public void FlushUIFrame(IContext ctx)
+ {
+ ctx.PopGroupToSource ();
+ ctx.Paint ();
+
+ if (disposeContextOnFlush)
+ ctx.Dispose ();
+ clipping = null;
+ }
+
+
+ #region IDispose implementation
+ bool isDisposed;
+ public void Dispose ()
+ {
+ Dispose (true);
+ GC.SuppressFinalize (this);
+ }
+ protected virtual void Dispose (bool disposing)
+ {
+ if (!isDisposed && disposing) {
+ surf.Dispose ();
+ FontRenderingOptions.Dispose ();
+ }
+ isDisposed = true;
+ }
+ #endregion
+ }
+}
+
diff --git a/Crow/src/Fill/BmpPicture.cs b/Crow/src/Fill/BmpPicture.cs
index 72cc36b8..813e8dec 100644
--- a/Crow/src/Fill/BmpPicture.cs
+++ b/Crow/src/Fill/BmpPicture.cs
@@ -40,7 +40,7 @@ namespace Crow
return;
}
using (Stream stream = iFace.GetStreamFromPath (Path)) {
- image = iFace.Device.LoadBitmap (stream, out Size dimensions);
+ image = iFace.Backend.LoadBitmap (stream, out Size dimensions);
Dimensions = dimensions;
iFace.sharedPictures[Path] = new sharedPicture (image, Dimensions);
}
@@ -89,13 +89,13 @@ namespace Crow
widthRatio = heightRatio;
}
- using (ISurface tmp = iFace.Device.CreateSurface (bounds.Width, bounds.Height)) {
- using (IContext gr = iFace.Device.CreateContext (tmp)) {
+ using (ISurface tmp = iFace.Backend.CreateSurface (bounds.Width, bounds.Height)) {
+ using (IContext gr = iFace.Backend.CreateContext (tmp)) {
gr.Translate (bounds.Left, bounds.Top);
gr.Scale (widthRatio, heightRatio);
gr.Translate ((bounds.Width/widthRatio - Dimensions.Width)/2, (bounds.Height/heightRatio - Dimensions.Height)/2);
- using (ISurface imgSurf = iFace.Device.CreateSurface (bounds.Width, bounds.Height)) {
+ using (ISurface imgSurf = iFace.Backend.CreateSurface (bounds.Width, bounds.Height)) {
gr.SetSource (imgSurf, 0,0);
gr.Paint ();
}
@@ -138,7 +138,7 @@ namespace Crow
gr.Scale (widthRatio, heightRatio);
gr.Translate ((rect.Width/widthRatio - Dimensions.Width)/2, (rect.Height/heightRatio - Dimensions.Height)/2);
- using (ISurface imgSurf = iFace.Device.CreateSurface (image, Dimensions.Width, Dimensions.Height)) {
+ using (ISurface imgSurf = iFace.Backend.CreateSurface (image, Dimensions.Width, Dimensions.Height)) {
gr.SetSource (imgSurf, 0,0);
gr.Paint ();
}
diff --git a/Crow/src/Fill/Gradient.cs b/Crow/src/Fill/Gradient.cs
index d161eba8..abf841e3 100644
--- a/Crow/src/Fill/Gradient.cs
+++ b/Crow/src/Fill/Gradient.cs
@@ -54,7 +54,7 @@ namespace Crow
public override void SetAsSource (Interface iFace, IContext ctx, Rectangle bounds = default(Rectangle))
{
- IGradient grad = iFace.Device.CreateGradient (Type, bounds);
+ IGradient grad = iFace.Backend.CreateGradient (Type, bounds);
foreach (ColorStop cs in Stops) {
if (cs == null)
continue;
diff --git a/Crow/src/Fill/SvgPicture.cs b/Crow/src/Fill/SvgPicture.cs
index d562b342..e6e54aff 100644
--- a/Crow/src/Fill/SvgPicture.cs
+++ b/Crow/src/Fill/SvgPicture.cs
@@ -38,13 +38,13 @@ namespace Crow
return;
}
using (Stream stream = iFace.GetStreamFromPath (Path))
- hSVG = iFace.Device.LoadSvg (stream);
+ hSVG = iFace.Backend.LoadSvg (stream);
Dimensions = hSVG.Dimensions;
iFace.sharedPictures [Path] = new sharedPicture (hSVG, Dimensions);
}
public void LoadSvgFragment (Interface iface, string fragment) {
- hSVG = iface.Device.LoadSvg (fragment);
+ hSVG = iface.Backend.LoadSvg (fragment);
Dimensions = hSVG.Dimensions;
}
@@ -70,8 +70,8 @@ namespace Crow
widthRatio = heightRatio;
}
- using (ISurface tmp = iFace.Device.CreateSurface (bounds.Width, bounds.Height)) {
- using (IContext gr = iFace.Device.CreateContext (tmp)) {
+ using (ISurface tmp = iFace.Backend.CreateSurface (bounds.Width, bounds.Height)) {
+ using (IContext gr = iFace.Backend.CreateContext (tmp)) {
gr.Translate (bounds.Left, bounds.Top);
gr.Scale (widthRatio, heightRatio);
gr.Translate ((bounds.Width/widthRatio - Dimensions.Width)/2, (bounds.Height/heightRatio - Dimensions.Height)/2);
diff --git a/Crow/src/Interface.cs b/Crow/src/Interface.cs
index e0c00ede..19d12f3f 100644
--- a/Crow/src/Interface.cs
+++ b/Crow/src/Interface.cs
@@ -50,6 +50,54 @@ namespace Crow
}
#endregion
+ #region Static and constants
+ //initial capacity for layouting and clipping queues.
+ const int INIT_QUEUE_CAPACITY = 512;
+ /// <summary>Time interval in milisecond between Updates of the interface</summary>
+ public static int UPDATE_INTERVAL = 5;
+ /// <summary>
+ /// Time interval in milisecond between Glfw polling for devices. Wait is done in
+ /// the 'UpdateFrame' method in the 'Run' cycle and may be overriden.
+ /// </summary>
+ public static int POLLING_INTERVAL = 1;
+ /// <summary>Crow configuration root path</summary>
+ public static string CROW_CONFIG_ROOT;
+ /// <summary>If true, mouse focus is given when mouse is over control</summary>
+ public static bool FOCUS_ON_HOVER = false;
+ /// <summary>If true, newly focused window will be put on top</summary>
+ public static bool RAISE_WIN_ON_FOCUS = true;
+ /// <summary> Threshold to catch borders for sizing </summary>
+ public static int BorderThreshold = 3;
+ /// <summary> delay before tooltip appears </summary>
+ public static int TOOLTIP_DELAY = 500;
+ /// <summary>Double click threshold in milisecond</summary>
+ public static int DOUBLECLICK_TRESHOLD = 320;//max duration between two mouse_down evt for a dbl clk in milisec.
+ /// <summary> Time to wait in millisecond before starting repeat loop</summary>
+ public static int DEVICE_REPEAT_DELAY = 600;
+ /// <summary> Time interval in millisecond between device event repeat</summary>
+ public static int DEVICE_REPEAT_INTERVAL = 100;
+ public static float WheelIncrement = 1;
+ /// <summary>Tabulation size in Text controls</summary>
+ public static int TAB_SIZE = 4;
+ [Obsolete]public static string LineBreak = "\n";
+ /// <summary> Allow rendering of interface in development environment </summary>
+ public static bool DesignerMode = false;
+ /// <summary> Disable caching for a widget if this threshold is reached </summary>
+ public const int MaxCacheSize = 2048;
+ /// <summary> Above this count, the layouting is discard from the current
+ /// update cycle and requeued for the next</summary>
+ public static int MaxLayoutingTries = 30;
+ /// <summary> Above this count, the layouting is discard for the widget and it
+ /// will not be rendered on screen </summary>
+ public static int MaxDiscardCount = 5;
+
+ /// <summary>
+ /// Each control need a ref to the root interface containing it, if not set in Widget.currentInterface,
+ /// the ref of this one will be stored in Widget.currentInterface
+ /// </summary>
+ //protected static Interface CurrentInterface;
+ #endregion
+
internal static List<Assembly> crowAssemblies = new List<Assembly> ();
/// <summary>
/// Add Assembly that may contains CROW ui ressources like custom widget classes, IML, images, ...
@@ -78,8 +126,6 @@ namespace Crow
init_internal ();
}
}
- static void nativeHelpMessage () {
- }
static IntPtr resolveUnmanaged(Assembly assembly, String libraryName)
{
try {
@@ -171,33 +217,31 @@ namespace Crow
/// <param name="height">the height of the window</param>
/// <param name="glfwWindowHandle">A valid GLFW window handle</param>
/// <returns></returns>
- public Interface (int width, int height, IntPtr glfwWindowHandle) : this (width, height, false, false)
+ public Interface (int width, int height, IntPtr glfwWindowHandle) : this (width, height, true, false)
{
hWin = glfwWindowHandle;
PerformanceMeasure.InitMeasures ();
}
- IDevice dev;
- public IDevice Device => dev;
-
/// <summary>
/// Create a standard Crow interface.
/// </summary>
/// <param name="width">the width of the native window</param>
/// <param name="height">the height of the native window</param>
- /// <param name="startUIThread">If 'yes' start the ui update (InterfaceThread method) in a dedicated thread</param>
+ /// <param name="singleThreaded">If 'false' start the ui update (InterfaceThread method) in a dedicated thread</param>
/// <param name="createSurface">If 'yes', create the main rendering surface on the native window</param>
- public Interface (int width = 800, int height = 600, bool startUIThread = true, bool createSurface = true)
+ public Interface (int width = 800, int height = 600, bool singleThreaded = false, bool createSurface = true)
{
CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture;
//CurrentInterface = this;
clientRectangle = new Rectangle (0, 0, width, height);
+ SingleThreaded = singleThreaded;
if (createSurface)
initSurface ();
PerformanceMeasure.InitMeasures ();
- if (startUIThread) {
+ if (!SingleThreaded) {
Thread t = new Thread (InterfaceThread) {
IsBackground = true
};
@@ -206,6 +250,57 @@ namespace Crow
}
#endregion
+ #region IDisposable Support
+ private bool disposedValue = false; // To detect redundant calls
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!disposedValue)
+ {
+ if (disposing)
+ {
+ disposeContextMenus ();
+ Backend.Dispose ();
+ }
+
+ currentCursor?.Dispose ();
+
+ if (ownWindow) {
+ Glfw3.DestroyWindow (hWin);
+ Glfw3.Terminate ();
+ }
+
+ disposedValue = true;
+ }
+ }
+ ~Interface() {
+ Dispose(false);
+ }
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+ #endregion
+
+
+ /// <summary>
+ /// Cache already searched extension methods to prevent searching again and again for
+ /// missing method or to speedup loading once a method is found.
+ /// </summary>
+ /// <remarks>
+ /// This cache is reseted when a crow assembly is removed, or the theme is changed.
+ /// </remarks>
+ protected Dictionary<string, MethodInfo> knownExtMethods;
+ /// <summary>
+ /// Cache already searched widget types.
+ /// </summary>
+ /// <remarks>
+ /// This cache is reseted when a crow assembly is removed, or the theme is changed.
+ /// </remarks>
+ protected Dictionary<string, Type> knownCrowWidgetTypes;
+ /// <summary>Client rectangle in the host context</summary>
+ protected Rectangle clientRectangle;
#if MEASURE_TIME
public PerformanceMeasure[] PerfMeasures => PerformanceMeasure.Measures;
#endif
@@ -214,12 +309,77 @@ namespace Crow
static Dictionary<IntPtr, Interface> windows = new Dictionary<IntPtr, Interface> ();
/** GLFW window native pointer and current native handle for mouse cursor */
IntPtr hWin;
+ protected IBackend backend;//backend device
+ /// <summary>Clipping rectangles on the root context</summary>
+ protected IRegion clipping;
+ static string backendDeviceTypeString = "Crow.CairoBackend.Device";
Cursor currentCursor;
bool ownWindow;
/// <summary>
+ /// If `true`, UI updates will be handle in the `Run()` method, so in the main thread of the application along with GLFW events polling.
+ /// If `false`, A dedicated thread will be started for the UI updates.
+ /// </summary>
+ public readonly bool SingleThreaded;
+ /// <summary>
/// Native GLFW window handle bound to this interface.
/// </summary>
public IntPtr WindowHandle => hWin;
+ public IBackend Backend => backend;
+ /// <summary>Main backend surface</summary>
+ public ISurface MainSurface => backend.MainSurface;
+ public IntPtr SurfacePointer {
+ get {
+ lock(UpdateMutex)
+ return MainSurface.Handle;
+ }
+ }
+
+ #region Public Fields
+ /// <summary>Graphic Tree of this interface</summary>
+ public List<Widget> GraphicTree = new List<Widget>();
+ /// <summary>Interface's resulting bitmap</summary>
+ public byte[] bmp;
+ /// <summary>resulting bitmap limited to last redrawn part</summary>
+ public byte[] dirtyBmp;
+ /// <summary>True when host has to repaint Interface</summary>
+ public bool IsDirty;
+ /// <summary>Coordinate of the dirty bmp on the original bmp</summary>
+ public Rectangle DirtyRect;
+ /// <summary>Locked for each layouting operation</summary>
+ public object LayoutMutex = new object();
+ /// <summary>Sync mutex between host and Crow for rendering operations (bmp, dirtyBmp,...)</summary>
+ public object RenderMutex = new object();
+ /// <summary>Global lock of the update cycle</summary>
+ public object UpdateMutex = new object();
+ /// <summary>Global lock of the clipping queue</summary>
+ public object ClippingMutex = new object();
+ //TODO:share resource instances
+ /// <summary>
+ /// Store loaded resources instances shared among controls to reduce memory footprint
+ /// </summary>
+ public Dictionary<string,object> Ressources = new Dictionary<string, object>();
+ /// <summary>The Main layouting queue.</summary>
+ public Queue<LayoutingQueueItem> LayoutingQueue = new Queue<LayoutingQueueItem> (INIT_QUEUE_CAPACITY);
+ /// <summary>Store discarded lqi between two updates</summary>
+ public Queue<LayoutingQueueItem> DiscardQueue;
+ /// <summary>Main drawing queue, holding layouted controls</summary>
+ public Queue<Widget> ClippingQueue = new Queue<Widget>(INIT_QUEUE_CAPACITY);
+ //TODO:use object instead for complex copy paste
+ public string Clipboard {
+ get => Glfw3.GetClipboardString (hWin);
+ set => Glfw3.SetClipboardString (hWin, value);
+ }
+ /// <summary>each IML and fragments (such as inline Templates) are compiled as a Dynamic Method stored here
+ /// on the first instance creation of a IML item.
+ /// </summary>
+ public Dictionary<String, Instantiator> Instantiators;
+ /// <summary>
+ /// Item templates stored with their index
+ /// </summary>
+ public Dictionary<String, ItemTemplate> ItemTemplates;
+
+ public List<CrowThread> CrowThreads = new List<CrowThread>();//used to monitor thread finished
+ #endregion
/// <summary>
/// Register GLFW window callbacs (mouse, keyboard, sizing, refresh).
@@ -240,19 +400,10 @@ namespace Crow
#endif
Glfw3.SetWindowRefreshCallback (hWin, HandleWindowRefreshDelegate);
}
-#if VKVG
- protected VulkanContextBase vkCtx;
- internal Device vkvgDevice => vkCtx.VkvgDevice;
- /// <summary>
- /// Create the VulkanContext with swapchain support. Override it to use another vulkan backend.
- /// </summary>
-#endif
- static string backendDeviceTypeString = "Crow.CairoBackend.Device";
- protected void initBackend (bool offscreen = false) {
-
- dev = new Crow.CairoBackend.Device ();
- clipping = dev.CreateRegion ();
+ protected virtual void initBackend () {
+ backend = new Crow.CairoBackend.ImageBackend (hWin, clientRectangle.Width, clientRectangle.Height);
+ clipping = Backend.CreateRegion ();
}
/// <summary>
/// Create the main rendering surface. The default is a GLFW window with a cairo surface bound to it.
@@ -261,89 +412,24 @@ namespace Crow
{
Glfw3.Init ();
- Glfw3.WindowHint (WindowAttribute.ClientApi, 0);
+ Glfw3.WindowHint (WindowAttribute.ClientApi, Constants.OpenglEsApi);
+ Glfw3.WindowHint (WindowAttribute.ContextVersionMajor, 3);
+ //Glfw3.WindowHint (WindowAttribute.ContextVersionMajor, 0);
+ Glfw3.WindowHint (WindowAttribute.ContextCreationApi, Constants.EglContextApi);
+
Glfw3.WindowHint (WindowAttribute.Resizable, 1);
Glfw3.WindowHint (WindowAttribute.Decorated, 1);
hWin = Glfw3.CreateWindow (clientRectangle.Width, clientRectangle.Height, "win name", MonitorHandle.Zero, IntPtr.Zero);
if (hWin == IntPtr.Zero)
- throw new Exception ("[GLFW3] Unable to create vulkan Window");
+ throw new Exception ("[GLFW3] Unable to create Window");
ownWindow = true;
registerGlfwCallbacks ();
initBackend ();
-
- CreateMainSurface (ref clientRectangle);
- }
- /// <summary>
- /// ??
- /// </summary>
- /// <param name="r"></param>
- public void CreateMainSurface (ref Rectangle r) {
- surf?.Dispose();
- surf = Device.CreateSurface (hWin, r.Width, r.Height);
- }
- public IntPtr SurfacePointer {
- get {
- lock(UpdateMutex)
- return surf.Handle;
- }
- }
- /// <summary>
- /// Set the main GLFW window icon.
- /// </summary>
- /// <param name="path"></param>
- public void SetWindowIcon (string path) {
- using (Stream stream = GetStreamFromPath (path)) {
-#if STB_SHARP
- StbImageSharp.ImageResult stbi = StbImageSharp.ImageResult.FromStream (stream, StbImageSharp.ColorComponents.RedGreenBlueAlpha);
- byte[] image = new byte[stbi.Data.Length];
- //rgba to argb for cairo.
- for (int i = 0; i < stbi.Data.Length; i += 4) {
- image[i] = stbi.Data[i + 2];
- image[i + 1] = stbi.Data[i + 1];
- image[i + 2] = stbi.Data[i];
- image[i + 3] = stbi.Data[i + 3];
- }
- Glfw.Image icon = new Glfw.Image ((uint)stbi.Width, (uint)stbi.Height, image);
- Glfw3.SetWindowIcon (hWin, 1, ref icon);
- icon.Dispose();
-
-#else
- using (StbImage stbi = new StbImage (stream)) {
- byte[] image = new byte [stbi.Size];
- //rgba to argb for cairo.
- for (int i = 0; i < stbi.Size; i+=4) {
- image [i] = Marshal.ReadByte (stbi.Handle, i + 2);
- image [i + 1] = Marshal.ReadByte (stbi.Handle, i + 1);
- image [i + 2] = Marshal.ReadByte (stbi.Handle, i);
- image [i + 3] = Marshal.ReadByte (stbi.Handle, i + 3);
- }
- Glfw.Image icon = new Glfw.Image ((uint)stbi.Width, (uint)stbi.Height, image);
- Glfw3.SetWindowIcon (hWin, 1, ref icon);
- icon.Dispose();
- }
-#endif
- }
}
/// <summary>
- /// Cache already searched extension methods to prevent searching again and again for
- /// missing method or to speedup loading once a method is found.
- /// </summary>
- /// <remarks>
- /// This cache is reseted when a crow assembly is removed, or the theme is changed.
- /// </remarks>
- protected Dictionary<string, MethodInfo> knownExtMethods;
- /// <summary>
- /// Cache already searched widget types.
- /// </summary>
- /// <remarks>
- /// This cache is reseted when a crow assembly is removed, or the theme is changed.
- /// </remarks>
- protected Dictionary<string, Type> knownCrowWidgetTypes;
-
- /// <summary>
/// search for graphic object type in crow assembly, if not found,
/// search for type independently of namespace in all the loaded assemblies
/// </summary>
@@ -403,17 +489,34 @@ namespace Crow
return mi;
}
- #region events delegates
+ #region Events
+ //public event EventHandler<MouseCursorChangedEventArgs> MouseCursorChanged;
+ ////public event EventHandler Quit;
+ public event EventHandler Initialized;
+ public event EventHandler StartDragOperation;
+ public event EventHandler EndDragOperation;
+ public event EventHandler<KeyEventArgs> KeyDown;
+ public event EventHandler<KeyEventArgs> KeyUp;
+
+ //public event EventHandler<MouseWheelEventArgs> MouseWheelChanged;
+ //public event EventHandler<MouseButtonEventArgs> MouseButtonUp;
+ //public event EventHandler<MouseButtonEventArgs> MouseButtonDown;
+ //public event EventHandler<MouseButtonEventArgs> MouseClick;
+ //public event EventHandler<MouseMoveEventArgs> MouseMove;
+ //public event EventHandler<KeyEventArgs> KeyDown;
+ //public event EventHandler<KeyPressEventArgs> KeyPress;
+ /*public event EventHandler<KeyEventArgs> KeyboardKeyDown;
+ public event EventHandler<KeyEventArgs> KeyboardKeyUp;*/
+ #region events delegates
static CursorPosDelegate HandleCursorPosDelegate = (window, xPosition, yPosition) => {
- windows [window].OnMouseMove ((int)(xPosition / windows [window].ZoomFactor), (int)(yPosition / windows [window].ZoomFactor));
+ windows [window].OnMouseMove ((int)(xPosition), (int)(yPosition));
};
static MouseButtonDelegate HandleMouseButtonDelegate = (IntPtr window, MouseButton button, InputAction action, Modifier mods) => {
if (action == InputAction.Release)
windows [window].OnMouseButtonUp (button);
else//press and repeat
windows [window].OnMouseButtonDown (button);
-
};
static ScrollDelegate HandleScrollDelegate = (IntPtr window, double xOffset, double yOffset) => {
windows [window].OnMouseWheelChanged ((int)yOffset);
@@ -438,24 +541,53 @@ namespace Crow
static WindowDelegate HandleWindowRefreshDelegate = (IntPtr window) => {
windows [window].registerRefreshClientRectangle ();
};
-
+ #endregion
#endregion
public string WindowTitle {
set => Glfw3.SetWindowTitle (hWin, value);
}
+ /// <summary>
+ /// Set the main GLFW window icon.
+ /// </summary>
+ /// <param name="path"></param>
+ public void SetWindowIcon (string path) {
+ using (Stream stream = GetStreamFromPath (path)) {
+#if STB_SHARP
+ StbImageSharp.ImageResult stbi = StbImageSharp.ImageResult.FromStream (stream, StbImageSharp.ColorComponents.RedGreenBlueAlpha);
+ byte[] image = new byte[stbi.Data.Length];
+ //rgba to argb for cairo.
+ for (int i = 0; i < stbi.Data.Length; i += 4) {
+ image[i] = stbi.Data[i + 2];
+ image[i + 1] = stbi.Data[i + 1];
+ image[i + 2] = stbi.Data[i];
+ image[i + 3] = stbi.Data[i + 3];
+ }
+ Glfw.Image icon = new Glfw.Image ((uint)stbi.Width, (uint)stbi.Height, image);
+ Glfw3.SetWindowIcon (hWin, 1, ref icon);
+ icon.Dispose();
+#else
+ using (StbImage stbi = new StbImage (stream)) {
+ byte[] image = new byte [stbi.Size];
+ //rgba to argb for cairo.
+ for (int i = 0; i < stbi.Size; i+=4) {
+ image [i] = Marshal.ReadByte (stbi.Handle, i + 2);
+ image [i + 1] = Marshal.ReadByte (stbi.Handle, i + 1);
+ image [i + 2] = Marshal.ReadByte (stbi.Handle, i);
+ image [i + 3] = Marshal.ReadByte (stbi.Handle, i + 3);
+ }
+ Glfw.Image icon = new Glfw.Image ((uint)stbi.Width, (uint)stbi.Height, image);
+ Glfw3.SetWindowIcon (hWin, 1, ref icon);
+ icon.Dispose();
+ }
+#endif
+ }
+ }
public bool Running {
get => !Glfw3.WindowShouldClose (hWin);
set => Glfw3.SetWindowShouldClose (hWin, value == true ? 0 : 1);
}
- public virtual void InterfaceThread ()
- {
- while (!Glfw3.WindowShouldClose (hWin)) {
- Update ();
- Thread.Sleep (UPDATE_INTERVAL);
- }
- }
protected virtual void OnInitialized ()
{
/*try {
@@ -484,29 +616,38 @@ namespace Crow
loadThemeFiles ();
initContextMenus ();
}
+ public virtual void InterfaceThread ()
+ {
+ while (!Glfw3.WindowShouldClose (hWin)) {
+ Update ();
+ Thread.Sleep (UPDATE_INTERVAL);
+ }
+ }
/// <summary>
/// call Init() then enter the running loop performing ProcessEvents until running==false.
/// </summary>
public virtual void Run () {
Init ();
- while (!Glfw3.WindowShouldClose (hWin)) {
- Glfw3.PollEvents ();
- UpdateFrame ();
+ if (SingleThreaded) {
+ while (!Glfw3.WindowShouldClose (WindowHandle)) {
+ Glfw3.PollEvents ();
+ Update();
+ UpdateFrame ();
+ Thread.Sleep (UPDATE_INTERVAL);
+ }
+ } else {
+ while (!Glfw3.WindowShouldClose (hWin)) {
+ Glfw3.PollEvents ();
+ UpdateFrame ();
+ Thread.Sleep (POLLING_INTERVAL);
+ }
}
Terminate ();
}
public virtual void Terminate () {}
- public virtual void UpdateFrame () {
-#if VKVG
- Update ();
- Thread.Sleep (UPDATE_INTERVAL);
-#else
- Thread.Sleep (POLLING_INTERVAL);
-#endif
- }
-
+ public virtual void UpdateFrame () {}
public virtual void Quit () => Glfw3.SetWindowShouldClose (hWin, 1);
public bool Shift => Glfw3.GetKey(hWin, Key.LeftShift) == InputAction.Press ||
@@ -532,164 +673,18 @@ namespace Crow
}
#endif
- #region IDisposable Support
- private bool disposedValue = false; // To detect redundant calls
-
- protected virtual void Dispose(bool disposing)
- {
- if (!disposedValue)
- {
- if (disposing)
- {
- disposeContextMenus ();
- dev.Dispose ();
- }
-
- currentCursor?.Dispose ();
-
- if (ownWindow) {
- Glfw3.DestroyWindow (hWin);
- Glfw3.Terminate ();
- }
-
- disposedValue = true;
- }
- }
- ~Interface() {
- Dispose(false);
- }
-
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
- #endregion
-
- #region Static and constants
- //initial capacity for layouting and clipping queues.
- const int INIT_QUEUE_CAPACITY = 512;
- /// <summary>Time interval in milisecond between Updates of the interface</summary>
- public static int UPDATE_INTERVAL = 5;
- /// <summary>
- /// Time interval in milisecond between Glfw polling for devices. Wait is done in
- /// the 'UpdateFrame' method in the 'Run' cycle and may be overriden.
- /// </summary>
- public static int POLLING_INTERVAL = 1;
- /// <summary>Crow configuration root path</summary>
- public static string CROW_CONFIG_ROOT;
- /// <summary>If true, mouse focus is given when mouse is over control</summary>
- public static bool FOCUS_ON_HOVER = false;
- /// <summary>If true, newly focused window will be put on top</summary>
- public static bool RAISE_WIN_ON_FOCUS = true;
- /// <summary> Threshold to catch borders for sizing </summary>
- public static int BorderThreshold = 3;
- /// <summary> delay before tooltip appears </summary>
- public static int TOOLTIP_DELAY = 500;
- /// <summary>Double click threshold in milisecond</summary>
- public static int DOUBLECLICK_TRESHOLD = 320;//max duration between two mouse_down evt for a dbl clk in milisec.
- /// <summary> Time to wait in millisecond before starting repeat loop</summary>
- public static int DEVICE_REPEAT_DELAY = 600;
- /// <summary> Time interval in millisecond between device event repeat</summary>
- public static int DEVICE_REPEAT_INTERVAL = 100;
- public static float WheelIncrement = 1;
- /// <summary>Tabulation size in Text controls</summary>
- public static int TAB_SIZE = 4;
- [Obsolete]public static string LineBreak = "\n";
- /// <summary> Allow rendering of interface in development environment </summary>
- public static bool DesignerMode = false;
- /// <summary> Disable caching for a widget if this threshold is reached </summary>
- public const int MaxCacheSize = 2048;
- /// <summary> Above this count, the layouting is discard from the current
- /// update cycle and requeued for the next</summary>
- public static int MaxLayoutingTries = 30;
- /// <summary> Above this count, the layouting is discard for the widget and it
- /// will not be rendered on screen </summary>
- public static int MaxDiscardCount = 5;
-
- /// <summary>
- /// Each control need a ref to the root interface containing it, if not set in Widget.currentInterface,
- /// the ref of this one will be stored in Widget.currentInterface
- /// </summary>
- //protected static Interface CurrentInterface;
- #endregion
- #region Events
- //public event EventHandler<MouseCursorChangedEventArgs> MouseCursorChanged;
- ////public event EventHandler Quit;
- public event EventHandler Initialized;
- public event EventHandler StartDragOperation;
- public event EventHandler EndDragOperation;
- public event EventHandler<KeyEventArgs> KeyDown;
- public event EventHandler<KeyEventArgs> KeyUp;
- //public event EventHandler<MouseWheelEventArgs> MouseWheelChanged;
- //public event EventHandler<MouseButtonEventArgs> MouseButtonUp;
- //public event EventHandler<MouseButtonEventArgs> MouseButtonDown;
- //public event EventHandler<MouseButtonEventArgs> MouseClick;
- //public event EventHandler<MouseMoveEventArgs> MouseMove;
- //public event EventHandler<KeyEventArgs> KeyDown;
- //public event EventHandler<KeyPressEventArgs> KeyPress;
- /*public event EventHandler<KeyEventArgs> KeyboardKeyDown;
- public event EventHandler<KeyEventArgs> KeyboardKeyUp;*/
- #endregion
- /// <summary>Main backend surface</summary>
- public ISurface surf;
- #region Public Fields
- /// <summary>Graphic Tree of this interface</summary>
- public List<Widget> GraphicTree = new List<Widget>();
- /// <summary>Interface's resulting bitmap</summary>
- public byte[] bmp;
- /// <summary>resulting bitmap limited to last redrawn part</summary>
- public byte[] dirtyBmp;
- /// <summary>True when host has to repaint Interface</summary>
- public bool IsDirty;
- /// <summary>Coordinate of the dirty bmp on the original bmp</summary>
- public Rectangle DirtyRect;
- /// <summary>Locked for each layouting operation</summary>
- public object LayoutMutex = new object();
- /// <summary>Sync mutex between host and Crow for rendering operations (bmp, dirtyBmp,...)</summary>
- public object RenderMutex = new object();
- /// <summary>Global lock of the update cycle</summary>
- public object UpdateMutex = new object();
- /// <summary>Global lock of the clipping queue</summary>
- public object ClippingMutex = new object();
- //TODO:share resource instances
- /// <summary>
- /// Store loaded resources instances shared among controls to reduce memory footprint
- /// </summary>
- public Dictionary<string,object> Ressources = new Dictionary<string, object>();
- /// <summary>The Main layouting queue.</summary>
- public Queue<LayoutingQueueItem> LayoutingQueue = new Queue<LayoutingQueueItem> (INIT_QUEUE_CAPACITY);
- /// <summary>Store discarded lqi between two updates</summary>
- public Queue<LayoutingQueueItem> DiscardQueue;
- /// <summary>Main drawing queue, holding layouted controls</summary>
- public Queue<Widget> ClippingQueue = new Queue<Widget>(INIT_QUEUE_CAPACITY);
- //TODO:use object instead for complex copy paste
- public string Clipboard {
- get => Glfw3.GetClipboardString (hWin);
- set => Glfw3.SetClipboardString (hWin, value);
- }
- /// <summary>each IML and fragments (such as inline Templates) are compiled as a Dynamic Method stored here
- /// on the first instance creation of a IML item.
- /// </summary>
- public Dictionary<String, Instantiator> Instantiators;
- /// <summary>
- /// Item templates stored with their index
- /// </summary>
- public Dictionary<String, ItemTemplate> ItemTemplates;
- public List<CrowThread> CrowThreads = new List<CrowThread>();//used to monitor thread finished
+ #region DragAndDrop
public bool DragAndDropInProgress => DragAndDropOperation != null;
public Widget DropTarget => DragAndDropOperation?.DropTarget;
-
public DragDropEventArgs DragAndDropOperation = null;
internal Widget dragndropHover;
-
public ISurface DragImage = null;
public Rectangle DragImageBounds, lastDragImageBounds;
public bool DragImageFolowMouse;//prevent dragImg to be moved by mouse
@@ -715,15 +710,6 @@ namespace Crow
}
#endregion
- #region Private Fields
- /// <summary>Client rectangle in the host context</summary>
- protected Rectangle clientRectangle;
- /// <summary>Clipping rectangles on the root context</summary>
- IRegion clipping;
- /// <summary>Main Cairo context</summary>
- //Context ctx;
- #endregion
-
#region Default values and Style loading
/// Default values of properties from Widgets are retrieve from XML Attributes.
/// The reflexion process used to retrieve those values being very slow, it is compiled in MSIL
@@ -816,10 +802,10 @@ namespace Crow
string resId = $"#{pic.Substring (path.Length + 1).Replace (Path.DirectorySeparatorChar, '.')}";
using (Stream s = new FileStream (pic, FileMode.Open, FileAccess.Read)) {
if (resId.EndsWith (".svg", StringComparison.OrdinalIgnoreCase)) {
- ISvgHandle hSVG = Device.LoadSvg (s);
+ ISvgHandle hSVG = Backend.LoadSvg (s);
sharedPictures[resId] = new sharedPicture (hSVG, hSVG.Dimensions);
} else {
- byte[] image = Device.LoadBitmap (s, out Size dimensions);
+ byte[] image = Backend.LoadBitmap (s, out Size dimensions);
sharedPictures[resId] = new sharedPicture (image, dimensions);
}
}
@@ -1151,11 +1137,9 @@ namespace Crow
}
if (!clipping.IsEmpty || shouldDrawTextCursor) {
- if (ctx == null) {
- using (ctx = Device.CreateContext (surf))
- processDrawing (ctx);
- }else
- processDrawing (ctx);
+ ctx = Backend.PrepareUIFrame (ctx, clipping);
+ processDrawing (ctx);
+ Backend.FlushUIFrame (ctx);
}
} finally {
@@ -1217,40 +1201,7 @@ namespace Crow
PerformanceMeasure.End (PerformanceMeasure.Kind.Clipping);
DbgLogger.EndEvent (DbgEvtType.ClippingRegistration, true);
}
- void clear(IContext ctx) {
- for (int i = 0; i < clipping.NumRectangles; i++)
- ctx.Rectangle (clipping.GetRectangle (i));
- ctx.ClipPreserve ();
- ctx.Operator = Operator.Clear;
- ctx.Fill ();
- ctx.Operator = Operator.Over;
- }
- bool solidBackground = false;
- public bool SolidBackground {
- get => solidBackground;
- set {
- if (Environment.OSVersion.Platform == PlatformID.Unix)
- solidBackground = value;
- else
- Debug.WriteLine ("SolidBackground property only available on unix.");
- }
- }
- double zoomFactor = 1.0;
- public double ZoomFactor {
- get => zoomFactor;
- set {
- if (zoomFactor == value)
- return;
- zoomFactor = value;
- NotifyValueChanged (zoomFactor);
- lock (UpdateMutex) {
- foreach (Widget g in GraphicTree)
- g.RegisterForLayouting (LayoutingType.All);
- registerRefreshClientRectangle ();
- }
- }
- }
/// <summary>Clipping Rectangles drive the drawing process. For compositing, each object under a clip rectangle should be
/// repainted. If it contains also clip rectangles, its cache will be update, or if not cached a full redraw will take place</summary>
@@ -1258,18 +1209,8 @@ namespace Crow
DbgLogger.StartEvent (DbgEvtType.ProcessDrawing);
PerformanceMeasure.Begin (PerformanceMeasure.Kind.Drawing);
- if (!clipping.IsEmpty) {
- ctx.Scale (zoomFactor,zoomFactor);
-
-#if VKVG
- clear (ctx);
-#else
- ctx.PushGroup ();
-
- if (SolidBackground)
- clear (ctx);
-#endif
+ if (!clipping.IsEmpty) {
for (int i = GraphicTree.Count -1; i >= 0 ; i--){
Widget p = GraphicTree[i];
if (!p.IsVisible)
@@ -1282,7 +1223,6 @@ namespace Crow
ctx.Restore ();
}
-
if (lastDragImageBounds != DragImageBounds) {
DirtyRect += lastDragImageBounds;
ctx.Save ();
@@ -1304,28 +1244,13 @@ namespace Crow
#endif
-#if VKVG
- ctx.Flush();
-#else
- ctx.PopGroupToSource ();
-
- if (!SolidBackground)
- clear (ctx);
-
- ctx.Paint ();
-
- surf.Flush ();
-#endif
-
clipping.Reset ();
PerformanceMeasure.End (PerformanceMeasure.Kind.Drawing);
IsDirty = true;
}
-#if !VKVG
drawTextCursor (ctx);
-#endif
debugHighlightFocus (ctx);
@@ -1354,7 +1279,7 @@ namespace Crow
/*if (DragAndDropInProgress) {
}*/
- surf.Flush ();
+ MainSurface.Flush ();
}
#region Blinking text cursor
@@ -1372,7 +1297,7 @@ namespace Crow
if (textCursor != null && c != textCursor.Value)
RegisterClip (textCursor.Value);
textCursor = c;
- surf.Flush ();
+ MainSurface.Flush ();
} else if (textCursor != null)
RegisterClip (textCursor.Value);
}
@@ -1386,7 +1311,7 @@ namespace Crow
if (blinkingCursor.ElapsedMilliseconds > TEXT_CURSOR_BLINK_FREQUENCY) {
if (lab.DrawCursor (ctx, out Rectangle c)) {
textCursor = c;
- surf.Flush ();
+ MainSurface.Flush ();
blinkingCursor.Restart ();
}
}
@@ -1506,7 +1431,7 @@ namespace Crow
public virtual void ProcessResize(Rectangle bounds){
lock (UpdateMutex) {
clientRectangle = bounds;
- surf.Resize (clientRectangle.Width, clientRectangle.Height);
+ MainSurface.Resize (clientRectangle.Width, clientRectangle.Height);
foreach (Widget g in GraphicTree)
g.RegisterForLayouting (LayoutingType.All);
@@ -1514,7 +1439,7 @@ namespace Crow
}
}
- internal void registerRefreshClientRectangle () => RegisterClip (clientRectangle);
+ protected void registerRefreshClientRectangle () => RegisterClip (clientRectangle);
#region Mouse and Keyboard Handling
MouseCursor cursor = MouseCursor.top_left_arrow;
@@ -1646,7 +1571,7 @@ namespace Crow
/// Ask OS to force the mouse position to the actual coordinate of Interface.MousePosition
/// </summary>
public virtual void ForceMousePosition () {
- Glfw3.SetCursorPosition (hWin, MousePosition.X * ZoomFactor, MousePosition.Y * ZoomFactor);
+ Glfw3.SetCursorPosition (hWin, MousePosition.X, MousePosition.Y);
}
/// <summary>Processes mouse move events from the root container, this function
@@ -2123,7 +2048,7 @@ namespace Crow
set { throw new NotImplementedException (); }
}
- public Rectangle ClientRectangle => clientRectangle.Scaled (1.0/zoomFactor);
+ public Rectangle ClientRectangle => clientRectangle;
public Rectangle GetClientRectangleForChild (ILayoutable child) => ClientRectangle;
public Interface HostContainer => this;
diff --git a/Crow/src/Widgets/DockWindow.cs b/Crow/src/Widgets/DockWindow.cs
index 6c6c49f9..620d31f3 100644
--- a/Crow/src/Widgets/DockWindow.cs
+++ b/Crow/src/Widgets/DockWindow.cs
@@ -200,8 +200,8 @@ namespace Crow
r.Inflate (r.Width / -3, r.Height / -3);
break;
}
- ISurface dragImg = IFace.Device.CreateSurface (r.Width, r.Height);
- using (IContext gr = IFace.Device.CreateContext (dragImg)) {
+ ISurface dragImg = IFace.Backend.CreateSurface (r.Width, r.Height);
+ using (IContext gr = IFace.Backend.CreateContext (dragImg)) {
gr.LineWidth = 1;
gr.Rectangle (0,0,r.Width,r.Height);
gr.SetSource (0.2,0.3,0.9,0.5);
diff --git a/Crow/src/Widgets/GroupBase.cs b/Crow/src/Widgets/GroupBase.cs
index 1f62eb90..e99b176e 100644
--- a/Crow/src/Widgets/GroupBase.cs
+++ b/Crow/src/Widgets/GroupBase.cs
@@ -251,7 +251,7 @@ namespace Crow
{
DbgLogger.StartEvent(DbgEvtType.GOUpdateCache, this);
if (!Clipping.IsEmpty) {
- using (IContext gr = IFace.Device.CreateContext (bmp)) {
+ using (IContext gr = IFace.Backend.CreateContext (bmp)) {
for (int i = 0; i < Clipping.NumRectangles; i++)
gr.Rectangle(Clipping.GetRectangle(i));
gr.ClipPreserve();
diff --git a/Crow/src/Widgets/Label.cs b/Crow/src/Widgets/Label.cs
index 5ef09523..330cbe55 100644
--- a/Crow/src/Widgets/Label.cs
+++ b/Crow/src/Widgets/Label.cs
@@ -514,7 +514,7 @@ namespace Crow
int hoverLine = _multiline ?
(int)Math.Min (Math.Max (0, Math.Floor (mouseLocalPos.Y / (fe.Ascent + fe.Descent))), lines.Count - 1) : 0;
hoverLoc = new CharLocation (hoverLine, -1, mouseLocalPos.X);
- using (IContext gr = IFace.Device.CreateContext (IFace.surf)) {
+ using (IContext gr = IFace.Backend.CreateContext (IFace.MainSurface)) {
gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
gr.SetFontSize (Font.Size);
updateLocation (gr, ClientRectangle.Width, ref hoverLoc);
@@ -650,7 +650,7 @@ namespace Crow
getLines ();
if (!textMeasureIsUpToDate) {
- using (IContext gr = IFace.Device.CreateContext (IFace.surf)) {
+ using (IContext gr = IFace.Backend.CreateContext (IFace.MainSurface)) {
gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
gr.SetFontSize (Font.Size);
measureTextBounds (gr);
diff --git a/Crow/src/Widgets/PrivateContainer.cs b/Crow/src/Widgets/PrivateContainer.cs
index 3b705ea5..f5345523 100644
--- a/Crow/src/Widgets/PrivateContainer.cs
+++ b/Crow/src/Widgets/PrivateContainer.cs
@@ -215,7 +215,7 @@ namespace Crow
Rectangle rb = Slot + Parent.ClientRectangle.Position;
if (!Clipping.IsEmpty) {
- using (IContext gr = IFace.Device.CreateContext (bmp)) {
+ using (IContext gr = IFace.Backend.CreateContext (bmp)) {
for (int i = 0; i < Clipping.NumRectangles; i++)
gr.Rectangle(Clipping.GetRectangle(i));
gr.ClipPreserve();
diff --git a/Crow/src/Widgets/ScrollingStack.cs b/Crow/src/Widgets/ScrollingStack.cs
index c67bf7d1..55535ded 100644
--- a/Crow/src/Widgets/ScrollingStack.cs
+++ b/Crow/src/Widgets/ScrollingStack.cs
@@ -136,7 +136,7 @@ namespace Crow {
{
DbgLogger.StartEvent(DbgEvtType.GOUpdateCache, this);
if (!Clipping.IsEmpty) {
- using (IContext gr = IFace.Device.CreateContext (bmp)) {
+ using (IContext gr = IFace.Backend.CreateContext (bmp)) {
for (int i = 0; i < Clipping.NumRectangles; i++)
gr.Rectangle(Clipping.GetRectangle(i));
gr.ClipPreserve();
diff --git a/Crow/src/Widgets/Shape.cs b/Crow/src/Widgets/Shape.cs
index efa8b45b..8322543e 100644
--- a/Crow/src/Widgets/Shape.cs
+++ b/Crow/src/Widgets/Shape.cs
@@ -242,7 +242,7 @@ namespace Crow
if (size != default (Size))
contentSize = size;
else {
- using (IContext ctx = IFace.Device.CreateContext (IFace.surf)) {
+ using (IContext ctx = IFace.Backend.CreateContext (IFace.MainSurface)) {
using (PathParser parser = new PathParser (path))
parser.Draw (ctx, true);
Rectangle r = ctx.StrokeExtents ();
diff --git a/Crow/src/Widgets/Widget.cs b/Crow/src/Widgets/Widget.cs
index 57b65aab..5d3e4c45 100644
--- a/Crow/src/Widgets/Widget.cs
+++ b/Crow/src/Widgets/Widget.cs
@@ -1168,7 +1168,7 @@ namespace Crow
{
DbgLogger.StartEvent (DbgEvtType.GOInitialization, this);
- Clipping = IFace.Device.CreateRegion ();
+ Clipping = IFace.Backend.CreateRegion ();
Type thisType = this.GetType ();
if (!string.IsNullOrEmpty (style)) {
@@ -1954,12 +1954,13 @@ namespace Crow
else if (LastPaintedSlot.Width != Slot.Width || LastPaintedSlot.Height != Slot.Height)
bmp.SetSize (Slot.Width, Slot.Height);*/
bmp?.Dispose ();
- bmp = IFace.Device.CreateSurface (Slot.Width, Slot.Height);
+ //bmp = IFace.Device.CreateSurface (Slot.Width, Slot.Height);
+ bmp = IFace.Backend.CreateSurface (Slot.Width, Slot.Height);
//bmp = new ImageSurface(Format.Argb32, Slot.Width, Slot.Height);
DbgLogger.StartEvent (DbgEvtType.GOCreateContext, this);
- using (IContext gr = IFace.Device.CreateContext (bmp)) {
+ using (IContext gr = IFace.Backend.CreateContext (bmp)) {
DbgLogger.EndEvent (DbgEvtType.GOCreateContext);
onDraw (gr);
}
diff --git a/Drawing2D/src/Enums.cs b/Drawing2D/src/Enums.cs
index 12a6f035..bf20a432 100644
--- a/Drawing2D/src/Enums.cs
+++ b/Drawing2D/src/Enums.cs
@@ -6,6 +6,12 @@ using System;
namespace Drawing2D
{
+ public enum BackendType {
+ Native,
+ OpenGL,
+ EGL,
+ Vulkan
+ }
public enum Status
{
Success = 0,
diff --git a/Drawing2D/src/IBackend.cs b/Drawing2D/src/IBackend.cs
new file mode 100644
index 00000000..811b95d5
--- /dev/null
+++ b/Drawing2D/src/IBackend.cs
@@ -0,0 +1,37 @@
+// Copyright (c) 2018-2021 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using System.IO;
+
+namespace Drawing2D
+{
+ public interface IBackend: IDisposable
+ {
+ ISurface CreateSurface (int width, int height);
+ ISurface CreateSurface (byte[] data, int width, int height);
+ //ISurface CreateMainSurface (IntPtr glfwWinHandle, int width, int height);
+ ISurface MainSurface { get; }
+ IRegion CreateRegion ();
+ IContext CreateContext (ISurface surf);
+ //IPattern CreatePattern (PatternType patternType);
+ IGradient CreateGradient (GradientType gradientType, Rectangle bounds);
+ byte[] LoadBitmap (Stream stream, out Size dimensions);
+ ISvgHandle LoadSvg (Stream stream);
+ ISvgHandle LoadSvg (string svgFragment);
+ IContext PrepareUIFrame (IContext existingContext, IRegion clipping);
+ void FlushUIFrame (IContext ctx);
+ /*IRegion CreateRegion ();
+ ISurface CreateSurface (int width, int height);
+ ISurface CreateSurface (byte[] data, int width, int height);
+ ISurface CreateSurface (IntPtr glfwWinHandle, int width, int height);
+ IContext CreateContext (ISurface surf);
+ //IPattern CreatePattern (PatternType patternType);
+ IGradient CreateGradient (GradientType gradientType, Rectangle bounds);
+ byte[] LoadBitmap (Stream stream, out Size dimensions);
+ ISvgHandle LoadSvg (Stream stream);
+ ISvgHandle LoadSvg (string svgFragment);*/
+ }
+}
+
diff --git a/Drawing2D/src/IDevice.cs b/Drawing2D/src/IDevice.cs
index 891f8b2e..14846271 100644
--- a/Drawing2D/src/IDevice.cs
+++ b/Drawing2D/src/IDevice.cs
@@ -13,16 +13,6 @@ namespace Drawing2D
void GetDpy (out int hdpy, out int vdpy);
void SetDpy (int hdpy, int vdpy);
- IRegion CreateRegion ();
- ISurface CreateSurface (int width, int height);
- ISurface CreateSurface (byte[] data, int width, int height);
- ISurface CreateSurface (IntPtr glfwWinHandle, int width, int height);
- IContext CreateContext (ISurface surf);
- //IPattern CreatePattern (PatternType patternType);
- IGradient CreateGradient (GradientType gradientType, Rectangle bounds);
- byte[] LoadBitmap (Stream stream, out Size dimensions);
- ISvgHandle LoadSvg (Stream stream);
- ISvgHandle LoadSvg (string svgFragment);
}
}
diff --git a/Samples/HelloWorld/main.cs b/Samples/HelloWorld/main.cs
index e60b9782..e84607b9 100644
--- a/Samples/HelloWorld/main.cs
+++ b/Samples/HelloWorld/main.cs
@@ -1,13 +1,15 @@
using System;
using Crow;
+using Glfw;
using Samples;
namespace HelloWorld
{
- class Program {
+ class Program : Interface {
+ Program() : base (800, 600, true, true) {}
static void Main (string[] args) {
- using (Interface app = new Interface ()) {
- app.Initialized += (sender, e) => app.LoadIMLFragment (@"<Label Text='Hello World'/>");
+ using (Program app = new Program ()) {
+ app.Initialized += (sender, e) => app.LoadIMLFragment (@"<Window Caption='Hello World'/>");
app.Run ();
}
}
diff --git a/Samples/PerfTests/Program.cs b/Samples/PerfTests/Program.cs
index d7f6a9be..cbe62738 100644
--- a/Samples/PerfTests/Program.cs
+++ b/Samples/PerfTests/Program.cs
@@ -64,7 +64,7 @@ namespace PerfTests
}
public TestInterface (string[] args, int width = 800, int height = 600)
- : base (width, height, false, false)
+ : base (width, height, true, false)
{
string outDir = null;
@@ -141,15 +141,10 @@ namespace PerfTests
writer.WriteLine ("Path;MinEllapsed;MaxEllapsed;MeanEllapsed;MedianEllapsed;sigmaEllapsed;MinMem;MaxMem;MeanMem;MedianMem;sigmaMem;MinAlloc;MaxAlloc;MeanAlloc;MedianAlloc;sigmaAlloc");
}
- if (screenOutput) {
- initBackend ();
+ if (screenOutput)
initSurface ();
- } else {
- SolidBackground = false;
- initBackend (true);
-
- CreateMainSurface (ref clientRectangle);
- }
+ else
+ initBackend ();
initDictionaries ();
loadStyling ();
@@ -163,6 +158,15 @@ namespace PerfTests
outStream.Dispose ();
}
}
+ protected override void initBackend()
+ {
+ if (screenOutput)
+ backend = new Crow.CairoBackend.ImageBackend (WindowHandle, clientRectangle.Width, clientRectangle.Height);
+ else
+ backend = new Crow.CairoBackend.ImageBackend (clientRectangle.Width, clientRectangle.Height);
+
+ clipping = Backend.CreateRegion ();
+ }
struct Measures
{
diff --git a/Samples/common/src/SampleBase.cs b/Samples/common/src/SampleBase.cs
index 2d773af4..2e7440a1 100644
--- a/Samples/common/src/SampleBase.cs
+++ b/Samples/common/src/SampleBase.cs
@@ -20,11 +20,6 @@ namespace Samples
{
public SampleBase(IntPtr hWin) : base(800, 600, hWin) { }
public SampleBase() : base(800, 600, true, true) { }
- public SampleBase(int width, int height, bool startUIThread, bool createSurface) :
- base(width, height, startUIThread, createSurface)
- {
-
- }
public Version CrowVersion => Assembly.GetAssembly(typeof(Widget)).GetName().Version;