Replace SDL dialogs with coroutine UI

This commit is contained in:
krzosa
2025-12-29 08:32:24 +01:00
parent 19d5a26966
commit 10fb5d77a1
2 changed files with 51 additions and 101 deletions

View File

@@ -1402,7 +1402,7 @@ bool IsNull(Buffer *buffer) {
void Close(BufferID id) {
Buffer *buffer = GetBuffer(id, NULL);
if (buffer) {
if (buffer->id.id == 0) {
if (buffer->id.id == 0 || buffer->special) {
return;
}

View File

@@ -158,51 +158,6 @@ void Appendf(View *view, const char *fmt, ...) {
Append(view, string, true);
}
bool YesNoMessageBox(const char *title, const char *msg) {
SDL_MessageBoxButtonData buttons[] = {
{ SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, 1, "No" },
{ SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, 0, "Yes" },
};
SDL_MessageBoxData data = {};
data.flags = SDL_MESSAGEBOX_WARNING;
data.title = title;
data.message = msg;
data.numbuttons = 2;
data.buttons = buttons;
int resp;
bool status = SDL_ShowMessageBox(&data, &resp);
Assert(status);
bool result = resp == 0;
return result;
}
enum SaveResult {
SAVE_CANCEL,
SAVE_NO,
SAVE_YES,
};
SaveResult SaveMessageBox(String filename) {
Scratch scratch;
const char *title = "There are unsaved changes, do you really want to quit?";
const char *msg = Format(scratch, "Do you really want to quit? Unsaved buffer: %S", filename).data;
SDL_MessageBoxButtonData buttons[] = {
{ SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, SAVE_YES, "Save" },
{ 0, SAVE_NO, "Don't save" },
{ SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, SAVE_CANCEL, "Cancel" },
};
SDL_MessageBoxData data = {};
data.flags = SDL_MESSAGEBOX_WARNING;
data.title = title;
data.message = msg;
data.numbuttons = 3;
data.buttons = buttons;
int resp;
bool status = SDL_ShowMessageBox(&data, &resp);
Assert(status);
return (SaveResult)resp;
}
void ReportErrorf(const char *fmt, ...) {
Scratch scratch;
STRING_FORMAT(scratch, fmt, string);
@@ -747,42 +702,7 @@ void Command_CloseWindow() {
Close(LastActiveLayoutWindowID);
} RegisterCommand(Command_CloseWindow, "");
SaveResult TrySavingBuffer(Buffer *buffer) {
if (buffer->special || buffer->garbage) {
return SAVE_NO;
}
if (buffer->dirty) {
SaveResult save = SaveMessageBox(buffer->name);
if (save == SAVE_CANCEL) {
return SAVE_CANCEL;
} else if (save == SAVE_YES) {
SaveBuffer(buffer);
return SAVE_YES;
} else {
return SAVE_NO;
}
}
return SAVE_YES;
}
SaveResult TrySavingAllBuffers() {
For (Buffers) {
if (it->garbage || it->special || it->dont_try_to_save_in_bulk_ops) {
continue;
}
if (it->dirty) {
SaveResult save = SaveMessageBox(it->name);
if (save == SAVE_CANCEL) {
return SAVE_CANCEL;
} else if (save == SAVE_YES) {
SaveBuffer(it);
}
}
}
return SAVE_YES;
}
String UIYesNoCancel(mco_coro *co, BSet main, String question) {
String Coro_YesNoCancel(mco_coro *co, BSet main, String question) {
JumpGarbageBuffer(&main);
NextActiveWindowID = main.window->id;
@@ -843,7 +763,7 @@ void Coro_Close(mco_coro *co) {
Scratch scratch;
String question = Format(scratch, "Do you want to save [%S] before closing?", main.buffer->name);
String result = UIYesNoCancel(co, main, question);
String result = Coro_YesNoCancel(co, main, question);
if (result == "Yes") {
SaveBuffer(main.buffer);
Close(main.buffer->id);
@@ -858,27 +778,57 @@ void Command_Close() {
CoAdd(Coro_Close);
} RegisterCommand(Command_Close, "ctrl-w");
void Command_Quit() {
if (TrySavingAllBuffers() != SAVE_CANCEL) {
// Considerations with coroutines:
// 1. Does scratch memory leak across Yield boundary? Or interacts badly with Yield stuff in any way?
// 2. Are pointers and globals correct over time? Or might they get deleted etc.
String Coro_CloseAllEx(mco_coro *co) {
Scratch scratch;
BSet main = GetBSet(LastActiveLayoutWindowID);
Array<BufferID> buffers = {scratch};
For (Buffers) Add(&buffers, it->id);
ForItem (id, buffers) {
Buffer *it = GetBuffer(id);
if (it->special || !it->dirty) {
continue;
}
if (it->garbage || it->dont_try_to_save_in_bulk_ops) {
continue;
}
String question = Format(scratch, "Do you want to save [%S] before closing?", it->name);
String result = Coro_YesNoCancel(co, main, question);
it = GetBuffer(id, NULL);
if (it && result == "Yes") {
SaveBuffer(it);
} else if (result == "No") {
} else if (result == "Cancel") {
return "Cancel";
} ElseInvalidCodepath();
}
For(Buffers) {
Close(it->id);
}
return "Yes";
}
void Coro_Quit(mco_coro *co) {
String res = Coro_CloseAllEx(co);
if (res != "Cancel") {
AppIsRunning = false;
}
}
void Command_Quit() {
CoAdd(Coro_Quit);
} RegisterCommand(Command_Quit, "");
void Coro_CloseAll(mco_coro *co) {
Coro_CloseAllEx(co);
}
void Command_CloseAll() {
if (TrySavingAllBuffers() != SAVE_CANCEL) {
For (Views) {
if (it->special) {
continue;
}
Close(it->id);
}
For (Buffers) {
if (it->special) {
continue;
}
Close(it->id);
}
}
CoAdd(Coro_CloseAll);
} RegisterCommand(Command_CloseAll, "");
void Command_JumpBack() {