Closed bagomot closed 1 year ago
Hi! I'm not sure what the exact problem could be, as I still don't really understand the layouting process. I think, it might be unrelated to the physical side of the vidget and its size -- I've seen that dlangui makes no effor to actually prevent rendering outside of physical widget borders.
Could you provide some sample code so I can at least debug it in any way?
Hi! I'm not sure what the exact problem could be, as I still don't really understand the layouting process. I think, it might be unrelated to the physical side of the vidget and its size -- I've seen that dlangui makes no effor to actually prevent rendering outside of physical widget borders.
Could you provide some sample code so I can at least debug it in any way?
Here is a code example that demonstrates incorrect behavior:
#!/usr/bin/env dub
/+ dub.sdl:
dependency "dlangui" version="~>0.10.2"
+/
import dlangui;
mixin APP_ENTRY_POINT;
extern (C) int UIAppMain(string[] args)
{
auto window = Platform.instance.createWindow("Test"d, null, WindowFlag.Resizable, 720, 405);
window.mainWidget = new MainFrame();
window.show;
return Platform.instance.enterMessageLoop();
}
class MainFrame : FrameLayout
{
this()
{
backgroundColor("white");
auto text = new TextWidget(null, "Test text"d);
text.textColor("white");
VerticalLayout vLayout = new VerticalLayout();
vLayout.alignment = Align.Center;
vLayout.layoutWidth(400); // ?
vLayout.maxWidth(400); // ?
vLayout.backgroundColor("black");
vLayout.layoutWidth(WRAP_CONTENT);
vLayout.margins(20);
vLayout.addChild(text);
addChild(vLayout);
}
}
OK, so, after debugging a little, here's what I came up with.
I think the layout engine is trying to "claim" all available space for it, as a vertical layout of 400
makes no sense in a parent layout of FILL_PARENT
. However, if you add two layouts, then the width becomes as expected. Here's the layout I used:
import dlangui;
mixin APP_ENTRY_POINT;
extern (C) int UIAppMain(string[] args)
{
auto window = Platform.instance.createWindow("Test"d, null, WindowFlag.Resizable, 720, 405);
window.mainWidget = new MainFrame();
window.show;
return Platform.instance.enterMessageLoop();
}
class MainFrame : FrameLayout
{
this()
{
super("FRAME");
backgroundColor("white");
auto text = new TextWidget("TEXT", "Test text"d);
text.textColor("white");
text.backgroundColor("red");
text.minWidth(200);
auto vLayout = new HorizontalLayout("HORZ");
vLayout.alignment = Align.Center;
vLayout.layoutWidth(400); // ?
vLayout.minWidth(400); // ?
vLayout.backgroundColor("black");
vLayout.layoutWidth(WRAP_CONTENT);
vLayout.margins(20);
vLayout.addChild(text);
auto abc = new VerticalLayout();
abc.layoutWidth(FILL_PARENT);
vLayout.addChild(abc);
addChild(vLayout);
auto extraLayout = new VerticalLayout();
extraLayout.layoutWidth(FILL_PARENT);
auto base = new HorizontalLayout();
base.addChild(vLayout);
base.addChild(extraLayout);
addChild(base);
}
}
NOTE: I'm using minWidth
instead of maxWidth
to make it exactly 400 pixels wide.
I'm not sure if this is a bug or a feature, but at least you can work this around if needed. I'm inclined to believe that it's indeed a feature, because the proposed layout makes very little sense to me.
The decision is tough, very tough.
UP: I made a new discovery -- you don't have to do the trickery, you just need to have a layout inside a layout. Otherwise it seems to be trying to fill parent regardless. This works just as fine:
class MainFrame : FrameLayout
{
this()
{
super("FRAME");
backgroundColor("white");
auto text = new TextWidget("TEXT", "Test text"d);
text.textColor("white");
text.backgroundColor("red");
text.layoutWidth(200);
auto vLayout = new HorizontalLayout("VERT");
vLayout.alignment = Align.Center;
vLayout.layoutWidth(400);
vLayout.backgroundColor("black");
vLayout.margins(20);
vLayout.addChild(text);
addChild(vLayout);
auto extraLayout = new VerticalLayout();
auto base = new HorizontalLayout();
base.addChild(vLayout);
addChild(base);
}
}
However, changing addChild(base)
to addChild(vLayout)
results in vLayout
being stretched to the window's width.
UP: I made a new discovery -- you don't have to do the trickery, you just need to have a layout inside a layout. Otherwise it seems to be trying to fill parent regardless. This works just as fine:
class MainFrame : FrameLayout { this() { super("FRAME"); backgroundColor("white"); auto text = new TextWidget("TEXT", "Test text"d); text.textColor("white"); text.backgroundColor("red"); text.layoutWidth(200); auto vLayout = new HorizontalLayout("VERT"); vLayout.alignment = Align.Center; vLayout.layoutWidth(400); vLayout.backgroundColor("black"); vLayout.margins(20); vLayout.addChild(text); addChild(vLayout); auto extraLayout = new VerticalLayout(); auto base = new HorizontalLayout(); base.addChild(vLayout); addChild(base); } }
However, changing
addChild(base)
toaddChild(vLayout)
results invLayout
being stretched to the window's width.
It works, now the size is taken into account. But another problem appeared: now the center alignment (vLayout.alignment = Align.Center;) does not work (even if it is applied to all containers).
I was able to make a working version of the alignment for my layout. This works by overriding the layout method for the layout where the widgets that need to be aligned will be placed:
override void layout(Rect rc)
{
_needLayout = false;
if (visibility == Visibility.Gone)
{
return;
}
_pos = rc;
applyMargins(rc);
applyPadding(rc);
if (_children.length == 0)
{
return;
}
// Layout the children
foreach (child; _children)
{
// Measure the child
child.measure(rc.width, rc.height);
// Calculate the starting x and y positions
int startX;
if (alignment() & Align.Left)
{
startX = rc.left;
}
else if (alignment() & Align.Right)
{
startX = rc.right - child.measuredWidth;
}
else // default to center alignment
{
startX = rc.left + (rc.width - child.measuredWidth) / 2;
}
int startY;
if (alignment() & Align.Top)
{
startY = rc.top;
}
else if (alignment() & Align.Bottom)
{
startY = rc.bottom - child.measuredHeight;
}
else // default to center alignment
{
startY = rc.top + (rc.height - child.measuredHeight) / 2;
}
// Calculate the end x and y positions
int endX = startX + child.measuredWidth;
int endY = startY + child.measuredHeight;
// Create a new rectangle for the child
auto childRect = Rect(Point(startX, startY), Point(endX, endY));
// Layout the child
child.layout(childRect);
}
}
This won't work if nested widgets need to be resized to fit the window.
I have a mainWidget that inherits from FrameLayout and takes up the full width of the window. Inside it is a VerticalLayout. This VerticalLayout should be 400px width, but it always stretches to the full width of the parent widget. I looked at the examples and source code, but couldn't figure out how to get the width I wanted. Help me please.