These are chat archives for AvaloniaUI/Avalonia

12th
Jun 2017
Nikita Tsukanov
@kekekeks
Jun 12 2017 08:44
@grokys I'm quite lost, we now have 3 PRs affecting layout system
In what order should they be merged?
Steven Kirk
@grokys
Jun 12 2017 08:45
i think there are only 2? #1014 and #1021?
Nikita Tsukanov
@kekekeks
Jun 12 2017 08:45
WPF integration also affects layout system a bit
It changes Arrange from DesiredSize to ClientSize
Steven Kirk
@grokys
Jun 12 2017 08:46
ah yeah, that's not actually correct behavior so i don't want to merge with that change in
what i'd say is do it like this: merge #1021 if you're happy with it
i will then fix up #1016 using an IEmbeddedLayoutRoot interface
using this interface you'll be able to customize the arrange size
Nikita Tsukanov
@kekekeks
Jun 12 2017 08:48
@joelday I think that you need to implement custom rendering only for basic visuals like TextBlock and Border (just like Avalonia does). Everything else is done by templates.
Also make sure that template is applied (you need layout pass for that, I think)

that's not actually correct behavior

Ehm, toplevel should occupy allocated space

It doesn't make sense otherwise
BTW, IEmbeddedLayoutRoot can still return Infinity as constraint
If someone places it inside ScrollViewer
Hm
In that case it will just grow as usual
Steven Kirk
@grokys
Jun 12 2017 08:53
the arrange finalSize isn't saying "you must occupy this space". a control can choose to occupy less space than passed in arrange, which is why you return a value
whether you pass ClientSize or not is academic, it's the size that's returned that decides the arrange size
so if your toplevel returns less than the size passed in, then this information must be passed up to WPF
Nikita Tsukanov
@kekekeks
Jun 12 2017 08:58
I'm not sure that ClientSize even makes sense for toplevels embedded to WPF
Steven Kirk
@grokys
Jun 12 2017 08:58
also i think ClientSize only makes sense for windows - it should be moved to WindowBase
ah, haha
yep
Nikita Tsukanov
@kekekeks
Jun 12 2017 08:59
The problem is that other toolkits don't have the concept of Measure/Arrange
Steven Kirk
@grokys
Jun 12 2017 08:59
yep, and for them you'll just set a fixed Width and Height
Nikita Tsukanov
@kekekeks
Jun 12 2017 08:59
UIKit/AppKit historically didn't have any auto layout, and the new one doesn't look like WPF at all
Steven Kirk
@grokys
Jun 12 2017 09:00
fixed with and height would work though?
Nikita Tsukanov
@kekekeks
Jun 12 2017 09:00
GTK has a concept of "size request" that asks widgets for "minimum" and "natural" sizes
Steven Kirk
@grokys
Jun 12 2017 09:00
natural size with be the DesiredSize
minimum size, i'm not sure
Nikita Tsukanov
@kekekeks
Jun 12 2017 09:01
It's better to leave non-WPF systems with fixed size for now
Steven Kirk
@grokys
Jun 12 2017 09:01
yep
so my plan was, if you're happy with #1021 we merge that
i'll then do a PR with #1016 as the target which implements IEmbeddedLayoutRoot and moves ClientSize to WindowBase
Nikita Tsukanov
@kekekeks
Jun 12 2017 09:03
It will break ios/android
moving ClientSize to WindowBase, I mean
Steven Kirk
@grokys
Jun 12 2017 09:04
where do you think it should be moved to?
Matthijs ter Woord
@mterwoord
Jun 12 2017 09:04
@kekekeks "It will break ios/android" if its the right thing to do, then better fix those targets?
Nikita Tsukanov
@kekekeks
Jun 12 2017 09:04
No idea, honestly. It's just WPF where our toplevel isn't a "real" toplevel
Steven Kirk
@grokys
Jun 12 2017 09:05
but in ios/android the toplevel is embedded now, is that correct?
Nikita Tsukanov
@kekekeks
Jun 12 2017 09:05
We need another level in class hierarchy, I think
Steven Kirk
@grokys
Jun 12 2017 09:05
tbh i'm not a big fan of TopLevel anyway
it mixes too many concepts
Nikita Tsukanov
@kekekeks
Jun 12 2017 09:06
yep, ios/android are using EmbeddableControlRoot
And they do need ClientSize, since it's fixed by external constaint
Steven Kirk
@grokys
Jun 12 2017 09:07
ok, so i say lets treat ios/android as being embedded controls as well, same as embedding in WPF
can't we just use Width/Height?
Nikita Tsukanov
@kekekeks
Jun 12 2017 09:07
Probably
It will be required to call toplevel directly instead of passing an event from ITopLevelImpl though
We could implement additional interface IExternalSizeTopLevelImpl interface or something
Steven Kirk
@grokys
Jun 12 2017 09:09
that's IEmbeddedLayoutRoot
Nikita Tsukanov
@kekekeks
Jun 12 2017 09:10
I'm talking about Impl part, sorry
Steven Kirk
@grokys
Jun 12 2017 09:10
ah ok
Nikita Tsukanov
@kekekeks
Jun 12 2017 09:10
fixed
We need a proper way of passing that info from platform implementation
What ClientSize is currently used for BTW?
Steven Kirk
@grokys
Jun 12 2017 09:11
ClientSize was originally meant to just pass the client size of the window from win32 to avalonia
it's kinda got warped with time
Nikita Tsukanov
@kekekeks
Jun 12 2017 09:12
It's not used outside of TopLevel and item virtualizer
Can we leave it as "currently allocated size" or something?
Steven Kirk
@grokys
Jun 12 2017 09:14
yeah, i guess so - part of my problem with it is the name ;)
Steven Kirk
@grokys
Jun 12 2017 09:14
there was originally going to be ClientSize and WindowSize which included the borders
Nikita Tsukanov
@kekekeks
Jun 12 2017 09:14
Android/iOS are doing this hack, actually
Steven Kirk
@grokys
Jun 12 2017 09:15
yeah, imo, the layout manager should be aware of that hack
it should be aware that there is an external constraint on measure
Nikita Tsukanov
@kekekeks
Jun 12 2017 09:16
Another problem is that in case of ios/android toplevel has to occupy the whole space
Steven Kirk
@grokys
Jun 12 2017 09:18
could override the Width and Height properties and add a coercion?
Nikita Tsukanov
@kekekeks
Jun 12 2017 09:18
TopLevel sets Width/Height to ClientSize
in HandleResized
So it should be fine
I've disabled this behavior for WPF integration, so it works properly
Steven Kirk
@grokys
Jun 12 2017 09:20
Yeah that behaviour should be moved to window base I think
Like TopLevel still has a closed event which isn't right
Nikita Tsukanov
@kekekeks
Jun 12 2017 09:21
But it still makes perfect sense for ios/android
The only problem with Closed event is it's name
Steven Kirk
@grokys
Jun 12 2017 09:21
Not for wpf embedding though..
Nikita Tsukanov
@kekekeks
Jun 12 2017 09:21
It should be Disposed, or something

Not for wpf embedding though..

HandleResized is virtual, so no big deal

The thing about TopLevel (base class) is that it doesn't have any control over its lifetime
It's either controlled by Window/Popup or by external UI toolkit
Steven Kirk
@grokys
Jun 12 2017 09:26
right... so there are a few things we need to change here
as a starting point though, does #1021 make sense to you?
i say lets start with that, then make the layout manager aware of external size constraints
then we can think about how to refactor the top level classes
so we could get #1021 and #1014 merged, then merge those into #1016
we can then merge #1016 and think about where we're at?
make sense?
as at the moment there are too many PRs flying around as you said!
oh i forgot a step - for #1016 we'll add IEmbeddedLayoutRoot
Nikita Tsukanov
@kekekeks
Jun 12 2017 09:31
It's funny that just changing HashSet to Queue was the most effective solution
Steven Kirk
@grokys
Jun 12 2017 09:31
hah, yeah
Nikita Tsukanov
@kekekeks
Jun 12 2017 09:31
I also see a problem with IsAttachedToVisualTree check in LayoutManager
It should throw an exception or something
Since control itself will mark its measure/arrange as invalid
call LayoutManager
and after that it won't ever try to do that again
Steven Kirk
@grokys
Jun 12 2017 09:32
the ones on line 33 and 47? yeah that might be better
ah actually no
a control might be measured explictly outside the layout manager
Nikita Tsukanov
@kekekeks
Jun 12 2017 09:33
It shouldn't be calling layoutmanager while detached from the tree anyway
Steven Kirk
@grokys
Jun 12 2017 09:34
ah yeah, you're right sorry
Nikita Tsukanov
@kekekeks
Jun 12 2017 09:35
Inside actual measure/arrange passes this check makes perfect sence since visual could have been detached from the tree
Steven Kirk
@grokys
Jun 12 2017 09:35
that means until we move layoutmanager to root the check needs to move to InvalidateMeasure
Nikita Tsukanov
@kekekeks
Jun 12 2017 09:37
I think that even with global layout manager we still should check for visual tree attachment in InvalidateMeasure/InvalidateArrange and call layout manager when control is attached back to the tree
Steven Kirk
@grokys
Jun 12 2017 09:37
ok yeah
Nikita Tsukanov
@kekekeks
Jun 12 2017 09:46
Hm
There comes a problem, actually
What if visual that's already queued for measure/arrange gets removed from the tree and then attached back?
Steven Kirk
@grokys
Jun 12 2017 09:50
it will be added to the queue twice, but the second time it's processed it should be a no-op due to https://github.com/AvaloniaUI/Avalonia/pull/1021/files#diff-16a0379833d7aa24d8644692f26770dbR119
Nikita Tsukanov
@kekekeks
Jun 12 2017 09:59
Ah, ok
I thought that check for IsMeasureValid was performed after tree traversla
Steven Kirk
@grokys
Jun 12 2017 10:07
yeah i added that check there to address that possibility
Joel Day
@joelday
Jun 12 2017 16:23
@kekekeks Yeah, I will only be supporting a limited subset of functionality, I do want to get layout at the very least, though. At the moment, I’m just trying to figure out why this isn’t working as is, though. I’m not sure if I’m just using the framework wrong, even. My expectation is that if I create a control heirarchy, and get the top-level ContentPresenter to work, everything should work its way down from there and give me render calls for whatever visual elements are in Button, etc.
What I am likely to do though, especially since there are going to be a lot of unsupported properties, ivisual and brush features, is to just build on top of the lower level logical things and then do my own render passes, like you had suggested.
Steven Kirk
@grokys
Jun 12 2017 16:29
@joelday can you inspect the visual tree in the debugger? take a look at the root and then IVisual.VisualChildren and then the visual children of the visual child and so on
make sure the controls that you expect are there
Joel Day
@joelday
Jun 12 2017 16:30
I’ll take a peek in a minute.
Steven Kirk
@grokys
Jun 12 2017 16:30
or even better use this method to dump the tree somewhere
Joel Day
@joelday
Jun 12 2017 16:31
Also going to see if I can get things working by referencing the source projects so I can step through.
Ooh.
Thanks!
By the way, for context, if you didn’t see my initial message, I’m making a console graphics rendering engine work as a platform.
Steven Kirk
@grokys
Jun 12 2017 16:33
yeah, i've been vaguely following along - sounds cool!
Joel Day
@joelday
Jun 12 2017 16:33
I was doing a bunch of Wpf-like UI framework stuff on top of it, but figured it didn’t make sense if I can support something else. That said, because of funamental differences between high-res desktop UI, I should probably start working on it at a lower-level.
Yeah, I like the idea of being able to do what Blessed (https://github.com/chjj/blessed) does, but for net standard and based on a modern UI framework.
(Also I like weird modern lo-fi hybrid projects.)
You guys have been super helpful, thanks for answering all the questions. :)
Steven Kirk
@grokys
Jun 12 2017 17:00
yeah, i'm definitely not sure how practical it is, but sounds cool anyway ;)
Joel Day
@joelday
Jun 12 2017 17:09
I’m all about questions to answers nobody asked. :D
Joel Day
@joelday
Jun 12 2017 17:59
Init: TopLevel: Avalonia.Controls.Embedding.EmbeddableControlRoot
CreateRenderTarget
CreateDrawingContext: Avalonia.Rendering.ImmediateRenderer
PushOpacity: 1
PushClip: 0, 0, 180, 34
PushOpacity: 1
PushOpacity: 1
PushClip: 0, 0, 180, 34
PushOpacity: 1
PopOpacity: 
PopClip: 
PopOpacity: 
PopOpacity: 
PopClip: 
PopOpacity: 
Loaded '/Users/joel.day/.nuget/packages/avalonia/0.5.1/lib/netcoreapp1.0/Avalonia.Diagnostics.dll'. Cannot find or open the PDB file.
TopLevel: EmbeddableControlRoot Avalonia.Controls.Classes
 |  Content = DarkId.Terminal.AvaloniaTestApp.MainView [LocalValue]
 |  Template = Avalonia.Controls.Templates.FuncControlTemplate`1[Avalonia.Controls.Embedding.EmbeddableControlRoot] [LocalValue]
 |  TransformedBounds = Avalonia.VisualTree.TransformedBounds [LocalValue]
 +- ContentPresenter Avalonia.Controls.Classes
     |  Content = DarkId.Terminal.AvaloniaTestApp.MainView [LocalValue]
     |  TemplatedParent = Avalonia.Controls.Embedding.EmbeddableControlRoot [LocalValue]
     |  IsEnabledCore = True [LocalValue]
     |  NameScope = Avalonia.Controls.NameScope [LocalValue]
     |  TransformedBounds = Avalonia.VisualTree.TransformedBounds [LocalValue]
     +- MainView Avalonia.Controls.Classes
         |  Content = Avalonia.Controls.Grid [LocalValue]
         |  Template = Avalonia.Controls.Templates.FuncControlTemplate`1[DarkId.Terminal.AvaloniaTestApp.MainView] [LocalValue]
         |  TemplatedParent = (null) [LocalValue]
         |  IsEnabledCore = True [LocalValue]
         |  TransformedBounds = Avalonia.VisualTree.TransformedBounds [LocalValue]
         +- ContentPresenter Avalonia.Controls.Classes
             |  Content = Avalonia.Controls.Grid [LocalValue]
             |  TemplatedParent = DarkId.Terminal.AvaloniaTestApp.MainView [LocalValue]
             |  IsEnabledCore = True [LocalValue]
             |  NameScope = Avalonia.Controls.NameScope [LocalValue]
             |  TransformedBounds = Avalonia.VisualTree.TransformedBounds [LocalValue]
MainView: MainView Avalonia.Controls.Classes
 |  Content = Avalonia.Controls.Grid [LocalValue]
 |  Template = Avalonia.Controls.Templates.FuncControlTemplate`1[DarkId.Terminal.AvaloniaTestApp.MainView] [LocalValue]
 |  TemplatedParent = (null) [LocalValue]
 |  IsEnabledCore = True [LocalValue]
 |  TransformedBounds = Avalonia.VisualTree.TransformedBounds [LocalValue]
 +- ContentPresenter Avalonia.Controls.Classes
     |  Content = Avalonia.Controls.Grid [LocalValue]
     |  TemplatedParent = DarkId.Terminal.AvaloniaTestApp.MainView [LocalValue]
     |  IsEnabledCore = True [LocalValue]
     |  NameScope = Avalonia.Controls.NameScope [LocalValue]
     |  TransformedBounds = Avalonia.VisualTree.TransformedBounds [LocalValue]
Grid: Grid Avalonia.Controls.Classes
 |  TemplatedParent = (null) [LocalValue]
 +- Rectangle Avalonia.Controls.Classes
     |  Fill = #ff0000ff [LocalValue]
 +- Button Avalonia.Controls.Classes
Button: Button Avalonia.Controls.Classes
CreateDrawingContext: Avalonia.Rendering.ImmediateRenderer
PushOpacity: 1
PushClip: 0, 0, 180, 34
PushOpacity: 1
PushOpacity: 1
PushClip: 0, 0, 180, 34
PushOpacity: 1
PopOpacity: 
PopClip: 
PopOpacity: 
PopOpacity: 
PopClip: 
PopOpacity:
Doh, didn’t copy all of it.
Steven Kirk
@grokys
Jun 12 2017 18:02
ok, you don't seem to have anything in the visual tree there that draws afaics
are you overriding the TopLevel control template?
it looks different to the default one
Joel Day
@joelday
Jun 12 2017 18:04
Hrm. I’m having to do a lot of manual Template = …, ApplyTemplate, everywhere.
Yeah, but if I just set TopLevel.Content, it doesn’t seem to do anything.
I haven’t seen anything actually pay attention to changes of ContentControl.Content
Steven Kirk
@grokys
Jun 12 2017 18:04
try putting a Border with a background color around the TopLevel's ContentPresenter
Joel Day
@joelday
Jun 12 2017 18:05
Okay, just a sec.
Steven Kirk
@grokys
Jun 12 2017 18:05
or even giving that content presenter a background for that matter
i'm not sure why you're having to set your templates manually and call ApplyTemplate manually though
Joel Day
@joelday
Jun 12 2017 18:06
No change it seems:
            var topLevel = new EmbeddableControlRoot(_window);

            topLevel.Template = new Avalonia.Controls.Templates.FuncControlTemplate<EmbeddableControlRoot>(t =>
            {
                var border = new Border();
                border.Child = new ContentPresenter() { Content = t.Content, Name = "PART_ContentPresenter" };
                return border;
            });

            return topLevel;
I’ll try removing all of that stuff now that I did this.
Oh crap, let me remove the Content thing.
Okay, yeah, no change.
Steven Kirk
@grokys
Jun 12 2017 18:10
hmm, not sure then - best i can suggest is to try stepping through this method https://github.com/AvaloniaUI/Avalonia/blob/master/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs#L219
Joel Day
@joelday
Jun 12 2017 18:11
Okay, I’ll take a peek. I’m wondering if there isn’t something closer to the platform level that I need in order to drive this. It’s weird since it seems to provide everything that the linux framebuffer platform impl does.
Nikita Tsukanov
@kekekeks
Jun 12 2017 23:43
@joelday you can't simply ignore TopLevel-related stuff
Tons of stuff in the framework expects widgets to be inside rooted visual tree
With something that implements ILayoutRoot, IRenderRoot, IInputRoot, IStyleRoot
@wieslawsoltes it seems that Cake got broken somehow
Probably because of auto-updated version or something like that