Giter Site home page Giter Site logo

Basic sample about squid HOT 93 CLOSED

roderik11 avatar roderik11 commented on May 17, 2024
Basic sample

from squid.

Comments (93)

shmutalov avatar shmutalov commented on May 17, 2024 5

Omg! That comments better than docs! :3

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

Thank you Gutemberg!
I think you're really close. DrawBox is only used in certain circumstances - you really want to monitor the DrawTexture (or GetTextureSize) call instead. Don't see anything wrong in that snippet.
Follow the DrawTexture call. Let me know what happens.

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

Oh, be aware the textures used in the standard skin are not part of the repository.
But once you catch it calling renderer.DrawTexture we can work from there.

PS:

  • make sure you call desktop.Update (before you draw)

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

Ok no success... None of the methods are ever called on the renderer except Scissor which is called with all parameters == 0.

This is our Renderer implementation:

public class PIRenderer : IRenderer
    {
        IDeviceGraphicsDriver _driver;
        SKSurface _surface;
        SKCanvas _canvas;

        public PIRenderer(IDeviceGraphicsDriver driver)
        {
            if (driver == null)
                throw new ArgumentNullException(nameof(driver));

            _driver = driver;

            var imgInfo = new SKImageInfo(_driver.ScreenWidth, _driver.ScreenHeight, SKColorType.Rgb_565, SKAlphaType.Unpremul);
            _surface = SKSurface.Create(imgInfo, _driver.FBPointer, imgInfo.RowBytes);
            _canvas = _surface.Canvas;
            if (_driver.RotateDegrees > 0)
            {
                _canvas.RotateDegrees(_driver.RotateDegrees);
                _canvas.Translate(0, -_driver.ScreenWidth);
            }
            _canvas.Clear(SKColors.Black);
        }

        public void DrawBox(int x, int y, int width, int height, int color)
        {
            using (var paint = new SKPaint())
            {
                paint.Color = SKColors.Red;//new SKColor((uint)color);
                paint.StrokeCap = SKStrokeCap.Round;
                paint.IsAntialias = true;
                var rect = SKRect.Create(x, y, width, height);
                _canvas.DrawRect(rect, paint);
            }
        }

        public void DrawText(string text, int x, int y, int size, string font, int color)
        {
            using (var paint = new SKPaint())
            {
                paint.TextSize = size;
                paint.IsAntialias = true;
                paint.Color = new SKColor((uint)color);
                paint.IsStroke = false;
                paint.Typeface = SKTypeface.FromFile(font, 0);

                _canvas.DrawText(text, x, y, paint);
            }
        }

        public void DrawImage(string image, int x, int y, int width, int height, Rectangle source, int color)
        {
            using (var fileStream = File.OpenRead(image))
            using (var stream = new SKManagedStream(fileStream))
            using (var bitmap = SKBitmap.Decode(stream))
            using (var paint = new SKPaint())
            {
                _canvas.DrawBitmap(bitmap, new SKRect(source.Left, source.Top, source.Right, source.Bottom), SKRect.Create(x, y, width, height), paint);
            }
        }

        public Point GetTextSize(string text, string font)
        {
            using (var fontFace = SKTypeface.FromFile(font))
            using (var paint = new SKPaint())
            {
                paint.Typeface = fontFace;
                var rect = new SKRect();
                paint.MeasureText(text, ref rect);
                return new Point((int)rect.Left, (int)rect.Top);
            }            
        }

        public Point GetImageSize(string image)
        {
            using(var fileStream = File.OpenRead(image))
            using (var stream = new SKManagedStream(fileStream))
            using (var bitmap = SKBitmap.Decode(stream))
            {
                return new Point(bitmap.Width, bitmap.Height);
            }
        }

        public void Scissor(int x, int y, int width, int height)
        {
            _canvas.ClipRect(SKRect.Create(x, y, width, height));
        }

        public void StartBatch()
        {
        }

        public void EndBatch(bool final)
        {
        }

        public void Dispose()
        {
            _canvas.Dispose();
            _surface.Dispose();
        }
    }

Also note that some methods where changed from your implementation for instance GetImageSize() to receive a string instead of a int so we can call directly the image from its name since idk the reason to have an int for it as you probably do.

Also, as you can see on the snippet, we are just adding a label with some text and no images are involved yet, so I would assume that DrawImage will never be called.

What am I missing?

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

make sure you call desktop.Update (before draw)

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

image
And that is why it isn't being renderer... The ClipRect has its sizes set to 0 so we will never get it pass from that if... I don't saw where we set it...

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

A few comments on the renderer implementation. You will end up wanting to cache as much as you can. GetTexture/Size etc should only do IO once and cache for lookup using a dictionary/hashtable.
The UI will call these methods every frame, so you really want to cache all the textures/fonts.

Let me know if desktop.Update did anything for you.

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024
System.MissingMethodException: Method 'Array.Empty' not found.
  at PI.SDK.UI.Core.Label.OnLateUpdate () [0x0007d] in c:\users\gutemberg\documents\visual studio 2015\Projects\PI.SDK-vNext\src\PI.SDK.UI.Core\Controls\Label.cs:707 
  at PI.SDK.UI.Core.Control.PerformLateUpdate () [0x00001] in c:\users\gutemberg\documents\visual studio 2015\Projects\PI.SDK-vNext\src\PI.SDK.UI.Core\Controls\Control.cs:2342 
  at PI.SDK.UI.Core.Control.PerformLateUpdate () [0x0004e] in c:\users\gutemberg\documents\visual studio 2015\Projects\PI.SDK-vNext\src\PI.SDK.UI.Core\Controls\Control.cs:2351 
  at PI.SDK.UI.Core.Control.PerformLateUpdate () [0x0000c] in c:\users\gutemberg\documents\visual studio 2015\Projects\PI.SDK-vNext\src\PI.SDK.UI.Core\Controls\Control.cs:2345 
  at PI.SDK.UI.Core.Desktop.Update () [0x00508] in c:\users\gutemberg\documents\visual studio 2015\Projects\PI.SDK-vNext\src\PI.SDK.UI.Core\Controls\Desktop.cs:529 
  at PI.SDK.Prolin.Playground.Program.Main (System.String[] args) [0x0013a] in C:\Users\Gutemberg\Documents\Visual Studio 2015\Projects\PI.SDK-vNext\src\PI.SDK.Prolin.Playground\Program.cs:40 

That is the exception while calling desktop.Update();

Re images, now I understand... Will revert that back and make a cache of it... The device has a very limited memory footprint so we try avoid cache in memory...

Re the batch on Renderer, we don't use batch cause it is tied directly to the device framebuffer so each pixel draw on it thru Skia apis is painted on the device screen.

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

Leaving the Start/Batch calls empty if every other call is immediate should be completely fine, but you will need to respect the scissor rectangle in the DrawBox/Texture/Text calls then.

I can't quite follow that stack trace; it almost looks like the desktop is being disposed when you're trying to update it. The lines it points to just use the protected collection Control.Elements.

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

The desktop should be in a scope where it's not getting garbage collected (unless you want it to).
What kind of device are you running on btw? I wonder if there's already some heap corruption happening.

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

Yeah forget about the last exception. The test project was set to .net 4.6.1 while the supported .net framework by Mono on the target device is 4.5.1. Now it is calling the methods from the PIRenderer however, nothing is draw yet cause of the textsize calculations... Don't know if they are correct at the renderer... Also, I don't see how to set font of the text :( That is probably the reason why it is getting size 0...

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

Regarding the device this is it:
img_1796

A payment terminal... We embedded Mono on it and made Skia work as our rendering backend...

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

That is badass, i love it.

Ok now that the interface is being called, lets get the rest done.

The flow is

  • int GetFont(string name) <- load your font, cache it, return a unique integer (across fonts)
  • GetTextSize(string text, int font) <- the id that you assigned above. lookup cache, measure.
  • DrawText(.... int font, int color) <- same id from above. use your cache

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

Re "I don't see how to set font of the text"

Just to get a result, load any font in GetFont().
The font is defined via styles - and the name passed to GetFont is the font name you defined in the style. (if there is none its "default"). Basically the font names are arbitrary and defined by you ;)

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

Here's a sample renderer using MonoGame:

namespace Sample_MonoGame
{
public class GuiRenderer : Squid.ISquidRenderer
{
private Dictionary<int, SpriteFont> FontById = new Dictionary<int, SpriteFont>();
private Dictionary<int, Texture2D> TextureById = new Dictionary<int, Texture2D>();
private Dictionary<string, int> FontIdByName = new Dictionary<string, int>();
private Dictionary<string, int> TextureIdByName = new Dictionary<string, int>();

    private Game Game;
    private SpriteBatch Batch;
    private Texture2D WhiteTexture;
    private RasterizerState Rasterizer;
    private string DefaultFont = "Arial10";

    int tempId;
    SpriteFont tempFont;
    Texture2D tempTex;

    public GuiRenderer(Game game)
    {
        Game = game;
        Batch = new SpriteBatch(game.GraphicsDevice);

        WhiteTexture = new Texture2D(Game.GraphicsDevice, 1, 1);
        WhiteTexture.SetData<Color>(new Color[] { new Color(255, 255, 255, 255) });

        Rasterizer = new RasterizerState();
        Rasterizer.ScissorTestEnable = true;
    }

    private Color ColorFromtInt32(int color)
    {
        Byte[] bytes = BitConverter.GetBytes(color);
        return new Color(bytes[2], bytes[1], bytes[0], bytes[3]);
    }

    public int GetTexture(string name)
    {
        if (TextureIdByName.TryGetValue(name, out tempId))
            return tempId;

        Texture2D texture = Game.Content.Load<Texture2D>(System.IO.Path.ChangeExtension(name, null));
        int index = TextureIdByName.Count;

        TextureIdByName.Add(name, index);
        TextureById.Add(index, texture);

        return index;
    }

    public int GetFont(string name)
    {
        if (name == "default") name = DefaultFont;

        if (FontIdByName.TryGetValue(name, out tempId))
            return tempId;

        SpriteFont font = Game.Content.Load<SpriteFont>(name);
        int index = FontIdByName.Count;

        FontIdByName.Add(name, index);
        FontById.Add(index, font);

        return index;
    }

    public Squid.Point GetTextSize(string text, int font)
    {
        if (string.IsNullOrEmpty(text)) return Squid.Point.Zero;

        if (!FontById.TryGetValue(font, out tempFont))
            return Squid.Point.Zero;

        Vector2 size = tempFont.MeasureString(text);
        return new Squid.Point((int)size.X, (int)size.Y);
    }

    public Squid.Point GetTextureSize(int texture)
    {
        if (TextureById.TryGetValue(texture, out tempTex))
            return new Squid.Point(tempTex.Width, tempTex.Height);

        return Squid.Point.Zero;
    }

    public void DrawBox(int x, int y, int w, int h, int color)
    {
        Batch.Draw(WhiteTexture, new Rectangle(x, y, w, h), ColorFromtInt32(color));
    }

    public void DrawText(string text, int x, int y, int font, int color)
    {
        if (FontById.TryGetValue(font, out tempFont))
            Batch.DrawString(tempFont, text, new Vector2(x, y), ColorFromtInt32(color));
    }

    public void DrawTexture(int texture, int x, int y, int w, int h, Squid.Rectangle rect, int color)
    {
        if (TextureById.TryGetValue(texture, out tempTex))
            Batch.Draw(tempTex, new Rectangle(x, y, w, h), new Rectangle(rect.Left, rect.Top, rect.Width, rect.Height), ColorFromtInt32(color), 0, Vector2.Zero, SpriteEffects.None, 0);
    }

    public void Scissor(int x, int y, int w, int h)
    {
        Game.GraphicsDevice.ScissorRectangle = new Rectangle(x, y, w, h);
    }

    public void StartBatch()
    {
        Batch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, null, Rasterizer, null);
    }

    public void EndBatch(bool final)
    {
        Batch.End();
    }

    public void Dispose() { }
}

}

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

Ok, thanks for the sample!

New render implementation based on your sample and reverting back to the original interface (with the id/cache):

public class PIRenderer : IRenderer
    {
        IDictionary<int, SKTypeface> _fontById = new Dictionary<int, SKTypeface>();
        IDictionary<int, SKBitmap> _bitmapById = new Dictionary<int, SKBitmap>();
        IDictionary<string, int> _fontIdByName = new Dictionary<string, int>();
        IDictionary<string, int> _bitmapIdByName = new Dictionary<string, int>();

        IDeviceGraphicsDriver _driver;
        SKSurface _surface;
        SKCanvas _canvas;
        int _tempId;
        SKTypeface _tempFont;
        SKBitmap _tempBmp;

        public PIRenderer(IDeviceGraphicsDriver driver)
        {
            if (driver == null)
                throw new ArgumentNullException(nameof(driver));

            _driver = driver;
            //TODO: Move those parameters to the ctor
            var imgInfo = new SKImageInfo(_driver.ScreenWidth, _driver.ScreenHeight, SKColorType.Rgb_565, SKAlphaType.Unpremul);
            _surface = SKSurface.Create(imgInfo, _driver.FBPointer, imgInfo.RowBytes);
            _canvas = _surface.Canvas;
            if (_driver.RotateDegrees > 0)
            {
                _canvas.RotateDegrees(_driver.RotateDegrees);
                _canvas.Translate(0, -_driver.ScreenWidth);
            }
            _canvas.Clear(SKColors.LightGray);
        }

        private SKColor ColorFromtInt32(int color)
        {
            Byte[] bytes = BitConverter.GetBytes(color);
            return new SKColor(bytes[2], bytes[1], bytes[0], bytes[3]);
        }

        public int GetTexture(string name)
        {
            if (_bitmapIdByName.TryGetValue(name, out _tempId))
                return _tempId;

            using (var fileStream = File.OpenRead(name))
            using (var stream = new SKManagedStream(fileStream))
            {
                var bitmap = SKBitmap.Decode(stream);
                int index = _bitmapIdByName.Count;

                _bitmapIdByName.Add(name, index);
                _bitmapById.Add(index, bitmap);

                return index;
            }
        }

        public int GetFont(string name)
        {
            if (string.IsNullOrWhiteSpace(name) || name == "default")
                throw new ArgumentNullException(nameof(name));

            if (_fontIdByName.TryGetValue(name, out _tempId))
                return _tempId;

            var font = SKTypeface.FromFile(name);
            int index = _fontIdByName.Count;

            _fontIdByName.Add(name, index);
            _fontById.Add(index, font);

            return index;
        }

        public Point GetTextSize(string text, int font)
        {
            if (string.IsNullOrEmpty(text)) return Point.Zero;

            if (!_fontById.TryGetValue(font, out _tempFont))
                return Point.Zero;

            using (var paint = new SKPaint())
            {
                paint.IsStroke = false;
                paint.Typeface = _tempFont;
                var bounds = new SKRect();
                var s = paint.MeasureText(text, ref bounds);
                return new Point((int)bounds.Bottom, (int)bounds.Right);
            }
        }

        public Point GetTextureSize(int texture)
        {
            if (_bitmapById.TryGetValue(texture, out _tempBmp))
                return new Point(_tempBmp.Width, _tempBmp.Height);

            return Point.Zero;
        }

        public void DrawBox(int x, int y, int width, int height, int color)
        {
            using (var paint = new SKPaint())
            {
                paint.Color = ColorFromtInt32(color);
                paint.StrokeCap = SKStrokeCap.Round;
                paint.IsAntialias = true;
                var rect = SKRect.Create(x, y, width, height);
                _canvas.DrawRect(rect, paint);
            }
        }

        public void DrawText(string text, int x, int y, int font, int color)
        {
            if (!_fontById.TryGetValue(font, out _tempFont))
                return;

            using (var paint = new SKPaint())
            {
                //TODO: How to get that font size?
                //paint.TextSize = size;
                paint.IsAntialias = true;
                paint.Color = ColorFromtInt32(color);
                paint.IsStroke = false;
                paint.Typeface = _tempFont;

                _canvas.DrawText(text, x, y, paint);
            }
        }

        public void DrawTexture(int texture, int x, int y, int width, int height, Rectangle source, int color)
        {
            if (!_bitmapById.TryGetValue(texture, out _tempBmp))
                return;

            using (var paint = new SKPaint())
            {
                _canvas.DrawBitmap(_tempBmp, new SKRect(source.Left, source.Top, source.Right, source.Bottom), SKRect.Create(x, y, width, height), paint);
            }
        }

        public void Scissor(int x, int y, int width, int height)
        {
            _canvas.ClipRect(SKRect.Create(x, y, width, height));
        }

        public void StartBatch()
        {
        }

        public void EndBatch(bool final)
        {
        }

        public void Dispose()
        {
            _canvas.Dispose();
            _surface.Dispose();
        }
    }

and this is my sample:

 var width = 320;
            var height = 240;
            var gfx = new FramebufferDeviceDriver("/dev/fb", width, height, (width * height * 16) >> 3, 90);
            Gui.Renderer = new PIRenderer(gfx);  
            var desktop = new Desktop();
            desktop.Size = new Point(240, 320);
            desktop.ModalColor = ColorInt.RGB(0, 0, 200);
            desktop.Visible = true;
            var aStyle = new Style { Font = "LaoUI.ttf" };
            aStyle.TextColor = ColorInt.RGB(200, 0, 0);

            desktop.Skin["test"] = new ControlStyle(aStyle);

            var window = new Window();
            window.Name = "home";
            window.Size = new Point(240, 320);
            var label = new Label();
            label.Name = "lblText";
            label.Text = "Testing Skia on new GUI!!!";
            label.Position = new Point(0, 20);
            label.Size = new Point(20, 20);
            label.TextColor = ColorInt.RGB(200, 0, 0);
            label.Style = "test";
            window.Controls.Add(label);
            window.Show(desktop);
            desktop.Update();
            desktop.Draw();

Note that I set some Style there just for the sake of test... Nothing renders and I noticed 2 things:

  1. When DrawText() is called, it comes with x = 0 and y = -36... Don't know where those values come from.
  2. Inside DrawText() I need set the font size in order to draw text on Skia... What is the correct way to get that value from your APIs?

I think we are close :D

Thanks!

PS: If you are on gitter you can ping me @galvesribeiro or at Skype with same alias.

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024
  1. You're not loading a valid font. The incoming "name" parameter is not a filename, but a string you define (in a style). You look up the filename using that string (or for testing, just load a font you know exists and dont care about the name param).
  2. Explained by 1.

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

I usually build a lookup table string-to-fontDefifnition using any abritratry struct/class.
There even is one in Squid still (but unused).

/// <summary>
/// Helper class to represent a font.
/// This class will eventually be obsolete. Do not use.
/// </summary>
[Obsolete]
public class Font
{
    public static readonly string Default = "default";

    public string Name { get; set; }
    public string Family { get; set; }

    public bool Bold { get; set; }
    public bool Italic { get; set; }
    public bool Underlined { get; set; }
    public bool International { get; set; }

    public int Size { get; set; }
}

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

Ok sorry, on second read i saw you are already using the style correctly.
Perhaps there's a path issue when loading the font? That would explain why the measure isnt working.

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

This looks wrong:

var s = paint.MeasureText(text, ref bounds);
return new Point((int)bounds.Bottom, (int)bounds.Right);

The point returned must be width, height

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

The struct from Skia is:

[StructLayout(LayoutKind.Sequential)]
    public struct SKRect {
        public float Left, Top, Right, Bottom;
        public SKRect (float left, float top, float right, float bottom)
        {
            Left = left;
            Right = right;
            Top = top;
            Bottom = bottom;
        }
}

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

Ok got it to render! 💃

The problem is that now I have on DrawText() the TextSize hardcoded...

   public void DrawText(string text, int x, int y, int font, int color)
        {
            if (!_fontById.TryGetValue(font, out _tempFont))
                return;

            using (var paint = new SKPaint())
            {
                **//TODO: How to get that font size?
                paint.TextSize = 64;**
                paint.IsAntialias = true;
                paint.Color = ColorFromtInt32(color);
                paint.IsStroke = false;
                paint.Typeface = _tempFont;

                _canvas.DrawText(text, x, y, paint);
            }
        }

So how to get that value?

Thanks!

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

Look up your own font definition.
The size is directly tied to the name of your chosing.

Example:
var style = ....
style.Font = "myFont1;

Somewhere else you define what "myFont1" means, what font file, what size etc.
And in DrawText you look up font name by id, and its properties.

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

Perhaps its easier to understand when i say:
There is a single size for each font id you define.
Thats why DrawText does not have a size parameter.
What a fontId entails is entirely up to you and defined unkown to squid. Squid only cares about what GetTextSize returns.

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

No no, the font is a truetype file. So there is the font definition like for example "LaoUI.ttf". This is the font file and I can use the same font for a text of size 10 like one of size 50. This is what the TextSize property means... We have to get it from somewhere...

Ok so the flow is:

int GetFont() <- load your font, cache it, return a unique integer (across fonts)
GetTextSize(string text, int font) <- the id that you assigned above. lookup cache, measure.
----> GetTextSize get the size like width and height of the text for a given font type but, it doesn't know about the font size number the user wants to use when drawing the string.
DrawText(.... int font, int color) <- same id from above. use your cache
-----> Ok I got that it will use same font already cached but, there is no way to specify the font size number here

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

"but, it doesn't know about the font size number the user wants to use when drawing the string."

  • the font size is defined by you when you create the font. Squid was developed with bitmap fonts in mind which cant be scaled dynamically without special rendering using distance fields. So 1 fontId = 1 font size, pre-determined when the font is created.

So there could be font names like:

"myFont1", id 0 = arial, 8px, bold
"myFont2", id 1 = verdana, 10px, italic

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

In GetTextSize you want to check your cache for the given FontId and find its size, which you determined when the font was created in GetFont. So you may need a small data wrapper class/struct for that.

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

I got it... So I'll need to have probably same truetype font loaded on multiple "font" structure as u suggested and embbed the font size into the name somehow otherwise, I would need to change Skia to not use the size which is unthinkable as Chrome and other zillion projects use it that way...

Now let me try draw images and other controls...

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

Hm you're overthinking it :)

  1. create a FontInfo struct. name/filename/size/bold etc
  2. in your ctor, build a lookup table of fontName-to-fontInfo
  3. in GetFont, load the font file using your FontInfo
  4. in GetTextSize/DrawText, again, lookup your FontInfo and measure with the size defined there

Yes, for different sizes you will need different font names, but there's no magic required in the renderer implementation, just one layer of indirection.

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

ok I understood that part however, on the struct I need to keep the actual SkFont object and not just the filename otherwise, I would have to lookup on it each frame as you mentioned before...

Talking about frame, since we are not in a game, assuming that we have a RenderLoop just like we have in a game engine, I need to always call both desktop.Update() followed by desktop.Draw() and internally if nothing changes, it will not redraw anything... In other words, it deals with partial rendering of just what was changed, right?

Thanks

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

No it will redraw everything. Squid doesnt maintain an internal pixel buffer.
A dirty-rect system usually ends up being more complex and slower than simple and clever batching.
Depending on the engine, you should try to batch as much as possible, avoid texture changes (texture atlas) and reduce geometry overhead (e.g. pointlist vertex buffer expanded in geometry shader).
Not knowing what API you're using down there i don't have much advice - yet :)

Yes, you call Update/Draw like in a typical render loop.

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

Its not a game. It is a simple ARM linux device for payment processing(the one on the picture I just posted) that exposes to me a linux framebuffer at /dev/fb which I already have mapped on my FramebufferDeviceDriver which pass into our render implementation, the PIRenderer. The renderer implementation uses Google Skia 2d graphics library which in turns draws directly to the framebuffer and prints directly to the device display. This device has a keyboard and a touchscreen.

I'm using your library now as the core UI Library for the device. It proofed here be REALLY fast and will save me a lot of time.

I noticed that while doing a test loop like:

window.Show(desktop);
            int i = 0;
            while (true)
            {
                i++;
                desktop.Update();
                desktop.Draw();
                Console.WriteLine(i);
            }

It was REALLY fast however, note on following pictures what happened with the font:

img_1816
This was the first call to Update()/Draw()

img_1815
And now in the loop, it got thicker each time the loop past...

Any reason for that?

I think the full redraw isn't going to be a problem... Noticed very minimal memory consumption and CPU from your code. Congratz! :)

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

I think you just need to clear the frame buffer.
There should be some method to clear the canvas, just call that every frame.

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

Clear() will literally clear the screen since it is cleaning the device framebuffer which means that the screen will be cleared and that caused this text over there to flick :(

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

Every frame you need to clear the frame buffer and then draw on top.
Flicker sounds like you're seeing the empty frame buffer, which shouldnt be the case if the call order is correct. But then again, i don't know how Skia works exactly. There's also canvas.flush and discard.

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

OK... I got the flick problem solved by creating some double buffering strategy here. Worked perfect and I now use your EndBatch :) Thanks for the tip.

So, the last thing that I need to understand is the Input systems. I have some classes which listen to the OS touch and/or Keyboard input and than fire an event... Where can I pass that information like for example the coordinates of a touch/click or a key press?

Thanks!

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

@Roderik11 ?

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

Here's a sample input manager (slimDX):

namespace Sample_SlimDX
{
public class KeyboardBuffer : Dictionary<int, bool> { }

public class InputManager : GameComponent
{
    [DllImport("user32.dll")]
    private static extern int GetKeyboardLayout(int dwLayout);
    [DllImport("user32.dll")]
    private static extern int GetKeyboardState(ref byte pbKeyState);
    [DllImport("user32.dll", EntryPoint = "MapVirtualKeyEx")]
    private static extern int MapVirtualKeyExA(int uCode, int uMapType, int dwhkl);
    [DllImport("user32.dll")]
    private static extern int ToAsciiEx(int uVirtKey, int uScanCode, ref byte lpKeyState, ref short lpChar, int uFlags, int dwhkl);

    private int KeyboardLayout;
    private byte[] KeyStates;

    private int Wheel;
    private int LastWheel;
    private KeyboardBuffer Buffer = new KeyboardBuffer();
    private bool[] Buttons = new bool[4];
    private static Dictionary<System.Windows.Forms.Keys, int> SpecialKeys = new Dictionary<System.Windows.Forms.Keys, int>();

    public InputManager(Game game)
        : base(game)
    {
        KeyStates = new byte[0x100];
        KeyboardLayout = GetKeyboardLayout(0);

        SpecialKeys.Add(System.Windows.Forms.Keys.Home, 0xC7);
        SpecialKeys.Add(System.Windows.Forms.Keys.Up, 0xC8);
        SpecialKeys.Add(System.Windows.Forms.Keys.Left, 0xCB);
        SpecialKeys.Add(System.Windows.Forms.Keys.Right, 0xCD);
        SpecialKeys.Add(System.Windows.Forms.Keys.End, 0xCF);
        SpecialKeys.Add(System.Windows.Forms.Keys.Down, 0xD0);
        SpecialKeys.Add(System.Windows.Forms.Keys.Insert, 0xD2);
        SpecialKeys.Add(System.Windows.Forms.Keys.Delete, 0xD3);
        SpecialKeys.Add(System.Windows.Forms.Keys.MediaPreviousTrack, 0x90);

        Device.RegisterDevice(UsagePage.Generic, UsageId.Keyboard, DeviceFlags.None);
        Device.RegisterDevice(UsagePage.Generic, UsageId.Mouse, DeviceFlags.None);

        Device.KeyboardInput += new EventHandler<KeyboardInputEventArgs>(Device_KeyboardInput);
        Device.MouseInput += new EventHandler<MouseInputEventArgs>(Device_MouseInput);
    }

    public char? ScancodeToChar(int code)
    {
        short lpChar = 0;
        if (GetKeyboardState(ref KeyStates[0]) == 0)
            return null;

        int result = ToAsciiEx(MapVirtualKeyExA(code, 1, KeyboardLayout), code, ref KeyStates[0], ref lpChar, 0, KeyboardLayout);
        if (result == 1)
        {
            return (char?)((ushort)lpChar);
        }

        return null;
    }

    void Device_MouseInput(object sender, MouseInputEventArgs e)
    {
        switch (e.ButtonFlags)
        {
            case MouseButtonFlags.MouseWheel:
                Wheel = e.WheelDelta > 500 ? 1 : (e.WheelDelta < 500 ? -1 : 0);
                break;
            case MouseButtonFlags.LeftDown:
                Buttons[0] = true;
                break;
            case MouseButtonFlags.LeftUp:
                Buttons[0] = false;
                break;
            case MouseButtonFlags.RightDown:
                Buttons[1] = true;
                break;
            case MouseButtonFlags.RightUp:
                Buttons[1] = false;
                break;
        }
    }

    void Device_KeyboardInput(object sender, KeyboardInputEventArgs e)
    {
        if (e.State == KeyState.Pressed || e.State == KeyState.Released)
        {
            int code = e.MakeCode;

            if (SpecialKeys.ContainsKey(e.Key))
                code = SpecialKeys[e.Key];

            if (!Buffer.ContainsKey(code))
                Buffer.Add(code, e.State == KeyState.Pressed);
        }
    }

    public override void Update(GameTime time)
    {
        List<KeyData> data = new List<KeyData>();
        char c = new char();

        foreach (int key in Buffer.Keys)
            data.Add(new KeyData { Pressed = Buffer[key], Released = !Buffer[key], Scancode = key, Char = ScancodeToChar(key) });

        Buffer.Clear();

        System.Drawing.Point p = Game.Form.PointToClient(System.Windows.Forms.Cursor.Position);

        Gui.SetMouse(p.X, p.Y, Wheel);
        Gui.SetButtons(Buttons);
        Gui.SetKeyboard(data.ToArray());
        Gui.TimeElapsed = Game.ElapsedMilliseconds;
        Wheel = 0;
    }
}

}

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

Ok thanks for the sample...

I end up with this:

public class InputManager
    {
        private IDictionary<Keys, Core.Keys> _keyMap = new Dictionary<Keys, Core.Keys>();
        private IList<KeyData> _keyEventBuffer = new List<KeyData>();
        private IKeyboardDeviceDriver _keyboard;

        public InputManager(IKeyboardDeviceDriver keyboardDriver)
        {
            MapKeys();
            _keyboard = keyboardDriver;
            _keyboard.KeyPressed += keyboard_KeyPressed;
            _keyboard.KeyReleased += keyboard_KeyReleased;            
        }

        private void MapKeys()
        {
            _keyMap.Add(Keys.Cancel, Core.Keys.ESCAPE);
            _keyMap.Add(Keys.Clear, Core.Keys.BACKSPACE);
            _keyMap.Add(Keys.Dot, Core.Keys.PERIOD);
            _keyMap.Add(Keys.Down, Core.Keys.DOWNARROW);
            _keyMap.Add(Keys.Enter, Core.Keys.RETURN);
            _keyMap.Add(Keys.F1, Core.Keys.F1);
            _keyMap.Add(Keys.F2, Core.Keys.F2);
            _keyMap.Add(Keys.F3, Core.Keys.F3);
            _keyMap.Add(Keys.F4, Core.Keys.F4);
            _keyMap.Add(Keys.Left, Core.Keys.LEFTARROW);
            _keyMap.Add(Keys.Num0, Core.Keys.NUMPAD0);
            _keyMap.Add(Keys.Num1, Core.Keys.NUMPAD1);
            _keyMap.Add(Keys.Num2, Core.Keys.NUMPAD2);
            _keyMap.Add(Keys.Num3, Core.Keys.NUMPAD3);
            _keyMap.Add(Keys.Num4, Core.Keys.NUMPAD4);
            _keyMap.Add(Keys.Num5, Core.Keys.NUMPAD5);
            _keyMap.Add(Keys.Num6, Core.Keys.NUMPAD6);
            _keyMap.Add(Keys.Num7, Core.Keys.NUMPAD7);
            _keyMap.Add(Keys.Num8, Core.Keys.NUMPAD8);
            _keyMap.Add(Keys.Num9, Core.Keys.NUMPAD9);
            _keyMap.Add(Keys.Ok, Core.Keys.RETURN);
            _keyMap.Add(Keys.Power, Core.Keys.POWER);
            _keyMap.Add(Keys.Right, Core.Keys.RIGHTARROW);
            _keyMap.Add(Keys.Shift, Core.Keys.LEFTSHIFT);
            _keyMap.Add(Keys.Up, Core.Keys.UPARROW);
        }

        private void keyboard_KeyReleased(Keys key)
        {
            HandleKeyboardEvent(key, false);
        }

        private void keyboard_KeyPressed(Keys key)
        {
            HandleKeyboardEvent(key, true);
        }

        private void HandleKeyboardEvent(Keys key, bool pressed)
        {
            Core.Keys uiKey;
            if (!_keyMap.TryGetValue(key, out uiKey))
                return;

            _keyEventBuffer.Add(new KeyData { Released = pressed, Scancode = (int)uiKey, Char = KeyToChar(uiKey) });
        }

        private char? KeyToChar(Core.Keys key)
        {
            switch (key)
            {
                case Core.Keys.NUMPAD0:
                    return '0';
                case Core.Keys.NUMPAD1:
                    return '1';
                case Core.Keys.NUMPAD2:
                    return '2';
                case Core.Keys.NUMPAD3:
                    return '3';
                case Core.Keys.NUMPAD4:
                    return '4';
                case Core.Keys.NUMPAD5:
                    return '5';
                case Core.Keys.NUMPAD6:
                    return '6';
                case Core.Keys.NUMPAD7:
                    return '7';
                case Core.Keys.NUMPAD8:
                    return '8';
                case Core.Keys.NUMPAD9:
                    return '9';
                default:
                    return null;
            }
        }

        public void Update()
        {
            if (_keyEventBuffer.Count > 0) 
            {
                Gui.SetKeyboard(_keyEventBuffer.ToArray());
                _keyEventBuffer.Clear();
            }
        }
    }

The KeyReleases/Pressed events from the _keyboard(our driver from the native keyboard) gets fired as usual, the KeyData is added to the _keyEventBuffer and Update() is called just fine however nothing happens...

The loop now changed to this:

while (true)
{
        InputManager.Update();
        desktop.Update();
        desktop.Draw();
}

And on the window class I have this:

public class DemoWindow : Window
    {
        public DemoWindow()
        {
            var image = new ImageControl();
            image.Texture = "Media/home.png";
            image.Position = new Point(0, 0);
            image.Size = new Point(320, 240);
            Controls.Add(image);

            var label = new TextBox();
            label.Name = "lblText";
            label.Text = "Testing Skia on new GUI!!!";
            label.Position = new Point(0, 20);
            label.Size = new Point(100, 100);
            label.TextColor = ColorInt.RGB(200, 0, 0);
            label.Style = "test";
            Controls.Add(label);
            var button = new Button();
            button.Text = "Click me!";
            button.Style = "test";
            button.Size = new Point(100, 100);
            button.Position = new Point(0, 100);
            Controls.Add(button);
        }
        protected override void OnKeyUp(KeyEventArgs args)
        {
            Console.WriteLine($"UP {args.Key}");
        }

        protected override void OnKeyDown(KeyEventArgs args)
        {
            Console.WriteLine($"Down {args.Key}");
        }
    }

Am I missing something?

Thanks

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

By nothing happens I mean, both OnKeyUp and Down overrides on window are never called...

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

Key events only fire on controls that can be focused (Windows dont grab focus be default).

Try something like this instead:

textbox.KeyDown += (sender, args) { Console.WriteLine($"UP {args.Key}"); };

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

Ok, i just realized you dont have a mouse pointer...

  1. set window.AllowFocus = true;
  2. call window.Focus();
  3. now OnKeyUp/Down should be called

or

  1. textbox.Focus()
  2. textbox.KeyDown/Up listeners fire

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

It should be called on every frame? or can I call once in the Window ctor? Its not calling none of both options... :(

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

You only need to focus the textbox once, but after everything is on the desktop; after the window ctor and window.show

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

Make sure you always do SetKeyboard, even if the array is empty

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024
    public override void Show(Desktop target)
    {
        base.Show(target);

        textbox.Focus();
    }

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

Nice! Now it is working! 💃 Thanks!

Other thing I noticed... I tried to load an image by using ImageControl on that same window ctor:

var image = new ImageControl();
image.Texture = "Media/home.png";
image.Position = new Point(0, 0);
image.Size = new Point(320, 240);
Controls.Add(image);

The image isn't appear.. Is there a common way to set background images and/or color for the window and/or the control?
Thanks

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

Completely sure the path to the image is correct?
The ImageControl does nothing if the textureId is negative:

From ImageControl:

        int texture = Gui.Renderer.GetTexture(Texture);
        if (texture < 0) return;

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

For styling look at: http://www.ionstar.org/?page_id=576

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

OHH nice! There are some docs :)

So, followed that and understood the idea behind the objects...

Now get this:

public DemoWindow()
        {
            var image = new ImageControl();
            image.Texture = "Media/home.png";
            image.Position = new Point(0, 0);
            image.Size = new Point(240, 320);
            Controls.Add(image);

            txtBox = new TextBox();
            txtBox.Name = "lblText";
            txtBox.Text = "";
            txtBox.Position = new Point(0, 20);
            txtBox.Size = new Point(240, 40);
            txtBox.TextColor = ColorInt.RGB(200, 0, 0);
            txtBox.Style = "test";
            txtBox.AllowFocus = false;
            Controls.Add(txtBox);

            var button = new Button();
            button.Text = "Click me!";
            button.Style = "test";
            button.Size = new Point(100, 100);
            button.Position = new Point(0, 100);
            button.TextColor = ColorInt.RGB(200, 0, 0);
            button.MouseClick += ClickHandler;
            Controls.Add(button);
        }

When a window loose focus for instance cause a click happened on a button, the OnKeyUP/Down() stops being fired. Ok understood. Need set focus on it again.

So, looking at this ctor, do you know why the button never appear on the screen? the image and textbox are there just fine but the button doesn't. If I click/touch on its area the MouseClick is fired just fine... It just got rendered never...

Also a question about windowing... As per documentation, the Desktop class is the shell of the application and there I call window.Shot(desktop) in order to start rendering a window... My question is, if at some point I create a second window and call show() on that, what is the behaviour with the previous window? Does it get disposed? I want to make sure of the window lifecycle while I'm building the navigation system here...

Again thank you very much for that! This UI framework is awesome! 👯

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

When you show a new window, the other window is not affected.
You decide when to show/close/dispose anything (window.show/close are just methods around desktop.controls.add/remove).

I would have to see the "test" style. My hunch is there's simply nothing to draw.

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

By the way, .TextColor is only used if .UseTextColor=true, else style.TextColor is used.

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024
  var aStyle = new Style { Font = "LaoUI.ttf" };
            aStyle.TextColor = ColorInt.RGB(200, 0, 0);
            aStyle.BackColor = ColorInt.RGB(0, 255, 0);
            desktop.Skin["test"] = new ControlStyle(aStyle);

This is the only style we have here...

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

You're omitting the color alpha component :)
Use ColorInt.ARGB !

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

Perhaps there's something with the DrawBox implementation (called when the style has a BackColor).

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

Weird thing is, the TextBox which uses the same style, is rendered correctly and with the green background...

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

Hmm ok that is weird. I dont see anything wrong.
Just an idea, set window.Scissor = false, perhaps its the scissor test :) (aka button is out of window bounds)

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

In the ctor or somewhere else?

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

Ctor or anywhere else; or just dont clip in renderer.Scissor()

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

Yeah, commented the Clip and it appear... What is the side-effect of remove that?

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

Well the side effect is that nothing gets clipped anymore - this was just for testing if the button gets clipped, you really want it enabled :)

Looking at the Skia docs briefly, i wonder what that clipRect method does.
It says "rect:: The rect to combine with the current clip".
You dont want to combine, you want to set a clip rect.

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

The problem is with that particular button... the clipping for all the rest is OK...

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

Clip works for any other cases... I was talking with Skia guys and it is clipping text, rectangles, everything... I can't disagree with them since the other the image and the textbox which comes before the button on the sample I pasted here are draw correctly and only this button doesn't.

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

There's nothing wrong with the button :)
Pretty sure the canvas.ClipRect function needs another parameter for the combine operation.
The problem is that after the TextBox the clip isnt reset back to the window bounds.
To test this, just dont add the textbox to the control and your button will show up.

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

Ok so, what exactly should I ask for the Skia people? They said it is clipping perfectly as well...

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

As i already mentioned, the Skia docs state that "clipRect" COMBINES with the currently active clipRect. My hunch is that by default this method "combines" rects instead of setting the one pass to it.

There should be an overload of that method with an operation parameter. Try to use that and pass an operation that replaces the rect, not combine them.

The fact that the textbox cliprect is not correctly reset after drawing it tells me that the canvas.clipRect method does not work as you would expect (at least not in the way it is used right now).

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

I dont doubt that Skia clips correctly.
But i doubt the clipRect method does what we think it does, since it clearly says it "combines" rects,
which is not what we want.

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

ok... Also, that is something probably related to the order of things... For example...

Given this base class:

public class BaseWindow : Window
    {
        public override void Show(Shell target)
        {
            var label = new Label();
            label.Size = new Point(240, 20);
            label.Position = new Point(0, 100);
            label.Style = "footer";
            label.Text = $"v1.0.1 Powered by Pay Insights - TI Pagos";
            Controls.Add(label);

            Show(target);
        }
    }

And this class:

public class SplashView : BaseWindow
    {
        public override void Show(Shell target)
        {           
            var bg = new ImageControl();
            bg.Texture = "Media/splash.png";
            bg.Size = target.Size;
            Controls.Add(bg);   

            base.Show(target);
        }
    }

The ImageControl is presented but the the label don't...

This is the Skin:

        private static Skin GetSkin() 
        {
            var skin = new Skin();

            var footStyle = new ControlStyle();
            footStyle.TextColor = ColorInt.RGB(255, 0, 0);
            footStyle.Font = "20|LaoUI.ttf";
            footStyle.TextAlign = Alignment.MiddleCenter;

            skin.Add("footer", footStyle);

            return skin;
        }

I'm trying to have some controls on the base class like a footer and a header that will be rendered for every window... Is that any magic on that point?

There is problem indeed on the clipping, Google guys will be shipping the change on master branch so I can grab it in a minute.

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

BaseWindow : Window override Show() calls Show() instead of base.Show, this should cause a stack overflow

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

bg.Size = target.Size;

If you want a control to span the whole of its container, you can simply say control.Dock= DockStyle.Fill.

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

Just to give you an idea how to use use control.Dock, consider this structure:

Desktop

  • Window
    • label.Dock = Top (always sticks to top of window, even if window resized/moved, given a size.y > 0)
    • label2.Dock = Top (stacks below the upper label)
    • image.Dock = Bottom (always sticks to bottom, given a size.y>0)

Same goes for Dock.Left/Right. Also the dock regions respect Padding and Margin.
This basically works exactly like Docking in Windows.Forms, which you can read about here:
https://msdn.microsoft.com/en-us/library/system.windows.forms.control.dock(v=vs.110).aspx
and here
https://msdn.microsoft.com/en-us/library/system.windows.forms.dockstyle(v=vs.110).aspx

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

Since you've managed to get this all working now, i'm gonna close this issue (as this discussion is already way too long for a single issue).

Please feel free to open new issues with questions.
Cheers.

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

Yeah I know how Dock works... It is just not working here... If I put to dock on top, the image just resize to a minimal thing and not full screen anymore...

Ok but how can I get the rest of things working? There are some samples anywhere but that 2 page docs? I'm in the middle of the port here to use it but things are not rendering as expected and it is probably cause we are doing something wrong due to the lack of docks... Will I have to open 1 issue per question here? Unless we have some basic wiki with a sample we will end up with a very polluted Issue list on this repo...

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

When you dock something Top, you have to give it a proper height. Make it size = x0,y20 and Dock = Top and it will sit at the top of the window at 20px height, stretched to full window width,

Open issues as you desire :)
I just want to keep the issue discussions short, since this isnt exactly a forum ;)

Also there's a user forum with a whole lot of tips and help right here:
http://www.ionstar.org/forum/

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

Again, if you want a control to completely fill its container, set it to Dock = Fill.

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

For example, take a look at this topic, which covers a Dock question:
http://ionstar.org/forum/index.php?topic=161.0

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

Tried Fil and have that weird resize behaviour...

I already looked at that forum and didn't found very much information...

Also, Issues on GH are to discuss questions of the users, just like a forum... To avoid that, you should have some samples, docs or Wiki pages so people would clearly see how your your stuff works... If I keep 1 question per issue, it will not exactly help you cause you probably will have a slower response time...

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

Then lets just keep talking here.
I'm happy to help but some patience would be appreciated.

  1. Please disable clipping to make sure we are not looking at side effects.
  2. Create an empty window. Add a button with a background color to it and set the button to Dock.Fill
  3. The button should now fill the entire window

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

There are plenty of examples, answer and tips in the forum.
Just use the search function. There are a lot of code samples and snippets.

Alternatively, download the full SDK on the download page which contains full samples for several different engines. The sample gui included should cover everything you might wonder about right now.
Download: http://www.ionstar.org/?page_id=8

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

I'll look at the samples right now...

Meanwhile, google guys replied:

DIFFERENCE_SK_REGION_OP,          //!< subtract the op region from the first region
    INTERSECT_SK_REGION_OP,           //!< intersect the two regions
    UNION_SK_REGION_OP,               //!< union (inclusive-or) the two regions
    XOR_SK_REGION_OP,                 //!< exclusive-or the two regions
    REVERSE_DIFFERENCE_SK_REGION_OP,  //!< subtract the first region from the op region
    REPLACE_SK_REGION_OP,             //!< replace the dst region with the op region

Which one of those operations is the correct for the Scissor case?

Thanks

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

REPLACE_SK_REGION_OP

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

ok

btw, you asked to drop a button... What is the diff between the button and the image? Should them both respect the dock?

        public override void Show(Shell target)
        {           
            var bg = new ImageControl();
            bg.Texture = "Media/splash.png";
            //bg.Size = target.Size;
            bg.Dock = DockStyle.Fill;
            Controls.Add(bg);   

            base.Show(target);
        }

This doesn't work... If I comment the dock and uncomment the size it does...

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

Doesnt matter what kind of control you dock there. Button was just an example.
That is really strange. The Dock=Fill should work just fine.

Could you paste me the full code?
I'd like to check if the window has a proper size, and maybe i can reproduce your problem here.

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

And some screenshot would also help...

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

https://gist.github.com/galvesribeiro/90be9fb9f81d2d5b307d7009848cadae is the code and here are the images:

img_1819
img_1818

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

Could you please try this:

  1. set desktop size to screen size
  2. add window, set window.dock=fill (you can set this in your window ctor, this.Dock = ..)
  3. add button/image to window, also dock=fill

If that does not correctly strech everything across the whole screen - something is really broken :D

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

ok looks like we got it... the docking is now working as expected thanks!

Also, got the Skia updated with the missing method overload:

     public void Scissor(int x, int y, int width, int height)
        {
            _canvas.ClipRect(SKRect.Create(x, y, width, height), SKRegionOperation.Replace);
        }

Now looks like the clipping is working as expected... Will do more tests and let you know, thanks!

One more question... What is the event/override for a Window that fire after the window is fully rendered and draw to the screen? On Windows Forms for instance, there was a Loaded event that we could hook up.

Thanks again for all the support and patience. Keep the great work up!

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

Hm there is no such event in Squid, however there is a protected void DrawCustom which is called after the control has drawn. You could override that and use a bool to implement this in your base window.

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

ok... will have a look on that... The reason for it is that I want to make sure that all controls where loaded, set its parents etc when this event is called... not necessarily draw, but at least all its fields are set and can be used... Thanks! :)

from squid.

galvesribeiro avatar galvesribeiro commented on May 17, 2024

just got the Loaded() effect like this:

               protected virtual void Loaded() { }

        protected override void DrawCustom()
        {
            if (!_loaded) 
            {
                _loaded = true;
                Loaded();
            }
        }

;)

from squid.

sgf avatar sgf commented on May 17, 2024

should i createWindow by myself?
look the Window or Desktop won't create any Windown on Windows OS.

from squid.

Roderik11 avatar Roderik11 commented on May 17, 2024

should i createWindow by myself? look the Window or Desktop won't create any Windown on Windows OS.

Squid does not come with a rendering engine.
You have to create OS windows yourself - as well as the whole render loop using the graphics API of your choice.

from squid.

sgf avatar sgf commented on May 17, 2024

should i createWindow by myself? look the Window or Desktop won't create any Windown on Windows OS.

Squid does not come with a rendering engine. You have to create OS windows yourself - as well as the whole render loop using the graphics API of your choice.

thanks

from squid.

Related Issues (6)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.