buggins / dlangui

Cross Platform GUI for D programming language
Boost Software License 1.0
805 stars 120 forks source link

Is this expected or not? #677

Open Imperatorn opened 10 months ago

Imperatorn commented 10 months ago

From a user in the forums

I know how to change the current AppFrame:

window.mainWidget = myFrame;

But how do I exit this frame?

I press the button, change to new frame, do the work, and now I want to return to the previous frame. How would I do this?

It crashes if I reset it to the previous one.

button.click = delegate(Widget src) {
    // window.mainWidget = homeLayout.child(0);
    window.mainWidget = myPreviousFrame;
    return true;
};

// crash
rillki commented 10 months ago

Here is the full code:

import dlangui;
import std;

mixin APP_ENTRY_POINT;

/// entry point for dlangui based application
extern (C) int UIAppMain(string[] args) {
    // create window
    Window window = Platform.instance.createWindow("DlangUI example - HelloWorld", null);

    // frames
    auto frame1 = new AppFrame();
    auto frame2 = new AppFrame();

    /****** FRAME 1 ********/
    auto frame1_button1 = new Button(null, "Press me"d);
    auto frame1_button2 = new Button(null, "Remove me"d);
    auto frame1_button3 = new Button(null, "new window frame"d);
    frame1.addChildren([
        new HorizontalLayout().addChildren([
            new TextWidget(null, "1 text item"d),
            new TextWidget(null, "2 text item"d),
            new TextWidget(null, "3 text item"d)
        ]),
        new TextWidget(null, "4 text item"d),
        new TextWidget(null, "5 text item"d),
        new TextWidget(null, "6 text item"d),
        frame1_button1,
        frame1_button2,
        frame1_button3,
    ]);
    frame1_button1.click = delegate(Widget src) {
        frame1.addChild(new TextWidget(null, "hello, world! "d ~ frame1.childCount.to!dstring));
        return true;
    };
    frame1_button2.click = delegate(Widget src) {
        frame1.removeChild(frame1.childCount-1);
        return true;
    };
    frame1_button3.click = delegate(Widget src) {
        window.executeInUiThread(() => window.mainWidget = frame2);
        return true;
    };

    /****** FRAME 2 ********/
    auto frame2_button1 = new Button(null, "Take me back"d);
    frame2.addChildren([
        new TextWidget(null, "4 text item"d),
        new TextWidget(null, "5 text item"d),
        frame2_button1,
    ]);
    frame2_button1.click = delegate(Widget src) {
        window.executeInUiThread(() => window.mainWidget = frame1);
        return true;
    };

    // start with frame 1
    window.executeInUiThread(() => window.mainWidget = frame1);

    // show window
    window.show();

    // run message loop
    return Platform.instance.enterMessageLoop();
}
GrimMaple commented 10 months ago

Thanks, I'll take a look when I get time!

GrimMaple commented 10 months ago

Here is the full code:

So the reason why this happens is:

    @property void mainWidget(Widget widget)
    {
        mainWidgetChange(this, _mainWidget, widget);
        if (_mainWidget !is null)
        {
            _mainWidget.window = null;
            destroy(_mainWidget); // This line
        }
        _mainWidget = widget;
        if (_mainWidget !is null)
            _mainWidget.window = this;
    }

When you change the widget, the "source" widget gets destroyed, so when you attempt to set it the second time it errors out. I cannot simply remove this behavior as it will break other parts of dlangui. For now, the workaround would be creating the frame from scratch.