Replace SDL dialogs with coroutine UI
This commit is contained in:
@@ -1402,7 +1402,7 @@ bool IsNull(Buffer *buffer) {
|
|||||||
void Close(BufferID id) {
|
void Close(BufferID id) {
|
||||||
Buffer *buffer = GetBuffer(id, NULL);
|
Buffer *buffer = GetBuffer(id, NULL);
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
if (buffer->id.id == 0) {
|
if (buffer->id.id == 0 || buffer->special) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -158,51 +158,6 @@ void Appendf(View *view, const char *fmt, ...) {
|
|||||||
Append(view, string, true);
|
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, ...) {
|
void ReportErrorf(const char *fmt, ...) {
|
||||||
Scratch scratch;
|
Scratch scratch;
|
||||||
STRING_FORMAT(scratch, fmt, string);
|
STRING_FORMAT(scratch, fmt, string);
|
||||||
@@ -747,42 +702,7 @@ void Command_CloseWindow() {
|
|||||||
Close(LastActiveLayoutWindowID);
|
Close(LastActiveLayoutWindowID);
|
||||||
} RegisterCommand(Command_CloseWindow, "");
|
} RegisterCommand(Command_CloseWindow, "");
|
||||||
|
|
||||||
SaveResult TrySavingBuffer(Buffer *buffer) {
|
String Coro_YesNoCancel(mco_coro *co, BSet main, String question) {
|
||||||
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) {
|
|
||||||
JumpGarbageBuffer(&main);
|
JumpGarbageBuffer(&main);
|
||||||
NextActiveWindowID = main.window->id;
|
NextActiveWindowID = main.window->id;
|
||||||
|
|
||||||
@@ -843,7 +763,7 @@ void Coro_Close(mco_coro *co) {
|
|||||||
|
|
||||||
Scratch scratch;
|
Scratch scratch;
|
||||||
String question = Format(scratch, "Do you want to save [%S] before closing?", main.buffer->name);
|
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") {
|
if (result == "Yes") {
|
||||||
SaveBuffer(main.buffer);
|
SaveBuffer(main.buffer);
|
||||||
Close(main.buffer->id);
|
Close(main.buffer->id);
|
||||||
@@ -858,27 +778,57 @@ void Command_Close() {
|
|||||||
CoAdd(Coro_Close);
|
CoAdd(Coro_Close);
|
||||||
} RegisterCommand(Command_Close, "ctrl-w");
|
} RegisterCommand(Command_Close, "ctrl-w");
|
||||||
|
|
||||||
void Command_Quit() {
|
// Considerations with coroutines:
|
||||||
if (TrySavingAllBuffers() != SAVE_CANCEL) {
|
// 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;
|
AppIsRunning = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Command_Quit() {
|
||||||
|
CoAdd(Coro_Quit);
|
||||||
} RegisterCommand(Command_Quit, "");
|
} RegisterCommand(Command_Quit, "");
|
||||||
|
|
||||||
|
void Coro_CloseAll(mco_coro *co) {
|
||||||
|
Coro_CloseAllEx(co);
|
||||||
|
}
|
||||||
|
|
||||||
void Command_CloseAll() {
|
void Command_CloseAll() {
|
||||||
if (TrySavingAllBuffers() != SAVE_CANCEL) {
|
CoAdd(Coro_CloseAll);
|
||||||
For (Views) {
|
|
||||||
if (it->special) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Close(it->id);
|
|
||||||
}
|
|
||||||
For (Buffers) {
|
|
||||||
if (it->special) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Close(it->id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} RegisterCommand(Command_CloseAll, "");
|
} RegisterCommand(Command_CloseAll, "");
|
||||||
|
|
||||||
void Command_JumpBack() {
|
void Command_JumpBack() {
|
||||||
|
|||||||
Reference in New Issue
Block a user