Skip to content

feat: add basic StandardDialog control#1053

Open
agaertner wants to merge 43 commits intoblish-hud:devfrom
agaertner:feature/screenPrompt
Open

feat: add basic StandardDialog control#1053
agaertner wants to merge 43 commits intoblish-hud:devfrom
agaertner:feature/screenPrompt

Conversation

@agaertner
Copy link
Copy Markdown
Member

@agaertner agaertner commented Feb 10, 2026

A basic auto-sizing screen prompt similar to system prompts.

A convinient way (and thus an incentive) for devs to alert the user when they are about todo a destructive or non-reversable action.

It's basically what GW2 does when you disconnect or are about to throw away an item.

Obviously due to the auto-scaling the background stretches if the text is too long.

@dlamkins
Copy link
Copy Markdown
Member

Can you include some screenshots of examples from in-game for comparison?

@agaertner
Copy link
Copy Markdown
Member Author

agaertner commented Feb 11, 2026

image image

Call examples

ScreenPrompt.Show("Some text"); // No icon; default button: "OK"

ScreenPrompt.Show("Some text", DialogIcon.Exclamation);

ScreenPrompt.Show("Some text", DialogIcon.Exclamation, DialogButton.Close);

ScreenPrompt.Show("Some text", DialogIcon.Question, DialogButton.Yes | DialogButton.No, (bttn) => { 
   if (bttn = DialogButton.Yes) // yes was pressed to close the window.
});

AsyncTexture2D customIcon;
ScreenPrompt.Show("Some text", customIcon);

ScreenPrompt.Show("Some text", customIcon, DialogButton.Close);

ScreenPrompt.Show("Some text", customIcon, DialogButton.Confirm | DialogButton.Cancel, (bttn) => { 
   if (bttn = DialogButton.Confirm) // confirm was pressed to close the window.
});

@greaka
Copy link
Copy Markdown
Member

greaka commented Feb 11, 2026

Here are a few ingame screenshots for reference.

image image

@agaertner
Copy link
Copy Markdown
Member Author

oh I just wanted to redo the system one for a quick way to alert a user, much like ScreenNotification but with a callback.
You could be right, however, you could dive deeper into this and abstract it more.

@dlamkins
Copy link
Copy Markdown
Member

Can a see a screenshot of the in-game popup this implementation is replicating?

I like the convenience of this implementation, but it immediately makes me want a way to provide custom button text or icons. 🤔 (but maybe that's not needed if the available button options cover most scenarios).

@agaertner
Copy link
Copy Markdown
Member Author

agaertner commented Feb 11, 2026

image (Original)

The disconnect one is colorless but the item destruction one is the same (except the displayed buttons of course). I thought of maybe adding an overload that takes LabelPart for colorization.

@agaertner
Copy link
Copy Markdown
Member Author

agaertner commented Feb 11, 2026

image Here it is without icon.

I refactored it to use FormattedLabelBuilder (yes, the builder. At first I wanted to use FormattedLabel but I want the prompt to enforce size and wrap. It's a win thought since the dev doesn't have to make those calls and Build it.)

Give me a second to clean it up.

Here's the result.
image

Call example:

var label = new FormattedLabelBuilder();
label.CreatePart(label.CreatePart("Are you sure you want to destroy "));
label.CreatePart("250 Refined Homestead Fibers", o => o.SetTextColor(new Color(255, 164, 5)));
label.CreatePart(label.CreatePart("?"));
ScreenPrompt.Show(label, ScreenPrompt.DialogIcon.Exclamation, ScreenPrompt.DialogButton.Yes | ScreenPrompt.DialogButton.No);

I noticed some strange overload of CreatePart in the formattedLabelBuilder. You can see that I am using CreatePart and then pass it to CreatePart again. It's because CreatePart(string) does not add it to the building process of FormattedBuilder.
I will weave in a fix for that. It doesn't break anything.

@agaertner
Copy link
Copy Markdown
Member Author

agaertner commented Feb 11, 2026

Alright. All done. :)

Call examples:

ScreenPrompt.Show("Some text"); // No icon; default button: "OK"

ScreenPrompt.Show("Some text", DialogIcon.Exclamation);

ScreenPrompt.Show("Some text", DialogIcon.Exclamation, DialogButton.Close);

ScreenPrompt.Show("Some text", DialogIcon.Question, DialogButton.Yes | DialogButton.No, (bttn) => { 
   if (bttn = DialogButton.Yes) // yes was pressed to close the window.
});

AsyncTexture2D customIcon;
ScreenPrompt.Show("Some text", customIcon);

ScreenPrompt.Show("Some text", customIcon, DialogButton.Close);

ScreenPrompt.Show("Some text", customIcon, DialogButton.Confirm | DialogButton.Cancel, (bttn) => { 
   if (bttn = DialogButton.Confirm) // confirm was pressed to close the window.
});

// Instead of a plain string a FormattedLabelBuilder can be prepared and passed with the rest of the params of above.

var label = new FormattedLabelBuilder();
label.CreatePart("Are you sure you want to destroy ");
label.CreatePart("250 Refined Homestead Fibers", o => o.SetTextColor(new Color(255, 164, 5)));
label.CreatePart("?");

ScreenPrompt.Show(label, ScreenPrompt.DialogIcon.Exclamation, ScreenPrompt.DialogButton.Yes | ScreenPrompt.DialogButton.No);

ScreenPrompt.Show(label, ScreenPrompt.DialogIcon.Exclamation, ScreenPrompt.DialogButton.Yes | ScreenPrompt.DialogButton.No, (bttn) => { 
   if (bttn = DialogButton.Yes) // yes was pressed to close the window.
});
image

Stress test (yes, the button's width do auto adjust; the container's width does not, thereby keeping it "dialog-like"):

image

@agaertner
Copy link
Copy Markdown
Member Author

agaertner commented Feb 12, 2026

Overlapping the original:

image

Close enough. 😅

@dlamkins
Copy link
Copy Markdown
Member

Your screenshots look pretty great! Could you please send a screenshot of your implementation next to a matching in-game version? I can see there are some differences, but it's hard to tell in the overlap. 😄

@agaertner
Copy link
Copy Markdown
Member Author

agaertner commented Feb 12, 2026

Your screenshots look pretty great! Could you please send a screenshot of your implementation next to a matching in-game version? I can see there are some differences, but it's hard to tell in the overlap. 😄

image (Original)

image (Blish HUD)

The border appears 1px thicker when I have it on my greenscreen window. I previously had it 1px lower because it looked thinner in-game. Might be due to the fuzzyness of BlishHUD/Monogame. I would keep as is.
The button text is a bit bigger (I believe) in the original but the StandardButton has the scope of its font private.

However, the remaining differences are so miniscule that it doesn't matter imo.

@agaertner
Copy link
Copy Markdown
Member Author

Custom button text:

image

@agaertner
Copy link
Copy Markdown
Member Author

agaertner commented Feb 12, 2026

UI size set to Large now:
image (Original)

image (BlishHUD)

Looks good

@agaertner
Copy link
Copy Markdown
Member Author

Are these pictures of the popup being taken while UI size is set to large? There shouldn't be any fuzziness while UI Size is set to large and that would help us determine if the lines are correct. 🤔

I also see that the background texture is the same, but this implementation resizes it to fit whereas the real one does not squish it. Can that be made to change?

Done and done.
Example
image

Stress test
image

Text content area debug (still correct after refactor)
image

Copy link
Copy Markdown
Collaborator

@Denrage Denrage left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if I'm alone with these comments and i wasn't explicitly asked to look at this PR, so i won't Request Changes, but those are things that give me a bad feeling seeing in core. @greaka @dlamkins

@agaertner agaertner changed the title feat: add basic ScreenPrompt control feat: add basic StandardDialog control Feb 15, 2026
@agaertner
Copy link
Copy Markdown
Member Author

agaertner commented Feb 16, 2026

  • Fix some math for button fitting if there are over 5 buttons.
  • Clean up margin consts and adjusted them more by comparison with original.
  • Fix a race condition on GetDefaultIcon and TextureSwapped (icon could stay empty if spammed fast enough because the Texture may already be in the AsyncTexture2D from DatAssetCache before TextureSwapped is subscribed to.
  • Clean up & Testing

Examples

var label = new FormattedLabelBuilder();
label.CreatePart("There's plenty of exotic", o => o.SetFontSize(FontSize.Size16));
label.CreatePart("fish", o => o.SetFontSize(FontSize.Size16).SetTextColor(new Color(255, 164, 5)));
label.CreatePart("in the sea.", o => o.SetFontSize(FontSize.Size16));
label.CreatePart("\n", o => o.SetFontSize(FontSize.Size16));
label.CreatePart("\nDo you agree?", o => o.SetFontSize(FontSize.Size16));
StandardDialog.Show(label,
    DialogIcon.Exclamation,
    DialogButton.Yes.Action(() => { }),
    DialogButton.No.Select());
image
StandardDialog.Show("The quick brown fox jumps over the lazy dog.", DialogIcon.Question, 
    DialogButton.Create("Pet the Dog").Action(() => { }), 
    DialogButton.Ignore.Select());
image image

In the following the icon margin have additionally been adjusted further to match the original.

StandardDialog.Show("Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.", DialogIcon.Question, 
                DialogButton.Create("Hello World").Action(() => { }), 
                DialogButton.Ignore.Select(),
                DialogButton.OK,
                DialogButton.Close,
                DialogButton.Cancel,
                DialogButton.Decline,
                DialogButton.Apply,
                DialogButton.Confirm,
                DialogButton.No);
image
StandardDialog.Show("Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.", 
                DialogIcon.Present,
                DialogButton.OK,
                DialogButton.Close);
image

@agaertner
Copy link
Copy Markdown
Member Author

image

@agaertner agaertner force-pushed the feature/screenPrompt branch from 3a92bad to eab492e Compare February 21, 2026 12:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants