mirror of
https://github.com/kichikuou/xsystem35-sdl2.git
synced 2026-10-13 17:48:12 +03:00
239 lines
6.2 KiB
C
239 lines
6.2 KiB
C
/*
|
|
* menu.c popup menu
|
|
*
|
|
* Copyright (C) 2000- Masaki Chikama (Wren) <masaki-c@is.aist-nara.ac.jp>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#ifdef __EMSCRIPTEN__
|
|
|
|
#include <stdio.h>
|
|
#include <emscripten.h>
|
|
|
|
#include "portab.h"
|
|
#include "menu.h"
|
|
|
|
void menu_open(void) {
|
|
return;
|
|
}
|
|
|
|
void menu_quitmenu_open(void) {
|
|
return;
|
|
}
|
|
|
|
void menu_init(void) {
|
|
return;
|
|
}
|
|
|
|
EM_JS(void, menu_setSkipState, (bool enabled, bool activated), {
|
|
xsystem35.shell.setSkipButtonState(enabled, activated);
|
|
});
|
|
|
|
#else // !__EMSCRIPTEN__
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <SDL.h>
|
|
|
|
#include "portab.h"
|
|
#include "event.h"
|
|
#include "system.h"
|
|
#include "nact.h"
|
|
#include "menu.h"
|
|
#include "gfx.h"
|
|
#include "msgskip.h"
|
|
#include "modal.h"
|
|
#include "volume.h"
|
|
|
|
// The middle-click popup menu.
|
|
|
|
// What the popup menu resolved to.
|
|
enum menu_action {
|
|
MENU_ACTION_NONE,
|
|
MENU_ACTION_VOLUME,
|
|
MENU_ACTION_RESET,
|
|
MENU_ACTION_QUIT,
|
|
};
|
|
|
|
struct popup_state {
|
|
modal base;
|
|
mu_Rect rect; // popup window rect from the most recent frame
|
|
enum menu_action action; // what the user selected
|
|
// A three-finger tap opens the menu, but SDL_GetNumTouchFingers() reports the
|
|
// live finger count, so it already returns 3 while the first of the three
|
|
// near-simultaneous FINGERDOWN events is being processed - the menu opens on
|
|
// that first event. The other two FINGERDOWN events of the same gesture are
|
|
// still queued and, once the menu is up, would be seen as taps that dismiss
|
|
// it. Ignore touches until every finger has lifted, then arm tap-to-dismiss.
|
|
bool touch_armed;
|
|
};
|
|
|
|
#ifndef _WIN32 // Windows uses the native menu bar
|
|
|
|
// Message-skip state, kept in sync via menu_setSkipState().
|
|
static bool skip_enabled = true;
|
|
static bool skip_activated;
|
|
|
|
static bool point_in_rect(int x, int y, mu_Rect r) {
|
|
return x >= r.x && x < r.x + r.w && y >= r.y && y < r.y + r.h;
|
|
}
|
|
|
|
static bool menu_popup_handler(const SDL_Event *e, modal *modal) {
|
|
struct popup_state *st = (struct popup_state *)modal;
|
|
if (e->type == SDL_MOUSEBUTTONUP) {
|
|
if (e->button.button == SDL_BUTTON_RIGHT ||
|
|
!point_in_rect(e->button.x, e->button.y, st->rect))
|
|
st->base.cancelled = true;
|
|
} else if (e->type == SDL_FINGERUP) {
|
|
// Arm tap-to-dismiss once the opening gesture's fingers are all lifted.
|
|
if (SDL_GetNumTouchFingers(e->tfinger.touchId) == 0)
|
|
st->touch_armed = true;
|
|
} else if (e->type == SDL_FINGERDOWN && st->touch_armed) {
|
|
// A tap outside the menu dismisses it.
|
|
SDL_Point p = event_get_touch_position(&e->tfinger);
|
|
if (!point_in_rect(p.x, p.y, st->rect))
|
|
st->base.cancelled = true;
|
|
}
|
|
return modal_default_handler(e, modal);
|
|
}
|
|
|
|
static bool menu_build(mu_Context *ctx, modal *modal) {
|
|
struct popup_state *st = (struct popup_state *)modal;
|
|
bool keep_open = true;
|
|
|
|
int rows = 5;
|
|
#ifdef __ANDROID__
|
|
rows--;
|
|
#endif
|
|
int row_h = ctx->style->size.y + ctx->style->padding * 2;
|
|
int w = 200;
|
|
// `rows` rows with (rows - 1) inter-row gaps, plus the window's body padding.
|
|
int h = rows * row_h + (rows - 1) * ctx->style->spacing + ctx->style->padding * 2;
|
|
mu_Rect r = modal_centered_rect(w, h);
|
|
st->rect = r;
|
|
|
|
if (mu_begin_window_ex(ctx, "menu", r,
|
|
MU_OPT_NOTITLE | MU_OPT_NORESIZE | MU_OPT_NOCLOSE | MU_OPT_NOSCROLL)) {
|
|
mu_layout_row(ctx, 1, (int[]){ -1 }, 0);
|
|
|
|
if (skip_enabled) {
|
|
int sk = skip_activated;
|
|
if (mu_checkbox(ctx, _("Message Skip"), &sk))
|
|
msgskip_activate(sk);
|
|
} else {
|
|
modal_disabled_checkbox(ctx, _("Message Skip"), skip_activated);
|
|
}
|
|
|
|
#ifndef __ANDROID__
|
|
int warp = nact->ags.mouse_warp_enabled;
|
|
if (mu_checkbox(ctx, _("Mouse Movement"), &warp))
|
|
nact->ags.mouse_warp_enabled = warp;
|
|
#endif
|
|
|
|
if (mu_button(ctx, _("Sound Settings"))) {
|
|
keep_open = false;
|
|
st->action = MENU_ACTION_VOLUME;
|
|
}
|
|
|
|
if (mu_button(ctx, _("Restart"))) {
|
|
keep_open = false;
|
|
st->action = MENU_ACTION_RESET;
|
|
}
|
|
|
|
if (mu_button(ctx, _("Quit"))) {
|
|
keep_open = false;
|
|
st->action = MENU_ACTION_QUIT;
|
|
}
|
|
mu_end_window(ctx);
|
|
}
|
|
|
|
if (st->base.cancelled)
|
|
keep_open = false;
|
|
|
|
return keep_open;
|
|
}
|
|
|
|
void menu_open(void) {
|
|
struct popup_state st = {
|
|
.base = { .build = menu_build, .handler = menu_popup_handler },
|
|
.action = MENU_ACTION_NONE,
|
|
};
|
|
modal_run(&st.base);
|
|
switch (st.action) {
|
|
case MENU_ACTION_VOLUME:
|
|
volume_dialog_open();
|
|
break;
|
|
case MENU_ACTION_RESET:
|
|
menu_resetmenu_open();
|
|
break;
|
|
case MENU_ACTION_QUIT:
|
|
menu_quitmenu_open();
|
|
break;
|
|
case MENU_ACTION_NONE:
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endif // !_WIN32
|
|
|
|
static bool confirm_lose_progress(const char *title, const char *confirm_label) {
|
|
const SDL_MessageBoxButtonData buttons[] = {
|
|
{ SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, 1, confirm_label },
|
|
{ SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, 0, _("Cancel") },
|
|
};
|
|
const SDL_MessageBoxData messagebox_data = {
|
|
.flags = SDL_MESSAGEBOX_INFORMATION,
|
|
.window = gfx_getWindow(),
|
|
.title = title,
|
|
.message = _("Any unsaved progress will be lost."),
|
|
.numbuttons = SDL_arraysize(buttons),
|
|
.buttons = buttons,
|
|
};
|
|
int buttonid = 0;
|
|
if (SDL_ShowMessageBox(&messagebox_data, &buttonid) < 0) {
|
|
WARNING("error displaying message box");
|
|
return false;
|
|
}
|
|
return buttonid == 1;
|
|
}
|
|
|
|
void menu_quitmenu_open(void) {
|
|
if (confirm_lose_progress(_("Quit game?"), _("Quit")))
|
|
nact_quit(false);
|
|
}
|
|
|
|
void menu_resetmenu_open(void) {
|
|
if (confirm_lose_progress(_("Restart game?"), _("Restart")))
|
|
nact_quit(true);
|
|
}
|
|
|
|
// On Windows, menu_open/menu_init/menu_setSkipState are provided by win/menubar.c.
|
|
#ifndef _WIN32
|
|
void menu_init(void) {
|
|
}
|
|
|
|
void menu_setSkipState(bool enabled, bool activated) {
|
|
skip_enabled = enabled;
|
|
skip_activated = activated;
|
|
}
|
|
#endif
|
|
|
|
#endif // !__EMSCRIPTEN__
|